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