Commit | Line | Data |
---|---|---|
611cb4a5 | 1 | /* Memory breakpoint operations for the remote server for GDB. |
4c38e0a4 | 2 | Copyright (C) 2002, 2003, 2005, 2007, 2008, 2009, 2010 |
0fb0cc75 | 3 | Free Software Foundation, Inc. |
611cb4a5 DJ |
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 | |
a9762ec7 | 11 | the Free Software Foundation; either version 3 of the License, or |
611cb4a5 DJ |
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 | |
a9762ec7 | 20 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
611cb4a5 DJ |
21 | |
22 | #include "server.h" | |
23 | ||
f450004a | 24 | const unsigned char *breakpoint_data; |
611cb4a5 DJ |
25 | int breakpoint_len; |
26 | ||
27 | #define MAX_BREAKPOINT_LEN 8 | |
28 | ||
8b07ae33 PA |
29 | /* GDB will never try to install multiple breakpoints at the same |
30 | address. But, we need to keep track of internal breakpoints too, | |
31 | and so we do need to be able to install multiple breakpoints at the | |
32 | same address transparently. We keep track of two different, and | |
33 | closely related structures. A raw breakpoint, which manages the | |
34 | low level, close to the metal aspect of a breakpoint. It holds the | |
35 | breakpoint address, and a buffer holding a copy of the instructions | |
36 | that would be in memory had not been a breakpoint there (we call | |
37 | that the shadow memory of the breakpoint). We occasionally need to | |
38 | temporarilly uninsert a breakpoint without the client knowing about | |
39 | it (e.g., to step over an internal breakpoint), so we keep an | |
40 | `inserted' state associated with this low level breakpoint | |
41 | structure. There can only be one such object for a given address. | |
42 | Then, we have (a bit higher level) breakpoints. This structure | |
43 | holds a callback to be called whenever a breakpoint is hit, a | |
44 | high-level type, and a link to a low level raw breakpoint. There | |
45 | can be many high-level breakpoints at the same address, and all of | |
46 | them will point to the same raw breakpoint, which is reference | |
47 | counted. */ | |
48 | ||
49 | /* The low level, physical, raw breakpoint. */ | |
50 | struct raw_breakpoint | |
51 | { | |
52 | struct raw_breakpoint *next; | |
53 | ||
54 | /* A reference count. Each high level breakpoint referencing this | |
55 | raw breakpoint accounts for one reference. */ | |
56 | int refcount; | |
57 | ||
58 | /* The breakpoint's insertion address. There can only be one raw | |
59 | breakpoint for a given PC. */ | |
60 | CORE_ADDR pc; | |
61 | ||
62 | /* The breakpoint's shadow memory. */ | |
63 | unsigned char old_data[MAX_BREAKPOINT_LEN]; | |
64 | ||
65 | /* Non-zero if this breakpoint is currently inserted in the | |
66 | inferior. */ | |
67 | int inserted; | |
d3bbe7a0 PA |
68 | |
69 | /* Non-zero if this breakpoint is currently disabled because we no | |
70 | longer detect it as inserted. */ | |
71 | int shlib_disabled; | |
8b07ae33 PA |
72 | }; |
73 | ||
414a389f PA |
74 | /* The type of a breakpoint. */ |
75 | enum bkpt_type | |
76 | { | |
8b07ae33 PA |
77 | /* A GDB breakpoint, requested with a Z0 packet. */ |
78 | gdb_breakpoint, | |
79 | ||
414a389f PA |
80 | /* A basic-software-single-step breakpoint. */ |
81 | reinsert_breakpoint, | |
82 | ||
83 | /* Any other breakpoint type that doesn't require specific | |
84 | treatment goes here. E.g., an event breakpoint. */ | |
85 | other_breakpoint, | |
86 | }; | |
87 | ||
8b07ae33 | 88 | /* A high level (in gdbserver's perspective) breakpoint. */ |
611cb4a5 DJ |
89 | struct breakpoint |
90 | { | |
91 | struct breakpoint *next; | |
611cb4a5 | 92 | |
414a389f PA |
93 | /* The breakpoint's type. */ |
94 | enum bkpt_type type; | |
95 | ||
8b07ae33 PA |
96 | /* Link to this breakpoint's raw breakpoint. This is always |
97 | non-NULL. */ | |
98 | struct raw_breakpoint *raw; | |
99 | ||
b65d95c5 | 100 | /* Function to call when we hit this breakpoint. If it returns 1, |
8b07ae33 PA |
101 | the breakpoint shall be deleted; 0 or if this callback is NULL, |
102 | it will be left inserted. */ | |
b65d95c5 | 103 | int (*handler) (CORE_ADDR); |
611cb4a5 DJ |
104 | }; |
105 | ||
8b07ae33 PA |
106 | static struct raw_breakpoint * |
107 | find_raw_breakpoint_at (CORE_ADDR where) | |
108 | { | |
109 | struct process_info *proc = current_process (); | |
110 | struct raw_breakpoint *bp; | |
414a389f | 111 | |
8b07ae33 PA |
112 | for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) |
113 | if (bp->pc == where) | |
114 | return bp; | |
115 | ||
116 | return NULL; | |
117 | } | |
118 | ||
119 | static struct raw_breakpoint * | |
d50171e4 | 120 | set_raw_breakpoint_at (CORE_ADDR where) |
611cb4a5 | 121 | { |
95954743 | 122 | struct process_info *proc = current_process (); |
8b07ae33 | 123 | struct raw_breakpoint *bp; |
d50171e4 | 124 | int err; |
611cb4a5 DJ |
125 | |
126 | if (breakpoint_data == NULL) | |
127 | error ("Target does not support breakpoints."); | |
128 | ||
8b07ae33 PA |
129 | bp = find_raw_breakpoint_at (where); |
130 | if (bp != NULL) | |
131 | { | |
132 | bp->refcount++; | |
133 | return bp; | |
134 | } | |
135 | ||
d50171e4 PA |
136 | bp = xcalloc (1, sizeof (*bp)); |
137 | bp->pc = where; | |
8b07ae33 | 138 | bp->refcount = 1; |
611cb4a5 | 139 | |
d50171e4 PA |
140 | err = (*the_target->read_memory) (where, bp->old_data, |
141 | breakpoint_len); | |
142 | if (err != 0) | |
143 | { | |
144 | if (debug_threads) | |
145 | fprintf (stderr, | |
146 | "Failed to read shadow memory of" | |
147 | " breakpoint at 0x%s (%s).\n", | |
148 | paddress (where), strerror (err)); | |
149 | free (bp); | |
150 | return NULL; | |
151 | } | |
611cb4a5 | 152 | |
d50171e4 PA |
153 | err = (*the_target->write_memory) (where, breakpoint_data, |
154 | breakpoint_len); | |
155 | if (err != 0) | |
156 | { | |
157 | if (debug_threads) | |
158 | fprintf (stderr, | |
159 | "Failed to insert breakpoint at 0x%s (%s).\n", | |
160 | paddress (where), strerror (err)); | |
161 | free (bp); | |
162 | return NULL; | |
163 | } | |
164 | ||
165 | /* Link the breakpoint in. */ | |
166 | bp->inserted = 1; | |
8b07ae33 PA |
167 | bp->next = proc->raw_breakpoints; |
168 | proc->raw_breakpoints = bp; | |
d50171e4 PA |
169 | return bp; |
170 | } | |
171 | ||
414a389f | 172 | struct breakpoint * |
d50171e4 PA |
173 | set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) |
174 | { | |
175 | struct process_info *proc = current_process (); | |
176 | struct breakpoint *bp; | |
8b07ae33 | 177 | struct raw_breakpoint *raw; |
d50171e4 | 178 | |
8b07ae33 | 179 | raw = set_raw_breakpoint_at (where); |
d50171e4 | 180 | |
8b07ae33 | 181 | if (raw == NULL) |
d50171e4 PA |
182 | { |
183 | /* warn? */ | |
414a389f | 184 | return NULL; |
d50171e4 PA |
185 | } |
186 | ||
187 | bp = xcalloc (1, sizeof (struct breakpoint)); | |
414a389f | 188 | bp->type = other_breakpoint; |
8b07ae33 PA |
189 | |
190 | bp->raw = raw; | |
611cb4a5 DJ |
191 | bp->handler = handler; |
192 | ||
95954743 PA |
193 | bp->next = proc->breakpoints; |
194 | proc->breakpoints = bp; | |
414a389f PA |
195 | |
196 | return bp; | |
611cb4a5 DJ |
197 | } |
198 | ||
8b07ae33 PA |
199 | static int |
200 | delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) | |
201 | { | |
202 | struct raw_breakpoint *bp, **bp_link; | |
203 | int ret; | |
204 | ||
205 | bp = proc->raw_breakpoints; | |
206 | bp_link = &proc->raw_breakpoints; | |
207 | ||
208 | while (bp) | |
209 | { | |
210 | if (bp == todel) | |
211 | { | |
212 | if (bp->inserted) | |
213 | { | |
214 | struct raw_breakpoint *prev_bp_link = *bp_link; | |
215 | ||
216 | *bp_link = bp->next; | |
217 | ||
218 | ret = (*the_target->write_memory) (bp->pc, bp->old_data, | |
219 | breakpoint_len); | |
220 | if (ret != 0) | |
221 | { | |
222 | /* Something went wrong, relink the breakpoint. */ | |
223 | *bp_link = prev_bp_link; | |
224 | ||
225 | if (debug_threads) | |
226 | fprintf (stderr, | |
227 | "Failed to uninsert raw breakpoint " | |
228 | "at 0x%s (%s) while deleting it.\n", | |
229 | paddress (bp->pc), strerror (ret)); | |
230 | return ret; | |
231 | } | |
232 | ||
233 | } | |
234 | else | |
235 | *bp_link = bp->next; | |
236 | ||
237 | free (bp); | |
238 | return 0; | |
239 | } | |
240 | else | |
241 | { | |
242 | bp_link = &bp->next; | |
243 | bp = *bp_link; | |
244 | } | |
245 | } | |
246 | ||
247 | warning ("Could not find raw breakpoint in list."); | |
248 | return ENOENT; | |
249 | } | |
250 | ||
251 | static int | |
252 | release_breakpoint (struct process_info *proc, struct breakpoint *bp) | |
253 | { | |
254 | int newrefcount; | |
255 | int ret; | |
256 | ||
257 | newrefcount = bp->raw->refcount - 1; | |
258 | if (newrefcount == 0) | |
259 | { | |
260 | ret = delete_raw_breakpoint (proc, bp->raw); | |
261 | if (ret != 0) | |
262 | return ret; | |
263 | } | |
264 | else | |
265 | bp->raw->refcount = newrefcount; | |
266 | ||
267 | free (bp); | |
268 | ||
269 | return 0; | |
270 | } | |
271 | ||
272 | static int | |
273 | delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) | |
611cb4a5 | 274 | { |
414a389f | 275 | struct breakpoint *bp, **bp_link; |
8b07ae33 | 276 | int err; |
611cb4a5 | 277 | |
414a389f PA |
278 | bp = proc->breakpoints; |
279 | bp_link = &proc->breakpoints; | |
280 | ||
281 | while (bp) | |
611cb4a5 | 282 | { |
414a389f | 283 | if (bp == todel) |
611cb4a5 | 284 | { |
414a389f PA |
285 | *bp_link = bp->next; |
286 | ||
8b07ae33 PA |
287 | err = release_breakpoint (proc, bp); |
288 | if (err != 0) | |
289 | return err; | |
290 | ||
291 | bp = *bp_link; | |
292 | return 0; | |
611cb4a5 | 293 | } |
414a389f PA |
294 | else |
295 | { | |
296 | bp_link = &bp->next; | |
297 | bp = *bp_link; | |
298 | } | |
611cb4a5 | 299 | } |
414a389f | 300 | |
611cb4a5 | 301 | warning ("Could not find breakpoint in list."); |
8b07ae33 PA |
302 | return ENOENT; |
303 | } | |
304 | ||
219f2f23 | 305 | int |
8b07ae33 PA |
306 | delete_breakpoint (struct breakpoint *todel) |
307 | { | |
308 | struct process_info *proc = current_process (); | |
309 | return delete_breakpoint_1 (proc, todel); | |
611cb4a5 DJ |
310 | } |
311 | ||
312 | static struct breakpoint * | |
8b07ae33 | 313 | find_gdb_breakpoint_at (CORE_ADDR where) |
611cb4a5 | 314 | { |
95954743 | 315 | struct process_info *proc = current_process (); |
8b07ae33 | 316 | struct breakpoint *bp; |
611cb4a5 | 317 | |
8b07ae33 PA |
318 | for (bp = proc->breakpoints; bp != NULL; bp = bp->next) |
319 | if (bp->type == gdb_breakpoint && bp->raw->pc == where) | |
320 | return bp; | |
611cb4a5 DJ |
321 | |
322 | return NULL; | |
323 | } | |
324 | ||
8b07ae33 PA |
325 | int |
326 | set_gdb_breakpoint_at (CORE_ADDR where) | |
68070c10 | 327 | { |
8b07ae33 PA |
328 | struct breakpoint *bp; |
329 | ||
330 | if (breakpoint_data == NULL) | |
331 | return 1; | |
332 | ||
d3bbe7a0 PA |
333 | /* If we see GDB inserting a second breakpoint at the same address, |
334 | then the first breakpoint must have disappeared due to a shared | |
335 | library unload. On targets where the shared libraries are | |
336 | handled by userspace, like SVR4, for example, GDBserver can't | |
337 | tell if a library was loaded or unloaded. Since we refcount | |
338 | breakpoints, if we didn't do this, we'd just increase the | |
339 | refcount of the previous breakpoint at this address, but the trap | |
340 | was not planted in the inferior anymore, thus the breakpoint | |
341 | would never be hit. */ | |
342 | bp = find_gdb_breakpoint_at (where); | |
343 | if (bp != NULL) | |
344 | { | |
345 | delete_gdb_breakpoint_at (where); | |
346 | ||
347 | /* Might as well validate all other breakpoints. */ | |
348 | validate_breakpoints (); | |
349 | } | |
350 | ||
8b07ae33 PA |
351 | bp = set_breakpoint_at (where, NULL); |
352 | if (bp == NULL) | |
353 | return -1; | |
354 | ||
355 | bp->type = gdb_breakpoint; | |
356 | return 0; | |
357 | } | |
358 | ||
359 | int | |
360 | delete_gdb_breakpoint_at (CORE_ADDR addr) | |
361 | { | |
362 | struct breakpoint *bp; | |
363 | int err; | |
364 | ||
365 | if (breakpoint_data == NULL) | |
366 | return 1; | |
367 | ||
368 | bp = find_gdb_breakpoint_at (addr); | |
369 | if (bp == NULL) | |
370 | return -1; | |
371 | ||
372 | err = delete_breakpoint (bp); | |
373 | if (err) | |
374 | return -1; | |
375 | ||
376 | return 0; | |
377 | } | |
378 | ||
379 | int | |
380 | gdb_breakpoint_here (CORE_ADDR where) | |
381 | { | |
382 | struct breakpoint *bp = find_gdb_breakpoint_at (where); | |
383 | ||
384 | return (bp != NULL); | |
68070c10 PA |
385 | } |
386 | ||
d50171e4 PA |
387 | void |
388 | set_reinsert_breakpoint (CORE_ADDR stop_at) | |
611cb4a5 | 389 | { |
414a389f PA |
390 | struct breakpoint *bp; |
391 | ||
392 | bp = set_breakpoint_at (stop_at, NULL); | |
414a389f | 393 | bp->type = reinsert_breakpoint; |
611cb4a5 DJ |
394 | } |
395 | ||
396 | void | |
d50171e4 | 397 | delete_reinsert_breakpoints (void) |
611cb4a5 | 398 | { |
d50171e4 PA |
399 | struct process_info *proc = current_process (); |
400 | struct breakpoint *bp, **bp_link; | |
611cb4a5 | 401 | |
d50171e4 PA |
402 | bp = proc->breakpoints; |
403 | bp_link = &proc->breakpoints; | |
611cb4a5 | 404 | |
d50171e4 PA |
405 | while (bp) |
406 | { | |
414a389f PA |
407 | if (bp->type == reinsert_breakpoint) |
408 | { | |
409 | *bp_link = bp->next; | |
8b07ae33 | 410 | release_breakpoint (proc, bp); |
414a389f PA |
411 | bp = *bp_link; |
412 | } | |
413 | else | |
414 | { | |
415 | bp_link = &bp->next; | |
416 | bp = *bp_link; | |
417 | } | |
d50171e4 PA |
418 | } |
419 | } | |
b65d95c5 | 420 | |
d50171e4 | 421 | static void |
8b07ae33 | 422 | uninsert_raw_breakpoint (struct raw_breakpoint *bp) |
d50171e4 PA |
423 | { |
424 | if (bp->inserted) | |
425 | { | |
426 | int err; | |
427 | ||
428 | bp->inserted = 0; | |
429 | err = (*the_target->write_memory) (bp->pc, bp->old_data, | |
430 | breakpoint_len); | |
431 | if (err != 0) | |
432 | { | |
433 | bp->inserted = 1; | |
611cb4a5 | 434 | |
d50171e4 PA |
435 | if (debug_threads) |
436 | fprintf (stderr, | |
437 | "Failed to uninsert raw breakpoint at 0x%s (%s).\n", | |
438 | paddress (bp->pc), strerror (err)); | |
439 | } | |
440 | } | |
611cb4a5 DJ |
441 | } |
442 | ||
443 | void | |
d50171e4 | 444 | uninsert_breakpoints_at (CORE_ADDR pc) |
611cb4a5 | 445 | { |
8b07ae33 | 446 | struct raw_breakpoint *bp; |
611cb4a5 | 447 | |
8b07ae33 | 448 | bp = find_raw_breakpoint_at (pc); |
611cb4a5 | 449 | if (bp == NULL) |
d50171e4 PA |
450 | { |
451 | /* This can happen when we remove all breakpoints while handling | |
452 | a step-over. */ | |
453 | if (debug_threads) | |
454 | fprintf (stderr, | |
455 | "Could not find breakpoint at 0x%s " | |
456 | "in list (uninserting).\n", | |
457 | paddress (pc)); | |
458 | return; | |
459 | } | |
611cb4a5 | 460 | |
d50171e4 | 461 | if (bp->inserted) |
8b07ae33 | 462 | uninsert_raw_breakpoint (bp); |
611cb4a5 DJ |
463 | } |
464 | ||
d50171e4 | 465 | static void |
8b07ae33 | 466 | reinsert_raw_breakpoint (struct raw_breakpoint *bp) |
611cb4a5 | 467 | { |
d50171e4 | 468 | int err; |
611cb4a5 | 469 | |
d50171e4 | 470 | if (bp->inserted) |
611cb4a5 DJ |
471 | error ("Breakpoint already inserted at reinsert time."); |
472 | ||
d50171e4 PA |
473 | err = (*the_target->write_memory) (bp->pc, breakpoint_data, |
474 | breakpoint_len); | |
475 | if (err == 0) | |
476 | bp->inserted = 1; | |
477 | else if (debug_threads) | |
478 | fprintf (stderr, | |
479 | "Failed to reinsert breakpoint at 0x%s (%s).\n", | |
480 | paddress (bp->pc), strerror (err)); | |
611cb4a5 DJ |
481 | } |
482 | ||
d50171e4 PA |
483 | void |
484 | reinsert_breakpoints_at (CORE_ADDR pc) | |
611cb4a5 | 485 | { |
8b07ae33 | 486 | struct raw_breakpoint *bp; |
611cb4a5 | 487 | |
8b07ae33 | 488 | bp = find_raw_breakpoint_at (pc); |
611cb4a5 | 489 | if (bp == NULL) |
611cb4a5 | 490 | { |
d50171e4 PA |
491 | /* This can happen when we remove all breakpoints while handling |
492 | a step-over. */ | |
493 | if (debug_threads) | |
494 | fprintf (stderr, | |
8b07ae33 | 495 | "Could not find raw breakpoint at 0x%s " |
d50171e4 PA |
496 | "in list (reinserting).\n", |
497 | paddress (pc)); | |
498 | return; | |
611cb4a5 DJ |
499 | } |
500 | ||
414a389f | 501 | reinsert_raw_breakpoint (bp); |
d50171e4 PA |
502 | } |
503 | ||
504 | void | |
505 | check_breakpoints (CORE_ADDR stop_pc) | |
506 | { | |
507 | struct process_info *proc = current_process (); | |
508 | struct breakpoint *bp, **bp_link; | |
509 | ||
510 | bp = proc->breakpoints; | |
511 | bp_link = &proc->breakpoints; | |
512 | ||
513 | while (bp) | |
b65d95c5 | 514 | { |
8b07ae33 | 515 | if (bp->raw->pc == stop_pc) |
d50171e4 | 516 | { |
8b07ae33 | 517 | if (!bp->raw->inserted) |
d50171e4 PA |
518 | { |
519 | warning ("Hit a removed breakpoint?"); | |
520 | return; | |
521 | } | |
522 | ||
523 | if (bp->handler != NULL && (*bp->handler) (stop_pc)) | |
524 | { | |
525 | *bp_link = bp->next; | |
526 | ||
8b07ae33 | 527 | release_breakpoint (proc, bp); |
d50171e4 PA |
528 | |
529 | bp = *bp_link; | |
530 | continue; | |
531 | } | |
532 | } | |
533 | ||
534 | bp_link = &bp->next; | |
535 | bp = *bp_link; | |
b65d95c5 | 536 | } |
611cb4a5 DJ |
537 | } |
538 | ||
539 | void | |
f450004a | 540 | set_breakpoint_data (const unsigned char *bp_data, int bp_len) |
611cb4a5 DJ |
541 | { |
542 | breakpoint_data = bp_data; | |
543 | breakpoint_len = bp_len; | |
544 | } | |
545 | ||
d50171e4 PA |
546 | int |
547 | breakpoint_here (CORE_ADDR addr) | |
548 | { | |
8b07ae33 | 549 | return (find_raw_breakpoint_at (addr) != NULL); |
d50171e4 PA |
550 | } |
551 | ||
552 | int | |
553 | breakpoint_inserted_here (CORE_ADDR addr) | |
554 | { | |
8b07ae33 | 555 | struct raw_breakpoint *bp; |
d50171e4 | 556 | |
8b07ae33 | 557 | bp = find_raw_breakpoint_at (addr); |
d50171e4 | 558 | |
8b07ae33 | 559 | return (bp != NULL && bp->inserted); |
d50171e4 PA |
560 | } |
561 | ||
d3bbe7a0 PA |
562 | static int |
563 | validate_inserted_breakpoint (struct raw_breakpoint *bp) | |
564 | { | |
565 | unsigned char *buf; | |
566 | int err; | |
567 | ||
568 | gdb_assert (bp->inserted); | |
569 | ||
570 | buf = alloca (breakpoint_len); | |
571 | err = (*the_target->read_memory) (bp->pc, buf, breakpoint_len); | |
572 | if (err || memcmp (buf, breakpoint_data, breakpoint_len) != 0) | |
573 | { | |
574 | /* Tag it as gone. */ | |
575 | bp->inserted = 0; | |
576 | bp->shlib_disabled = 1; | |
577 | return 0; | |
578 | } | |
579 | ||
580 | return 1; | |
581 | } | |
582 | ||
583 | static void | |
584 | delete_disabled_breakpoints (void) | |
585 | { | |
586 | struct process_info *proc = current_process (); | |
587 | struct breakpoint *bp, *next; | |
588 | ||
589 | for (bp = proc->breakpoints; bp != NULL; bp = next) | |
590 | { | |
591 | next = bp->next; | |
592 | if (bp->raw->shlib_disabled) | |
593 | delete_breakpoint_1 (proc, bp); | |
594 | } | |
595 | } | |
596 | ||
597 | /* Check if breakpoints we inserted still appear to be inserted. They | |
598 | may disappear due to a shared library unload, and worse, a new | |
599 | shared library may be reloaded at the same address as the | |
600 | previously unloaded one. If that happens, we should make sure that | |
601 | the shadow memory of the old breakpoints isn't used when reading or | |
602 | writing memory. */ | |
603 | ||
604 | void | |
605 | validate_breakpoints (void) | |
606 | { | |
607 | struct process_info *proc = current_process (); | |
608 | struct breakpoint *bp; | |
609 | ||
610 | for (bp = proc->breakpoints; bp != NULL; bp = bp->next) | |
611 | { | |
612 | if (bp->raw->inserted) | |
613 | validate_inserted_breakpoint (bp->raw); | |
614 | } | |
615 | ||
616 | delete_disabled_breakpoints (); | |
617 | } | |
618 | ||
611cb4a5 | 619 | void |
f450004a | 620 | check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) |
611cb4a5 | 621 | { |
95954743 | 622 | struct process_info *proc = current_process (); |
8b07ae33 | 623 | struct raw_breakpoint *bp = proc->raw_breakpoints; |
611cb4a5 | 624 | CORE_ADDR mem_end = mem_addr + mem_len; |
d3bbe7a0 | 625 | int disabled_one = 0; |
611cb4a5 DJ |
626 | |
627 | for (; bp != NULL; bp = bp->next) | |
628 | { | |
629 | CORE_ADDR bp_end = bp->pc + breakpoint_len; | |
630 | CORE_ADDR start, end; | |
631 | int copy_offset, copy_len, buf_offset; | |
632 | ||
633 | if (mem_addr >= bp_end) | |
634 | continue; | |
635 | if (bp->pc >= mem_end) | |
636 | continue; | |
637 | ||
638 | start = bp->pc; | |
639 | if (mem_addr > start) | |
640 | start = mem_addr; | |
641 | ||
642 | end = bp_end; | |
643 | if (end > mem_end) | |
644 | end = mem_end; | |
645 | ||
646 | copy_len = end - start; | |
647 | copy_offset = start - bp->pc; | |
648 | buf_offset = start - mem_addr; | |
649 | ||
8b07ae33 | 650 | if (bp->inserted) |
d3bbe7a0 PA |
651 | { |
652 | if (validate_inserted_breakpoint (bp)) | |
653 | memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); | |
654 | else | |
655 | disabled_one = 1; | |
656 | } | |
611cb4a5 | 657 | } |
d3bbe7a0 PA |
658 | |
659 | if (disabled_one) | |
660 | delete_disabled_breakpoints (); | |
611cb4a5 DJ |
661 | } |
662 | ||
663 | void | |
f450004a | 664 | check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) |
611cb4a5 | 665 | { |
95954743 | 666 | struct process_info *proc = current_process (); |
8b07ae33 | 667 | struct raw_breakpoint *bp = proc->raw_breakpoints; |
611cb4a5 | 668 | CORE_ADDR mem_end = mem_addr + mem_len; |
d3bbe7a0 | 669 | int disabled_one = 0; |
611cb4a5 DJ |
670 | |
671 | for (; bp != NULL; bp = bp->next) | |
672 | { | |
673 | CORE_ADDR bp_end = bp->pc + breakpoint_len; | |
674 | CORE_ADDR start, end; | |
675 | int copy_offset, copy_len, buf_offset; | |
676 | ||
677 | if (mem_addr >= bp_end) | |
678 | continue; | |
679 | if (bp->pc >= mem_end) | |
680 | continue; | |
681 | ||
682 | start = bp->pc; | |
683 | if (mem_addr > start) | |
684 | start = mem_addr; | |
685 | ||
686 | end = bp_end; | |
687 | if (end > mem_end) | |
688 | end = mem_end; | |
689 | ||
690 | copy_len = end - start; | |
691 | copy_offset = start - bp->pc; | |
692 | buf_offset = start - mem_addr; | |
693 | ||
694 | memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len); | |
d50171e4 | 695 | if (bp->inserted) |
d3bbe7a0 PA |
696 | { |
697 | if (validate_inserted_breakpoint (bp)) | |
698 | memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len); | |
699 | else | |
700 | disabled_one = 1; | |
701 | } | |
611cb4a5 | 702 | } |
d3bbe7a0 PA |
703 | |
704 | if (disabled_one) | |
705 | delete_disabled_breakpoints (); | |
611cb4a5 | 706 | } |
ae13219e | 707 | |
95954743 | 708 | /* Delete all breakpoints, and un-insert them from the inferior. */ |
ae13219e DJ |
709 | |
710 | void | |
711 | delete_all_breakpoints (void) | |
712 | { | |
95954743 PA |
713 | struct process_info *proc = current_process (); |
714 | ||
715 | while (proc->breakpoints) | |
8b07ae33 | 716 | delete_breakpoint_1 (proc, proc->breakpoints); |
95954743 PA |
717 | } |
718 | ||
f9e39928 | 719 | /* Clear the "inserted" flag in all breakpoints. */ |
95954743 PA |
720 | |
721 | void | |
f9e39928 | 722 | mark_breakpoints_out (struct process_info *proc) |
95954743 | 723 | { |
8b07ae33 | 724 | struct raw_breakpoint *raw_bp; |
95954743 | 725 | |
8b07ae33 PA |
726 | for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next) |
727 | raw_bp->inserted = 0; | |
f9e39928 PA |
728 | } |
729 | ||
730 | /* Release all breakpoints, but do not try to un-insert them from the | |
731 | inferior. */ | |
732 | ||
733 | void | |
734 | free_all_breakpoints (struct process_info *proc) | |
735 | { | |
736 | mark_breakpoints_out (proc); | |
8b07ae33 PA |
737 | |
738 | /* Note: use PROC explicitly instead of deferring to | |
739 | delete_all_breakpoints --- CURRENT_INFERIOR may already have been | |
740 | released when we get here. There should be no call to | |
741 | current_process from here on. */ | |
95954743 | 742 | while (proc->breakpoints) |
8b07ae33 | 743 | delete_breakpoint_1 (proc, proc->breakpoints); |
ae13219e | 744 | } |