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 int watchpoint_add_internal(struct target *target, target_addr_t address,
396 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_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, uint32_t value, uint32_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 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);