jtag: linuxgpiod: drop extra parenthesis
[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 enum breakpoint_watchpoint {
21 BREAKPOINT,
22 WATCHPOINT,
23 };
24
25 static const char * const breakpoint_type_strings[] = {
26 "hardware",
27 "software"
28 };
29
30 static const char * const watchpoint_rw_strings[] = {
31 "read",
32 "write",
33 "access"
34 };
35
36 /* monotonic counter/id-number for breakpoints and watch points */
37 static int bpwp_unique_id;
38
39 static int breakpoint_add_internal(struct target *target,
40 target_addr_t address,
41 uint32_t length,
42 enum breakpoint_type type)
43 {
44 struct breakpoint *breakpoint = target->breakpoints;
45 struct breakpoint **breakpoint_p = &target->breakpoints;
46 const char *reason;
47 int retval;
48
49 while (breakpoint) {
50 if (breakpoint->address == address) {
51 /* FIXME don't assume "same address" means "same
52 * breakpoint" ... check all the parameters before
53 * succeeding.
54 */
55 LOG_TARGET_ERROR(target, "Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
56 address, breakpoint->unique_id);
57 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
58 }
59 breakpoint_p = &breakpoint->next;
60 breakpoint = breakpoint->next;
61 }
62
63 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
64 (*breakpoint_p)->address = address;
65 (*breakpoint_p)->asid = 0;
66 (*breakpoint_p)->length = length;
67 (*breakpoint_p)->type = type;
68 (*breakpoint_p)->is_set = false;
69 (*breakpoint_p)->orig_instr = malloc(length);
70 (*breakpoint_p)->next = NULL;
71 (*breakpoint_p)->unique_id = bpwp_unique_id++;
72
73 retval = target_add_breakpoint(target, *breakpoint_p);
74 switch (retval) {
75 case ERROR_OK:
76 break;
77 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
78 reason = "resource not available";
79 goto fail;
80 case ERROR_TARGET_NOT_HALTED:
81 reason = "target running";
82 goto fail;
83 default:
84 reason = "unknown reason";
85 fail:
86 LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason);
87 free((*breakpoint_p)->orig_instr);
88 free(*breakpoint_p);
89 *breakpoint_p = NULL;
90 return retval;
91 }
92
93 LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT
94 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
95 breakpoint_type_strings[(*breakpoint_p)->type],
96 (*breakpoint_p)->address, (*breakpoint_p)->length,
97 (*breakpoint_p)->unique_id);
98
99 return ERROR_OK;
100 }
101
102 static int context_breakpoint_add_internal(struct target *target,
103 uint32_t asid,
104 uint32_t length,
105 enum breakpoint_type type)
106 {
107 struct breakpoint *breakpoint = target->breakpoints;
108 struct breakpoint **breakpoint_p = &target->breakpoints;
109 int retval;
110
111 while (breakpoint) {
112 if (breakpoint->asid == asid) {
113 /* FIXME don't assume "same address" means "same
114 * breakpoint" ... check all the parameters before
115 * succeeding.
116 */
117 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
118 asid, breakpoint->unique_id);
119 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
120 }
121 breakpoint_p = &breakpoint->next;
122 breakpoint = breakpoint->next;
123 }
124
125 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
126 (*breakpoint_p)->address = 0;
127 (*breakpoint_p)->asid = asid;
128 (*breakpoint_p)->length = length;
129 (*breakpoint_p)->type = type;
130 (*breakpoint_p)->is_set = false;
131 (*breakpoint_p)->orig_instr = malloc(length);
132 (*breakpoint_p)->next = NULL;
133 (*breakpoint_p)->unique_id = bpwp_unique_id++;
134 retval = target_add_context_breakpoint(target, *breakpoint_p);
135 if (retval != ERROR_OK) {
136 LOG_TARGET_ERROR(target, "could not add breakpoint");
137 free((*breakpoint_p)->orig_instr);
138 free(*breakpoint_p);
139 *breakpoint_p = NULL;
140 return retval;
141 }
142
143 LOG_TARGET_DEBUG(target, "added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
144 breakpoint_type_strings[(*breakpoint_p)->type],
145 (*breakpoint_p)->asid, (*breakpoint_p)->length,
146 (*breakpoint_p)->unique_id);
147
148 return ERROR_OK;
149 }
150
151 static int hybrid_breakpoint_add_internal(struct target *target,
152 target_addr_t address,
153 uint32_t asid,
154 uint32_t length,
155 enum breakpoint_type type)
156 {
157 struct breakpoint *breakpoint = target->breakpoints;
158 struct breakpoint **breakpoint_p = &target->breakpoints;
159 int retval;
160
161 while (breakpoint) {
162 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
163 /* FIXME don't assume "same address" means "same
164 * breakpoint" ... check all the parameters before
165 * succeeding.
166 */
167 LOG_TARGET_ERROR(target, "Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
168 asid, breakpoint->unique_id);
169 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
170 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
171 LOG_TARGET_ERROR(target, "Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
172 address, breakpoint->unique_id);
173 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
174
175 }
176 breakpoint_p = &breakpoint->next;
177 breakpoint = breakpoint->next;
178 }
179 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
180 (*breakpoint_p)->address = address;
181 (*breakpoint_p)->asid = asid;
182 (*breakpoint_p)->length = length;
183 (*breakpoint_p)->type = type;
184 (*breakpoint_p)->is_set = false;
185 (*breakpoint_p)->orig_instr = malloc(length);
186 (*breakpoint_p)->next = NULL;
187 (*breakpoint_p)->unique_id = bpwp_unique_id++;
188
189
190 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
191 if (retval != ERROR_OK) {
192 LOG_TARGET_ERROR(target, "could not add breakpoint");
193 free((*breakpoint_p)->orig_instr);
194 free(*breakpoint_p);
195 *breakpoint_p = NULL;
196 return retval;
197 }
198 LOG_TARGET_DEBUG(target,
199 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
200 breakpoint_type_strings[(*breakpoint_p)->type],
201 (*breakpoint_p)->address,
202 (*breakpoint_p)->length,
203 (*breakpoint_p)->unique_id);
204
205 return ERROR_OK;
206 }
207
208 int breakpoint_add(struct target *target,
209 target_addr_t address,
210 uint32_t length,
211 enum breakpoint_type type)
212 {
213 if (target->smp) {
214 struct target_list *head;
215
216 if (type == BKPT_SOFT) {
217 head = list_first_entry(target->smp_targets, struct target_list, lh);
218 return breakpoint_add_internal(head->target, address, length, type);
219 }
220
221 foreach_smp_target(head, target->smp_targets) {
222 struct target *curr = head->target;
223 int retval = breakpoint_add_internal(curr, address, length, type);
224 if (retval != ERROR_OK)
225 return retval;
226 }
227
228 return ERROR_OK;
229 } else {
230 return breakpoint_add_internal(target, address, length, type);
231 }
232 }
233
234 int context_breakpoint_add(struct target *target,
235 uint32_t asid,
236 uint32_t length,
237 enum breakpoint_type type)
238 {
239 if (target->smp) {
240 struct target_list *head;
241
242 foreach_smp_target(head, target->smp_targets) {
243 struct target *curr = head->target;
244 int retval = context_breakpoint_add_internal(curr, asid, length, type);
245 if (retval != ERROR_OK)
246 return retval;
247 }
248
249 return ERROR_OK;
250 } else {
251 return context_breakpoint_add_internal(target, asid, length, type);
252 }
253 }
254
255 int hybrid_breakpoint_add(struct target *target,
256 target_addr_t address,
257 uint32_t asid,
258 uint32_t length,
259 enum breakpoint_type type)
260 {
261 if (target->smp) {
262 struct target_list *head;
263
264 foreach_smp_target(head, target->smp_targets) {
265 struct target *curr = head->target;
266 int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
267 if (retval != ERROR_OK)
268 return retval;
269 }
270
271 return ERROR_OK;
272 } else
273 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
274 }
275
276 /* free up a breakpoint */
277 static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
278 {
279 struct breakpoint *breakpoint = target->breakpoints;
280 struct breakpoint **breakpoint_p = &target->breakpoints;
281 int retval;
282
283 while (breakpoint) {
284 if (breakpoint == breakpoint_to_remove)
285 break;
286 breakpoint_p = &breakpoint->next;
287 breakpoint = breakpoint->next;
288 }
289
290 if (!breakpoint)
291 return ERROR_OK;
292
293 retval = target_remove_breakpoint(target, breakpoint);
294 if (retval != ERROR_OK) {
295 LOG_TARGET_ERROR(target, "could not remove breakpoint #%d on this target",
296 breakpoint->number);
297 return retval;
298 }
299
300 LOG_TARGET_DEBUG(target, "free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
301 (*breakpoint_p) = breakpoint->next;
302 free(breakpoint->orig_instr);
303 free(breakpoint);
304
305 return ERROR_OK;
306 }
307
308 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
309 {
310 struct breakpoint *breakpoint = target->breakpoints;
311
312 while (breakpoint) {
313 if ((breakpoint->address == address) ||
314 (breakpoint->address == 0 && breakpoint->asid == address))
315 break;
316 breakpoint = breakpoint->next;
317 }
318
319 if (breakpoint) {
320 return breakpoint_free(target, breakpoint);
321 } else {
322 return ERROR_BREAKPOINT_NOT_FOUND;
323 }
324 }
325
326 static int breakpoint_remove_all_internal(struct target *target)
327 {
328 LOG_TARGET_DEBUG(target, "Delete all breakpoints");
329
330 struct breakpoint *breakpoint = target->breakpoints;
331 int retval = ERROR_OK;
332
333 while (breakpoint) {
334 struct breakpoint *tmp = breakpoint;
335 breakpoint = breakpoint->next;
336 int status = breakpoint_free(target, tmp);
337 if (status != ERROR_OK)
338 retval = status;
339 }
340
341 return retval;
342 }
343
344 int breakpoint_remove(struct target *target, target_addr_t address)
345 {
346 int retval = ERROR_OK;
347 unsigned int num_found_breakpoints = 0;
348 if (target->smp) {
349 struct target_list *head;
350
351 foreach_smp_target(head, target->smp_targets) {
352 struct target *curr = head->target;
353 int status = breakpoint_remove_internal(curr, address);
354
355 if (status != ERROR_BREAKPOINT_NOT_FOUND) {
356 num_found_breakpoints++;
357
358 if (status != ERROR_OK) {
359 LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
360 retval = status;
361 }
362 }
363 }
364
365 } else {
366 retval = breakpoint_remove_internal(target, address);
367
368 if (retval != ERROR_BREAKPOINT_NOT_FOUND) {
369 num_found_breakpoints++;
370
371 if (retval != ERROR_OK)
372 LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
373 }
374 }
375
376 if (num_found_breakpoints == 0) {
377 LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address);
378 return ERROR_BREAKPOINT_NOT_FOUND;
379 }
380
381 return retval;
382 }
383
384 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
385 {
386 struct watchpoint *watchpoint = target->watchpoints;
387 struct watchpoint **watchpoint_p = &target->watchpoints;
388 int retval;
389
390 while (watchpoint) {
391 if (watchpoint == watchpoint_to_remove)
392 break;
393 watchpoint_p = &watchpoint->next;
394 watchpoint = watchpoint->next;
395 }
396
397 if (!watchpoint)
398 return ERROR_OK;
399 retval = target_remove_watchpoint(target, watchpoint);
400 if (retval != ERROR_OK) {
401 LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
402 watchpoint->number);
403 return retval;
404 }
405
406 LOG_TARGET_DEBUG(target, "free WPID: %d --> %d", watchpoint->unique_id, retval);
407 (*watchpoint_p) = watchpoint->next;
408 free(watchpoint);
409
410 return ERROR_OK;
411 }
412
413 static int watchpoint_remove_all_internal(struct target *target)
414 {
415 struct watchpoint *watchpoint = target->watchpoints;
416 int retval = ERROR_OK;
417
418 while (watchpoint) {
419 struct watchpoint *tmp = watchpoint;
420 watchpoint = watchpoint->next;
421 int status = watchpoint_free(target, tmp);
422 if (status != ERROR_OK)
423 retval = status;
424 }
425
426 return retval;
427 }
428
429 static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp)
430 {
431 assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT);
432 int retval = ERROR_OK;
433 if (target->smp) {
434 struct target_list *head;
435
436 foreach_smp_target(head, target->smp_targets) {
437 struct target *curr = head->target;
438
439 int status = ERROR_OK;
440 if (bp_wp == BREAKPOINT)
441 status = breakpoint_remove_all_internal(curr);
442 else
443 status = watchpoint_remove_all_internal(curr);
444
445 if (status != ERROR_OK)
446 retval = status;
447 }
448 } else {
449 if (bp_wp == BREAKPOINT)
450 retval = breakpoint_remove_all_internal(target);
451 else
452 retval = watchpoint_remove_all_internal(target);
453 }
454
455 return retval;
456 }
457
458 int breakpoint_remove_all(struct target *target)
459 {
460 return breakpoint_watchpoint_remove_all(target, BREAKPOINT);
461 }
462
463 int watchpoint_remove_all(struct target *target)
464 {
465 return breakpoint_watchpoint_remove_all(target, WATCHPOINT);
466 }
467
468 int breakpoint_clear_target(struct target *target)
469 {
470 int retval = ERROR_OK;
471
472 if (target->smp) {
473 struct target_list *head;
474
475 foreach_smp_target(head, target->smp_targets) {
476 struct target *curr = head->target;
477 int status = breakpoint_remove_all_internal(curr);
478
479 if (status != ERROR_OK)
480 retval = status;
481 }
482 } else {
483 retval = breakpoint_remove_all_internal(target);
484 }
485
486 return retval;
487 }
488
489 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
490 {
491 struct breakpoint *breakpoint = target->breakpoints;
492
493 while (breakpoint) {
494 if (breakpoint->address == address)
495 return breakpoint;
496 breakpoint = breakpoint->next;
497 }
498
499 return NULL;
500 }
501
502 static int watchpoint_add_internal(struct target *target, target_addr_t address,
503 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
504 {
505 struct watchpoint *watchpoint = target->watchpoints;
506 struct watchpoint **watchpoint_p = &target->watchpoints;
507 int retval;
508 const char *reason;
509
510 while (watchpoint) {
511 if (watchpoint->address == address) {
512 if (watchpoint->length != length
513 || watchpoint->value != value
514 || watchpoint->mask != mask
515 || watchpoint->rw != rw) {
516 LOG_TARGET_ERROR(target, "address " TARGET_ADDR_FMT
517 " already has watchpoint %d",
518 address, watchpoint->unique_id);
519 return ERROR_FAIL;
520 }
521
522 /* ignore duplicate watchpoint */
523 return ERROR_OK;
524 }
525 watchpoint_p = &watchpoint->next;
526 watchpoint = watchpoint->next;
527 }
528
529 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
530 (*watchpoint_p)->address = address;
531 (*watchpoint_p)->length = length;
532 (*watchpoint_p)->value = value;
533 (*watchpoint_p)->mask = mask;
534 (*watchpoint_p)->rw = rw;
535 (*watchpoint_p)->unique_id = bpwp_unique_id++;
536
537 retval = target_add_watchpoint(target, *watchpoint_p);
538 switch (retval) {
539 case ERROR_OK:
540 break;
541 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
542 reason = "resource not available";
543 goto bye;
544 case ERROR_TARGET_NOT_HALTED:
545 reason = "target running";
546 goto bye;
547 default:
548 reason = "unrecognized error";
549 bye:
550 LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
551 watchpoint_rw_strings[(*watchpoint_p)->rw],
552 address, reason);
553 free(*watchpoint_p);
554 *watchpoint_p = NULL;
555 return retval;
556 }
557
558 LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT
559 " of length 0x%8.8" PRIx32 " (WPID: %d)",
560 watchpoint_rw_strings[(*watchpoint_p)->rw],
561 (*watchpoint_p)->address,
562 (*watchpoint_p)->length,
563 (*watchpoint_p)->unique_id);
564
565 return ERROR_OK;
566 }
567
568 int watchpoint_add(struct target *target, target_addr_t address,
569 uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
570 {
571 if (target->smp) {
572 struct target_list *head;
573
574 foreach_smp_target(head, target->smp_targets) {
575 struct target *curr = head->target;
576 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
577 if (retval != ERROR_OK)
578 return retval;
579 }
580
581 return ERROR_OK;
582 } else {
583 return watchpoint_add_internal(target, address, length, rw, value,
584 mask);
585 }
586 }
587
588 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
589 {
590 struct watchpoint *watchpoint = target->watchpoints;
591
592 while (watchpoint) {
593 if (watchpoint->address == address)
594 break;
595 watchpoint = watchpoint->next;
596 }
597
598 if (watchpoint) {
599 return watchpoint_free(target, watchpoint);
600 } else {
601 return ERROR_WATCHPOINT_NOT_FOUND;
602 }
603 }
604
605 int watchpoint_remove(struct target *target, target_addr_t address)
606 {
607 int retval = ERROR_OK;
608 unsigned int num_found_watchpoints = 0;
609 if (target->smp) {
610 struct target_list *head;
611
612 foreach_smp_target(head, target->smp_targets) {
613 struct target *curr = head->target;
614 int status = watchpoint_remove_internal(curr, address);
615
616 if (status != ERROR_WATCHPOINT_NOT_FOUND) {
617 num_found_watchpoints++;
618
619 if (status != ERROR_OK) {
620 LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
621 retval = status;
622 }
623 }
624 }
625 } else {
626 retval = watchpoint_remove_internal(target, address);
627
628 if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
629 num_found_watchpoints++;
630
631 if (retval != ERROR_OK)
632 LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
633 }
634 }
635
636 if (num_found_watchpoints == 0) {
637 LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
638 return ERROR_WATCHPOINT_NOT_FOUND;
639 }
640
641 return retval;
642 }
643
644 int watchpoint_clear_target(struct target *target)
645 {
646 LOG_DEBUG("Delete all watchpoints for target: %s",
647 target_name(target));
648
649 struct watchpoint *watchpoint = target->watchpoints;
650 int retval = ERROR_OK;
651
652 while (watchpoint) {
653 struct watchpoint *tmp = watchpoint;
654 watchpoint = watchpoint->next;
655 int status = watchpoint_free(target, tmp);
656 if (status != ERROR_OK)
657 retval = status;
658 }
659 return retval;
660 }
661
662 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
663 target_addr_t *address)
664 {
665 int retval;
666 struct watchpoint *hit_watchpoint;
667
668 retval = target_hit_watchpoint(target, &hit_watchpoint);
669 if (retval != ERROR_OK)
670 return ERROR_FAIL;
671
672 *rw = hit_watchpoint->rw;
673 *address = hit_watchpoint->address;
674
675 LOG_TARGET_DEBUG(target, "Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
676 hit_watchpoint->address,
677 hit_watchpoint->unique_id);
678
679 return ERROR_OK;
680 }

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)