94e8a823d07fdb225e8b3f0aed68fbf5a72added
[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 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 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 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 int context_breakpoint_add(struct target *target,
245 uint32_t asid,
246 uint32_t length,
247 enum breakpoint_type type)
248 {
249 int retval = ERROR_OK;
250 if (target->smp) {
251 struct target_list *head;
252 struct target *curr;
253 head = target->head;
254 while (head != (struct target_list *)NULL) {
255 curr = head->target;
256 retval = context_breakpoint_add_internal(curr, asid, length, type);
257 if (retval != ERROR_OK)
258 return retval;
259 head = head->next;
260 }
261 return retval;
262 } else
263 return context_breakpoint_add_internal(target, asid, length, type);
264 }
265 int hybrid_breakpoint_add(struct target *target,
266 target_addr_t address,
267 uint32_t asid,
268 uint32_t length,
269 enum breakpoint_type type)
270 {
271 int retval = ERROR_OK;
272 if (target->smp) {
273 struct target_list *head;
274 struct target *curr;
275 head = target->head;
276 while (head != (struct target_list *)NULL) {
277 curr = head->target;
278 retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
279 if (retval != ERROR_OK)
280 return retval;
281 head = head->next;
282 }
283 return retval;
284 } else
285 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
286 }
287
288 /* free up a breakpoint */
289 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
290 {
291 struct breakpoint *breakpoint = target->breakpoints;
292 struct breakpoint **breakpoint_p = &target->breakpoints;
293 int retval;
294
295 while (breakpoint) {
296 if (breakpoint == breakpoint_to_remove)
297 break;
298 breakpoint_p = &breakpoint->next;
299 breakpoint = breakpoint->next;
300 }
301
302 if (breakpoint == NULL)
303 return;
304
305 retval = target_remove_breakpoint(target, breakpoint);
306
307 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
308 (*breakpoint_p) = breakpoint->next;
309 free(breakpoint->orig_instr);
310 free(breakpoint);
311 }
312
313 int breakpoint_remove_internal(struct target *target, target_addr_t address)
314 {
315 struct breakpoint *breakpoint = target->breakpoints;
316
317 while (breakpoint) {
318 if ((breakpoint->address == address) ||
319 (breakpoint->address == 0 && breakpoint->asid == address))
320 break;
321 breakpoint = breakpoint->next;
322 }
323
324 if (breakpoint) {
325 breakpoint_free(target, breakpoint);
326 return 1;
327 } else {
328 if (!target->smp)
329 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
330 return 0;
331 }
332 }
333 void breakpoint_remove(struct target *target, target_addr_t address)
334 {
335 int found = 0;
336 if (target->smp) {
337 struct target_list *head;
338 struct target *curr;
339 head = target->head;
340 while (head != (struct target_list *)NULL) {
341 curr = head->target;
342 found += breakpoint_remove_internal(curr, address);
343 head = head->next;
344 }
345 if (found == 0)
346 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
347 } else
348 breakpoint_remove_internal(target, address);
349 }
350
351 void breakpoint_clear_target_internal(struct target *target)
352 {
353 LOG_DEBUG("Delete all breakpoints for target: %s",
354 target_name(target));
355 while (target->breakpoints != NULL)
356 breakpoint_free(target, target->breakpoints);
357 }
358
359 void breakpoint_clear_target(struct target *target)
360 {
361 if (target->smp) {
362 struct target_list *head;
363 struct target *curr;
364 head = target->head;
365 while (head != (struct target_list *)NULL) {
366 curr = head->target;
367 breakpoint_clear_target_internal(curr);
368 head = head->next;
369 }
370 } else
371 breakpoint_clear_target_internal(target);
372
373 }
374
375 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
376 {
377 struct breakpoint *breakpoint = target->breakpoints;
378
379 while (breakpoint) {
380 if (breakpoint->address == address)
381 return breakpoint;
382 breakpoint = breakpoint->next;
383 }
384
385 return NULL;
386 }
387
388 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
389 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
390 {
391 struct watchpoint *watchpoint = target->watchpoints;
392 struct watchpoint **watchpoint_p = &target->watchpoints;
393 int retval;
394 const char *reason;
395
396 while (watchpoint) {
397 if (watchpoint->address == address) {
398 if (watchpoint->length != length
399 || watchpoint->value != value
400 || watchpoint->mask != mask
401 || watchpoint->rw != rw) {
402 LOG_ERROR("address " TARGET_ADDR_FMT
403 " already has watchpoint %d",
404 address, watchpoint->unique_id);
405 return ERROR_FAIL;
406 }
407
408 /* ignore duplicate watchpoint */
409 return ERROR_OK;
410 }
411 watchpoint_p = &watchpoint->next;
412 watchpoint = watchpoint->next;
413 }
414
415 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
416 (*watchpoint_p)->address = address;
417 (*watchpoint_p)->length = length;
418 (*watchpoint_p)->value = value;
419 (*watchpoint_p)->mask = mask;
420 (*watchpoint_p)->rw = rw;
421 (*watchpoint_p)->unique_id = bpwp_unique_id++;
422
423 retval = target_add_watchpoint(target, *watchpoint_p);
424 switch (retval) {
425 case ERROR_OK:
426 break;
427 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
428 reason = "resource not available";
429 goto bye;
430 case ERROR_TARGET_NOT_HALTED:
431 reason = "target running";
432 goto bye;
433 default:
434 reason = "unrecognized error";
435 bye:
436 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
437 watchpoint_rw_strings[(*watchpoint_p)->rw],
438 address, reason);
439 free(*watchpoint_p);
440 *watchpoint_p = NULL;
441 return retval;
442 }
443
444 LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
445 " of length 0x%8.8" PRIx32 " (WPID: %d)",
446 watchpoint_rw_strings[(*watchpoint_p)->rw],
447 (*watchpoint_p)->address,
448 (*watchpoint_p)->length,
449 (*watchpoint_p)->unique_id);
450
451 return ERROR_OK;
452 }
453
454 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
455 {
456 struct watchpoint *watchpoint = target->watchpoints;
457 struct watchpoint **watchpoint_p = &target->watchpoints;
458 int retval;
459
460 while (watchpoint) {
461 if (watchpoint == watchpoint_to_remove)
462 break;
463 watchpoint_p = &watchpoint->next;
464 watchpoint = watchpoint->next;
465 }
466
467 if (watchpoint == NULL)
468 return;
469 retval = target_remove_watchpoint(target, watchpoint);
470 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
471 (*watchpoint_p) = watchpoint->next;
472 free(watchpoint);
473 }
474
475 void watchpoint_remove(struct target *target, target_addr_t address)
476 {
477 struct watchpoint *watchpoint = target->watchpoints;
478
479 while (watchpoint) {
480 if (watchpoint->address == address)
481 break;
482 watchpoint = watchpoint->next;
483 }
484
485 if (watchpoint)
486 watchpoint_free(target, watchpoint);
487 else
488 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
489 }
490
491 void watchpoint_clear_target(struct target *target)
492 {
493 LOG_DEBUG("Delete all watchpoints for target: %s",
494 target_name(target));
495 while (target->watchpoints != NULL)
496 watchpoint_free(target, target->watchpoints);
497 }
498
499 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
500 target_addr_t *address)
501 {
502 int retval;
503 struct watchpoint *hit_watchpoint;
504
505 retval = target_hit_watchpoint(target, &hit_watchpoint);
506 if (retval != ERROR_OK)
507 return ERROR_FAIL;
508
509 *rw = hit_watchpoint->rw;
510 *address = hit_watchpoint->address;
511
512 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
513 hit_watchpoint->address,
514 hit_watchpoint->unique_id);
515
516 return ERROR_OK;
517 }

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)