gdb/
[deliverable/binutils-gdb.git] / gdb / gdbserver / mem-break.c
1 /* Memory breakpoint operations for the remote server for GDB.
2 Copyright (C) 2002, 2003, 2005, 2007, 2008, 2009, 2010
3 Free Software Foundation, Inc.
4
5 Contributed by MontaVista Software.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "server.h"
23
24 const unsigned char *breakpoint_data;
25 int breakpoint_len;
26
27 #define MAX_BREAKPOINT_LEN 8
28
29 /* The type of a breakpoint. */
30 enum bkpt_type
31 {
32 /* A basic-software-single-step breakpoint. */
33 reinsert_breakpoint,
34
35 /* Any other breakpoint type that doesn't require specific
36 treatment goes here. E.g., an event breakpoint. */
37 other_breakpoint,
38 };
39
40 struct breakpoint
41 {
42 struct breakpoint *next;
43 CORE_ADDR pc;
44 unsigned char old_data[MAX_BREAKPOINT_LEN];
45
46 /* Non-zero if this breakpoint is currently inserted in the
47 inferior. */
48 int inserted;
49
50 /* The breakpoint's type. */
51 enum bkpt_type type;
52
53 /* Function to call when we hit this breakpoint. If it returns 1,
54 the breakpoint shall be deleted; 0, it will be left inserted. */
55 int (*handler) (CORE_ADDR);
56 };
57
58 static void uninsert_breakpoint (struct breakpoint *bp);
59
60 static struct breakpoint *
61 set_raw_breakpoint_at (CORE_ADDR where)
62 {
63 struct process_info *proc = current_process ();
64 struct breakpoint *bp;
65 int err;
66
67 if (breakpoint_data == NULL)
68 error ("Target does not support breakpoints.");
69
70 bp = xcalloc (1, sizeof (*bp));
71 bp->pc = where;
72
73 err = (*the_target->read_memory) (where, bp->old_data,
74 breakpoint_len);
75 if (err != 0)
76 {
77 if (debug_threads)
78 fprintf (stderr,
79 "Failed to read shadow memory of"
80 " breakpoint at 0x%s (%s).\n",
81 paddress (where), strerror (err));
82 free (bp);
83 return NULL;
84 }
85
86 err = (*the_target->write_memory) (where, breakpoint_data,
87 breakpoint_len);
88 if (err != 0)
89 {
90 if (debug_threads)
91 fprintf (stderr,
92 "Failed to insert breakpoint at 0x%s (%s).\n",
93 paddress (where), strerror (err));
94 free (bp);
95 return NULL;
96 }
97
98 /* Link the breakpoint in. */
99 bp->inserted = 1;
100 bp->next = proc->breakpoints;
101 proc->breakpoints = bp;
102 return bp;
103 }
104
105 struct breakpoint *
106 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
107 {
108 struct process_info *proc = current_process ();
109 struct breakpoint *bp;
110
111 bp = set_raw_breakpoint_at (where);
112
113 if (bp == NULL)
114 {
115 /* warn? */
116 return NULL;
117 }
118
119 bp = xcalloc (1, sizeof (struct breakpoint));
120 bp->type = other_breakpoint;
121 bp->handler = handler;
122
123 bp->next = proc->breakpoints;
124 proc->breakpoints = bp;
125
126 return bp;
127 }
128
129 static void
130 delete_breakpoint (struct breakpoint *todel)
131 {
132 struct process_info *proc = current_process ();
133 struct breakpoint *bp, **bp_link;
134
135 bp = proc->breakpoints;
136 bp_link = &proc->breakpoints;
137
138 while (bp)
139 {
140 if (bp == todel)
141 {
142 *bp_link = bp->next;
143
144 uninsert_breakpoint (bp);
145 free (bp);
146 return;
147 }
148 else
149 {
150 bp_link = &bp->next;
151 bp = *bp_link;
152 }
153 }
154
155 warning ("Could not find breakpoint in list.");
156 }
157
158 static struct breakpoint *
159 find_breakpoint_at (CORE_ADDR where)
160 {
161 struct process_info *proc = current_process ();
162 struct breakpoint *bp = proc->breakpoints;
163
164 while (bp != NULL)
165 {
166 if (bp->pc == where)
167 return bp;
168 bp = bp->next;
169 }
170
171 return NULL;
172 }
173
174 void
175 delete_breakpoint_at (CORE_ADDR addr)
176 {
177 struct breakpoint *bp = find_breakpoint_at (addr);
178 if (bp != NULL)
179 delete_breakpoint (bp);
180 }
181
182 void
183 set_reinsert_breakpoint (CORE_ADDR stop_at)
184 {
185 struct breakpoint *bp;
186
187 bp = set_breakpoint_at (stop_at, NULL);
188
189 bp->type = reinsert_breakpoint;
190 }
191
192 void
193 delete_reinsert_breakpoints (void)
194 {
195 struct process_info *proc = current_process ();
196 struct breakpoint *bp, **bp_link;
197
198 bp = proc->breakpoints;
199 bp_link = &proc->breakpoints;
200
201 while (bp)
202 {
203 if (bp->type == reinsert_breakpoint)
204 {
205 *bp_link = bp->next;
206
207 /* If something goes wrong, maybe this is a shared library
208 breakpoint, and the shared library has been unmapped.
209 Assume the breakpoint is gone anyway. */
210 uninsert_breakpoint (bp);
211 free (bp);
212
213 bp = *bp_link;
214 }
215 else
216 {
217 bp_link = &bp->next;
218 bp = *bp_link;
219 }
220 }
221 }
222
223 static void
224 uninsert_breakpoint (struct breakpoint *bp)
225 {
226 if (bp->inserted)
227 {
228 int err;
229
230 bp->inserted = 0;
231 err = (*the_target->write_memory) (bp->pc, bp->old_data,
232 breakpoint_len);
233 if (err != 0)
234 {
235 bp->inserted = 1;
236
237 if (debug_threads)
238 fprintf (stderr,
239 "Failed to uninsert raw breakpoint at 0x%s (%s).\n",
240 paddress (bp->pc), strerror (err));
241 }
242 }
243 }
244
245 void
246 uninsert_breakpoints_at (CORE_ADDR pc)
247 {
248 struct breakpoint *bp;
249
250 bp = find_breakpoint_at (pc);
251 if (bp == NULL)
252 {
253 /* This can happen when we remove all breakpoints while handling
254 a step-over. */
255 if (debug_threads)
256 fprintf (stderr,
257 "Could not find breakpoint at 0x%s "
258 "in list (uninserting).\n",
259 paddress (pc));
260 return;
261 }
262
263 if (bp->inserted)
264 uninsert_breakpoint (bp);
265 }
266
267 static void
268 reinsert_raw_breakpoint (struct breakpoint *bp)
269 {
270 int err;
271
272 if (bp->inserted)
273 error ("Breakpoint already inserted at reinsert time.");
274
275 err = (*the_target->write_memory) (bp->pc, breakpoint_data,
276 breakpoint_len);
277 if (err == 0)
278 bp->inserted = 1;
279 else if (debug_threads)
280 fprintf (stderr,
281 "Failed to reinsert breakpoint at 0x%s (%s).\n",
282 paddress (bp->pc), strerror (err));
283 }
284
285 void
286 reinsert_breakpoints_at (CORE_ADDR pc)
287 {
288 struct breakpoint *bp;
289
290 bp = find_breakpoint_at (pc);
291 if (bp == NULL)
292 {
293 /* This can happen when we remove all breakpoints while handling
294 a step-over. */
295 if (debug_threads)
296 fprintf (stderr,
297 "Could not find breakpoint at 0x%s "
298 "in list (reinserting).\n",
299 paddress (pc));
300 return;
301 }
302
303 reinsert_raw_breakpoint (bp);
304 }
305
306 void
307 check_breakpoints (CORE_ADDR stop_pc)
308 {
309 struct process_info *proc = current_process ();
310 struct breakpoint *bp, **bp_link;
311
312 bp = proc->breakpoints;
313 bp_link = &proc->breakpoints;
314
315 while (bp)
316 {
317 if (bp->pc == stop_pc)
318 {
319 if (!bp->inserted)
320 {
321 warning ("Hit a removed breakpoint?");
322 return;
323 }
324
325 if (bp->handler != NULL && (*bp->handler) (stop_pc))
326 {
327 *bp_link = bp->next;
328
329 delete_breakpoint (bp);
330
331 bp = *bp_link;
332 continue;
333 }
334 }
335
336 bp_link = &bp->next;
337 bp = *bp_link;
338 }
339 }
340
341 void
342 set_breakpoint_data (const unsigned char *bp_data, int bp_len)
343 {
344 breakpoint_data = bp_data;
345 breakpoint_len = bp_len;
346 }
347
348 int
349 breakpoint_here (CORE_ADDR addr)
350 {
351 struct process_info *proc = current_process ();
352 struct breakpoint *bp;
353
354 for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
355 if (bp->pc == addr)
356 return 1;
357
358 return 0;
359 }
360
361 int
362 breakpoint_inserted_here (CORE_ADDR addr)
363 {
364 struct process_info *proc = current_process ();
365 struct breakpoint *bp;
366
367 for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
368 if (bp->pc == addr && bp->inserted)
369 return 1;
370
371 return 0;
372 }
373
374 void
375 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
376 {
377 struct process_info *proc = current_process ();
378 struct breakpoint *bp = proc->breakpoints;
379 CORE_ADDR mem_end = mem_addr + mem_len;
380
381 for (; bp != NULL; bp = bp->next)
382 {
383 CORE_ADDR bp_end = bp->pc + breakpoint_len;
384 CORE_ADDR start, end;
385 int copy_offset, copy_len, buf_offset;
386
387 if (mem_addr >= bp_end)
388 continue;
389 if (bp->pc >= mem_end)
390 continue;
391
392 start = bp->pc;
393 if (mem_addr > start)
394 start = mem_addr;
395
396 end = bp_end;
397 if (end > mem_end)
398 end = mem_end;
399
400 copy_len = end - start;
401 copy_offset = start - bp->pc;
402 buf_offset = start - mem_addr;
403
404 memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
405 }
406 }
407
408 void
409 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
410 {
411 struct process_info *proc = current_process ();
412 struct breakpoint *bp = proc->breakpoints;
413 CORE_ADDR mem_end = mem_addr + mem_len;
414
415 for (; bp != NULL; bp = bp->next)
416 {
417 CORE_ADDR bp_end = bp->pc + breakpoint_len;
418 CORE_ADDR start, end;
419 int copy_offset, copy_len, buf_offset;
420
421 if (mem_addr >= bp_end)
422 continue;
423 if (bp->pc >= mem_end)
424 continue;
425
426 start = bp->pc;
427 if (mem_addr > start)
428 start = mem_addr;
429
430 end = bp_end;
431 if (end > mem_end)
432 end = mem_end;
433
434 copy_len = end - start;
435 copy_offset = start - bp->pc;
436 buf_offset = start - mem_addr;
437
438 memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
439 if (bp->inserted)
440 memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
441 }
442 }
443
444 /* Delete all breakpoints, and un-insert them from the inferior. */
445
446 void
447 delete_all_breakpoints (void)
448 {
449 struct process_info *proc = current_process ();
450
451 while (proc->breakpoints)
452 delete_breakpoint (proc->breakpoints);
453 }
454
455 /* Release all breakpoints, but do not try to un-insert them from the
456 inferior. */
457
458 void
459 free_all_breakpoints (struct process_info *proc)
460 {
461 struct breakpoint *bp;
462
463 while (proc->breakpoints)
464 {
465 bp = proc->breakpoints;
466 proc->breakpoints = bp->next;
467 free (bp);
468 }
469 }
This page took 0.041004 seconds and 5 git commands to generate.