c4a959df3ea949d4a70e93f4375126f70602f02d
[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 uint32_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_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %" PRIu32 ")",
64 address, breakpoint->unique_id);
65 return ERROR_OK;
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 0x%8.8" PRIx32 " 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_DEBUG("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
128 asid, breakpoint->unique_id);
129 return -1;
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 uint32_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_DEBUG("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
180 asid, breakpoint->unique_id);
181 return -1;
182 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
183 LOG_DEBUG("Duplicate Breakpoint IVA: 0x%08" PRIx32 " (BP %" PRIu32 ")",
184 address, breakpoint->unique_id);
185 return -1;
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 0x%8.8" PRIx32 " 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 uint32_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 uint32_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, uint32_t address)
314 {
315 struct breakpoint *breakpoint = target->breakpoints;
316
317 while (breakpoint) {
318 if ((breakpoint->address == address) && (breakpoint->asid == 0))
319 break;
320 else if ((breakpoint->address == 0) && (breakpoint->asid == address))
321 break;
322 else if ((breakpoint->address == address) && (breakpoint->asid != 0))
323 break;
324 breakpoint = breakpoint->next;
325 }
326
327 if (breakpoint) {
328 breakpoint_free(target, breakpoint);
329 return 1;
330 } else {
331 if (!target->smp)
332 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
333 return 0;
334 }
335 }
336 void breakpoint_remove(struct target *target, uint32_t address)
337 {
338 int found = 0;
339 if (target->smp) {
340 struct target_list *head;
341 struct target *curr;
342 head = target->head;
343 while (head != (struct target_list *)NULL) {
344 curr = head->target;
345 found += breakpoint_remove_internal(curr, address);
346 head = head->next;
347 }
348 if (found == 0)
349 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
350 } else
351 breakpoint_remove_internal(target, address);
352 }
353
354 void breakpoint_clear_target_internal(struct target *target)
355 {
356 LOG_DEBUG("Delete all breakpoints for target: %s",
357 target_name(target));
358 while (target->breakpoints != NULL)
359 breakpoint_free(target, target->breakpoints);
360 }
361
362 void breakpoint_clear_target(struct target *target)
363 {
364 if (target->smp) {
365 struct target_list *head;
366 struct target *curr;
367 head = target->head;
368 while (head != (struct target_list *)NULL) {
369 curr = head->target;
370 breakpoint_clear_target_internal(curr);
371 head = head->next;
372 }
373 } else
374 breakpoint_clear_target_internal(target);
375
376 }
377
378 struct breakpoint *breakpoint_find(struct target *target, uint32_t address)
379 {
380 struct breakpoint *breakpoint = target->breakpoints;
381
382 while (breakpoint) {
383 if (breakpoint->address == address)
384 return breakpoint;
385 breakpoint = breakpoint->next;
386 }
387
388 return NULL;
389 }
390
391 int watchpoint_add(struct target *target, uint32_t address, uint32_t length,
392 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
393 {
394 struct watchpoint *watchpoint = target->watchpoints;
395 struct watchpoint **watchpoint_p = &target->watchpoints;
396 int retval;
397 const char *reason;
398
399 while (watchpoint) {
400 if (watchpoint->address == address) {
401 if (watchpoint->length != length
402 || watchpoint->value != value
403 || watchpoint->mask != mask
404 || watchpoint->rw != rw) {
405 LOG_ERROR("address 0x%8.8" PRIx32
406 " already has watchpoint %d",
407 address, watchpoint->unique_id);
408 return ERROR_FAIL;
409 }
410
411 /* ignore duplicate watchpoint */
412 return ERROR_OK;
413 }
414 watchpoint_p = &watchpoint->next;
415 watchpoint = watchpoint->next;
416 }
417
418 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
419 (*watchpoint_p)->address = address;
420 (*watchpoint_p)->length = length;
421 (*watchpoint_p)->value = value;
422 (*watchpoint_p)->mask = mask;
423 (*watchpoint_p)->rw = rw;
424 (*watchpoint_p)->unique_id = bpwp_unique_id++;
425
426 retval = target_add_watchpoint(target, *watchpoint_p);
427 switch (retval) {
428 case ERROR_OK:
429 break;
430 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
431 reason = "resource not available";
432 goto bye;
433 case ERROR_TARGET_NOT_HALTED:
434 reason = "target running";
435 goto bye;
436 default:
437 reason = "unrecognized error";
438 bye:
439 LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
440 watchpoint_rw_strings[(*watchpoint_p)->rw],
441 address, reason);
442 free(*watchpoint_p);
443 *watchpoint_p = NULL;
444 return retval;
445 }
446
447 LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32
448 " of length 0x%8.8" PRIx32 " (WPID: %d)",
449 watchpoint_rw_strings[(*watchpoint_p)->rw],
450 (*watchpoint_p)->address,
451 (*watchpoint_p)->length,
452 (*watchpoint_p)->unique_id);
453
454 return ERROR_OK;
455 }
456
457 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
458 {
459 struct watchpoint *watchpoint = target->watchpoints;
460 struct watchpoint **watchpoint_p = &target->watchpoints;
461 int retval;
462
463 while (watchpoint) {
464 if (watchpoint == watchpoint_to_remove)
465 break;
466 watchpoint_p = &watchpoint->next;
467 watchpoint = watchpoint->next;
468 }
469
470 if (watchpoint == NULL)
471 return;
472 retval = target_remove_watchpoint(target, watchpoint);
473 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
474 (*watchpoint_p) = watchpoint->next;
475 free(watchpoint);
476 }
477
478 void watchpoint_remove(struct target *target, uint32_t address)
479 {
480 struct watchpoint *watchpoint = target->watchpoints;
481
482 while (watchpoint) {
483 if (watchpoint->address == address)
484 break;
485 watchpoint = watchpoint->next;
486 }
487
488 if (watchpoint)
489 watchpoint_free(target, watchpoint);
490 else
491 LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
492 }
493
494 void watchpoint_clear_target(struct target *target)
495 {
496 LOG_DEBUG("Delete all watchpoints for target: %s",
497 target_name(target));
498 while (target->watchpoints != NULL)
499 watchpoint_free(target, target->watchpoints);
500 }
501
502 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address)
503 {
504 int retval;
505 struct watchpoint *hit_watchpoint;
506
507 retval = target_hit_watchpoint(target, &hit_watchpoint);
508 if (retval != ERROR_OK)
509 return ERROR_FAIL;
510
511 *rw = hit_watchpoint->rw;
512 *address = hit_watchpoint->address;
513
514 LOG_DEBUG("Found hit watchpoint at 0x%8.8" PRIx32 " (WPID: %d)",
515 hit_watchpoint->address,
516 hit_watchpoint->unique_id);
517
518 return ERROR_OK;
519 }

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)