422705bc9c187ef1834bc77bf149483d3afb78e6
[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, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
22 ***************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "target.h"
29 #include <helper/log.h>
30 #include "breakpoints.h"
31
32 static char *breakpoint_type_strings[] = {
33 "hardware",
34 "software"
35 };
36
37 static char *watchpoint_rw_strings[] = {
38 "read",
39 "write",
40 "access"
41 };
42
43 /* monotonic counter/id-number for breakpoints and watch points */
44 static int bpwp_unique_id;
45
46 int breakpoint_add_internal(struct target *target,
47 uint32_t address,
48 uint32_t length,
49 enum breakpoint_type type)
50 {
51 struct breakpoint *breakpoint = target->breakpoints;
52 struct breakpoint **breakpoint_p = &target->breakpoints;
53 char *reason;
54 int retval;
55 int n;
56
57 n = 0;
58 while (breakpoint) {
59 n++;
60 if (breakpoint->address == address) {
61 /* FIXME don't assume "same address" means "same
62 * breakpoint" ... check all the parameters before
63 * succeeding.
64 */
65 LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %d)",
66 address, breakpoint->unique_id);
67 return ERROR_OK;
68 }
69 breakpoint_p = &breakpoint->next;
70 breakpoint = breakpoint->next;
71 }
72
73 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
74 (*breakpoint_p)->address = address;
75 (*breakpoint_p)->asid = 0;
76 (*breakpoint_p)->length = length;
77 (*breakpoint_p)->type = type;
78 (*breakpoint_p)->set = 0;
79 (*breakpoint_p)->orig_instr = malloc(length);
80 (*breakpoint_p)->next = NULL;
81 (*breakpoint_p)->unique_id = bpwp_unique_id++;
82
83 retval = target_add_breakpoint(target, *breakpoint_p);
84 switch (retval) {
85 case ERROR_OK:
86 break;
87 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
88 reason = "resource not available";
89 goto fail;
90 case ERROR_TARGET_NOT_HALTED:
91 reason = "target running";
92 goto fail;
93 default:
94 reason = "unknown reason";
95 fail:
96 LOG_ERROR("can't add breakpoint: %s", reason);
97 free((*breakpoint_p)->orig_instr);
98 free(*breakpoint_p);
99 *breakpoint_p = NULL;
100 return retval;
101 }
102
103 LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
104 breakpoint_type_strings[(*breakpoint_p)->type],
105 (*breakpoint_p)->address, (*breakpoint_p)->length,
106 (*breakpoint_p)->unique_id);
107
108 return ERROR_OK;
109 }
110
111 int context_breakpoint_add_internal(struct target *target,
112 uint32_t asid,
113 uint32_t length,
114 enum breakpoint_type type)
115 {
116 struct breakpoint *breakpoint = target->breakpoints;
117 struct breakpoint **breakpoint_p = &target->breakpoints;
118 int retval;
119 int n;
120
121 n = 0;
122 while (breakpoint) {
123 n++;
124 if (breakpoint->asid == asid) {
125 /* FIXME don't assume "same address" means "same
126 * breakpoint" ... check all the parameters before
127 * succeeding.
128 */
129 LOG_DEBUG("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %d)",
130 asid, breakpoint->unique_id);
131 return -1;
132 }
133 breakpoint_p = &breakpoint->next;
134 breakpoint = breakpoint->next;
135 }
136
137 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
138 (*breakpoint_p)->address = 0;
139 (*breakpoint_p)->asid = asid;
140 (*breakpoint_p)->length = length;
141 (*breakpoint_p)->type = type;
142 (*breakpoint_p)->set = 0;
143 (*breakpoint_p)->orig_instr = malloc(length);
144 (*breakpoint_p)->next = NULL;
145 (*breakpoint_p)->unique_id = bpwp_unique_id++;
146 retval = target_add_context_breakpoint(target, *breakpoint_p);
147 if (retval != ERROR_OK) {
148 LOG_ERROR("could not add breakpoint");
149 free((*breakpoint_p)->orig_instr);
150 free(*breakpoint_p);
151 *breakpoint_p = NULL;
152 return retval;
153 }
154
155 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
156 breakpoint_type_strings[(*breakpoint_p)->type],
157 (*breakpoint_p)->asid, (*breakpoint_p)->length,
158 (*breakpoint_p)->unique_id);
159
160 return ERROR_OK;
161 }
162
163 int hybrid_breakpoint_add_internal(struct target *target,
164 uint32_t address,
165 uint32_t asid,
166 uint32_t length,
167 enum breakpoint_type type)
168 {
169 struct breakpoint *breakpoint = target->breakpoints;
170 struct breakpoint **breakpoint_p = &target->breakpoints;
171 int retval;
172 int n;
173 n = 0;
174 while (breakpoint) {
175 n++;
176 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
177 /* FIXME don't assume "same address" means "same
178 * breakpoint" ... check all the parameters before
179 * succeeding.
180 */
181 LOG_DEBUG("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %d)",
182 asid, breakpoint->unique_id);
183 return -1;
184 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
185 LOG_DEBUG("Duplicate Breakpoint IVA: 0x%08" PRIx32 " (BP %d)",
186 address, breakpoint->unique_id);
187 return -1;
188
189 }
190 breakpoint_p = &breakpoint->next;
191 breakpoint = breakpoint->next;
192 }
193 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
194 (*breakpoint_p)->address = address;
195 (*breakpoint_p)->asid = asid;
196 (*breakpoint_p)->length = length;
197 (*breakpoint_p)->type = type;
198 (*breakpoint_p)->set = 0;
199 (*breakpoint_p)->orig_instr = malloc(length);
200 (*breakpoint_p)->next = NULL;
201 (*breakpoint_p)->unique_id = bpwp_unique_id++;
202
203
204 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
205 if (retval != ERROR_OK) {
206 LOG_ERROR("could not add breakpoint");
207 free((*breakpoint_p)->orig_instr);
208 free(*breakpoint_p);
209 *breakpoint_p = NULL;
210 return retval;
211 }
212 LOG_DEBUG(
213 "added %s Hybrid breakpoint at address 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
214 breakpoint_type_strings[(*breakpoint_p)->type],
215 (*breakpoint_p)->address,
216 (*breakpoint_p)->length,
217 (*breakpoint_p)->unique_id);
218
219 return ERROR_OK;
220 }
221
222 int breakpoint_add(struct target *target,
223 uint32_t address,
224 uint32_t length,
225 enum breakpoint_type type)
226 {
227 int retval = ERROR_OK;
228 if (target->smp) {
229 struct target_list *head;
230 struct target *curr;
231 head = target->head;
232 if (type == BKPT_SOFT)
233 return breakpoint_add_internal(head->target, address, length, type);
234
235 while (head != (struct target_list *)NULL) {
236 curr = head->target;
237 retval = breakpoint_add_internal(curr, address, length, type);
238 if (retval != ERROR_OK)
239 return retval;
240 head = head->next;
241 }
242 return retval;
243 } else
244 return breakpoint_add_internal(target, address, length, type);
245 }
246 int context_breakpoint_add(struct target *target,
247 uint32_t asid,
248 uint32_t length,
249 enum breakpoint_type type)
250 {
251 int retval = ERROR_OK;
252 if (target->smp) {
253 struct target_list *head;
254 struct target *curr;
255 head = target->head;
256 while (head != (struct target_list *)NULL) {
257 curr = head->target;
258 retval = context_breakpoint_add_internal(curr, asid, length, type);
259 if (retval != ERROR_OK)
260 return retval;
261 head = head->next;
262 }
263 return retval;
264 } else
265 return context_breakpoint_add_internal(target, asid, length, type);
266 }
267 int hybrid_breakpoint_add(struct target *target,
268 uint32_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: %d --> %d", breakpoint->unique_id, retval);
310 (*breakpoint_p) = breakpoint->next;
311 free(breakpoint->orig_instr);
312 free(breakpoint);
313 }
314
315 int breakpoint_remove_internal(struct target *target, uint32_t address)
316 {
317 struct breakpoint *breakpoint = target->breakpoints;
318
319 while (breakpoint) {
320 if ((breakpoint->address == address) && (breakpoint->asid == 0))
321 break;
322 else if ((breakpoint->address == 0) && (breakpoint->asid == address))
323 break;
324 else if ((breakpoint->address == address) && (breakpoint->asid != 0))
325 break;
326 breakpoint = breakpoint->next;
327 }
328
329 if (breakpoint) {
330 breakpoint_free(target, breakpoint);
331 return 1;
332 } else {
333 if (!target->smp)
334 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
335 return 0;
336 }
337 }
338 void breakpoint_remove(struct target *target, uint32_t address)
339 {
340 int found = 0;
341 if (target->smp) {
342 struct target_list *head;
343 struct target *curr;
344 head = target->head;
345 while (head != (struct target_list *)NULL) {
346 curr = head->target;
347 found += breakpoint_remove_internal(curr, address);
348 head = head->next;
349 }
350 if (found == 0)
351 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
352 } else
353 breakpoint_remove_internal(target, address);
354 }
355
356 void breakpoint_clear_target_internal(struct target *target)
357 {
358 LOG_DEBUG("Delete all breakpoints for target: %s",
359 target_name(target));
360 while (target->breakpoints != NULL)
361 breakpoint_free(target, target->breakpoints);
362 }
363
364 void breakpoint_clear_target(struct target *target)
365 {
366 if (target->smp) {
367 struct target_list *head;
368 struct target *curr;
369 head = target->head;
370 while (head != (struct target_list *)NULL) {
371 curr = head->target;
372 breakpoint_clear_target_internal(curr);
373 head = head->next;
374 }
375 } else
376 breakpoint_clear_target_internal(target);
377
378 }
379
380 struct breakpoint *breakpoint_find(struct target *target, uint32_t address)
381 {
382 struct breakpoint *breakpoint = target->breakpoints;
383
384 while (breakpoint) {
385 if (breakpoint->address == address)
386 return breakpoint;
387 breakpoint = breakpoint->next;
388 }
389
390 return NULL;
391 }
392
393 int watchpoint_add(struct target *target, uint32_t address, uint32_t length,
394 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
395 {
396 struct watchpoint *watchpoint = target->watchpoints;
397 struct watchpoint **watchpoint_p = &target->watchpoints;
398 int retval;
399 char *reason;
400
401 while (watchpoint) {
402 if (watchpoint->address == address) {
403 if (watchpoint->length != length
404 || watchpoint->value != value
405 || watchpoint->mask != mask
406 || watchpoint->rw != rw) {
407 LOG_ERROR("address 0x%8.8" PRIx32
408 "already has watchpoint %d",
409 address, watchpoint->unique_id);
410 return ERROR_FAIL;
411 }
412
413 /* ignore duplicate watchpoint */
414 return ERROR_OK;
415 }
416 watchpoint_p = &watchpoint->next;
417 watchpoint = watchpoint->next;
418 }
419
420 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
421 (*watchpoint_p)->address = address;
422 (*watchpoint_p)->length = length;
423 (*watchpoint_p)->value = value;
424 (*watchpoint_p)->mask = mask;
425 (*watchpoint_p)->rw = rw;
426 (*watchpoint_p)->unique_id = bpwp_unique_id++;
427
428 retval = target_add_watchpoint(target, *watchpoint_p);
429 switch (retval) {
430 case ERROR_OK:
431 break;
432 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
433 reason = "resource not available";
434 goto bye;
435 case ERROR_TARGET_NOT_HALTED:
436 reason = "target running";
437 goto bye;
438 default:
439 reason = "unrecognized error";
440 bye:
441 LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
442 watchpoint_rw_strings[(*watchpoint_p)->rw],
443 address, reason);
444 free(*watchpoint_p);
445 *watchpoint_p = NULL;
446 return retval;
447 }
448
449 LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32
450 " of length 0x%8.8" PRIx32 " (WPID: %d)",
451 watchpoint_rw_strings[(*watchpoint_p)->rw],
452 (*watchpoint_p)->address,
453 (*watchpoint_p)->length,
454 (*watchpoint_p)->unique_id);
455
456 return ERROR_OK;
457 }
458
459 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
460 {
461 struct watchpoint *watchpoint = target->watchpoints;
462 struct watchpoint **watchpoint_p = &target->watchpoints;
463 int retval;
464
465 while (watchpoint) {
466 if (watchpoint == watchpoint_to_remove)
467 break;
468 watchpoint_p = &watchpoint->next;
469 watchpoint = watchpoint->next;
470 }
471
472 if (watchpoint == NULL)
473 return;
474 retval = target_remove_watchpoint(target, watchpoint);
475 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
476 (*watchpoint_p) = watchpoint->next;
477 free(watchpoint);
478 }
479
480 void watchpoint_remove(struct target *target, uint32_t address)
481 {
482 struct watchpoint *watchpoint = target->watchpoints;
483
484 while (watchpoint) {
485 if (watchpoint->address == address)
486 break;
487 watchpoint = watchpoint->next;
488 }
489
490 if (watchpoint)
491 watchpoint_free(target, watchpoint);
492 else
493 LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
494 }
495
496 void watchpoint_clear_target(struct target *target)
497 {
498 LOG_DEBUG("Delete all watchpoints for target: %s",
499 target_name(target));
500 while (target->watchpoints != NULL)
501 watchpoint_free(target, target->watchpoints);
502 }
503
504 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address)
505 {
506 int retval;
507 struct watchpoint *hit_watchpoint;
508
509 retval = target_hit_watchpoint(target, &hit_watchpoint);
510 if (retval != ERROR_OK)
511 return ERROR_FAIL;
512
513 *rw = hit_watchpoint->rw;
514 *address = hit_watchpoint->address;
515
516 LOG_DEBUG("Found hit watchpoint at 0x%8.8" PRIx32 " (WPID: %d)",
517 hit_watchpoint->address,
518 hit_watchpoint->unique_id);
519
520 return ERROR_OK;
521 }

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)