79c68fea828ee3a955370fa5384f6b689d0cccb8
[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 #include "smp.h"
30
31 static const char * const breakpoint_type_strings[] = {
32 "hardware",
33 "software"
34 };
35
36 static const char * const watchpoint_rw_strings[] = {
37 "read",
38 "write",
39 "access"
40 };
41
42 /* monotonic counter/id-number for breakpoints and watch points */
43 static int bpwp_unique_id;
44
45 static int breakpoint_add_internal(struct target *target,
46 target_addr_t address,
47 uint32_t length,
48 enum breakpoint_type type)
49 {
50 struct breakpoint *breakpoint = target->breakpoints;
51 struct breakpoint **breakpoint_p = &target->breakpoints;
52 const char *reason;
53 int retval;
54
55 while (breakpoint) {
56 if (breakpoint->address == address) {
57 /* FIXME don't assume "same address" means "same
58 * breakpoint" ... check all the parameters before
59 * succeeding.
60 */
61 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
62 address, breakpoint->unique_id);
63 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
64 }
65 breakpoint_p = &breakpoint->next;
66 breakpoint = breakpoint->next;
67 }
68
69 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
70 (*breakpoint_p)->address = address;
71 (*breakpoint_p)->asid = 0;
72 (*breakpoint_p)->length = length;
73 (*breakpoint_p)->type = type;
74 (*breakpoint_p)->is_set = false;
75 (*breakpoint_p)->orig_instr = malloc(length);
76 (*breakpoint_p)->next = NULL;
77 (*breakpoint_p)->unique_id = bpwp_unique_id++;
78
79 retval = target_add_breakpoint(target, *breakpoint_p);
80 switch (retval) {
81 case ERROR_OK:
82 break;
83 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
84 reason = "resource not available";
85 goto fail;
86 case ERROR_TARGET_NOT_HALTED:
87 reason = "target running";
88 goto fail;
89 default:
90 reason = "unknown reason";
91 fail:
92 LOG_ERROR("can't add breakpoint: %s", reason);
93 free((*breakpoint_p)->orig_instr);
94 free(*breakpoint_p);
95 *breakpoint_p = NULL;
96 return retval;
97 }
98
99 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
100 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
101 target->coreid,
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
118 while (breakpoint) {
119 if (breakpoint->asid == asid) {
120 /* FIXME don't assume "same address" means "same
121 * breakpoint" ... check all the parameters before
122 * succeeding.
123 */
124 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
125 asid, breakpoint->unique_id);
126 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
127 }
128 breakpoint_p = &breakpoint->next;
129 breakpoint = breakpoint->next;
130 }
131
132 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
133 (*breakpoint_p)->address = 0;
134 (*breakpoint_p)->asid = asid;
135 (*breakpoint_p)->length = length;
136 (*breakpoint_p)->type = type;
137 (*breakpoint_p)->is_set = false;
138 (*breakpoint_p)->orig_instr = malloc(length);
139 (*breakpoint_p)->next = NULL;
140 (*breakpoint_p)->unique_id = bpwp_unique_id++;
141 retval = target_add_context_breakpoint(target, *breakpoint_p);
142 if (retval != ERROR_OK) {
143 LOG_ERROR("could not add breakpoint");
144 free((*breakpoint_p)->orig_instr);
145 free(*breakpoint_p);
146 *breakpoint_p = NULL;
147 return retval;
148 }
149
150 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
151 breakpoint_type_strings[(*breakpoint_p)->type],
152 (*breakpoint_p)->asid, (*breakpoint_p)->length,
153 (*breakpoint_p)->unique_id);
154
155 return ERROR_OK;
156 }
157
158 static int hybrid_breakpoint_add_internal(struct target *target,
159 target_addr_t address,
160 uint32_t asid,
161 uint32_t length,
162 enum breakpoint_type type)
163 {
164 struct breakpoint *breakpoint = target->breakpoints;
165 struct breakpoint **breakpoint_p = &target->breakpoints;
166 int retval;
167
168 while (breakpoint) {
169 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
170 /* FIXME don't assume "same address" means "same
171 * breakpoint" ... check all the parameters before
172 * succeeding.
173 */
174 LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
175 asid, breakpoint->unique_id);
176 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
177 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
178 LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
179 address, breakpoint->unique_id);
180 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
181
182 }
183 breakpoint_p = &breakpoint->next;
184 breakpoint = breakpoint->next;
185 }
186 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
187 (*breakpoint_p)->address = address;
188 (*breakpoint_p)->asid = asid;
189 (*breakpoint_p)->length = length;
190 (*breakpoint_p)->type = type;
191 (*breakpoint_p)->is_set = false;
192 (*breakpoint_p)->orig_instr = malloc(length);
193 (*breakpoint_p)->next = NULL;
194 (*breakpoint_p)->unique_id = bpwp_unique_id++;
195
196
197 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
198 if (retval != ERROR_OK) {
199 LOG_ERROR("could not add breakpoint");
200 free((*breakpoint_p)->orig_instr);
201 free(*breakpoint_p);
202 *breakpoint_p = NULL;
203 return retval;
204 }
205 LOG_DEBUG(
206 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
207 breakpoint_type_strings[(*breakpoint_p)->type],
208 (*breakpoint_p)->address,
209 (*breakpoint_p)->length,
210 (*breakpoint_p)->unique_id);
211
212 return ERROR_OK;
213 }
214
215 int breakpoint_add(struct target *target,
216 target_addr_t address,
217 uint32_t length,
218 enum breakpoint_type type)
219 {
220 if (target->smp) {
221 struct target_list *head;
222
223 if (type == BKPT_SOFT) {
224 head = list_first_entry(target->smp_targets, struct target_list, lh);
225 return breakpoint_add_internal(head->target, address, length, type);
226 }
227
228 foreach_smp_target(head, target->smp_targets) {
229 struct target *curr = head->target;
230 int retval = breakpoint_add_internal(curr, address, length, type);
231 if (retval != ERROR_OK)
232 return retval;
233 }
234
235 return ERROR_OK;
236 } else {
237 return breakpoint_add_internal(target, address, length, type);
238 }
239 }
240
241 int context_breakpoint_add(struct target *target,
242 uint32_t asid,
243 uint32_t length,
244 enum breakpoint_type type)
245 {
246 if (target->smp) {
247 struct target_list *head;
248
249 foreach_smp_target(head, target->smp_targets) {
250 struct target *curr = head->target;
251 int retval = context_breakpoint_add_internal(curr, asid, length, type);
252 if (retval != ERROR_OK)
253 return retval;
254 }
255
256 return ERROR_OK;
257 } else {
258 return context_breakpoint_add_internal(target, asid, length, type);
259 }
260 }
261
262 int hybrid_breakpoint_add(struct target *target,
263 target_addr_t address,
264 uint32_t asid,
265 uint32_t length,
266 enum breakpoint_type type)
267 {
268 if (target->smp) {
269 struct target_list *head;
270
271 foreach_smp_target(head, target->smp_targets) {
272 struct target *curr = head->target;
273 int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
274 if (retval != ERROR_OK)
275 return retval;
276 }
277
278 return ERROR_OK;
279 } else
280 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
281 }
282
283 /* free up a breakpoint */
284 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
285 {
286 struct breakpoint *breakpoint = target->breakpoints;
287 struct breakpoint **breakpoint_p = &target->breakpoints;
288 int retval;
289
290 while (breakpoint) {
291 if (breakpoint == breakpoint_to_remove)
292 break;
293 breakpoint_p = &breakpoint->next;
294 breakpoint = breakpoint->next;
295 }
296
297 if (!breakpoint)
298 return;
299
300 retval = target_remove_breakpoint(target, breakpoint);
301
302 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
303 (*breakpoint_p) = breakpoint->next;
304 free(breakpoint->orig_instr);
305 free(breakpoint);
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 breakpoint_free(target, breakpoint);
321 return 1;
322 } else {
323 if (!target->smp)
324 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
325 return 0;
326 }
327 }
328
329 static void breakpoint_remove_all_internal(struct target *target)
330 {
331 struct breakpoint *breakpoint = target->breakpoints;
332
333 while (breakpoint) {
334 struct breakpoint *tmp = breakpoint;
335 breakpoint = breakpoint->next;
336 breakpoint_free(target, tmp);
337 }
338 }
339
340 void breakpoint_remove(struct target *target, target_addr_t address)
341 {
342 if (target->smp) {
343 unsigned int num_breakpoints = 0;
344 struct target_list *head;
345
346 foreach_smp_target(head, target->smp_targets) {
347 struct target *curr = head->target;
348 num_breakpoints += breakpoint_remove_internal(curr, address);
349 }
350 if (!num_breakpoints)
351 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
352 } else {
353 breakpoint_remove_internal(target, address);
354 }
355 }
356
357 void breakpoint_remove_all(struct target *target)
358 {
359 if (target->smp) {
360 struct target_list *head;
361
362 foreach_smp_target(head, target->smp_targets) {
363 struct target *curr = head->target;
364 breakpoint_remove_all_internal(curr);
365 }
366 } else {
367 breakpoint_remove_all_internal(target);
368 }
369 }
370
371 static void breakpoint_clear_target_internal(struct target *target)
372 {
373 LOG_DEBUG("Delete all breakpoints for target: %s",
374 target_name(target));
375 while (target->breakpoints)
376 breakpoint_free(target, target->breakpoints);
377 }
378
379 void breakpoint_clear_target(struct target *target)
380 {
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 breakpoint_clear_target_internal(curr);
387 }
388 } else {
389 breakpoint_clear_target_internal(target);
390 }
391 }
392
393 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
394 {
395 struct breakpoint *breakpoint = target->breakpoints;
396
397 while (breakpoint) {
398 if (breakpoint->address == address)
399 return breakpoint;
400 breakpoint = breakpoint->next;
401 }
402
403 return NULL;
404 }
405
406 int watchpoint_add_internal(struct target *target, target_addr_t address,
407 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
408 {
409 struct watchpoint *watchpoint = target->watchpoints;
410 struct watchpoint **watchpoint_p = &target->watchpoints;
411 int retval;
412 const char *reason;
413
414 while (watchpoint) {
415 if (watchpoint->address == address) {
416 if (watchpoint->length != length
417 || watchpoint->value != value
418 || watchpoint->mask != mask
419 || watchpoint->rw != rw) {
420 LOG_ERROR("address " TARGET_ADDR_FMT
421 " already has watchpoint %d",
422 address, watchpoint->unique_id);
423 return ERROR_FAIL;
424 }
425
426 /* ignore duplicate watchpoint */
427 return ERROR_OK;
428 }
429 watchpoint_p = &watchpoint->next;
430 watchpoint = watchpoint->next;
431 }
432
433 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
434 (*watchpoint_p)->address = address;
435 (*watchpoint_p)->length = length;
436 (*watchpoint_p)->value = value;
437 (*watchpoint_p)->mask = mask;
438 (*watchpoint_p)->rw = rw;
439 (*watchpoint_p)->unique_id = bpwp_unique_id++;
440
441 retval = target_add_watchpoint(target, *watchpoint_p);
442 switch (retval) {
443 case ERROR_OK:
444 break;
445 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
446 reason = "resource not available";
447 goto bye;
448 case ERROR_TARGET_NOT_HALTED:
449 reason = "target running";
450 goto bye;
451 default:
452 reason = "unrecognized error";
453 bye:
454 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
455 watchpoint_rw_strings[(*watchpoint_p)->rw],
456 address, reason);
457 free(*watchpoint_p);
458 *watchpoint_p = NULL;
459 return retval;
460 }
461
462 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
463 " of length 0x%8.8" PRIx32 " (WPID: %d)",
464 target->coreid,
465 watchpoint_rw_strings[(*watchpoint_p)->rw],
466 (*watchpoint_p)->address,
467 (*watchpoint_p)->length,
468 (*watchpoint_p)->unique_id);
469
470 return ERROR_OK;
471 }
472
473 int watchpoint_add(struct target *target, target_addr_t address,
474 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
475 {
476 if (target->smp) {
477 struct target_list *head;
478
479 foreach_smp_target(head, target->smp_targets) {
480 struct target *curr = head->target;
481 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
482 if (retval != ERROR_OK)
483 return retval;
484 }
485
486 return ERROR_OK;
487 } else {
488 return watchpoint_add_internal(target, address, length, rw, value,
489 mask);
490 }
491 }
492
493 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
494 {
495 struct watchpoint *watchpoint = target->watchpoints;
496 struct watchpoint **watchpoint_p = &target->watchpoints;
497 int retval;
498
499 while (watchpoint) {
500 if (watchpoint == watchpoint_to_remove)
501 break;
502 watchpoint_p = &watchpoint->next;
503 watchpoint = watchpoint->next;
504 }
505
506 if (!watchpoint)
507 return;
508 retval = target_remove_watchpoint(target, watchpoint);
509 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
510 (*watchpoint_p) = watchpoint->next;
511 free(watchpoint);
512 }
513
514 int watchpoint_remove_internal(struct target *target, target_addr_t address)
515 {
516 struct watchpoint *watchpoint = target->watchpoints;
517
518 while (watchpoint) {
519 if (watchpoint->address == address)
520 break;
521 watchpoint = watchpoint->next;
522 }
523
524 if (watchpoint) {
525 watchpoint_free(target, watchpoint);
526 return 1;
527 } else {
528 if (!target->smp)
529 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
530 return 0;
531 }
532 }
533
534 void watchpoint_remove(struct target *target, target_addr_t address)
535 {
536 if (target->smp) {
537 unsigned int num_watchpoints = 0;
538 struct target_list *head;
539
540 foreach_smp_target(head, target->smp_targets) {
541 struct target *curr = head->target;
542 num_watchpoints += watchpoint_remove_internal(curr, address);
543 }
544 if (num_watchpoints == 0)
545 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
546 } else {
547 watchpoint_remove_internal(target, address);
548 }
549 }
550
551 void watchpoint_clear_target(struct target *target)
552 {
553 LOG_DEBUG("Delete all watchpoints for target: %s",
554 target_name(target));
555 while (target->watchpoints)
556 watchpoint_free(target, target->watchpoints);
557 }
558
559 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
560 target_addr_t *address)
561 {
562 int retval;
563 struct watchpoint *hit_watchpoint;
564
565 retval = target_hit_watchpoint(target, &hit_watchpoint);
566 if (retval != ERROR_OK)
567 return ERROR_FAIL;
568
569 *rw = hit_watchpoint->rw;
570 *address = hit_watchpoint->address;
571
572 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
573 hit_watchpoint->address,
574 hit_watchpoint->unique_id);
575
576 return ERROR_OK;
577 }

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)