target: Fix an issue with rwp/rbp command in smp targets
[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 return ERROR_BREAKPOINT_NOT_FOUND;
373 }
374
375 return retval;
376 }
377
378 int breakpoint_remove_all(struct target *target)
379 {
380 int retval = ERROR_OK;
381 if (target->smp) {
382 struct target_list *head;
383
384 foreach_smp_target(head, target->smp_targets) {
385 struct target *curr = head->target;
386 int status = breakpoint_remove_all_internal(curr);
387
388 if (status != ERROR_OK)
389 retval = status;
390 }
391 } else {
392 retval = breakpoint_remove_all_internal(target);
393 }
394
395 return retval;
396 }
397
398 static int breakpoint_clear_target_internal(struct target *target)
399 {
400 LOG_DEBUG("Delete all breakpoints for target: %s",
401 target_name(target));
402
403 int retval = ERROR_OK;
404
405 while (target->breakpoints) {
406 int status = breakpoint_free(target, target->breakpoints);
407 if (status != ERROR_OK)
408 retval = status;
409 }
410
411 return retval;
412 }
413
414 int breakpoint_clear_target(struct target *target)
415 {
416 int retval = ERROR_OK;
417
418 if (target->smp) {
419 struct target_list *head;
420
421 foreach_smp_target(head, target->smp_targets) {
422 struct target *curr = head->target;
423 int status = breakpoint_clear_target_internal(curr);
424
425 if (status != ERROR_OK)
426 retval = status;
427 }
428 } else {
429 retval = breakpoint_clear_target_internal(target);
430 }
431
432 return retval;
433 }
434
435 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
436 {
437 struct breakpoint *breakpoint = target->breakpoints;
438
439 while (breakpoint) {
440 if (breakpoint->address == address)
441 return breakpoint;
442 breakpoint = breakpoint->next;
443 }
444
445 return NULL;
446 }
447
448 static int watchpoint_add_internal(struct target *target, target_addr_t address,
449 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
450 {
451 struct watchpoint *watchpoint = target->watchpoints;
452 struct watchpoint **watchpoint_p = &target->watchpoints;
453 int retval;
454 const char *reason;
455
456 while (watchpoint) {
457 if (watchpoint->address == address) {
458 if (watchpoint->length != length
459 || watchpoint->value != value
460 || watchpoint->mask != mask
461 || watchpoint->rw != rw) {
462 LOG_ERROR("address " TARGET_ADDR_FMT
463 " already has watchpoint %d",
464 address, watchpoint->unique_id);
465 return ERROR_FAIL;
466 }
467
468 /* ignore duplicate watchpoint */
469 return ERROR_OK;
470 }
471 watchpoint_p = &watchpoint->next;
472 watchpoint = watchpoint->next;
473 }
474
475 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
476 (*watchpoint_p)->address = address;
477 (*watchpoint_p)->length = length;
478 (*watchpoint_p)->value = value;
479 (*watchpoint_p)->mask = mask;
480 (*watchpoint_p)->rw = rw;
481 (*watchpoint_p)->unique_id = bpwp_unique_id++;
482
483 retval = target_add_watchpoint(target, *watchpoint_p);
484 switch (retval) {
485 case ERROR_OK:
486 break;
487 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
488 reason = "resource not available";
489 goto bye;
490 case ERROR_TARGET_NOT_HALTED:
491 reason = "target running";
492 goto bye;
493 default:
494 reason = "unrecognized error";
495 bye:
496 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
497 watchpoint_rw_strings[(*watchpoint_p)->rw],
498 address, reason);
499 free(*watchpoint_p);
500 *watchpoint_p = NULL;
501 return retval;
502 }
503
504 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
505 " of length 0x%8.8" PRIx32 " (WPID: %d)",
506 target->coreid,
507 watchpoint_rw_strings[(*watchpoint_p)->rw],
508 (*watchpoint_p)->address,
509 (*watchpoint_p)->length,
510 (*watchpoint_p)->unique_id);
511
512 return ERROR_OK;
513 }
514
515 int watchpoint_add(struct target *target, target_addr_t address,
516 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
517 {
518 if (target->smp) {
519 struct target_list *head;
520
521 foreach_smp_target(head, target->smp_targets) {
522 struct target *curr = head->target;
523 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
524 if (retval != ERROR_OK)
525 return retval;
526 }
527
528 return ERROR_OK;
529 } else {
530 return watchpoint_add_internal(target, address, length, rw, value,
531 mask);
532 }
533 }
534
535 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
536 {
537 struct watchpoint *watchpoint = target->watchpoints;
538 struct watchpoint **watchpoint_p = &target->watchpoints;
539 int retval;
540
541 while (watchpoint) {
542 if (watchpoint == watchpoint_to_remove)
543 break;
544 watchpoint_p = &watchpoint->next;
545 watchpoint = watchpoint->next;
546 }
547
548 if (!watchpoint)
549 return ERROR_OK;
550 retval = target_remove_watchpoint(target, watchpoint);
551 if (retval != ERROR_OK) {
552 LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
553 watchpoint->number);
554 return retval;
555 }
556
557 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
558 (*watchpoint_p) = watchpoint->next;
559 free(watchpoint);
560
561 return ERROR_OK;
562 }
563
564 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
565 {
566 struct watchpoint *watchpoint = target->watchpoints;
567
568 while (watchpoint) {
569 if (watchpoint->address == address)
570 break;
571 watchpoint = watchpoint->next;
572 }
573
574 if (watchpoint) {
575 return watchpoint_free(target, watchpoint);
576 } else {
577 return ERROR_WATCHPOINT_NOT_FOUND;
578 }
579 }
580
581 int watchpoint_remove(struct target *target, target_addr_t address)
582 {
583 int retval = ERROR_OK;
584 unsigned int num_found_watchpoints = 0;
585 if (target->smp) {
586 struct target_list *head;
587
588 foreach_smp_target(head, target->smp_targets) {
589 struct target *curr = head->target;
590 int status = watchpoint_remove_internal(curr, address);
591
592 if (status != ERROR_WATCHPOINT_NOT_FOUND) {
593 num_found_watchpoints++;
594
595 if (status != ERROR_OK) {
596 LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
597 retval = status;
598 }
599 }
600 }
601 } else {
602 retval = watchpoint_remove_internal(target, address);
603
604 if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
605 num_found_watchpoints++;
606
607 if (retval != ERROR_OK)
608 LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
609 }
610 }
611
612 if (num_found_watchpoints == 0) {
613 LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
614 return ERROR_WATCHPOINT_NOT_FOUND;
615 }
616
617 return retval;
618 }
619
620 int watchpoint_clear_target(struct target *target)
621 {
622 int retval = ERROR_OK;
623
624 LOG_DEBUG("Delete all watchpoints for target: %s",
625 target_name(target));
626 while (target->watchpoints) {
627 int status = watchpoint_free(target, target->watchpoints);
628 if (status != ERROR_OK)
629 retval = status;
630 }
631
632 return retval;
633 }
634
635 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
636 target_addr_t *address)
637 {
638 int retval;
639 struct watchpoint *hit_watchpoint;
640
641 retval = target_hit_watchpoint(target, &hit_watchpoint);
642 if (retval != ERROR_OK)
643 return ERROR_FAIL;
644
645 *rw = hit_watchpoint->rw;
646 *address = hit_watchpoint->address;
647
648 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
649 hit_watchpoint->address,
650 hit_watchpoint->unique_id);
651
652 return ERROR_OK;
653 }

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)