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 void 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
);
291 LOG_DEBUG("free BPID: %" PRIu32
" --> %d", breakpoint
->unique_id
, retval
);
292 (*breakpoint_p
) = breakpoint
->next
;
293 free(breakpoint
->orig_instr
);
297 static int breakpoint_remove_internal(struct target
*target
, target_addr_t address
)
299 struct breakpoint
*breakpoint
= target
->breakpoints
;
302 if ((breakpoint
->address
== address
) ||
303 (breakpoint
->address
== 0 && breakpoint
->asid
== address
))
305 breakpoint
= breakpoint
->next
;
309 breakpoint_free(target
, breakpoint
);
313 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT
" found", address
);
318 static void breakpoint_remove_all_internal(struct target
*target
)
320 struct breakpoint
*breakpoint
= target
->breakpoints
;
323 struct breakpoint
*tmp
= breakpoint
;
324 breakpoint
= breakpoint
->next
;
325 breakpoint_free(target
, tmp
);
329 void breakpoint_remove(struct target
*target
, target_addr_t address
)
332 unsigned int num_breakpoints
= 0;
333 struct target_list
*head
;
335 foreach_smp_target(head
, target
->smp_targets
) {
336 struct target
*curr
= head
->target
;
337 num_breakpoints
+= breakpoint_remove_internal(curr
, address
);
339 if (!num_breakpoints
)
340 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT
" found", address
);
342 breakpoint_remove_internal(target
, address
);
346 void breakpoint_remove_all(struct target
*target
)
349 struct target_list
*head
;
351 foreach_smp_target(head
, target
->smp_targets
) {
352 struct target
*curr
= head
->target
;
353 breakpoint_remove_all_internal(curr
);
356 breakpoint_remove_all_internal(target
);
360 static void breakpoint_clear_target_internal(struct target
*target
)
362 LOG_DEBUG("Delete all breakpoints for target: %s",
363 target_name(target
));
364 while (target
->breakpoints
)
365 breakpoint_free(target
, target
->breakpoints
);
368 void breakpoint_clear_target(struct target
*target
)
371 struct target_list
*head
;
373 foreach_smp_target(head
, target
->smp_targets
) {
374 struct target
*curr
= head
->target
;
375 breakpoint_clear_target_internal(curr
);
378 breakpoint_clear_target_internal(target
);
382 struct breakpoint
*breakpoint_find(struct target
*target
, target_addr_t address
)
384 struct breakpoint
*breakpoint
= target
->breakpoints
;
387 if (breakpoint
->address
== address
)
389 breakpoint
= breakpoint
->next
;
395 static int watchpoint_add_internal(struct target
*target
, target_addr_t address
,
396 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
398 struct watchpoint
*watchpoint
= target
->watchpoints
;
399 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
404 if (watchpoint
->address
== address
) {
405 if (watchpoint
->length
!= length
406 || watchpoint
->value
!= value
407 || watchpoint
->mask
!= mask
408 || watchpoint
->rw
!= rw
) {
409 LOG_ERROR("address " TARGET_ADDR_FMT
410 " already has watchpoint %d",
411 address
, watchpoint
->unique_id
);
415 /* ignore duplicate watchpoint */
418 watchpoint_p
= &watchpoint
->next
;
419 watchpoint
= watchpoint
->next
;
422 (*watchpoint_p
) = calloc(1, sizeof(struct watchpoint
));
423 (*watchpoint_p
)->address
= address
;
424 (*watchpoint_p
)->length
= length
;
425 (*watchpoint_p
)->value
= value
;
426 (*watchpoint_p
)->mask
= mask
;
427 (*watchpoint_p
)->rw
= rw
;
428 (*watchpoint_p
)->unique_id
= bpwp_unique_id
++;
430 retval
= target_add_watchpoint(target
, *watchpoint_p
);
434 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE
:
435 reason
= "resource not available";
437 case ERROR_TARGET_NOT_HALTED
:
438 reason
= "target running";
441 reason
= "unrecognized error";
443 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT
", %s",
444 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
447 *watchpoint_p
= NULL
;
451 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
452 " of length 0x%8.8" PRIx32
" (WPID: %d)",
454 watchpoint_rw_strings
[(*watchpoint_p
)->rw
],
455 (*watchpoint_p
)->address
,
456 (*watchpoint_p
)->length
,
457 (*watchpoint_p
)->unique_id
);
462 int watchpoint_add(struct target
*target
, target_addr_t address
,
463 uint32_t length
, enum watchpoint_rw rw
, uint64_t value
, uint64_t mask
)
466 struct target_list
*head
;
468 foreach_smp_target(head
, target
->smp_targets
) {
469 struct target
*curr
= head
->target
;
470 int retval
= watchpoint_add_internal(curr
, address
, length
, rw
, value
, mask
);
471 if (retval
!= ERROR_OK
)
477 return watchpoint_add_internal(target
, address
, length
, rw
, value
,
482 static void watchpoint_free(struct target
*target
, struct watchpoint
*watchpoint_to_remove
)
484 struct watchpoint
*watchpoint
= target
->watchpoints
;
485 struct watchpoint
**watchpoint_p
= &target
->watchpoints
;
489 if (watchpoint
== watchpoint_to_remove
)
491 watchpoint_p
= &watchpoint
->next
;
492 watchpoint
= watchpoint
->next
;
497 retval
= target_remove_watchpoint(target
, watchpoint
);
498 LOG_DEBUG("free WPID: %d --> %d", watchpoint
->unique_id
, retval
);
499 (*watchpoint_p
) = watchpoint
->next
;
503 static int watchpoint_remove_internal(struct target
*target
, target_addr_t address
)
505 struct watchpoint
*watchpoint
= target
->watchpoints
;
508 if (watchpoint
->address
== address
)
510 watchpoint
= watchpoint
->next
;
514 watchpoint_free(target
, watchpoint
);
518 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT
" found", address
);
523 void watchpoint_remove(struct target
*target
, target_addr_t address
)
526 unsigned int num_watchpoints
= 0;
527 struct target_list
*head
;
529 foreach_smp_target(head
, target
->smp_targets
) {
530 struct target
*curr
= head
->target
;
531 num_watchpoints
+= watchpoint_remove_internal(curr
, address
);
533 if (num_watchpoints
== 0)
534 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT
" num_watchpoints", address
);
536 watchpoint_remove_internal(target
, address
);
540 void watchpoint_clear_target(struct target
*target
)
542 LOG_DEBUG("Delete all watchpoints for target: %s",
543 target_name(target
));
544 while (target
->watchpoints
)
545 watchpoint_free(target
, target
->watchpoints
);
548 int watchpoint_hit(struct target
*target
, enum watchpoint_rw
*rw
,
549 target_addr_t
*address
)
552 struct watchpoint
*hit_watchpoint
;
554 retval
= target_hit_watchpoint(target
, &hit_watchpoint
);
555 if (retval
!= ERROR_OK
)
558 *rw
= hit_watchpoint
->rw
;
559 *address
= hit_watchpoint
->address
;
561 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT
" (WPID: %d)",
562 hit_watchpoint
->address
,
563 hit_watchpoint
->unique_id
);