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

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)