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 struct breakpoint
*breakpoint
= target
->breakpoints
;
330 int retval
= ERROR_OK
;
333 struct breakpoint
*tmp
= breakpoint
;
334 breakpoint
= breakpoint
->next
;
335 int status
= breakpoint_free(target
, tmp
);
336 if (status
!= ERROR_OK
)
343 int breakpoint_remove(struct target
*target
, target_addr_t address
)
345 int retval
= ERROR_OK
;
346 unsigned int num_found_breakpoints
= 0;
348 struct target_list
*head
;
350 foreach_smp_target(head
, target
->smp_targets
) {
351 struct target
*curr
= head
->target
;
352 int status
= breakpoint_remove_internal(curr
, address
);
354 if (status
!= ERROR_BREAKPOINT_NOT_FOUND
) {
355 num_found_breakpoints
++;
357 if (status
!= ERROR_OK
) {
358 LOG_TARGET_ERROR(curr
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
365 retval
= breakpoint_remove_internal(target
, address
);
367 if (retval
!= ERROR_BREAKPOINT_NOT_FOUND
) {
368 num_found_breakpoints
++;
370 if (retval
!= ERROR_OK
)
371 LOG_TARGET_ERROR(target
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
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
;
383 static int watchpoint_free(struct target
*target
, struct watchpoint
*watchpoint_to_remove
)
385 struct watchpoint
*watchpoint
= target
->watchpoints
;
386 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
390 if (watchpoint
== watchpoint_to_remove
)
392 watchpoint_p
= &watchpoint
->next
;
393 watchpoint
= watchpoint
->next
;
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",
405 LOG_DEBUG("free WPID: %d --> %d", watchpoint
->unique_id
, retval
);
406 (*watchpoint_p
) = watchpoint
->next
;
412 static int watchpoint_remove_all_internal(struct target
*target
)
414 struct watchpoint
*watchpoint
= target
->watchpoints
;
415 int retval
= ERROR_OK
;
418 struct watchpoint
*tmp
= watchpoint
;
419 watchpoint
= watchpoint
->next
;
420 int status
= watchpoint_free(target
, tmp
);
421 if (status
!= ERROR_OK
)
428 static int breakpoint_watchpoint_remove_all(struct target
*target
, enum breakpoint_watchpoint bp_wp
)
430 assert(bp_wp
== BREAKPOINT
|| bp_wp
== WATCHPOINT
);
431 int retval
= ERROR_OK
;
433 struct target_list
*head
;
435 foreach_smp_target(head
, target
->smp_targets
) {
436 struct target
*curr
= head
->target
;
438 int status
= ERROR_OK
;
439 if (bp_wp
== BREAKPOINT
)
440 status
= breakpoint_remove_all_internal(curr
);
442 status
= watchpoint_remove_all_internal(curr
);
444 if (status
!= ERROR_OK
)
448 if (bp_wp
== BREAKPOINT
)
449 retval
= breakpoint_remove_all_internal(target
);
451 retval
= watchpoint_remove_all_internal(target
);
457 int breakpoint_remove_all(struct target
*target
)
459 return breakpoint_watchpoint_remove_all(target
, BREAKPOINT
);
462 int watchpoint_remove_all(struct target
*target
)
464 return breakpoint_watchpoint_remove_all(target
, WATCHPOINT
);
467 static int breakpoint_clear_target_internal(struct target
*target
)
469 LOG_DEBUG("Delete all breakpoints for target: %s",
470 target_name(target
));
472 int retval
= ERROR_OK
;
474 while (target
->breakpoints
) {
475 int status
= breakpoint_free(target
, target
->breakpoints
);
476 if (status
!= ERROR_OK
)
483 int breakpoint_clear_target(struct target
*target
)
485 int retval
= ERROR_OK
;
488 struct target_list
*head
;
490 foreach_smp_target(head
, target
->smp_targets
) {
491 struct target
*curr
= head
->target
;
492 int status
= breakpoint_clear_target_internal(curr
);
494 if (status
!= ERROR_OK
)
498 retval
= breakpoint_clear_target_internal(target
);
504 struct breakpoint
*breakpoint_find(struct target
*target
, target_addr_t address
)
506 struct breakpoint
*breakpoint
= target
->breakpoints
;
509 if (breakpoint
->address
== address
)
511 breakpoint
= breakpoint
->next
;
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
)
520 struct watchpoint
*watchpoint
= target
->watchpoints
;
521 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
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
);
537 /* ignore duplicate watchpoint */
540 watchpoint_p
= &watchpoint
->next
;
541 watchpoint
= watchpoint
->next
;
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
++;
552 retval
= target_add_watchpoint(target
, *watchpoint_p
);
556 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
557 reason
= "resource not available";
559 case ERROR_TARGET_NOT_HALTED
:
560 reason
= "target running";
563 reason
= "unrecognized error";
565 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT
", %s",
566 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
569 *watchpoint_p
= NULL
;
573 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
574 " of length 0x%8.8" PRIx32
" (WPID: %d)",
576 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
577 (*watchpoint_p
)->address
,
578 (*watchpoint_p
)->length
,
579 (*watchpoint_p
)->unique_id
);
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
)
588 struct target_list
*head
;
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
)
599 return watchpoint_add_internal(target
, address
, length
, rw
, value
,
604 static int watchpoint_remove_internal(struct target
*target
, target_addr_t address
)
606 struct watchpoint
*watchpoint
= target
->watchpoints
;
609 if (watchpoint
->address
== address
)
611 watchpoint
= watchpoint
->next
;
615 return watchpoint_free(target
, watchpoint
);
617 return ERROR_WATCHPOINT_NOT_FOUND
;
621 int watchpoint_remove(struct target
*target
, target_addr_t address
)
623 int retval
= ERROR_OK
;
624 unsigned int num_found_watchpoints
= 0;
626 struct target_list
*head
;
628 foreach_smp_target(head
, target
->smp_targets
) {
629 struct target
*curr
= head
->target
;
630 int status
= watchpoint_remove_internal(curr
, address
);
632 if (status
!= ERROR_WATCHPOINT_NOT_FOUND
) {
633 num_found_watchpoints
++;
635 if (status
!= ERROR_OK
) {
636 LOG_TARGET_ERROR(curr
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
642 retval
= watchpoint_remove_internal(target
, address
);
644 if (retval
!= ERROR_WATCHPOINT_NOT_FOUND
) {
645 num_found_watchpoints
++;
647 if (retval
!= ERROR_OK
)
648 LOG_TARGET_ERROR(target
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
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
;
660 int watchpoint_clear_target(struct target
*target
)
662 int retval
= ERROR_OK
;
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
)
675 int watchpoint_hit(struct target
*target
, enum watchpoint_rw
*rw
,
676 target_addr_t
*address
)
679 struct watchpoint
*hit_watchpoint
;
681 retval
= target_hit_watchpoint(target
, &hit_watchpoint
);
682 if (retval
!= ERROR_OK
)
685 *rw
= hit_watchpoint
->rw
;
686 *address
= hit_watchpoint
->address
;
688 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT
" (WPID: %d)",
689 hit_watchpoint
->address
,
690 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)