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

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)