target: Change policy of removing watchpoints/breakpoints.
[openocd.git] / src / target / breakpoints.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
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 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include "target.h"
16 #include <helper/log.h>
17 #include "breakpoints.h"
18 #include "smp.h"
19
20 static const char * const breakpoint_type_strings[] = {
21 "hardware",
22 "software"
23 };
24
25 static const char * const watchpoint_rw_strings[] = {
26 "read",
27 "write",
28 "access"
29 };
30
31 /* monotonic counter/id-number for breakpoints and watch points */
32 static int bpwp_unique_id;
33
34 static int breakpoint_add_internal(struct target *target,
35 target_addr_t address,
36 uint32_t length,
37 enum breakpoint_type type)
38 {
39 struct breakpoint *breakpoint = target->breakpoints;
40 struct breakpoint **breakpoint_p = &target->breakpoints;
41 const char *reason;
42 int retval;
43
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.
49 */
50 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
51 address, breakpoint->unique_id);
52 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
53 }
54 breakpoint_p = &breakpoint->next;
55 breakpoint = breakpoint->next;
56 }
57
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++;
67
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;
86 }
87
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);
94
95 return ERROR_OK;
96 }
97
98 static int context_breakpoint_add_internal(struct target *target,
99 uint32_t asid,
100 uint32_t length,
101 enum breakpoint_type type)
102 {
103 struct breakpoint *breakpoint = target->breakpoints;
104 struct breakpoint **breakpoint_p = &target->breakpoints;
105 int retval;
106
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.
112 */
113 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
114 asid, breakpoint->unique_id);
115 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
116 }
117 breakpoint_p = &breakpoint->next;
118 breakpoint = breakpoint->next;
119 }
120
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;
137 }
138
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);
143
144 return ERROR_OK;
145 }
146
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)
152 {
153 struct breakpoint *breakpoint = target->breakpoints;
154 struct breakpoint **breakpoint_p = &target->breakpoints;
155 int retval;
156
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.
162 */
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;
170
171 }
172 breakpoint_p = &breakpoint->next;
173 breakpoint = breakpoint->next;
174 }
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++;
184
185
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;
193 }
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);
200
201 return ERROR_OK;
202 }
203
204 int breakpoint_add(struct target *target,
205 target_addr_t address,
206 uint32_t length,
207 enum breakpoint_type type)
208 {
209 if (target->smp) {
210 struct target_list *head;
211
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);
215 }
216
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;
222 }
223
224 return ERROR_OK;
225 } else {
226 return breakpoint_add_internal(target, address, length, type);
227 }
228 }
229
230 int context_breakpoint_add(struct target *target,
231 uint32_t asid,
232 uint32_t length,
233 enum breakpoint_type type)
234 {
235 if (target->smp) {
236 struct target_list *head;
237
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;
243 }
244
245 return ERROR_OK;
246 } else {
247 return context_breakpoint_add_internal(target, asid, length, type);
248 }
249 }
250
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)
256 {
257 if (target->smp) {
258 struct target_list *head;
259
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;
265 }
266
267 return ERROR_OK;
268 } else
269 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
270 }
271
272 /* free up a breakpoint */
273 static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
274 {
275 struct breakpoint *breakpoint = target->breakpoints;
276 struct breakpoint **breakpoint_p = &target->breakpoints;
277 int retval;
278
279 while (breakpoint) {
280 if (breakpoint == breakpoint_to_remove)
281 break;
282 breakpoint_p = &breakpoint->next;
283 breakpoint = breakpoint->next;
284 }
285
286 if (!breakpoint)
287 return ERROR_OK;
288
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",
292 breakpoint->number);
293 return retval;
294 }
295
296 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
297 (*breakpoint_p) = breakpoint->next;
298 free(breakpoint->orig_instr);
299 free(breakpoint);
300
301 return ERROR_OK;
302 }
303
304 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
305 {
306 struct breakpoint *breakpoint = target->breakpoints;
307
308 while (breakpoint) {
309 if ((breakpoint->address == address) ||
310 (breakpoint->address == 0 && breakpoint->asid == address))
311 break;
312 breakpoint = breakpoint->next;
313 }
314
315 if (breakpoint) {
316 return breakpoint_free(target, breakpoint);
317 } else {
318 return ERROR_BREAKPOINT_NOT_FOUND;
319 }
320 }
321
322 static int breakpoint_remove_all_internal(struct target *target)
323 {
324 struct breakpoint *breakpoint = target->breakpoints;
325 int retval = ERROR_OK;
326
327 while (breakpoint) {
328 struct breakpoint *tmp = breakpoint;
329 breakpoint = breakpoint->next;
330 int status = breakpoint_free(target, tmp);
331 if (status != ERROR_OK)
332 retval = status;
333 }
334
335 return retval;
336 }
337
338 int breakpoint_remove(struct target *target, target_addr_t address)
339 {
340 int retval = ERROR_OK;
341 unsigned int num_found_breakpoints = 0;
342 if (target->smp) {
343 struct target_list *head;
344
345 foreach_smp_target(head, target->smp_targets) {
346 struct target *curr = head->target;
347 int status = breakpoint_remove_internal(curr, address);
348
349 if (status != ERROR_BREAKPOINT_NOT_FOUND) {
350 num_found_breakpoints++;
351
352 if (status != ERROR_OK) {
353 LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
354 retval = status;
355 }
356 }
357 }
358
359 } else {
360 retval = breakpoint_remove_internal(target, address);
361
362 if (retval != ERROR_BREAKPOINT_NOT_FOUND) {
363 num_found_breakpoints++;
364
365 if (retval != ERROR_OK)
366 LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
367 }
368 }
369
370 if (num_found_breakpoints == 0)
371 LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address);
372
373 return retval;
374 }
375
376 int breakpoint_remove_all(struct target *target)
377 {
378 int retval = ERROR_OK;
379 if (target->smp) {
380 struct target_list *head;
381
382 foreach_smp_target(head, target->smp_targets) {
383 struct target *curr = head->target;
384 int status = breakpoint_remove_all_internal(curr);
385
386 if (status != ERROR_OK)
387 retval = status;
388 }
389 } else {
390 retval = breakpoint_remove_all_internal(target);
391 }
392
393 return retval;
394 }
395
396 static int breakpoint_clear_target_internal(struct target *target)
397 {
398 LOG_DEBUG("Delete all breakpoints for target: %s",
399 target_name(target));
400
401 int retval = ERROR_OK;
402
403 while (target->breakpoints) {
404 int status = breakpoint_free(target, target->breakpoints);
405 if (status != ERROR_OK)
406 retval = status;
407 }
408
409 return retval;
410 }
411
412 int breakpoint_clear_target(struct target *target)
413 {
414 int retval = ERROR_OK;
415
416 if (target->smp) {
417 struct target_list *head;
418
419 foreach_smp_target(head, target->smp_targets) {
420 struct target *curr = head->target;
421 int status = breakpoint_clear_target_internal(curr);
422
423 if (status != ERROR_OK)
424 retval = status;
425 }
426 } else {
427 retval = breakpoint_clear_target_internal(target);
428 }
429
430 return retval;
431 }
432
433 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
434 {
435 struct breakpoint *breakpoint = target->breakpoints;
436
437 while (breakpoint) {
438 if (breakpoint->address == address)
439 return breakpoint;
440 breakpoint = breakpoint->next;
441 }
442
443 return NULL;
444 }
445
446 static int watchpoint_add_internal(struct target *target, target_addr_t address,
447 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
448 {
449 struct watchpoint *watchpoint = target->watchpoints;
450 struct watchpoint **watchpoint_p = &target->watchpoints;
451 int retval;
452 const char *reason;
453
454 while (watchpoint) {
455 if (watchpoint->address == address) {
456 if (watchpoint->length != length
457 || watchpoint->value != value
458 || watchpoint->mask != mask
459 || watchpoint->rw != rw) {
460 LOG_ERROR("address " TARGET_ADDR_FMT
461 " already has watchpoint %d",
462 address, watchpoint->unique_id);
463 return ERROR_FAIL;
464 }
465
466 /* ignore duplicate watchpoint */
467 return ERROR_OK;
468 }
469 watchpoint_p = &watchpoint->next;
470 watchpoint = watchpoint->next;
471 }
472
473 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
474 (*watchpoint_p)->address = address;
475 (*watchpoint_p)->length = length;
476 (*watchpoint_p)->value = value;
477 (*watchpoint_p)->mask = mask;
478 (*watchpoint_p)->rw = rw;
479 (*watchpoint_p)->unique_id = bpwp_unique_id++;
480
481 retval = target_add_watchpoint(target, *watchpoint_p);
482 switch (retval) {
483 case ERROR_OK:
484 break;
485 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
486 reason = "resource not available";
487 goto bye;
488 case ERROR_TARGET_NOT_HALTED:
489 reason = "target running";
490 goto bye;
491 default:
492 reason = "unrecognized error";
493 bye:
494 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
495 watchpoint_rw_strings[(*watchpoint_p)->rw],
496 address, reason);
497 free(*watchpoint_p);
498 *watchpoint_p = NULL;
499 return retval;
500 }
501
502 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
503 " of length 0x%8.8" PRIx32 " (WPID: %d)",
504 target->coreid,
505 watchpoint_rw_strings[(*watchpoint_p)->rw],
506 (*watchpoint_p)->address,
507 (*watchpoint_p)->length,
508 (*watchpoint_p)->unique_id);
509
510 return ERROR_OK;
511 }
512
513 int watchpoint_add(struct target *target, target_addr_t address,
514 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
515 {
516 if (target->smp) {
517 struct target_list *head;
518
519 foreach_smp_target(head, target->smp_targets) {
520 struct target *curr = head->target;
521 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
522 if (retval != ERROR_OK)
523 return retval;
524 }
525
526 return ERROR_OK;
527 } else {
528 return watchpoint_add_internal(target, address, length, rw, value,
529 mask);
530 }
531 }
532
533 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
534 {
535 struct watchpoint *watchpoint = target->watchpoints;
536 struct watchpoint **watchpoint_p = &target->watchpoints;
537 int retval;
538
539 while (watchpoint) {
540 if (watchpoint == watchpoint_to_remove)
541 break;
542 watchpoint_p = &watchpoint->next;
543 watchpoint = watchpoint->next;
544 }
545
546 if (!watchpoint)
547 return ERROR_OK;
548 retval = target_remove_watchpoint(target, watchpoint);
549 if (retval != ERROR_OK) {
550 LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
551 watchpoint->number);
552 return retval;
553 }
554
555 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
556 (*watchpoint_p) = watchpoint->next;
557 free(watchpoint);
558
559 return ERROR_OK;
560 }
561
562 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
563 {
564 struct watchpoint *watchpoint = target->watchpoints;
565
566 while (watchpoint) {
567 if (watchpoint->address == address)
568 break;
569 watchpoint = watchpoint->next;
570 }
571
572 if (watchpoint) {
573 return watchpoint_free(target, watchpoint);
574 } else {
575 return ERROR_WATCHPOINT_NOT_FOUND;
576 }
577 }
578
579 int watchpoint_remove(struct target *target, target_addr_t address)
580 {
581 int retval = ERROR_OK;
582 unsigned int num_found_watchpoints = 0;
583 if (target->smp) {
584 struct target_list *head;
585
586 foreach_smp_target(head, target->smp_targets) {
587 struct target *curr = head->target;
588 int status = watchpoint_remove_internal(curr, address);
589
590 if (status != ERROR_WATCHPOINT_NOT_FOUND) {
591 num_found_watchpoints++;
592
593 if (status != ERROR_OK) {
594 LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address" TARGET_ADDR_FMT, address);
595 retval = status;
596 }
597 }
598 }
599 } else {
600 retval = watchpoint_remove_internal(target, address);
601
602 if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
603 num_found_watchpoints++;
604
605 if (retval != ERROR_OK)
606 LOG_TARGET_ERROR(target, "failed to remove watchpoint at address" TARGET_ADDR_FMT, address);
607 }
608 }
609
610 if (num_found_watchpoints == 0)
611 LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
612
613 return retval;
614 }
615
616 int watchpoint_clear_target(struct target *target)
617 {
618 int retval = ERROR_OK;
619
620 LOG_DEBUG("Delete all watchpoints for target: %s",
621 target_name(target));
622 while (target->watchpoints) {
623 int status = watchpoint_free(target, target->watchpoints);
624 if (status != ERROR_OK)
625 retval = status;
626 }
627
628 return retval;
629 }
630
631 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
632 target_addr_t *address)
633 {
634 int retval;
635 struct watchpoint *hit_watchpoint;
636
637 retval = target_hit_watchpoint(target, &hit_watchpoint);
638 if (retval != ERROR_OK)
639 return ERROR_FAIL;
640
641 *rw = hit_watchpoint->rw;
642 *address = hit_watchpoint->address;
643
644 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
645 hit_watchpoint->address,
646 hit_watchpoint->unique_id);
647
648 return ERROR_OK;
649 }

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)