jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / breakpoints.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) ST-Ericsson SA 2011 *
6 * michel.jaouen@stericsson.com : smp minimum support *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "target.h"
27 #include <helper/log.h>
28 #include "breakpoints.h"
29
30 static const char * const breakpoint_type_strings[] = {
31 "hardware",
32 "software"
33 };
34
35 static const char * const watchpoint_rw_strings[] = {
36 "read",
37 "write",
38 "access"
39 };
40
41 /* monotonic counter/id-number for breakpoints and watch points */
42 static int bpwp_unique_id;
43
44 static int breakpoint_add_internal(struct target *target,
45 target_addr_t address,
46 uint32_t length,
47 enum breakpoint_type type)
48 {
49 struct breakpoint *breakpoint = target->breakpoints;
50 struct breakpoint **breakpoint_p = &target->breakpoints;
51 const char *reason;
52 int retval;
53 int n;
54
55 n = 0;
56 while (breakpoint) {
57 n++;
58 if (breakpoint->address == address) {
59 /* FIXME don't assume "same address" means "same
60 * breakpoint" ... check all the parameters before
61 * succeeding.
62 */
63 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
64 address, breakpoint->unique_id);
65 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
66 }
67 breakpoint_p = &breakpoint->next;
68 breakpoint = breakpoint->next;
69 }
70
71 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
72 (*breakpoint_p)->address = address;
73 (*breakpoint_p)->asid = 0;
74 (*breakpoint_p)->length = length;
75 (*breakpoint_p)->type = type;
76 (*breakpoint_p)->set = 0;
77 (*breakpoint_p)->orig_instr = malloc(length);
78 (*breakpoint_p)->next = NULL;
79 (*breakpoint_p)->unique_id = bpwp_unique_id++;
80
81 retval = target_add_breakpoint(target, *breakpoint_p);
82 switch (retval) {
83 case ERROR_OK:
84 break;
85 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
86 reason = "resource not available";
87 goto fail;
88 case ERROR_TARGET_NOT_HALTED:
89 reason = "target running";
90 goto fail;
91 default:
92 reason = "unknown reason";
93 fail:
94 LOG_ERROR("can't add breakpoint: %s", reason);
95 free((*breakpoint_p)->orig_instr);
96 free(*breakpoint_p);
97 *breakpoint_p = NULL;
98 return retval;
99 }
100
101 LOG_DEBUG("added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
102 breakpoint_type_strings[(*breakpoint_p)->type],
103 (*breakpoint_p)->address, (*breakpoint_p)->length,
104 (*breakpoint_p)->unique_id);
105
106 return ERROR_OK;
107 }
108
109 static int context_breakpoint_add_internal(struct target *target,
110 uint32_t asid,
111 uint32_t length,
112 enum breakpoint_type type)
113 {
114 struct breakpoint *breakpoint = target->breakpoints;
115 struct breakpoint **breakpoint_p = &target->breakpoints;
116 int retval;
117 int n;
118
119 n = 0;
120 while (breakpoint) {
121 n++;
122 if (breakpoint->asid == asid) {
123 /* FIXME don't assume "same address" means "same
124 * breakpoint" ... check all the parameters before
125 * succeeding.
126 */
127 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
128 asid, breakpoint->unique_id);
129 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
130 }
131 breakpoint_p = &breakpoint->next;
132 breakpoint = breakpoint->next;
133 }
134
135 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
136 (*breakpoint_p)->address = 0;
137 (*breakpoint_p)->asid = asid;
138 (*breakpoint_p)->length = length;
139 (*breakpoint_p)->type = type;
140 (*breakpoint_p)->set = 0;
141 (*breakpoint_p)->orig_instr = malloc(length);
142 (*breakpoint_p)->next = NULL;
143 (*breakpoint_p)->unique_id = bpwp_unique_id++;
144 retval = target_add_context_breakpoint(target, *breakpoint_p);
145 if (retval != ERROR_OK) {
146 LOG_ERROR("could not add breakpoint");
147 free((*breakpoint_p)->orig_instr);
148 free(*breakpoint_p);
149 *breakpoint_p = NULL;
150 return retval;
151 }
152
153 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
154 breakpoint_type_strings[(*breakpoint_p)->type],
155 (*breakpoint_p)->asid, (*breakpoint_p)->length,
156 (*breakpoint_p)->unique_id);
157
158 return ERROR_OK;
159 }
160
161 static int hybrid_breakpoint_add_internal(struct target *target,
162 target_addr_t address,
163 uint32_t asid,
164 uint32_t length,
165 enum breakpoint_type type)
166 {
167 struct breakpoint *breakpoint = target->breakpoints;
168 struct breakpoint **breakpoint_p = &target->breakpoints;
169 int retval;
170 int n;
171 n = 0;
172 while (breakpoint) {
173 n++;
174 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
175 /* FIXME don't assume "same address" means "same
176 * breakpoint" ... check all the parameters before
177 * succeeding.
178 */
179 LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
180 asid, breakpoint->unique_id);
181 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
182 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
183 LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
184 address, breakpoint->unique_id);
185 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
186
187 }
188 breakpoint_p = &breakpoint->next;
189 breakpoint = breakpoint->next;
190 }
191 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
192 (*breakpoint_p)->address = address;
193 (*breakpoint_p)->asid = asid;
194 (*breakpoint_p)->length = length;
195 (*breakpoint_p)->type = type;
196 (*breakpoint_p)->set = 0;
197 (*breakpoint_p)->orig_instr = malloc(length);
198 (*breakpoint_p)->next = NULL;
199 (*breakpoint_p)->unique_id = bpwp_unique_id++;
200
201
202 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
203 if (retval != ERROR_OK) {
204 LOG_ERROR("could not add breakpoint");
205 free((*breakpoint_p)->orig_instr);
206 free(*breakpoint_p);
207 *breakpoint_p = NULL;
208 return retval;
209 }
210 LOG_DEBUG(
211 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
212 breakpoint_type_strings[(*breakpoint_p)->type],
213 (*breakpoint_p)->address,
214 (*breakpoint_p)->length,
215 (*breakpoint_p)->unique_id);
216
217 return ERROR_OK;
218 }
219
220 int breakpoint_add(struct target *target,
221 target_addr_t address,
222 uint32_t length,
223 enum breakpoint_type type)
224 {
225 int retval = ERROR_OK;
226 if (target->smp) {
227 struct target_list *head;
228 struct target *curr;
229 head = target->head;
230 if (type == BKPT_SOFT)
231 return breakpoint_add_internal(head->target, address, length, type);
232
233 while (head != (struct target_list *)NULL) {
234 curr = head->target;
235 retval = breakpoint_add_internal(curr, address, length, type);
236 if (retval != ERROR_OK)
237 return retval;
238 head = head->next;
239 }
240 return retval;
241 } else
242 return breakpoint_add_internal(target, address, length, type);
243 }
244
245 int context_breakpoint_add(struct target *target,
246 uint32_t asid,
247 uint32_t length,
248 enum breakpoint_type type)
249 {
250 int retval = ERROR_OK;
251 if (target->smp) {
252 struct target_list *head;
253 struct target *curr;
254 head = target->head;
255 while (head != (struct target_list *)NULL) {
256 curr = head->target;
257 retval = context_breakpoint_add_internal(curr, asid, length, type);
258 if (retval != ERROR_OK)
259 return retval;
260 head = head->next;
261 }
262 return retval;
263 } else
264 return context_breakpoint_add_internal(target, asid, length, type);
265 }
266
267 int hybrid_breakpoint_add(struct target *target,
268 target_addr_t address,
269 uint32_t asid,
270 uint32_t length,
271 enum breakpoint_type type)
272 {
273 int retval = ERROR_OK;
274 if (target->smp) {
275 struct target_list *head;
276 struct target *curr;
277 head = target->head;
278 while (head != (struct target_list *)NULL) {
279 curr = head->target;
280 retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
281 if (retval != ERROR_OK)
282 return retval;
283 head = head->next;
284 }
285 return retval;
286 } else
287 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
288 }
289
290 /* free up a breakpoint */
291 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
292 {
293 struct breakpoint *breakpoint = target->breakpoints;
294 struct breakpoint **breakpoint_p = &target->breakpoints;
295 int retval;
296
297 while (breakpoint) {
298 if (breakpoint == breakpoint_to_remove)
299 break;
300 breakpoint_p = &breakpoint->next;
301 breakpoint = breakpoint->next;
302 }
303
304 if (breakpoint == NULL)
305 return;
306
307 retval = target_remove_breakpoint(target, breakpoint);
308
309 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
310 (*breakpoint_p) = breakpoint->next;
311 free(breakpoint->orig_instr);
312 free(breakpoint);
313 }
314
315 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
316 {
317 struct breakpoint *breakpoint = target->breakpoints;
318
319 while (breakpoint) {
320 if ((breakpoint->address == address) ||
321 (breakpoint->address == 0 && breakpoint->asid == address))
322 break;
323 breakpoint = breakpoint->next;
324 }
325
326 if (breakpoint) {
327 breakpoint_free(target, breakpoint);
328 return 1;
329 } else {
330 if (!target->smp)
331 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
332 return 0;
333 }
334 }
335
336 static void breakpoint_remove_all_internal(struct target *target)
337 {
338 struct breakpoint *breakpoint = target->breakpoints;
339
340 while (breakpoint) {
341 struct breakpoint *tmp = breakpoint;
342 breakpoint = breakpoint->next;
343 breakpoint_free(target, tmp);
344 }
345 }
346
347 void breakpoint_remove(struct target *target, target_addr_t address)
348 {
349 int found = 0;
350 if (target->smp) {
351 struct target_list *head;
352 struct target *curr;
353 head = target->head;
354 while (head != (struct target_list *)NULL) {
355 curr = head->target;
356 found += breakpoint_remove_internal(curr, address);
357 head = head->next;
358 }
359 if (found == 0)
360 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
361 } else
362 breakpoint_remove_internal(target, address);
363 }
364
365 void breakpoint_remove_all(struct target *target)
366 {
367 if (target->smp) {
368 struct target_list *head;
369 struct target *curr;
370 head = target->head;
371 while (head != (struct target_list *)NULL) {
372 curr = head->target;
373 breakpoint_remove_all_internal(curr);
374 head = head->next;
375 }
376 } else {
377 breakpoint_remove_all_internal(target);
378 }
379 }
380
381 static void breakpoint_clear_target_internal(struct target *target)
382 {
383 LOG_DEBUG("Delete all breakpoints for target: %s",
384 target_name(target));
385 while (target->breakpoints != NULL)
386 breakpoint_free(target, target->breakpoints);
387 }
388
389 void breakpoint_clear_target(struct target *target)
390 {
391 if (target->smp) {
392 struct target_list *head;
393 struct target *curr;
394 head = target->head;
395 while (head != (struct target_list *)NULL) {
396 curr = head->target;
397 breakpoint_clear_target_internal(curr);
398 head = head->next;
399 }
400 } else
401 breakpoint_clear_target_internal(target);
402
403 }
404
405 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
406 {
407 struct breakpoint *breakpoint = target->breakpoints;
408
409 while (breakpoint) {
410 if (breakpoint->address == address)
411 return breakpoint;
412 breakpoint = breakpoint->next;
413 }
414
415 return NULL;
416 }
417
418 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
419 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
420 {
421 struct watchpoint *watchpoint = target->watchpoints;
422 struct watchpoint **watchpoint_p = &target->watchpoints;
423 int retval;
424 const char *reason;
425
426 while (watchpoint) {
427 if (watchpoint->address == address) {
428 if (watchpoint->length != length
429 || watchpoint->value != value
430 || watchpoint->mask != mask
431 || watchpoint->rw != rw) {
432 LOG_ERROR("address " TARGET_ADDR_FMT
433 " already has watchpoint %d",
434 address, watchpoint->unique_id);
435 return ERROR_FAIL;
436 }
437
438 /* ignore duplicate watchpoint */
439 return ERROR_OK;
440 }
441 watchpoint_p = &watchpoint->next;
442 watchpoint = watchpoint->next;
443 }
444
445 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
446 (*watchpoint_p)->address = address;
447 (*watchpoint_p)->length = length;
448 (*watchpoint_p)->value = value;
449 (*watchpoint_p)->mask = mask;
450 (*watchpoint_p)->rw = rw;
451 (*watchpoint_p)->unique_id = bpwp_unique_id++;
452
453 retval = target_add_watchpoint(target, *watchpoint_p);
454 switch (retval) {
455 case ERROR_OK:
456 break;
457 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
458 reason = "resource not available";
459 goto bye;
460 case ERROR_TARGET_NOT_HALTED:
461 reason = "target running";
462 goto bye;
463 default:
464 reason = "unrecognized error";
465 bye:
466 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
467 watchpoint_rw_strings[(*watchpoint_p)->rw],
468 address, reason);
469 free(*watchpoint_p);
470 *watchpoint_p = NULL;
471 return retval;
472 }
473
474 LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
475 " of length 0x%8.8" PRIx32 " (WPID: %d)",
476 watchpoint_rw_strings[(*watchpoint_p)->rw],
477 (*watchpoint_p)->address,
478 (*watchpoint_p)->length,
479 (*watchpoint_p)->unique_id);
480
481 return ERROR_OK;
482 }
483
484 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
485 {
486 struct watchpoint *watchpoint = target->watchpoints;
487 struct watchpoint **watchpoint_p = &target->watchpoints;
488 int retval;
489
490 while (watchpoint) {
491 if (watchpoint == watchpoint_to_remove)
492 break;
493 watchpoint_p = &watchpoint->next;
494 watchpoint = watchpoint->next;
495 }
496
497 if (watchpoint == NULL)
498 return;
499 retval = target_remove_watchpoint(target, watchpoint);
500 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
501 (*watchpoint_p) = watchpoint->next;
502 free(watchpoint);
503 }
504
505 void watchpoint_remove(struct target *target, target_addr_t address)
506 {
507 struct watchpoint *watchpoint = target->watchpoints;
508
509 while (watchpoint) {
510 if (watchpoint->address == address)
511 break;
512 watchpoint = watchpoint->next;
513 }
514
515 if (watchpoint)
516 watchpoint_free(target, watchpoint);
517 else
518 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
519 }
520
521 void watchpoint_clear_target(struct target *target)
522 {
523 LOG_DEBUG("Delete all watchpoints for target: %s",
524 target_name(target));
525 while (target->watchpoints != NULL)
526 watchpoint_free(target, target->watchpoints);
527 }
528
529 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
530 target_addr_t *address)
531 {
532 int retval;
533 struct watchpoint *hit_watchpoint;
534
535 retval = target_hit_watchpoint(target, &hit_watchpoint);
536 if (retval != ERROR_OK)
537 return ERROR_FAIL;
538
539 *rw = hit_watchpoint->rw;
540 *address = hit_watchpoint->address;
541
542 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
543 hit_watchpoint->address,
544 hit_watchpoint->unique_id);
545
546 return ERROR_OK;
547 }

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)