target/cortex_m: workaround Cortex-M7 erratum 3092511
[openocd.git] / src / target / breakpoints.c
blobc39a9805701ab90d49232a2713b020d81fd4f4f5
1 // SPDX-License-Identifier: GPL-2.0-or-later
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 ***************************************************************************/
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
15 #include "target.h"
16 #include <helper/log.h>
17 #include "breakpoints.h"
18 #include "smp.h"
20 enum breakpoint_watchpoint {
21 BREAKPOINT,
22 WATCHPOINT,
25 static const char * const breakpoint_type_strings[] = {
26 "hardware",
27 "software"
30 static const char * const watchpoint_rw_strings[] = {
31 "read",
32 "write",
33 "access"
36 /* monotonic counter/id-number for breakpoints and watch points */
37 static int bpwp_unique_id;
39 static int breakpoint_add_internal(struct target *target,
40 target_addr_t address,
41 uint32_t length,
42 enum breakpoint_type type)
44 struct breakpoint *breakpoint = target->breakpoints;
45 struct breakpoint **breakpoint_p = &target->breakpoints;
46 const char *reason;
47 int retval;
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.
55 LOG_TARGET_ERROR(target, "Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
56 address, breakpoint->unique_id);
57 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
59 breakpoint_p = &breakpoint->next;
60 breakpoint = breakpoint->next;
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++;
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_TARGET_ERROR(target, "can't add breakpoint: %s", reason);
87 free((*breakpoint_p)->orig_instr);
88 free(*breakpoint_p);
89 *breakpoint_p = NULL;
90 return retval;
93 LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT
94 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
95 breakpoint_type_strings[(*breakpoint_p)->type],
96 (*breakpoint_p)->address, (*breakpoint_p)->length,
97 (*breakpoint_p)->unique_id);
99 return ERROR_OK;
102 static int context_breakpoint_add_internal(struct target *target,
103 uint32_t asid,
104 uint32_t length,
105 enum breakpoint_type type)
107 struct breakpoint *breakpoint = target->breakpoints;
108 struct breakpoint **breakpoint_p = &target->breakpoints;
109 int retval;
111 while (breakpoint) {
112 if (breakpoint->asid == asid) {
113 /* FIXME don't assume "same address" means "same
114 * breakpoint" ... check all the parameters before
115 * succeeding.
117 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
118 asid, breakpoint->unique_id);
119 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
121 breakpoint_p = &breakpoint->next;
122 breakpoint = breakpoint->next;
125 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
126 (*breakpoint_p)->address = 0;
127 (*breakpoint_p)->asid = asid;
128 (*breakpoint_p)->length = length;
129 (*breakpoint_p)->type = type;
130 (*breakpoint_p)->is_set = false;
131 (*breakpoint_p)->orig_instr = malloc(length);
132 (*breakpoint_p)->next = NULL;
133 (*breakpoint_p)->unique_id = bpwp_unique_id++;
134 retval = target_add_context_breakpoint(target, *breakpoint_p);
135 if (retval != ERROR_OK) {
136 LOG_TARGET_ERROR(target, "could not add breakpoint");
137 free((*breakpoint_p)->orig_instr);
138 free(*breakpoint_p);
139 *breakpoint_p = NULL;
140 return retval;
143 LOG_TARGET_DEBUG(target, "added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
144 breakpoint_type_strings[(*breakpoint_p)->type],
145 (*breakpoint_p)->asid, (*breakpoint_p)->length,
146 (*breakpoint_p)->unique_id);
148 return ERROR_OK;
151 static int hybrid_breakpoint_add_internal(struct target *target,
152 target_addr_t address,
153 uint32_t asid,
154 uint32_t length,
155 enum breakpoint_type type)
157 struct breakpoint *breakpoint = target->breakpoints;
158 struct breakpoint **breakpoint_p = &target->breakpoints;
159 int retval;
161 while (breakpoint) {
162 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
163 /* FIXME don't assume "same address" means "same
164 * breakpoint" ... check all the parameters before
165 * succeeding.
167 LOG_TARGET_ERROR(target, "Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
168 asid, breakpoint->unique_id);
169 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
170 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
171 LOG_TARGET_ERROR(target, "Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
172 address, breakpoint->unique_id);
173 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
176 breakpoint_p = &breakpoint->next;
177 breakpoint = breakpoint->next;
179 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
180 (*breakpoint_p)->address = address;
181 (*breakpoint_p)->asid = asid;
182 (*breakpoint_p)->length = length;
183 (*breakpoint_p)->type = type;
184 (*breakpoint_p)->is_set = false;
185 (*breakpoint_p)->orig_instr = malloc(length);
186 (*breakpoint_p)->next = NULL;
187 (*breakpoint_p)->unique_id = bpwp_unique_id++;
190 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
191 if (retval != ERROR_OK) {
192 LOG_TARGET_ERROR(target, "could not add breakpoint");
193 free((*breakpoint_p)->orig_instr);
194 free(*breakpoint_p);
195 *breakpoint_p = NULL;
196 return retval;
198 LOG_TARGET_DEBUG(target,
199 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
200 breakpoint_type_strings[(*breakpoint_p)->type],
201 (*breakpoint_p)->address,
202 (*breakpoint_p)->length,
203 (*breakpoint_p)->unique_id);
205 return ERROR_OK;
208 int breakpoint_add(struct target *target,
209 target_addr_t address,
210 uint32_t length,
211 enum breakpoint_type type)
213 if (target->smp) {
214 struct target_list *head;
216 if (type == BKPT_SOFT) {
217 head = list_first_entry(target->smp_targets, struct target_list, lh);
218 return breakpoint_add_internal(head->target, address, length, type);
221 foreach_smp_target(head, target->smp_targets) {
222 struct target *curr = head->target;
223 int retval = breakpoint_add_internal(curr, address, length, type);
224 if (retval != ERROR_OK)
225 return retval;
228 return ERROR_OK;
229 } else {
230 return breakpoint_add_internal(target, address, length, type);
234 int context_breakpoint_add(struct target *target,
235 uint32_t asid,
236 uint32_t length,
237 enum breakpoint_type type)
239 if (target->smp) {
240 struct target_list *head;
242 foreach_smp_target(head, target->smp_targets) {
243 struct target *curr = head->target;
244 int retval = context_breakpoint_add_internal(curr, asid, length, type);
245 if (retval != ERROR_OK)
246 return retval;
249 return ERROR_OK;
250 } else {
251 return context_breakpoint_add_internal(target, asid, length, type);
255 int hybrid_breakpoint_add(struct target *target,
256 target_addr_t address,
257 uint32_t asid,
258 uint32_t length,
259 enum breakpoint_type type)
261 if (target->smp) {
262 struct target_list *head;
264 foreach_smp_target(head, target->smp_targets) {
265 struct target *curr = head->target;
266 int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
267 if (retval != ERROR_OK)
268 return retval;
271 return ERROR_OK;
272 } else
273 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
276 /* free up a breakpoint */
277 static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
279 struct breakpoint *breakpoint = target->breakpoints;
280 struct breakpoint **breakpoint_p = &target->breakpoints;
281 int retval;
283 while (breakpoint) {
284 if (breakpoint == breakpoint_to_remove)
285 break;
286 breakpoint_p = &breakpoint->next;
287 breakpoint = breakpoint->next;
290 if (!breakpoint)
291 return ERROR_OK;
293 retval = target_remove_breakpoint(target, breakpoint);
294 if (retval != ERROR_OK) {
295 LOG_TARGET_ERROR(target, "could not remove breakpoint #%d on this target",
296 breakpoint->number);
297 return retval;
300 LOG_TARGET_DEBUG(target, "free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
301 (*breakpoint_p) = breakpoint->next;
302 free(breakpoint->orig_instr);
303 free(breakpoint);
305 return ERROR_OK;
308 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
310 struct breakpoint *breakpoint = target->breakpoints;
312 while (breakpoint) {
313 if ((breakpoint->address == address) ||
314 (breakpoint->address == 0 && breakpoint->asid == address))
315 break;
316 breakpoint = breakpoint->next;
319 if (breakpoint) {
320 return breakpoint_free(target, breakpoint);
321 } else {
322 return ERROR_BREAKPOINT_NOT_FOUND;
326 static int breakpoint_remove_all_internal(struct target *target)
328 LOG_TARGET_DEBUG(target, "Delete all breakpoints");
330 struct breakpoint *breakpoint = target->breakpoints;
331 int retval = ERROR_OK;
333 while (breakpoint) {
334 struct breakpoint *tmp = breakpoint;
335 breakpoint = breakpoint->next;
336 int status = breakpoint_free(target, tmp);
337 if (status != ERROR_OK)
338 retval = status;
341 return retval;
344 int breakpoint_remove(struct target *target, target_addr_t address)
346 int retval = ERROR_OK;
347 unsigned int num_found_breakpoints = 0;
348 if (target->smp) {
349 struct target_list *head;
351 foreach_smp_target(head, target->smp_targets) {
352 struct target *curr = head->target;
353 int status = breakpoint_remove_internal(curr, address);
355 if (status != ERROR_BREAKPOINT_NOT_FOUND) {
356 num_found_breakpoints++;
358 if (status != ERROR_OK) {
359 LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
360 retval = status;
365 } else {
366 retval = breakpoint_remove_internal(target, address);
368 if (retval != ERROR_BREAKPOINT_NOT_FOUND) {
369 num_found_breakpoints++;
371 if (retval != ERROR_OK)
372 LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
376 if (num_found_breakpoints == 0) {
377 LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address);
378 return ERROR_BREAKPOINT_NOT_FOUND;
381 return retval;
384 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
386 struct watchpoint *watchpoint = target->watchpoints;
387 struct watchpoint **watchpoint_p = &target->watchpoints;
388 int retval;
390 while (watchpoint) {
391 if (watchpoint == watchpoint_to_remove)
392 break;
393 watchpoint_p = &watchpoint->next;
394 watchpoint = watchpoint->next;
397 if (!watchpoint)
398 return ERROR_OK;
399 retval = target_remove_watchpoint(target, watchpoint);
400 if (retval != ERROR_OK) {
401 LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
402 watchpoint->number);
403 return retval;
406 LOG_TARGET_DEBUG(target, "free WPID: %d --> %d", watchpoint->unique_id, retval);
407 (*watchpoint_p) = watchpoint->next;
408 free(watchpoint);
410 return ERROR_OK;
413 static int watchpoint_remove_all_internal(struct target *target)
415 struct watchpoint *watchpoint = target->watchpoints;
416 int retval = ERROR_OK;
418 while (watchpoint) {
419 struct watchpoint *tmp = watchpoint;
420 watchpoint = watchpoint->next;
421 int status = watchpoint_free(target, tmp);
422 if (status != ERROR_OK)
423 retval = status;
426 return retval;
429 static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp)
431 assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT);
432 int retval = ERROR_OK;
433 if (target->smp) {
434 struct target_list *head;
436 foreach_smp_target(head, target->smp_targets) {
437 struct target *curr = head->target;
439 int status = ERROR_OK;
440 if (bp_wp == BREAKPOINT)
441 status = breakpoint_remove_all_internal(curr);
442 else
443 status = watchpoint_remove_all_internal(curr);
445 if (status != ERROR_OK)
446 retval = status;
448 } else {
449 if (bp_wp == BREAKPOINT)
450 retval = breakpoint_remove_all_internal(target);
451 else
452 retval = watchpoint_remove_all_internal(target);
455 return retval;
458 int breakpoint_remove_all(struct target *target)
460 return breakpoint_watchpoint_remove_all(target, BREAKPOINT);
463 int watchpoint_remove_all(struct target *target)
465 return breakpoint_watchpoint_remove_all(target, WATCHPOINT);
468 int breakpoint_clear_target(struct target *target)
470 int retval = ERROR_OK;
472 if (target->smp) {
473 struct target_list *head;
475 foreach_smp_target(head, target->smp_targets) {
476 struct target *curr = head->target;
477 int status = breakpoint_remove_all_internal(curr);
479 if (status != ERROR_OK)
480 retval = status;
482 } else {
483 retval = breakpoint_remove_all_internal(target);
486 return retval;
489 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
491 struct breakpoint *breakpoint = target->breakpoints;
493 while (breakpoint) {
494 if (breakpoint->address == address)
495 return breakpoint;
496 breakpoint = breakpoint->next;
499 return NULL;
502 static int watchpoint_add_internal(struct target *target, target_addr_t address,
503 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
505 struct watchpoint *watchpoint = target->watchpoints;
506 struct watchpoint **watchpoint_p = &target->watchpoints;
507 int retval;
508 const char *reason;
510 while (watchpoint) {
511 if (watchpoint->address == address) {
512 if (watchpoint->length != length
513 || watchpoint->value != value
514 || watchpoint->mask != mask
515 || watchpoint->rw != rw) {
516 LOG_TARGET_ERROR(target, "address " TARGET_ADDR_FMT
517 " already has watchpoint %d",
518 address, watchpoint->unique_id);
519 return ERROR_FAIL;
522 /* ignore duplicate watchpoint */
523 return ERROR_OK;
525 watchpoint_p = &watchpoint->next;
526 watchpoint = watchpoint->next;
529 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
530 (*watchpoint_p)->address = address;
531 (*watchpoint_p)->length = length;
532 (*watchpoint_p)->value = value;
533 (*watchpoint_p)->mask = mask;
534 (*watchpoint_p)->rw = rw;
535 (*watchpoint_p)->unique_id = bpwp_unique_id++;
537 retval = target_add_watchpoint(target, *watchpoint_p);
538 switch (retval) {
539 case ERROR_OK:
540 break;
541 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
542 reason = "resource not available";
543 goto bye;
544 case ERROR_TARGET_NOT_HALTED:
545 reason = "target running";
546 goto bye;
547 default:
548 reason = "unrecognized error";
549 bye:
550 LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
551 watchpoint_rw_strings[(*watchpoint_p)->rw],
552 address, reason);
553 free(*watchpoint_p);
554 *watchpoint_p = NULL;
555 return retval;
558 LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT
559 " of length 0x%8.8" PRIx32 " (WPID: %d)",
560 watchpoint_rw_strings[(*watchpoint_p)->rw],
561 (*watchpoint_p)->address,
562 (*watchpoint_p)->length,
563 (*watchpoint_p)->unique_id);
565 return ERROR_OK;
568 int watchpoint_add(struct target *target, target_addr_t address,
569 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
571 if (target->smp) {
572 struct target_list *head;
574 foreach_smp_target(head, target->smp_targets) {
575 struct target *curr = head->target;
576 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
577 if (retval != ERROR_OK)
578 return retval;
581 return ERROR_OK;
582 } else {
583 return watchpoint_add_internal(target, address, length, rw, value,
584 mask);
588 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
590 struct watchpoint *watchpoint = target->watchpoints;
592 while (watchpoint) {
593 if (watchpoint->address == address)
594 break;
595 watchpoint = watchpoint->next;
598 if (watchpoint) {
599 return watchpoint_free(target, watchpoint);
600 } else {
601 return ERROR_WATCHPOINT_NOT_FOUND;
605 int watchpoint_remove(struct target *target, target_addr_t address)
607 int retval = ERROR_OK;
608 unsigned int num_found_watchpoints = 0;
609 if (target->smp) {
610 struct target_list *head;
612 foreach_smp_target(head, target->smp_targets) {
613 struct target *curr = head->target;
614 int status = watchpoint_remove_internal(curr, address);
616 if (status != ERROR_WATCHPOINT_NOT_FOUND) {
617 num_found_watchpoints++;
619 if (status != ERROR_OK) {
620 LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
621 retval = status;
625 } else {
626 retval = watchpoint_remove_internal(target, address);
628 if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
629 num_found_watchpoints++;
631 if (retval != ERROR_OK)
632 LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
636 if (num_found_watchpoints == 0) {
637 LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
638 return ERROR_WATCHPOINT_NOT_FOUND;
641 return retval;
644 int watchpoint_clear_target(struct target *target)
646 LOG_DEBUG("Delete all watchpoints for target: %s",
647 target_name(target));
649 struct watchpoint *watchpoint = target->watchpoints;
650 int retval = ERROR_OK;
652 while (watchpoint) {
653 struct watchpoint *tmp = watchpoint;
654 watchpoint = watchpoint->next;
655 int status = watchpoint_free(target, tmp);
656 if (status != ERROR_OK)
657 retval = status;
659 return retval;
662 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
663 target_addr_t *address)
665 int retval;
666 struct watchpoint *hit_watchpoint;
668 retval = target_hit_watchpoint(target, &hit_watchpoint);
669 if (retval != ERROR_OK)
670 return ERROR_FAIL;
672 *rw = hit_watchpoint->rw;
673 *address = hit_watchpoint->address;
675 LOG_TARGET_DEBUG(target, "Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
676 hit_watchpoint->address,
677 hit_watchpoint->unique_id);
679 return ERROR_OK;