1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) ST-Ericsson SA 2011 *
8 * michel.jaouen@stericsson.com : smp minimum support *
9 ***************************************************************************/
16 #include <helper/log.h>
17 #include "breakpoints.h"
20 enum breakpoint_watchpoint
{
25 static const char * const breakpoint_type_strings
[] = {
30 static const char * const watchpoint_rw_strings
[] = {
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
,
42 enum breakpoint_type type
)
44 struct breakpoint
*breakpoint
= target
->breakpoints
;
45 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
50 if (breakpoint
->address
== address
) {
51 /* FIXME don't assume "same address" means "same
52 * breakpoint" ... check all the parameters before
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
);
77 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
78 reason
= "resource not available";
80 case ERROR_TARGET_NOT_HALTED
:
81 reason
= "target running";
84 reason
= "unknown reason";
86 LOG_TARGET_ERROR(target
, "can't add breakpoint: %s", reason
);
87 free((*breakpoint_p
)->orig_instr
);
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
);
102 static int context_breakpoint_add_internal(struct target
*target
,
105 enum breakpoint_type type
)
107 struct breakpoint
*breakpoint
= target
->breakpoints
;
108 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
112 if (breakpoint
->asid
== asid
) {
113 /* FIXME don't assume "same address" means "same
114 * breakpoint" ... check all the parameters before
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
);
139 *breakpoint_p
= NULL
;
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
);
151 static int hybrid_breakpoint_add_internal(struct target
*target
,
152 target_addr_t address
,
155 enum breakpoint_type type
)
157 struct breakpoint
*breakpoint
= target
->breakpoints
;
158 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
162 if ((breakpoint
->asid
== asid
) && (breakpoint
->address
== address
)) {
163 /* FIXME don't assume "same address" means "same
164 * breakpoint" ... check all the parameters before
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
);
195 *breakpoint_p
= NULL
;
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
);
208 int breakpoint_add(struct target
*target
,
209 target_addr_t address
,
211 enum breakpoint_type type
)
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
)
230 return breakpoint_add_internal(target
, address
, length
, type
);
234 int context_breakpoint_add(struct target
*target
,
237 enum breakpoint_type type
)
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
)
251 return context_breakpoint_add_internal(target
, asid
, length
, type
);
255 int hybrid_breakpoint_add(struct target
*target
,
256 target_addr_t address
,
259 enum breakpoint_type type
)
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
)
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
;
284 if (breakpoint
== breakpoint_to_remove
)
286 breakpoint_p
= &breakpoint
->next
;
287 breakpoint
= breakpoint
->next
;
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",
300 LOG_TARGET_DEBUG(target
, "free BPID: %" PRIu32
" --> %d", breakpoint
->unique_id
, retval
);
301 (*breakpoint_p
) = breakpoint
->next
;
302 free(breakpoint
->orig_instr
);
308 static int breakpoint_remove_internal(struct target
*target
, target_addr_t address
)
310 struct breakpoint
*breakpoint
= target
->breakpoints
;
313 if ((breakpoint
->address
== address
) ||
314 (breakpoint
->address
== 0 && breakpoint
->asid
== address
))
316 breakpoint
= breakpoint
->next
;
320 return breakpoint_free(target
, breakpoint
);
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
;
334 struct breakpoint
*tmp
= breakpoint
;
335 breakpoint
= breakpoint
->next
;
336 int status
= breakpoint_free(target
, tmp
);
337 if (status
!= ERROR_OK
)
344 int breakpoint_remove(struct target
*target
, target_addr_t address
)
346 int retval
= ERROR_OK
;
347 unsigned int num_found_breakpoints
= 0;
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
);
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
;
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
;
391 if (watchpoint
== watchpoint_to_remove
)
393 watchpoint_p
= &watchpoint
->next
;
394 watchpoint
= watchpoint
->next
;
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",
406 LOG_TARGET_DEBUG(target
, "free WPID: %d --> %d", watchpoint
->unique_id
, retval
);
407 (*watchpoint_p
) = watchpoint
->next
;
413 static int watchpoint_remove_all_internal(struct target
*target
)
415 struct watchpoint
*watchpoint
= target
->watchpoints
;
416 int retval
= ERROR_OK
;
419 struct watchpoint
*tmp
= watchpoint
;
420 watchpoint
= watchpoint
->next
;
421 int status
= watchpoint_free(target
, tmp
);
422 if (status
!= ERROR_OK
)
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
;
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
);
443 status
= watchpoint_remove_all_internal(curr
);
445 if (status
!= ERROR_OK
)
449 if (bp_wp
== BREAKPOINT
)
450 retval
= breakpoint_remove_all_internal(target
);
452 retval
= watchpoint_remove_all_internal(target
);
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
;
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
)
483 retval
= breakpoint_remove_all_internal(target
);
489 struct breakpoint
*breakpoint_find(struct target
*target
, target_addr_t address
)
491 struct breakpoint
*breakpoint
= target
->breakpoints
;
494 if (breakpoint
->address
== address
)
496 breakpoint
= breakpoint
->next
;
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
;
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
);
522 /* ignore duplicate watchpoint */
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
);
541 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
542 reason
= "resource not available";
544 case ERROR_TARGET_NOT_HALTED
:
545 reason
= "target running";
548 reason
= "unrecognized error";
550 LOG_TARGET_ERROR(target
, "can't add %s watchpoint at " TARGET_ADDR_FMT
", %s",
551 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
554 *watchpoint_p
= NULL
;
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
);
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
)
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
)
583 return watchpoint_add_internal(target
, address
, length
, rw
, value
,
588 static int watchpoint_remove_internal(struct target
*target
, target_addr_t address
)
590 struct watchpoint
*watchpoint
= target
->watchpoints
;
593 if (watchpoint
->address
== address
)
595 watchpoint
= watchpoint
->next
;
599 return watchpoint_free(target
, watchpoint
);
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;
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
);
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
;
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
;
653 struct watchpoint
*tmp
= watchpoint
;
654 watchpoint
= watchpoint
->next
;
655 int status
= watchpoint_free(target
, tmp
);
656 if (status
!= ERROR_OK
)
662 int watchpoint_hit(struct target
*target
, enum watchpoint_rw
*rw
,
663 target_addr_t
*address
)
666 struct watchpoint
*hit_watchpoint
;
668 retval
= target_hit_watchpoint(target
, &hit_watchpoint
);
669 if (retval
!= ERROR_OK
)
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
);
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)