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
);