breakpoints: add rwp all command
[openocd.git] / src / target / breakpoints.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
6 * *
7 * Copyright (C) ST-Ericsson SA 2011 *
8 * michel.jaouen@stericsson.com : smp minimum support *
9 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include "target.h"
16 #include <helper/log.h>
17 #include "breakpoints.h"
18 #include "smp.h"
19
20 enum breakpoint_watchpoint {
21 BREAKPOINT,
22 WATCHPOINT,
23 };
24
25 static const char * const breakpoint_type_strings[] = {
26 "hardware",
27 "software"
28 };
29
30 static const char * const watchpoint_rw_strings[] = {
31 "read",
32 "write",
33 "access"
34 };
35
36 /* monotonic counter/id-number for breakpoints and watch points */
37 static int bpwp_unique_id;
38
39 static int breakpoint_add_internal(struct target *target,
40 target_addr_t address,
41 uint32_t length,
42 enum breakpoint_type type)
43 {
44 struct breakpoint *breakpoint = target->breakpoints;
45 struct breakpoint **breakpoint_p = &target->breakpoints;
46 const char *reason;
47 int retval;
48
49 while (breakpoint) {
50 if (breakpoint->address == address) {
51 /* FIXME don't assume "same address" means "same
52 * breakpoint" ... check all the parameters before
53 * succeeding.
54 */
55 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
56 address, breakpoint->unique_id);
57 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
58 }
59 breakpoint_p = &breakpoint->next;
60 breakpoint = breakpoint->next;
61 }
62
63 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
64 (*breakpoint_p)->address = address;
65 (*breakpoint_p)->asid = 0;
66 (*breakpoint_p)->length = length;
67 (*breakpoint_p)->type = type;
68 (*breakpoint_p)->is_set = false;
69 (*breakpoint_p)->orig_instr = malloc(length);
70 (*breakpoint_p)->next = NULL;
71 (*breakpoint_p)->unique_id = bpwp_unique_id++;
72
73 retval = target_add_breakpoint(target, *breakpoint_p);
74 switch (retval) {
75 case ERROR_OK:
76 break;
77 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
78 reason = "resource not available";
79 goto fail;
80 case ERROR_TARGET_NOT_HALTED:
81 reason = "target running";
82 goto fail;
83 default:
84 reason = "unknown reason";
85 fail:
86 LOG_ERROR("can't add breakpoint: %s", reason);
87 free((*breakpoint_p)->orig_instr);
88 free(*breakpoint_p);
89 *breakpoint_p = NULL;
90 return retval;
91 }
92
93 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
94 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
95 target->coreid,
96 breakpoint_type_strings[(*breakpoint_p)->type],
97 (*breakpoint_p)->address, (*breakpoint_p)->length,
98 (*breakpoint_p)->unique_id);
99
100 return ERROR_OK;
101 }
102
103 static int context_breakpoint_add_internal(struct target *target,
104 uint32_t asid,
105 uint32_t length,
106 enum breakpoint_type type)
107 {
108 struct breakpoint *breakpoint = target->breakpoints;
109 struct breakpoint **breakpoint_p = &target->breakpoints;
110 int retval;
111
112 while (breakpoint) {
113 if (breakpoint->asid == asid) {
114 /* FIXME don't assume "same address" means "same
115 * breakpoint" ... check all the parameters before
116 * succeeding.
117 */
118 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
119 asid, breakpoint->unique_id);
120 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
121 }
122 breakpoint_p = &breakpoint->next;
123 breakpoint = breakpoint->next;
124 }
125
126 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
127 (*breakpoint_p)->address = 0;
128 (*breakpoint_p)->asid = asid;
129 (*breakpoint_p)->length = length;
130 (*breakpoint_p)->type = type;
131 (*breakpoint_p)->is_set = false;
132 (*breakpoint_p)->orig_instr = malloc(length);
133 (*breakpoint_p)->next = NULL;
134 (*breakpoint_p)->unique_id = bpwp_unique_id++;
135 retval = target_add_context_breakpoint(target, *breakpoint_p);
136 if (retval != ERROR_OK) {
137 LOG_ERROR("could not add breakpoint");
138 free((*breakpoint_p)->orig_instr);
139 free(*breakpoint_p);
140 *breakpoint_p = NULL;
141 return retval;
142 }
143
144 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
145 breakpoint_type_strings[(*breakpoint_p)->type],
146 (*breakpoint_p)->asid, (*breakpoint_p)->length,
147 (*breakpoint_p)->unique_id);
148
149 return ERROR_OK;
150 }
151
152 static int hybrid_breakpoint_add_internal(struct target *target,
153 target_addr_t address,
154 uint32_t asid,
155 uint32_t length,
156 enum breakpoint_type type)
157 {
158 struct breakpoint *breakpoint = target->breakpoints;
159 struct breakpoint **breakpoint_p = &target->breakpoints;
160 int retval;
161
162 while (breakpoint) {
163 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
164 /* FIXME don't assume "same address" means "same
165 * breakpoint" ... check all the parameters before
166 * succeeding.
167 */
168 LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
169 asid, breakpoint->unique_id);
170 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
171 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
172 LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
173 address, breakpoint->unique_id);
174 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
175
176 }
177 breakpoint_p = &breakpoint->next;
178 breakpoint = breakpoint->next;
179 }
180 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
181 (*breakpoint_p)->address = address;
182 (*breakpoint_p)->asid = asid;
183 (*breakpoint_p)->length = length;
184 (*breakpoint_p)->type = type;
185 (*breakpoint_p)->is_set = false;
186 (*breakpoint_p)->orig_instr = malloc(length);
187 (*breakpoint_p)->next = NULL;
188 (*breakpoint_p)->unique_id = bpwp_unique_id++;
189
190
191 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
192 if (retval != ERROR_OK) {
193 LOG_ERROR("could not add breakpoint");
194 free((*breakpoint_p)->orig_instr);
195 free(*breakpoint_p);
196 *breakpoint_p = NULL;
197 return retval;
198 }
199 LOG_DEBUG(
200 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
201 breakpoint_type_strings[(*breakpoint_p)->type],
202 (*breakpoint_p)->address,
203 (*breakpoint_p)->length,
204 (*breakpoint_p)->unique_id);
205
206 return ERROR_OK;
207 }
208
209 int breakpoint_add(struct target *target,
210 target_addr_t address,
211 uint32_t length,
212 enum breakpoint_type type)
213 {
214 if (target->smp) {
215 struct target_list *head;
216
217 if (type == BKPT_SOFT) {
218 head = list_first_entry(target->smp_targets, struct target_list, lh);
219 return breakpoint_add_internal(head->target, address, length, type);
220 }
221
222 foreach_smp_target(head, target->smp_targets) {
223 struct target *curr = head->target;
224 int retval = breakpoint_add_internal(curr, address, length, type);
225 if (retval != ERROR_OK)
226 return retval;
227 }
228
229 return ERROR_OK;
230 } else {
231 return breakpoint_add_internal(target, address, length, type);
232 }
233 }
234
235 int context_breakpoint_add(struct target *target,
236 uint32_t asid,
237 uint32_t length,
238 enum breakpoint_type type)
239 {
240 if (target->smp) {
241 struct target_list *head;
242
243 foreach_smp_target(head, target->smp_targets) {
244 struct target *curr = head->target;
245 int retval = context_breakpoint_add_internal(curr, asid, length, type);
246 if (retval != ERROR_OK)
247 return retval;
248 }
249
250 return ERROR_OK;
251 } else {
252 return context_breakpoint_add_internal(target, asid, length, type);
253 }
254 }
255
256 int hybrid_breakpoint_add(struct target *target,
257 target_addr_t address,
258 uint32_t asid,
259 uint32_t length,
260 enum breakpoint_type type)
261 {
262 if (target->smp) {
263 struct target_list *head;
264
265 foreach_smp_target(head, target->smp_targets) {
266 struct target *curr = head->target;
267 int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
268 if (retval != ERROR_OK)
269 return retval;
270 }
271
272 return ERROR_OK;
273 } else
274 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
275 }
276
277 /* free up a breakpoint */
278 static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
279 {
280 struct breakpoint *breakpoint = target->breakpoints;
281 struct breakpoint **breakpoint_p = &target->breakpoints;
282 int retval;
283
284 while (breakpoint) {
285 if (breakpoint == breakpoint_to_remove)
286 break;
287 breakpoint_p = &breakpoint->next;
288 breakpoint = breakpoint->next;
289 }
290
291 if (!breakpoint)
292 return ERROR_OK;
293
294 retval = target_remove_breakpoint(target, breakpoint);
295 if (retval != ERROR_OK) {
296 LOG_TARGET_ERROR(target, "could not remove breakpoint #%d on this target",
297 breakpoint->number);
298 return retval;
299 }
300
301 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
302 (*breakpoint_p) = breakpoint->next;
303 free(breakpoint->orig_instr);
304 free(breakpoint);
305
306 return ERROR_OK;
307 }
308
309 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
310 {
311 struct breakpoint *breakpoint = target->breakpoints;
312
313 while (breakpoint) {
314 if ((breakpoint->address == address) ||
315 (breakpoint->address == 0 && breakpoint->asid == address))
316 break;
317 breakpoint = breakpoint->next;
318 }
319
320 if (breakpoint) {
321 return breakpoint_free(target, breakpoint);
322 } else {
323 return ERROR_BREAKPOINT_NOT_FOUND;
324 }
325 }
326
327 static int breakpoint_remove_all_internal(struct target *target)
328 {
329 struct breakpoint *breakpoint = target->breakpoints;
330 int retval = ERROR_OK;
331
332 while (breakpoint) {
333 struct breakpoint *tmp = breakpoint;
334 breakpoint = breakpoint->next;
335 int status = breakpoint_free(target, tmp);
336 if (status != ERROR_OK)
337 retval = status;
338 }
339
340 return retval;
341 }
342
343 int breakpoint_remove(struct target *target, target_addr_t address)
344 {
345 int retval = ERROR_OK;
346 unsigned int num_found_breakpoints = 0;
347 if (target->smp) {
348 struct target_list *head;
349
350 foreach_smp_target(head, target->smp_targets) {
351 struct target *curr = head->target;
352 int status = breakpoint_remove_internal(curr, address);
353
354 if (status != ERROR_BREAKPOINT_NOT_FOUND) {
355 num_found_breakpoints++;
356
357 if (status != ERROR_OK) {
358 LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
359 retval = status;
360 }
361 }
362 }
363
364 } else {
365 retval = breakpoint_remove_internal(target, address);
366
367 if (retval != ERROR_BREAKPOINT_NOT_FOUND) {
368 num_found_breakpoints++;
369
370 if (retval != ERROR_OK)
371 LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
372 }
373 }
374
375 if (num_found_breakpoints == 0) {
376 LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address);
377 return ERROR_BREAKPOINT_NOT_FOUND;
378 }
379
380 return retval;
381 }
382
383 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
384 {
385 struct watchpoint *watchpoint = target->watchpoints;
386 struct watchpoint **watchpoint_p = &target->watchpoints;
387 int retval;
388
389 while (watchpoint) {
390 if (watchpoint == watchpoint_to_remove)
391 break;
392 watchpoint_p = &watchpoint->next;
393 watchpoint = watchpoint->next;
394 }
395
396 if (!watchpoint)
397 return ERROR_OK;
398 retval = target_remove_watchpoint(target, watchpoint);
399 if (retval != ERROR_OK) {
400 LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
401 watchpoint->number);
402 return retval;
403 }
404
405 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
406 (*watchpoint_p) = watchpoint->next;
407 free(watchpoint);
408
409 return ERROR_OK;
410 }
411
412 static int watchpoint_remove_all_internal(struct target *target)
413 {
414 struct watchpoint *watchpoint = target->watchpoints;
415 int retval = ERROR_OK;
416
417 while (watchpoint) {
418 struct watchpoint *tmp = watchpoint;
419 watchpoint = watchpoint->next;
420 int status = watchpoint_free(target, tmp);
421 if (status != ERROR_OK)
422 retval = status;
423 }
424
425 return retval;
426 }
427
428 int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp)
429 {
430 assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT);
431 int retval = ERROR_OK;
432 if (target->smp) {
433 struct target_list *head;
434
435 foreach_smp_target(head, target->smp_targets) {
436 struct target *curr = head->target;
437
438 int status = ERROR_OK;
439 if (bp_wp == BREAKPOINT)
440 status = breakpoint_remove_all_internal(curr);
441 else
442 status = watchpoint_remove_all_internal(curr);
443
444 if (status != ERROR_OK)
445 retval = status;
446 }
447 } else {
448 if (bp_wp == BREAKPOINT)
449 retval = breakpoint_remove_all_internal(target);
450 else
451 retval = watchpoint_remove_all_internal(target);
452 }
453
454 return retval;
455 }
456
457 int breakpoint_remove_all(struct target *target)
458 {
459 return breakpoint_watchpoint_remove_all(target, BREAKPOINT);
460 }
461
462 int watchpoint_remove_all(struct target *target)
463 {
464 return breakpoint_watchpoint_remove_all(target, WATCHPOINT);
465 }
466
467 static int breakpoint_clear_target_internal(struct target *target)
468 {
469 LOG_DEBUG("Delete all breakpoints for target: %s",
470 target_name(target));
471
472 int retval = ERROR_OK;
473
474 while (target->breakpoints) {
475 int status = breakpoint_free(target, target->breakpoints);
476 if (status != ERROR_OK)
477 retval = status;
478 }
479
480 return retval;
481 }
482
483 int breakpoint_clear_target(struct target *target)
484 {
485 int retval = ERROR_OK;
486
487 if (target->smp) {
488 struct target_list *head;
489
490 foreach_smp_target(head, target->smp_targets) {
491 struct target *curr = head->target;
492 int status = breakpoint_clear_target_internal(curr);
493
494 if (status != ERROR_OK)
495 retval = status;
496 }
497 } else {
498 retval = breakpoint_clear_target_internal(target);
499 }
500
501 return retval;
502 }
503
504 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
505 {
506 struct breakpoint *breakpoint = target->breakpoints;
507
508 while (breakpoint) {
509 if (breakpoint->address == address)
510 return breakpoint;
511 breakpoint = breakpoint->next;
512 }
513
514 return NULL;
515 }
516
517 static int watchpoint_add_internal(struct target *target, target_addr_t address,
518 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
519 {
520 struct watchpoint *watchpoint = target->watchpoints;
521 struct watchpoint **watchpoint_p = &target->watchpoints;
522 int retval;
523 const char *reason;
524
525 while (watchpoint) {
526 if (watchpoint->address == address) {
527 if (watchpoint->length != length
528 || watchpoint->value != value
529 || watchpoint->mask != mask
530 || watchpoint->rw != rw) {
531 LOG_ERROR("address " TARGET_ADDR_FMT
532 " already has watchpoint %d",
533 address, watchpoint->unique_id);
534 return ERROR_FAIL;
535 }
536
537 /* ignore duplicate watchpoint */
538 return ERROR_OK;
539 }
540 watchpoint_p = &watchpoint->next;
541 watchpoint = watchpoint->next;
542 }
543
544 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
545 (*watchpoint_p)->address = address;
546 (*watchpoint_p)->length = length;
547 (*watchpoint_p)->value = value;
548 (*watchpoint_p)->mask = mask;
549 (*watchpoint_p)->rw = rw;
550 (*watchpoint_p)->unique_id = bpwp_unique_id++;
551
552 retval = target_add_watchpoint(target, *watchpoint_p);
553 switch (retval) {
554 case ERROR_OK:
555 break;
556 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
557 reason = "resource not available";
558 goto bye;
559 case ERROR_TARGET_NOT_HALTED:
560 reason = "target running";
561 goto bye;
562 default:
563 reason = "unrecognized error";
564 bye:
565 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
566 watchpoint_rw_strings[(*watchpoint_p)->rw],
567 address, reason);
568 free(*watchpoint_p);
569 *watchpoint_p = NULL;
570 return retval;
571 }
572
573 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
574 " of length 0x%8.8" PRIx32 " (WPID: %d)",
575 target->coreid,
576 watchpoint_rw_strings[(*watchpoint_p)->rw],
577 (*watchpoint_p)->address,
578 (*watchpoint_p)->length,
579 (*watchpoint_p)->unique_id);
580
581 return ERROR_OK;
582 }
583
584 int watchpoint_add(struct target *target, target_addr_t address,
585 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
586 {
587 if (target->smp) {
588 struct target_list *head;
589
590 foreach_smp_target(head, target->smp_targets) {
591 struct target *curr = head->target;
592 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
593 if (retval != ERROR_OK)
594 return retval;
595 }
596
597 return ERROR_OK;
598 } else {
599 return watchpoint_add_internal(target, address, length, rw, value,
600 mask);
601 }
602 }
603
604 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
605 {
606 struct watchpoint *watchpoint = target->watchpoints;
607
608 while (watchpoint) {
609 if (watchpoint->address == address)
610 break;
611 watchpoint = watchpoint->next;
612 }
613
614 if (watchpoint) {
615 return watchpoint_free(target, watchpoint);
616 } else {
617 return ERROR_WATCHPOINT_NOT_FOUND;
618 }
619 }
620
621 int watchpoint_remove(struct target *target, target_addr_t address)
622 {
623 int retval = ERROR_OK;
624 unsigned int num_found_watchpoints = 0;
625 if (target->smp) {
626 struct target_list *head;
627
628 foreach_smp_target(head, target->smp_targets) {
629 struct target *curr = head->target;
630 int status = watchpoint_remove_internal(curr, address);
631
632 if (status != ERROR_WATCHPOINT_NOT_FOUND) {
633 num_found_watchpoints++;
634
635 if (status != ERROR_OK) {
636 LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
637 retval = status;
638 }
639 }
640 }
641 } else {
642 retval = watchpoint_remove_internal(target, address);
643
644 if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
645 num_found_watchpoints++;
646
647 if (retval != ERROR_OK)
648 LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
649 }
650 }
651
652 if (num_found_watchpoints == 0) {
653 LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
654 return ERROR_WATCHPOINT_NOT_FOUND;
655 }
656
657 return retval;
658 }
659
660 int watchpoint_clear_target(struct target *target)
661 {
662 int retval = ERROR_OK;
663
664 LOG_DEBUG("Delete all watchpoints for target: %s",
665 target_name(target));
666 while (target->watchpoints) {
667 int status = watchpoint_free(target, target->watchpoints);
668 if (status != ERROR_OK)
669 retval = status;
670 }
671
672 return retval;
673 }
674
675 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
676 target_addr_t *address)
677 {
678 int retval;
679 struct watchpoint *hit_watchpoint;
680
681 retval = target_hit_watchpoint(target, &hit_watchpoint);
682 if (retval != ERROR_OK)
683 return ERROR_FAIL;
684
685 *rw = hit_watchpoint->rw;
686 *address = hit_watchpoint->address;
687
688 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
689 hit_watchpoint->address,
690 hit_watchpoint->unique_id);
691
692 return ERROR_OK;
693 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)