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_ERROR("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_ERROR("can't add breakpoint: %s", reason
);
87 free((*breakpoint_p
)->orig_instr
);
93 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
94 " of length 0x%8.8x, (BPID: %" PRIu32
")",
96 breakpoint_type_strings
[(*breakpoint_p
)->type
],
97 (*breakpoint_p
)->address
, (*breakpoint_p
)->length
,
98 (*breakpoint_p
)->unique_id
);
103 static int context_breakpoint_add_internal(struct target
*target
,
106 enum breakpoint_type type
)
108 struct breakpoint
*breakpoint
= target
->breakpoints
;
109 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
113 if (breakpoint
->asid
== asid
) {
114 /* FIXME don't assume "same address" means "same
115 * breakpoint" ... check all the parameters before
118 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32
" (BP %" PRIu32
")",
119 asid
, breakpoint
->unique_id
);
120 return ERROR_TARGET_DUPLICATE_BREAKPOINT
;
122 breakpoint_p
= &breakpoint
->next
;
123 breakpoint
= breakpoint
->next
;
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
);
140 *breakpoint_p
= NULL
;
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
);
152 static int hybrid_breakpoint_add_internal(struct target
*target
,
153 target_addr_t address
,
156 enum breakpoint_type type
)
158 struct breakpoint
*breakpoint
= target
->breakpoints
;
159 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
163 if ((breakpoint
->asid
== asid
) && (breakpoint
->address
== address
)) {
164 /* FIXME don't assume "same address" means "same
165 * breakpoint" ... check all the parameters before
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
;
177 breakpoint_p
= &breakpoint
->next
;
178 breakpoint
= breakpoint
->next
;
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
++;
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
);
196 *breakpoint_p
= NULL
;
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
);
209 int breakpoint_add(struct target
*target
,
210 target_addr_t address
,
212 enum breakpoint_type type
)
215 struct target_list
*head
;
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
);
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
)
231 return breakpoint_add_internal(target
, address
, length
, type
);
235 int context_breakpoint_add(struct target
*target
,
238 enum breakpoint_type type
)
241 struct target_list
*head
;
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
)
252 return context_breakpoint_add_internal(target
, asid
, length
, type
);
256 int hybrid_breakpoint_add(struct target
*target
,
257 target_addr_t address
,
260 enum breakpoint_type type
)
263 struct target_list
*head
;
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
)
274 return hybrid_breakpoint_add_internal(target
, address
, asid
, length
, type
);
277 /* free up a breakpoint */
278 static int breakpoint_free(struct target
*target
, struct breakpoint
*breakpoint_to_remove
)
280 struct breakpoint
*breakpoint
= target
->breakpoints
;
281 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
285 if (breakpoint
== breakpoint_to_remove
)
287 breakpoint_p
= &breakpoint
->next
;
288 breakpoint
= breakpoint
->next
;
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",
301 LOG_DEBUG("free BPID: %" PRIu32
" --> %d", breakpoint
->unique_id
, retval
);
302 (*breakpoint_p
) = breakpoint
->next
;
303 free(breakpoint
->orig_instr
);
309 static int breakpoint_remove_internal(struct target
*target
, target_addr_t address
)
311 struct breakpoint
*breakpoint
= target
->breakpoints
;
314 if ((breakpoint
->address
== address
) ||
315 (breakpoint
->address
== 0 && breakpoint
->asid
== address
))
317 breakpoint
= breakpoint
->next
;
321 return breakpoint_free(target
, breakpoint
);
323 return ERROR_BREAKPOINT_NOT_FOUND
;
327 static int breakpoint_remove_all_internal(struct target
*target
)
329 LOG_TARGET_DEBUG(target
, "Delete all breakpoints");
331 struct breakpoint
*breakpoint
= target
->breakpoints
;
332 int retval
= ERROR_OK
;
335 struct breakpoint
*tmp
= breakpoint
;
336 breakpoint
= breakpoint
->next
;
337 int status
= breakpoint_free(target
, tmp
);
338 if (status
!= ERROR_OK
)
345 int breakpoint_remove(struct target
*target
, target_addr_t address
)
347 int retval
= ERROR_OK
;
348 unsigned int num_found_breakpoints
= 0;
350 struct target_list
*head
;
352 foreach_smp_target(head
, target
->smp_targets
) {
353 struct target
*curr
= head
->target
;
354 int status
= breakpoint_remove_internal(curr
, address
);
356 if (status
!= ERROR_BREAKPOINT_NOT_FOUND
) {
357 num_found_breakpoints
++;
359 if (status
!= ERROR_OK
) {
360 LOG_TARGET_ERROR(curr
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
367 retval
= breakpoint_remove_internal(target
, address
);
369 if (retval
!= ERROR_BREAKPOINT_NOT_FOUND
) {
370 num_found_breakpoints
++;
372 if (retval
!= ERROR_OK
)
373 LOG_TARGET_ERROR(target
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
377 if (num_found_breakpoints
== 0) {
378 LOG_TARGET_ERROR(target
, "no breakpoint at address " TARGET_ADDR_FMT
" found", address
);
379 return ERROR_BREAKPOINT_NOT_FOUND
;
385 static int watchpoint_free(struct target
*target
, struct watchpoint
*watchpoint_to_remove
)
387 struct watchpoint
*watchpoint
= target
->watchpoints
;
388 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
392 if (watchpoint
== watchpoint_to_remove
)
394 watchpoint_p
= &watchpoint
->next
;
395 watchpoint
= watchpoint
->next
;
400 retval
= target_remove_watchpoint(target
, watchpoint
);
401 if (retval
!= ERROR_OK
) {
402 LOG_TARGET_ERROR(target
, "could not remove watchpoint #%d on this target",
407 LOG_DEBUG("free WPID: %d --> %d", watchpoint
->unique_id
, retval
);
408 (*watchpoint_p
) = watchpoint
->next
;
414 static int watchpoint_remove_all_internal(struct target
*target
)
416 struct watchpoint
*watchpoint
= target
->watchpoints
;
417 int retval
= ERROR_OK
;
420 struct watchpoint
*tmp
= watchpoint
;
421 watchpoint
= watchpoint
->next
;
422 int status
= watchpoint_free(target
, tmp
);
423 if (status
!= ERROR_OK
)
430 static int breakpoint_watchpoint_remove_all(struct target
*target
, enum breakpoint_watchpoint bp_wp
)
432 assert(bp_wp
== BREAKPOINT
|| bp_wp
== WATCHPOINT
);
433 int retval
= ERROR_OK
;
435 struct target_list
*head
;
437 foreach_smp_target(head
, target
->smp_targets
) {
438 struct target
*curr
= head
->target
;
440 int status
= ERROR_OK
;
441 if (bp_wp
== BREAKPOINT
)
442 status
= breakpoint_remove_all_internal(curr
);
444 status
= watchpoint_remove_all_internal(curr
);
446 if (status
!= ERROR_OK
)
450 if (bp_wp
== BREAKPOINT
)
451 retval
= breakpoint_remove_all_internal(target
);
453 retval
= watchpoint_remove_all_internal(target
);
459 int breakpoint_remove_all(struct target
*target
)
461 return breakpoint_watchpoint_remove_all(target
, BREAKPOINT
);
464 int watchpoint_remove_all(struct target
*target
)
466 return breakpoint_watchpoint_remove_all(target
, WATCHPOINT
);
469 int breakpoint_clear_target(struct target
*target
)
471 int retval
= ERROR_OK
;
474 struct target_list
*head
;
476 foreach_smp_target(head
, target
->smp_targets
) {
477 struct target
*curr
= head
->target
;
478 int status
= breakpoint_remove_all_internal(curr
);
480 if (status
!= ERROR_OK
)
484 retval
= breakpoint_remove_all_internal(target
);
490 struct breakpoint
*breakpoint_find(struct target
*target
, target_addr_t address
)
492 struct breakpoint
*breakpoint
= target
->breakpoints
;
495 if (breakpoint
->address
== address
)
497 breakpoint
= breakpoint
->next
;
503 static int watchpoint_add_internal(struct target
*target
, target_addr_t address
,
504 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
506 struct watchpoint
*watchpoint
= target
->watchpoints
;
507 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
512 if (watchpoint
->address
== address
) {
513 if (watchpoint
->length
!= length
514 || watchpoint
->value
!= value
515 || watchpoint
->mask
!= mask
516 || watchpoint
->rw
!= rw
) {
517 LOG_ERROR("address " TARGET_ADDR_FMT
518 " already has watchpoint %d",
519 address
, watchpoint
->unique_id
);
523 /* ignore duplicate watchpoint */
526 watchpoint_p
= &watchpoint
->next
;
527 watchpoint
= watchpoint
->next
;
530 (*watchpoint_p
) = calloc(1, sizeof(struct watchpoint
));
531 (*watchpoint_p
)->address
= address
;
532 (*watchpoint_p
)->length
= length
;
533 (*watchpoint_p
)->value
= value
;
534 (*watchpoint_p
)->mask
= mask
;
535 (*watchpoint_p
)->rw
= rw
;
536 (*watchpoint_p
)->unique_id
= bpwp_unique_id
++;
538 retval
= target_add_watchpoint(target
, *watchpoint_p
);
542 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
543 reason
= "resource not available";
545 case ERROR_TARGET_NOT_HALTED
:
546 reason
= "target running";
549 reason
= "unrecognized error";
551 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT
", %s",
552 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
555 *watchpoint_p
= NULL
;
559 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
560 " of length 0x%8.8" PRIx32
" (WPID: %d)",
562 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
563 (*watchpoint_p
)->address
,
564 (*watchpoint_p
)->length
,
565 (*watchpoint_p
)->unique_id
);
570 int watchpoint_add(struct target
*target
, target_addr_t address
,
571 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
574 struct target_list
*head
;
576 foreach_smp_target(head
, target
->smp_targets
) {
577 struct target
*curr
= head
->target
;
578 int retval
= watchpoint_add_internal(curr
, address
, length
, rw
, value
, mask
);
579 if (retval
!= ERROR_OK
)
585 return watchpoint_add_internal(target
, address
, length
, rw
, value
,
590 static int watchpoint_remove_internal(struct target
*target
, target_addr_t address
)
592 struct watchpoint
*watchpoint
= target
->watchpoints
;
595 if (watchpoint
->address
== address
)
597 watchpoint
= watchpoint
->next
;
601 return watchpoint_free(target
, watchpoint
);
603 return ERROR_WATCHPOINT_NOT_FOUND
;
607 int watchpoint_remove(struct target
*target
, target_addr_t address
)
609 int retval
= ERROR_OK
;
610 unsigned int num_found_watchpoints
= 0;
612 struct target_list
*head
;
614 foreach_smp_target(head
, target
->smp_targets
) {
615 struct target
*curr
= head
->target
;
616 int status
= watchpoint_remove_internal(curr
, address
);
618 if (status
!= ERROR_WATCHPOINT_NOT_FOUND
) {
619 num_found_watchpoints
++;
621 if (status
!= ERROR_OK
) {
622 LOG_TARGET_ERROR(curr
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
628 retval
= watchpoint_remove_internal(target
, address
);
630 if (retval
!= ERROR_WATCHPOINT_NOT_FOUND
) {
631 num_found_watchpoints
++;
633 if (retval
!= ERROR_OK
)
634 LOG_TARGET_ERROR(target
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
638 if (num_found_watchpoints
== 0) {
639 LOG_TARGET_ERROR(target
, "no watchpoint at address " TARGET_ADDR_FMT
" found", address
);
640 return ERROR_WATCHPOINT_NOT_FOUND
;
646 int watchpoint_clear_target(struct target
*target
)
648 LOG_DEBUG("Delete all watchpoints for target: %s",
649 target_name(target
));
651 struct watchpoint
*watchpoint
= target
->watchpoints
;
652 int retval
= ERROR_OK
;
655 struct watchpoint
*tmp
= watchpoint
;
656 watchpoint
= watchpoint
->next
;
657 int status
= watchpoint_free(target
, tmp
);
658 if (status
!= ERROR_OK
)
664 int watchpoint_hit(struct target
*target
, enum watchpoint_rw
*rw
,
665 target_addr_t
*address
)
668 struct watchpoint
*hit_watchpoint
;
670 retval
= target_hit_watchpoint(target
, &hit_watchpoint
);
671 if (retval
!= ERROR_OK
)
674 *rw
= hit_watchpoint
->rw
;
675 *address
= hit_watchpoint
->address
;
677 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT
" (WPID: %d)",
678 hit_watchpoint
->address
,
679 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)