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 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 void 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;
288
289 retval = target_remove_breakpoint(target, breakpoint);
290
291 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
292 (*breakpoint_p) = breakpoint->next;
293 free(breakpoint->orig_instr);
294 free(breakpoint);
295 }
296
297 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
298 {
299 struct breakpoint *breakpoint = target->breakpoints;
300
301 while (breakpoint) {
302 if ((breakpoint->address == address) ||
303 (breakpoint->address == 0 && breakpoint->asid == address))
304 break;
305 breakpoint = breakpoint->next;
306 }
307
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;
315 }
316 }
317
318 static void breakpoint_remove_all_internal(struct target *target)
319 {
320 struct breakpoint *breakpoint = target->breakpoints;
321
322 while (breakpoint) {
323 struct breakpoint *tmp = breakpoint;
324 breakpoint = breakpoint->next;
325 breakpoint_free(target, tmp);
326 }
327 }
328
329 void breakpoint_remove(struct target *target, target_addr_t address)
330 {
331 if (target->smp) {
332 unsigned int num_breakpoints = 0;
333 struct target_list *head;
334
335 foreach_smp_target(head, target->smp_targets) {
336 struct target *curr = head->target;
337 num_breakpoints += breakpoint_remove_internal(curr, address);
338 }
339 if (!num_breakpoints)
340 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
341 } else {
342 breakpoint_remove_internal(target, address);
343 }
344 }
345
346 void breakpoint_remove_all(struct target *target)
347 {
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 breakpoint_remove_all_internal(curr);
354 }
355 } else {
356 breakpoint_remove_all_internal(target);
357 }
358 }
359
360 static void breakpoint_clear_target_internal(struct target *target)
361 {
362 LOG_DEBUG("Delete all breakpoints for target: %s",
363 target_name(target));
364 while (target->breakpoints)
365 breakpoint_free(target, target->breakpoints);
366 }
367
368 void breakpoint_clear_target(struct target *target)
369 {
370 if (target->smp) {
371 struct target_list *head;
372
373 foreach_smp_target(head, target->smp_targets) {
374 struct target *curr = head->target;
375 breakpoint_clear_target_internal(curr);
376 }
377 } else {
378 breakpoint_clear_target_internal(target);
379 }
380 }
381
382 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
383 {
384 struct breakpoint *breakpoint = target->breakpoints;
385
386 while (breakpoint) {
387 if (breakpoint->address == address)
388 return breakpoint;
389 breakpoint = breakpoint->next;
390 }
391
392 return NULL;
393 }
394
395 static 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)
397 {
398 struct watchpoint *watchpoint = target->watchpoints;
399 struct watchpoint **watchpoint_p = &target->watchpoints;
400 int retval;
401 const char *reason;
402
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;
413 }
414
415 /* ignore duplicate watchpoint */
416 return ERROR_OK;
417 }
418 watchpoint_p = &watchpoint->next;
419 watchpoint = watchpoint->next;
420 }
421
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++;
429
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;
449 }
450
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);
458
459 return ERROR_OK;
460 }
461
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)
464 {
465 if (target->smp) {
466 struct target_list *head;
467
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;
473 }
474
475 return ERROR_OK;
476 } else {
477 return watchpoint_add_internal(target, address, length, rw, value,
478 mask);
479 }
480 }
481
482 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
483 {
484 struct watchpoint *watchpoint = target->watchpoints;
485 struct watchpoint **watchpoint_p = &target->watchpoints;
486 int retval;
487
488 while (watchpoint) {
489 if (watchpoint == watchpoint_to_remove)
490 break;
491 watchpoint_p = &watchpoint->next;
492 watchpoint = watchpoint->next;
493 }
494
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);
501 }
502
503 static int watchpoint_remove_internal(struct target *target, target_addr_t address)
504 {
505 struct watchpoint *watchpoint = target->watchpoints;
506
507 while (watchpoint) {
508 if (watchpoint->address == address)
509 break;
510 watchpoint = watchpoint->next;
511 }
512
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;
520 }
521 }
522
523 void watchpoint_remove(struct target *target, target_addr_t address)
524 {
525 if (target->smp) {
526 unsigned int num_watchpoints = 0;
527 struct target_list *head;
528
529 foreach_smp_target(head, target->smp_targets) {
530 struct target *curr = head->target;
531 num_watchpoints += watchpoint_remove_internal(curr, address);
532 }
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);
537 }
538 }
539
540 void watchpoint_clear_target(struct target *target)
541 {
542 LOG_DEBUG("Delete all watchpoints for target: %s",
543 target_name(target));
544 while (target->watchpoints)
545 watchpoint_free(target, target->watchpoints);
546 }
547
548 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
549 target_addr_t *address)
550 {
551 int retval;
552 struct watchpoint *hit_watchpoint;
553
554 retval = target_hit_watchpoint(target, &hit_watchpoint);
555 if (retval != ERROR_OK)
556 return ERROR_FAIL;
557
558 *rw = hit_watchpoint->rw;
559 *address = hit_watchpoint->address;
560
561 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
562 hit_watchpoint->address,
563 hit_watchpoint->unique_id);
564
565 return ERROR_OK;
566 }

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)