1130803Smarcel/* Memory breakpoint operations for the remote server for GDB.
2130803Smarcel   Copyright 2002
3130803Smarcel   Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   Contributed by MontaVista Software.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "server.h"
25130803Smarcel
26130803Smarcelconst char *breakpoint_data;
27130803Smarcelint breakpoint_len;
28130803Smarcel
29130803Smarcel#define MAX_BREAKPOINT_LEN 8
30130803Smarcel
31130803Smarcelstruct breakpoint
32130803Smarcel{
33130803Smarcel  struct breakpoint *next;
34130803Smarcel  CORE_ADDR pc;
35130803Smarcel  unsigned char old_data[MAX_BREAKPOINT_LEN];
36130803Smarcel
37130803Smarcel  /* Non-zero iff we are stepping over this breakpoint.  */
38130803Smarcel  int reinserting;
39130803Smarcel
40130803Smarcel  /* Non-NULL iff this breakpoint was inserted to step over
41130803Smarcel     another one.  Points to the other breakpoint (which is also
42130803Smarcel     in the *next chain somewhere).  */
43130803Smarcel  struct breakpoint *breakpoint_to_reinsert;
44130803Smarcel
45130803Smarcel  /* Function to call when we hit this breakpoint.  */
46130803Smarcel  void (*handler) (CORE_ADDR);
47130803Smarcel};
48130803Smarcel
49130803Smarcelstruct breakpoint *breakpoints;
50130803Smarcel
51130803Smarcelvoid
52130803Smarcelset_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR))
53130803Smarcel{
54130803Smarcel  struct breakpoint *bp;
55130803Smarcel
56130803Smarcel  if (breakpoint_data == NULL)
57130803Smarcel    error ("Target does not support breakpoints.");
58130803Smarcel
59130803Smarcel  bp = malloc (sizeof (struct breakpoint));
60130803Smarcel  memset (bp, 0, sizeof (struct breakpoint));
61130803Smarcel
62130803Smarcel  (*the_target->read_memory) (where, bp->old_data,
63130803Smarcel			      breakpoint_len);
64130803Smarcel  (*the_target->write_memory) (where, breakpoint_data,
65130803Smarcel			       breakpoint_len);
66130803Smarcel
67130803Smarcel  bp->pc = where;
68130803Smarcel  bp->handler = handler;
69130803Smarcel
70130803Smarcel  bp->next = breakpoints;
71130803Smarcel  breakpoints = bp;
72130803Smarcel}
73130803Smarcel
74130803Smarcelstatic void
75130803Smarceldelete_breakpoint (struct breakpoint *bp)
76130803Smarcel{
77130803Smarcel  struct breakpoint *cur;
78130803Smarcel
79130803Smarcel  if (breakpoints == bp)
80130803Smarcel    {
81130803Smarcel      breakpoints = bp->next;
82130803Smarcel      (*the_target->write_memory) (bp->pc, bp->old_data,
83130803Smarcel				   breakpoint_len);
84130803Smarcel      free (bp);
85130803Smarcel      return;
86130803Smarcel    }
87130803Smarcel  cur = breakpoints;
88130803Smarcel  while (cur->next)
89130803Smarcel    {
90130803Smarcel      if (cur->next == bp)
91130803Smarcel	{
92130803Smarcel	  cur->next = bp->next;
93130803Smarcel	  (*the_target->write_memory) (bp->pc, bp->old_data,
94130803Smarcel				       breakpoint_len);
95130803Smarcel	  free (bp);
96130803Smarcel	  return;
97130803Smarcel	}
98130803Smarcel    }
99130803Smarcel  warning ("Could not find breakpoint in list.");
100130803Smarcel}
101130803Smarcel
102130803Smarcelstatic struct breakpoint *
103130803Smarcelfind_breakpoint_at (CORE_ADDR where)
104130803Smarcel{
105130803Smarcel  struct breakpoint *bp = breakpoints;
106130803Smarcel
107130803Smarcel  while (bp != NULL)
108130803Smarcel    {
109130803Smarcel      if (bp->pc == where)
110130803Smarcel	return bp;
111130803Smarcel      bp = bp->next;
112130803Smarcel    }
113130803Smarcel
114130803Smarcel  return NULL;
115130803Smarcel}
116130803Smarcel
117130803Smarcelstatic void
118130803Smarcelreinsert_breakpoint_handler (CORE_ADDR stop_pc)
119130803Smarcel{
120130803Smarcel  struct breakpoint *stop_bp, *orig_bp;
121130803Smarcel
122130803Smarcel  stop_bp = find_breakpoint_at (stop_pc);
123130803Smarcel  if (stop_bp == NULL)
124130803Smarcel    error ("lost the stopping breakpoint.");
125130803Smarcel
126130803Smarcel  orig_bp = stop_bp->breakpoint_to_reinsert;
127130803Smarcel  if (orig_bp == NULL)
128130803Smarcel    error ("no breakpoint to reinsert");
129130803Smarcel
130130803Smarcel  (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
131130803Smarcel			       breakpoint_len);
132130803Smarcel  orig_bp->reinserting = 0;
133130803Smarcel  delete_breakpoint (stop_bp);
134130803Smarcel}
135130803Smarcel
136130803Smarcelvoid
137130803Smarcelreinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
138130803Smarcel{
139130803Smarcel  struct breakpoint *bp, *orig_bp;
140130803Smarcel
141130803Smarcel  set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
142130803Smarcel
143130803Smarcel  orig_bp = find_breakpoint_at (stop_pc);
144130803Smarcel  if (orig_bp == NULL)
145130803Smarcel    error ("Could not find original breakpoint in list.");
146130803Smarcel
147130803Smarcel  bp = find_breakpoint_at (stop_at);
148130803Smarcel  if (bp == NULL)
149130803Smarcel    error ("Could not find breakpoint in list (reinserting by breakpoint).");
150130803Smarcel  bp->breakpoint_to_reinsert = orig_bp;
151130803Smarcel
152130803Smarcel  (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
153130803Smarcel			       breakpoint_len);
154130803Smarcel  orig_bp->reinserting = 1;
155130803Smarcel}
156130803Smarcel
157130803Smarcelvoid
158130803Smarceluninsert_breakpoint (CORE_ADDR stopped_at)
159130803Smarcel{
160130803Smarcel  struct breakpoint *bp;
161130803Smarcel
162130803Smarcel  bp = find_breakpoint_at (stopped_at);
163130803Smarcel  if (bp == NULL)
164130803Smarcel    error ("Could not find breakpoint in list (uninserting).");
165130803Smarcel
166130803Smarcel  (*the_target->write_memory) (bp->pc, bp->old_data,
167130803Smarcel			       breakpoint_len);
168130803Smarcel  bp->reinserting = 1;
169130803Smarcel}
170130803Smarcel
171130803Smarcelvoid
172130803Smarcelreinsert_breakpoint (CORE_ADDR stopped_at)
173130803Smarcel{
174130803Smarcel  struct breakpoint *bp;
175130803Smarcel
176130803Smarcel  bp = find_breakpoint_at (stopped_at);
177130803Smarcel  if (bp == NULL)
178130803Smarcel    error ("Could not find breakpoint in list (uninserting).");
179130803Smarcel  if (! bp->reinserting)
180130803Smarcel    error ("Breakpoint already inserted at reinsert time.");
181130803Smarcel
182130803Smarcel  (*the_target->write_memory) (bp->pc, breakpoint_data,
183130803Smarcel			       breakpoint_len);
184130803Smarcel  bp->reinserting = 0;
185130803Smarcel}
186130803Smarcel
187130803Smarcelint
188130803Smarcelcheck_breakpoints (CORE_ADDR stop_pc)
189130803Smarcel{
190130803Smarcel  struct breakpoint *bp;
191130803Smarcel
192130803Smarcel  bp = find_breakpoint_at (stop_pc);
193130803Smarcel  if (bp == NULL)
194130803Smarcel    return 0;
195130803Smarcel  if (bp->reinserting)
196130803Smarcel    {
197130803Smarcel      warning ("Hit a removed breakpoint?");
198130803Smarcel      return 0;
199130803Smarcel    }
200130803Smarcel
201130803Smarcel  (*bp->handler) (bp->pc);
202130803Smarcel  return 1;
203130803Smarcel}
204130803Smarcel
205130803Smarcelvoid
206130803Smarcelset_breakpoint_data (const char *bp_data, int bp_len)
207130803Smarcel{
208130803Smarcel  breakpoint_data = bp_data;
209130803Smarcel  breakpoint_len = bp_len;
210130803Smarcel}
211130803Smarcel
212130803Smarcelvoid
213130803Smarcelcheck_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len)
214130803Smarcel{
215130803Smarcel  struct breakpoint *bp = breakpoints;
216130803Smarcel  CORE_ADDR mem_end = mem_addr + mem_len;
217130803Smarcel
218130803Smarcel  for (; bp != NULL; bp = bp->next)
219130803Smarcel    {
220130803Smarcel      CORE_ADDR bp_end = bp->pc + breakpoint_len;
221130803Smarcel      CORE_ADDR start, end;
222130803Smarcel      int copy_offset, copy_len, buf_offset;
223130803Smarcel
224130803Smarcel      if (mem_addr >= bp_end)
225130803Smarcel	continue;
226130803Smarcel      if (bp->pc >= mem_end)
227130803Smarcel	continue;
228130803Smarcel
229130803Smarcel      start = bp->pc;
230130803Smarcel      if (mem_addr > start)
231130803Smarcel	start = mem_addr;
232130803Smarcel
233130803Smarcel      end = bp_end;
234130803Smarcel      if (end > mem_end)
235130803Smarcel	end = mem_end;
236130803Smarcel
237130803Smarcel      copy_len = end - start;
238130803Smarcel      copy_offset = start - bp->pc;
239130803Smarcel      buf_offset = start - mem_addr;
240130803Smarcel
241130803Smarcel      memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
242130803Smarcel    }
243130803Smarcel}
244130803Smarcel
245130803Smarcelvoid
246130803Smarcelcheck_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len)
247130803Smarcel{
248130803Smarcel  struct breakpoint *bp = breakpoints;
249130803Smarcel  CORE_ADDR mem_end = mem_addr + mem_len;
250130803Smarcel
251130803Smarcel  for (; bp != NULL; bp = bp->next)
252130803Smarcel    {
253130803Smarcel      CORE_ADDR bp_end = bp->pc + breakpoint_len;
254130803Smarcel      CORE_ADDR start, end;
255130803Smarcel      int copy_offset, copy_len, buf_offset;
256130803Smarcel
257130803Smarcel      if (mem_addr >= bp_end)
258130803Smarcel	continue;
259130803Smarcel      if (bp->pc >= mem_end)
260130803Smarcel	continue;
261130803Smarcel
262130803Smarcel      start = bp->pc;
263130803Smarcel      if (mem_addr > start)
264130803Smarcel	start = mem_addr;
265130803Smarcel
266130803Smarcel      end = bp_end;
267130803Smarcel      if (end > mem_end)
268130803Smarcel	end = mem_end;
269130803Smarcel
270130803Smarcel      copy_len = end - start;
271130803Smarcel      copy_offset = start - bp->pc;
272130803Smarcel      buf_offset = start - mem_addr;
273130803Smarcel
274130803Smarcel      memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
275130803Smarcel      if (bp->reinserting == 0)
276130803Smarcel	memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
277130803Smarcel    }
278130803Smarcel}
279