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 static const char * const breakpoint_type_strings
[] = {
25 static const char * const watchpoint_rw_strings
[] = {
31 /* monotonic counter/id-number for breakpoints and watch points */
32 static int bpwp_unique_id
;
34 static int breakpoint_add_internal(struct target
*target
,
35 target_addr_t address
,
37 enum breakpoint_type type
)
39 struct breakpoint
*breakpoint
= target
->breakpoints
;
40 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
45 if (breakpoint
->address
== address
) {
46 /* FIXME don't assume "same address" means "same
47 * breakpoint" ... check all the parameters before
50 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT
" (BP %" PRIu32
")",
51 address
, breakpoint
->unique_id
);
52 return ERROR_TARGET_DUPLICATE_BREAKPOINT
;
54 breakpoint_p
= &breakpoint
->next
;
55 breakpoint
= breakpoint
->next
;
58 (*breakpoint_p
) = malloc(sizeof(struct breakpoint
));
59 (*breakpoint_p
)->address
= address
;
60 (*breakpoint_p
)->asid
= 0;
61 (*breakpoint_p
)->length
= length
;
62 (*breakpoint_p
)->type
= type
;
63 (*breakpoint_p
)->is_set
= false;
64 (*breakpoint_p
)->orig_instr
= malloc(length
);
65 (*breakpoint_p
)->next
= NULL
;
66 (*breakpoint_p
)->unique_id
= bpwp_unique_id
++;
68 retval
= target_add_breakpoint(target
, *breakpoint_p
);
72 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
73 reason
= "resource not available";
75 case ERROR_TARGET_NOT_HALTED
:
76 reason
= "target running";
79 reason
= "unknown reason";
81 LOG_ERROR("can't add breakpoint: %s", reason
);
82 free((*breakpoint_p
)->orig_instr
);
88 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
89 " of length 0x%8.8x, (BPID: %" PRIu32
")",
91 breakpoint_type_strings
[(*breakpoint_p
)->type
],
92 (*breakpoint_p
)->address
, (*breakpoint_p
)->length
,
93 (*breakpoint_p
)->unique_id
);
98 static int context_breakpoint_add_internal(struct target
*target
,
101 enum breakpoint_type type
)
103 struct breakpoint
*breakpoint
= target
->breakpoints
;
104 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
108 if (breakpoint
->asid
== asid
) {
109 /* FIXME don't assume "same address" means "same
110 * breakpoint" ... check all the parameters before
113 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32
" (BP %" PRIu32
")",
114 asid
, breakpoint
->unique_id
);
115 return ERROR_TARGET_DUPLICATE_BREAKPOINT
;
117 breakpoint_p
= &breakpoint
->next
;
118 breakpoint
= breakpoint
->next
;
121 (*breakpoint_p
) = malloc(sizeof(struct breakpoint
));
122 (*breakpoint_p
)->address
= 0;
123 (*breakpoint_p
)->asid
= asid
;
124 (*breakpoint_p
)->length
= length
;
125 (*breakpoint_p
)->type
= type
;
126 (*breakpoint_p
)->is_set
= false;
127 (*breakpoint_p
)->orig_instr
= malloc(length
);
128 (*breakpoint_p
)->next
= NULL
;
129 (*breakpoint_p
)->unique_id
= bpwp_unique_id
++;
130 retval
= target_add_context_breakpoint(target
, *breakpoint_p
);
131 if (retval
!= ERROR_OK
) {
132 LOG_ERROR("could not add breakpoint");
133 free((*breakpoint_p
)->orig_instr
);
135 *breakpoint_p
= NULL
;
139 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32
" of length 0x%8.8x, (BPID: %" PRIu32
")",
140 breakpoint_type_strings
[(*breakpoint_p
)->type
],
141 (*breakpoint_p
)->asid
, (*breakpoint_p
)->length
,
142 (*breakpoint_p
)->unique_id
);
147 static int hybrid_breakpoint_add_internal(struct target
*target
,
148 target_addr_t address
,
151 enum breakpoint_type type
)
153 struct breakpoint
*breakpoint
= target
->breakpoints
;
154 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
158 if ((breakpoint
->asid
== asid
) && (breakpoint
->address
== address
)) {
159 /* FIXME don't assume "same address" means "same
160 * breakpoint" ... check all the parameters before
163 LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32
" (BP %" PRIu32
")",
164 asid
, breakpoint
->unique_id
);
165 return ERROR_TARGET_DUPLICATE_BREAKPOINT
;
166 } else if ((breakpoint
->address
== address
) && (breakpoint
->asid
== 0)) {
167 LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT
" (BP %" PRIu32
")",
168 address
, breakpoint
->unique_id
);
169 return ERROR_TARGET_DUPLICATE_BREAKPOINT
;
172 breakpoint_p
= &breakpoint
->next
;
173 breakpoint
= breakpoint
->next
;
175 (*breakpoint_p
) = malloc(sizeof(struct breakpoint
));
176 (*breakpoint_p
)->address
= address
;
177 (*breakpoint_p
)->asid
= asid
;
178 (*breakpoint_p
)->length
= length
;
179 (*breakpoint_p
)->type
= type
;
180 (*breakpoint_p
)->is_set
= false;
181 (*breakpoint_p
)->orig_instr
= malloc(length
);
182 (*breakpoint_p
)->next
= NULL
;
183 (*breakpoint_p
)->unique_id
= bpwp_unique_id
++;
186 retval
= target_add_hybrid_breakpoint(target
, *breakpoint_p
);
187 if (retval
!= ERROR_OK
) {
188 LOG_ERROR("could not add breakpoint");
189 free((*breakpoint_p
)->orig_instr
);
191 *breakpoint_p
= NULL
;
195 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT
" of length 0x%8.8x, (BPID: %" PRIu32
")",
196 breakpoint_type_strings
[(*breakpoint_p
)->type
],
197 (*breakpoint_p
)->address
,
198 (*breakpoint_p
)->length
,
199 (*breakpoint_p
)->unique_id
);
204 int breakpoint_add(struct target
*target
,
205 target_addr_t address
,
207 enum breakpoint_type type
)
210 struct target_list
*head
;
212 if (type
== BKPT_SOFT
) {
213 head
= list_first_entry(target
->smp_targets
, struct target_list
, lh
);
214 return breakpoint_add_internal(head
->target
, address
, length
, type
);
217 foreach_smp_target(head
, target
->smp_targets
) {
218 struct target
*curr
= head
->target
;
219 int retval
= breakpoint_add_internal(curr
, address
, length
, type
);
220 if (retval
!= ERROR_OK
)
226 return breakpoint_add_internal(target
, address
, length
, type
);
230 int context_breakpoint_add(struct target
*target
,
233 enum breakpoint_type type
)
236 struct target_list
*head
;
238 foreach_smp_target(head
, target
->smp_targets
) {
239 struct target
*curr
= head
->target
;
240 int retval
= context_breakpoint_add_internal(curr
, asid
, length
, type
);
241 if (retval
!= ERROR_OK
)
247 return context_breakpoint_add_internal(target
, asid
, length
, type
);
251 int hybrid_breakpoint_add(struct target
*target
,
252 target_addr_t address
,
255 enum breakpoint_type type
)
258 struct target_list
*head
;
260 foreach_smp_target(head
, target
->smp_targets
) {
261 struct target
*curr
= head
->target
;
262 int retval
= hybrid_breakpoint_add_internal(curr
, address
, asid
, length
, type
);
263 if (retval
!= ERROR_OK
)
269 return hybrid_breakpoint_add_internal(target
, address
, asid
, length
, type
);
272 /* free up a breakpoint */
273 static int breakpoint_free(struct target
*target
, struct breakpoint
*breakpoint_to_remove
)
275 struct breakpoint
*breakpoint
= target
->breakpoints
;
276 struct breakpoint
**breakpoint_p
= &target
->breakpoints
;
280 if (breakpoint
== breakpoint_to_remove
)
282 breakpoint_p
= &breakpoint
->next
;
283 breakpoint
= breakpoint
->next
;
289 retval
= target_remove_breakpoint(target
, breakpoint
);
290 if (retval
!= ERROR_OK
) {
291 LOG_TARGET_ERROR(target
, "could not remove breakpoint #%d on this target",
296 LOG_DEBUG("free BPID: %" PRIu32
" --> %d", breakpoint
->unique_id
, retval
);
297 (*breakpoint_p
) = breakpoint
->next
;
298 free(breakpoint
->orig_instr
);
304 static int breakpoint_remove_internal(struct target
*target
, target_addr_t address
)
306 struct breakpoint
*breakpoint
= target
->breakpoints
;
309 if ((breakpoint
->address
== address
) ||
310 (breakpoint
->address
== 0 && breakpoint
->asid
== address
))
312 breakpoint
= breakpoint
->next
;
316 return breakpoint_free(target
, breakpoint
);
318 return ERROR_BREAKPOINT_NOT_FOUND
;
322 static int breakpoint_remove_all_internal(struct target
*target
)
324 struct breakpoint
*breakpoint
= target
->breakpoints
;
325 int retval
= ERROR_OK
;
328 struct breakpoint
*tmp
= breakpoint
;
329 breakpoint
= breakpoint
->next
;
330 int status
= breakpoint_free(target
, tmp
);
331 if (status
!= ERROR_OK
)
338 int breakpoint_remove(struct target
*target
, target_addr_t address
)
340 int retval
= ERROR_OK
;
341 unsigned int num_found_breakpoints
= 0;
343 struct target_list
*head
;
345 foreach_smp_target(head
, target
->smp_targets
) {
346 struct target
*curr
= head
->target
;
347 int status
= breakpoint_remove_internal(curr
, address
);
349 if (status
!= ERROR_BREAKPOINT_NOT_FOUND
) {
350 num_found_breakpoints
++;
352 if (status
!= ERROR_OK
) {
353 LOG_TARGET_ERROR(curr
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
360 retval
= breakpoint_remove_internal(target
, address
);
362 if (retval
!= ERROR_BREAKPOINT_NOT_FOUND
) {
363 num_found_breakpoints
++;
365 if (retval
!= ERROR_OK
)
366 LOG_TARGET_ERROR(target
, "failed to remove breakpoint at address " TARGET_ADDR_FMT
, address
);
370 if (num_found_breakpoints
== 0) {
371 LOG_TARGET_ERROR(target
, "no breakpoint at address " TARGET_ADDR_FMT
" found", address
);
372 return ERROR_BREAKPOINT_NOT_FOUND
;
378 int breakpoint_remove_all(struct target
*target
)
380 int retval
= ERROR_OK
;
382 struct target_list
*head
;
384 foreach_smp_target(head
, target
->smp_targets
) {
385 struct target
*curr
= head
->target
;
386 int status
= breakpoint_remove_all_internal(curr
);
388 if (status
!= ERROR_OK
)
392 retval
= breakpoint_remove_all_internal(target
);
398 static int breakpoint_clear_target_internal(struct target
*target
)
400 LOG_DEBUG("Delete all breakpoints for target: %s",
401 target_name(target
));
403 int retval
= ERROR_OK
;
405 while (target
->breakpoints
) {
406 int status
= breakpoint_free(target
, target
->breakpoints
);
407 if (status
!= ERROR_OK
)
414 int breakpoint_clear_target(struct target
*target
)
416 int retval
= ERROR_OK
;
419 struct target_list
*head
;
421 foreach_smp_target(head
, target
->smp_targets
) {
422 struct target
*curr
= head
->target
;
423 int status
= breakpoint_clear_target_internal(curr
);
425 if (status
!= ERROR_OK
)
429 retval
= breakpoint_clear_target_internal(target
);
435 struct breakpoint
*breakpoint_find(struct target
*target
, target_addr_t address
)
437 struct breakpoint
*breakpoint
= target
->breakpoints
;
440 if (breakpoint
->address
== address
)
442 breakpoint
= breakpoint
->next
;
448 static int watchpoint_add_internal(struct target
*target
, target_addr_t address
,
449 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
451 struct watchpoint
*watchpoint
= target
->watchpoints
;
452 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
457 if (watchpoint
->address
== address
) {
458 if (watchpoint
->length
!= length
459 || watchpoint
->value
!= value
460 || watchpoint
->mask
!= mask
461 || watchpoint
->rw
!= rw
) {
462 LOG_ERROR("address " TARGET_ADDR_FMT
463 " already has watchpoint %d",
464 address
, watchpoint
->unique_id
);
468 /* ignore duplicate watchpoint */
471 watchpoint_p
= &watchpoint
->next
;
472 watchpoint
= watchpoint
->next
;
475 (*watchpoint_p
) = calloc(1, sizeof(struct watchpoint
));
476 (*watchpoint_p
)->address
= address
;
477 (*watchpoint_p
)->length
= length
;
478 (*watchpoint_p
)->value
= value
;
479 (*watchpoint_p
)->mask
= mask
;
480 (*watchpoint_p
)->rw
= rw
;
481 (*watchpoint_p
)->unique_id
= bpwp_unique_id
++;
483 retval
= target_add_watchpoint(target
, *watchpoint_p
);
487 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
488 reason
= "resource not available";
490 case ERROR_TARGET_NOT_HALTED
:
491 reason
= "target running";
494 reason
= "unrecognized error";
496 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT
", %s",
497 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
500 *watchpoint_p
= NULL
;
504 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
505 " of length 0x%8.8" PRIx32
" (WPID: %d)",
507 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
508 (*watchpoint_p
)->address
,
509 (*watchpoint_p
)->length
,
510 (*watchpoint_p
)->unique_id
);
515 int watchpoint_add(struct target
*target
, target_addr_t address
,
516 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
519 struct target_list
*head
;
521 foreach_smp_target(head
, target
->smp_targets
) {
522 struct target
*curr
= head
->target
;
523 int retval
= watchpoint_add_internal(curr
, address
, length
, rw
, value
, mask
);
524 if (retval
!= ERROR_OK
)
530 return watchpoint_add_internal(target
, address
, length
, rw
, value
,
535 static int watchpoint_free(struct target
*target
, struct watchpoint
*watchpoint_to_remove
)
537 struct watchpoint
*watchpoint
= target
->watchpoints
;
538 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
542 if (watchpoint
== watchpoint_to_remove
)
544 watchpoint_p
= &watchpoint
->next
;
545 watchpoint
= watchpoint
->next
;
550 retval
= target_remove_watchpoint(target
, watchpoint
);
551 if (retval
!= ERROR_OK
) {
552 LOG_TARGET_ERROR(target
, "could not remove watchpoint #%d on this target",
557 LOG_DEBUG("free WPID: %d --> %d", watchpoint
->unique_id
, retval
);
558 (*watchpoint_p
) = watchpoint
->next
;
564 static int watchpoint_remove_internal(struct target
*target
, target_addr_t address
)
566 struct watchpoint
*watchpoint
= target
->watchpoints
;
569 if (watchpoint
->address
== address
)
571 watchpoint
= watchpoint
->next
;
575 return watchpoint_free(target
, watchpoint
);
577 return ERROR_WATCHPOINT_NOT_FOUND
;
581 int watchpoint_remove(struct target
*target
, target_addr_t address
)
583 int retval
= ERROR_OK
;
584 unsigned int num_found_watchpoints
= 0;
586 struct target_list
*head
;
588 foreach_smp_target(head
, target
->smp_targets
) {
589 struct target
*curr
= head
->target
;
590 int status
= watchpoint_remove_internal(curr
, address
);
592 if (status
!= ERROR_WATCHPOINT_NOT_FOUND
) {
593 num_found_watchpoints
++;
595 if (status
!= ERROR_OK
) {
596 LOG_TARGET_ERROR(curr
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
602 retval
= watchpoint_remove_internal(target
, address
);
604 if (retval
!= ERROR_WATCHPOINT_NOT_FOUND
) {
605 num_found_watchpoints
++;
607 if (retval
!= ERROR_OK
)
608 LOG_TARGET_ERROR(target
, "failed to remove watchpoint at address " TARGET_ADDR_FMT
, address
);
612 if (num_found_watchpoints
== 0) {
613 LOG_TARGET_ERROR(target
, "no watchpoint at address " TARGET_ADDR_FMT
" found", address
);
614 return ERROR_WATCHPOINT_NOT_FOUND
;
620 int watchpoint_clear_target(struct target
*target
)
622 int retval
= ERROR_OK
;
624 LOG_DEBUG("Delete all watchpoints for target: %s",
625 target_name(target
));
626 while (target
->watchpoints
) {
627 int status
= watchpoint_free(target
, target
->watchpoints
);
628 if (status
!= ERROR_OK
)
635 int watchpoint_hit(struct target
*target
, enum watchpoint_rw
*rw
,
636 target_addr_t
*address
)
639 struct watchpoint
*hit_watchpoint
;
641 retval
= target_hit_watchpoint(target
, &hit_watchpoint
);
642 if (retval
!= ERROR_OK
)
645 *rw
= hit_watchpoint
->rw
;
646 *address
= hit_watchpoint
->address
;
648 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT
" (WPID: %d)",
649 hit_watchpoint
->address
,
650 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)