breakpoints: use 64-bit type for watchpoint mask and value
[openocd.git] / src / target / breakpoints.c
blob4d268cebb3f460f3768eb1c256207bb35c4cef9a
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
6 * *
7 * Copyright (C) ST-Ericsson SA 2011 *
8 * michel.jaouen@stericsson.com : smp minimum support *
9 ***************************************************************************/
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
15 #include "target.h"
16 #include <helper/log.h>
17 #include "breakpoints.h"
18 #include "smp.h"
20 static const char * const breakpoint_type_strings[] = {
21 "hardware",
22 "software"
25 static const char * const watchpoint_rw_strings[] = {
26 "read",
27 "write",
28 "access"
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,
36 uint32_t length,
37 enum breakpoint_type type)
39 struct breakpoint *breakpoint = target->breakpoints;
40 struct breakpoint **breakpoint_p = &target->breakpoints;
41 const char *reason;
42 int retval;
44 while (breakpoint) {
45 if (breakpoint->address == address) {
46 /* FIXME don't assume "same address" means "same
47 * breakpoint" ... check all the parameters before
48 * succeeding.
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);
69 switch (retval) {
70 case ERROR_OK:
71 break;
72 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
73 reason = "resource not available";
74 goto fail;
75 case ERROR_TARGET_NOT_HALTED:
76 reason = "target running";
77 goto fail;
78 default:
79 reason = "unknown reason";
80 fail:
81 LOG_ERROR("can't add breakpoint: %s", reason);
82 free((*breakpoint_p)->orig_instr);
83 free(*breakpoint_p);
84 *breakpoint_p = NULL;
85 return retval;
88 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
89 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
90 target->coreid,
91 breakpoint_type_strings[(*breakpoint_p)->type],
92 (*breakpoint_p)->address, (*breakpoint_p)->length,
93 (*breakpoint_p)->unique_id);
95 return ERROR_OK;
98 static int context_breakpoint_add_internal(struct target *target,
99 uint32_t asid,
100 uint32_t length,
101 enum breakpoint_type type)
103 struct breakpoint *breakpoint = target->breakpoints;
104 struct breakpoint **breakpoint_p = &target->breakpoints;
105 int retval;
107 while (breakpoint) {
108 if (breakpoint->asid == asid) {
109 /* FIXME don't assume "same address" means "same
110 * breakpoint" ... check all the parameters before
111 * succeeding.
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);
134 free(*breakpoint_p);
135 *breakpoint_p = NULL;
136 return retval;
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);
144 return ERROR_OK;
147 static int hybrid_breakpoint_add_internal(struct target *target,
148 target_addr_t address,
149 uint32_t asid,
150 uint32_t length,
151 enum breakpoint_type type)
153 struct breakpoint *breakpoint = target->breakpoints;
154 struct breakpoint **breakpoint_p = &target->breakpoints;
155 int retval;
157 while (breakpoint) {
158 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
159 /* FIXME don't assume "same address" means "same
160 * breakpoint" ... check all the parameters before
161 * succeeding.
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);
190 free(*breakpoint_p);
191 *breakpoint_p = NULL;
192 return retval;
194 LOG_DEBUG(
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);
201 return ERROR_OK;
204 int breakpoint_add(struct target *target,
205 target_addr_t address,
206 uint32_t length,
207 enum breakpoint_type type)
209 if (target->smp) {
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)
221 return retval;
224 return ERROR_OK;
225 } else {
226 return breakpoint_add_internal(target, address, length, type);
230 int context_breakpoint_add(struct target *target,
231 uint32_t asid,
232 uint32_t length,
233 enum breakpoint_type type)
235 if (target->smp) {
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)
242 return retval;
245 return ERROR_OK;
246 } else {
247 return context_breakpoint_add_internal(target, asid, length, type);
251 int hybrid_breakpoint_add(struct target *target,
252 target_addr_t address,
253 uint32_t asid,
254 uint32_t length,
255 enum breakpoint_type type)
257 if (target->smp) {
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)
264 return retval;
267 return ERROR_OK;
268 } else
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;
277 int retval;
279 while (breakpoint) {
280 if (breakpoint == breakpoint_to_remove)
281 break;
282 breakpoint_p = &breakpoint->next;
283 breakpoint = breakpoint->next;
286 if (!breakpoint)
287 return;
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);
294 free(breakpoint);
297 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
299 struct breakpoint *breakpoint = target->breakpoints;
301 while (breakpoint) {
302 if ((breakpoint->address == address) ||
303 (breakpoint->address == 0 && breakpoint->asid == address))
304 break;
305 breakpoint = breakpoint->next;
308 if (breakpoint) {
309 breakpoint_free(target, breakpoint);
310 return 1;
311 } else {
312 if (!target->smp)
313 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
314 return 0;
318 static void breakpoint_remove_all_internal(struct target *target)
320 struct breakpoint *breakpoint = target->breakpoints;
322 while (breakpoint) {
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)
331 if (target->smp) {
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);
341 } else {
342 breakpoint_remove_internal(target, address);
346 void breakpoint_remove_all(struct target *target)
348 if (target->smp) {
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);
355 } else {
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)
370 if (target->smp) {
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);
377 } else {
378 breakpoint_clear_target_internal(target);
382 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
384 struct breakpoint *breakpoint = target->breakpoints;
386 while (breakpoint) {
387 if (breakpoint->address == address)
388 return breakpoint;
389 breakpoint = breakpoint->next;
392 return NULL;
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;
400 int retval;
401 const char *reason;
403 while (watchpoint) {
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);
412 return ERROR_FAIL;
415 /* ignore duplicate watchpoint */
416 return ERROR_OK;
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);
431 switch (retval) {
432 case ERROR_OK:
433 break;
434 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
435 reason = "resource not available";
436 goto bye;
437 case ERROR_TARGET_NOT_HALTED:
438 reason = "target running";
439 goto bye;
440 default:
441 reason = "unrecognized error";
442 bye:
443 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
444 watchpoint_rw_strings[(*watchpoint_p)->rw],
445 address, reason);
446 free(*watchpoint_p);
447 *watchpoint_p = NULL;
448 return retval;
451 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
452 " of length 0x%8.8" PRIx32 " (WPID: %d)",
453 target->coreid,
454 watchpoint_rw_strings[(*watchpoint_p)->rw],
455 (*watchpoint_p)->address,
456 (*watchpoint_p)->length,
457 (*watchpoint_p)->unique_id);
459 return ERROR_OK;
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)
465 if (target->smp) {
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)
472 return retval;
475 return ERROR_OK;
476 } else {
477 return watchpoint_add_internal(target, address, length, rw, value,
478 mask);
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;
486 int retval;
488 while (watchpoint) {
489 if (watchpoint == watchpoint_to_remove)
490 break;
491 watchpoint_p = &watchpoint->next;
492 watchpoint = watchpoint->next;
495 if (!watchpoint)
496 return;
497 retval = target_remove_watchpoint(target, watchpoint);
498 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
499 (*watchpoint_p) = watchpoint->next;
500 free(watchpoint);
503 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
505 struct watchpoint *watchpoint = target->watchpoints;
507 while (watchpoint) {
508 if (watchpoint->address == address)
509 break;
510 watchpoint = watchpoint->next;
513 if (watchpoint) {
514 watchpoint_free(target, watchpoint);
515 return 1;
516 } else {
517 if (!target->smp)
518 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
519 return 0;
523 void watchpoint_remove(struct target *target, target_addr_t address)
525 if (target->smp) {
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);
535 } else {
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)
551 int retval;
552 struct watchpoint *hit_watchpoint;
554 retval = target_hit_watchpoint(target, &hit_watchpoint);
555 if (retval != ERROR_OK)
556 return ERROR_FAIL;
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);
565 return ERROR_OK;