1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) ST-Ericsson SA 2011 *
6 * michel.jaouen@stericsson.com : smp minimum support *
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. *
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. *
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 ***************************************************************************/
27 #include <helper/log.h>
28 #include "breakpoints.h"
31 static const char * const breakpoint_type_strings[] = {
36 static const char * const watchpoint_rw_strings[] = {
42 /* monotonic counter/id-number for breakpoints and watch points */
43 static int bpwp_unique_id;
45 static int breakpoint_add_internal(struct target *target,
46 target_addr_t address,
48 enum breakpoint_type type)
50 struct breakpoint *breakpoint = target->breakpoints;
51 struct breakpoint **breakpoint_p = &target->breakpoints;
56 if (breakpoint->address == address) {
57 /* FIXME don't assume "same address" means "same
58 * breakpoint" ... check all the parameters before
61 LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
62 address, breakpoint->unique_id);
63 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
65 breakpoint_p = &breakpoint->next;
66 breakpoint = breakpoint->next;
69 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
70 (*breakpoint_p)->address = address;
71 (*breakpoint_p)->asid = 0;
72 (*breakpoint_p)->length = length;
73 (*breakpoint_p)->type = type;
74 (*breakpoint_p)->is_set = false;
75 (*breakpoint_p)->orig_instr = malloc(length);
76 (*breakpoint_p)->next = NULL;
77 (*breakpoint_p)->unique_id = bpwp_unique_id++;
79 retval = target_add_breakpoint(target, *breakpoint_p);
83 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
84 reason = "resource not available";
86 case ERROR_TARGET_NOT_HALTED:
87 reason = "target running";
90 reason = "unknown reason";
92 LOG_ERROR("can't add breakpoint: %s", reason);
93 free((*breakpoint_p)->orig_instr);
99 LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
100 " 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);
109 static int context_breakpoint_add_internal(struct target *target,
112 enum breakpoint_type type)
114 struct breakpoint *breakpoint = target->breakpoints;
115 struct breakpoint **breakpoint_p = &target->breakpoints;
119 if (breakpoint->asid == asid) {
120 /* FIXME don't assume "same address" means "same
121 * breakpoint" ... check all the parameters before
124 LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
125 asid, breakpoint->unique_id);
126 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
128 breakpoint_p = &breakpoint->next;
129 breakpoint = breakpoint->next;
132 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
133 (*breakpoint_p)->address = 0;
134 (*breakpoint_p)->asid = asid;
135 (*breakpoint_p)->length = length;
136 (*breakpoint_p)->type = type;
137 (*breakpoint_p)->is_set = false;
138 (*breakpoint_p)->orig_instr = malloc(length);
139 (*breakpoint_p)->next = NULL;
140 (*breakpoint_p)->unique_id = bpwp_unique_id++;
141 retval = target_add_context_breakpoint(target, *breakpoint_p);
142 if (retval != ERROR_OK) {
143 LOG_ERROR("could not add breakpoint");
144 free((*breakpoint_p)->orig_instr);
146 *breakpoint_p = NULL;
150 LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
151 breakpoint_type_strings[(*breakpoint_p)->type],
152 (*breakpoint_p)->asid, (*breakpoint_p)->length,
153 (*breakpoint_p)->unique_id);
158 static int hybrid_breakpoint_add_internal(struct target *target,
159 target_addr_t address,
162 enum breakpoint_type type)
164 struct breakpoint *breakpoint = target->breakpoints;
165 struct breakpoint **breakpoint_p = &target->breakpoints;
169 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
170 /* FIXME don't assume "same address" means "same
171 * breakpoint" ... check all the parameters before
174 LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
175 asid, breakpoint->unique_id);
176 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
177 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
178 LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
179 address, breakpoint->unique_id);
180 return ERROR_TARGET_DUPLICATE_BREAKPOINT;
183 breakpoint_p = &breakpoint->next;
184 breakpoint = breakpoint->next;
186 (*breakpoint_p) = malloc(sizeof(struct breakpoint));
187 (*breakpoint_p)->address = address;
188 (*breakpoint_p)->asid = asid;
189 (*breakpoint_p)->length = length;
190 (*breakpoint_p)->type = type;
191 (*breakpoint_p)->is_set = false;
192 (*breakpoint_p)->orig_instr = malloc(length);
193 (*breakpoint_p)->next = NULL;
194 (*breakpoint_p)->unique_id = bpwp_unique_id++;
197 retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
198 if (retval != ERROR_OK) {
199 LOG_ERROR("could not add breakpoint");
200 free((*breakpoint_p)->orig_instr);
202 *breakpoint_p = NULL;
206 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
207 breakpoint_type_strings[(*breakpoint_p)->type],
208 (*breakpoint_p)->address,
209 (*breakpoint_p)->length,
210 (*breakpoint_p)->unique_id);
215 int breakpoint_add(struct target *target,
216 target_addr_t address,
218 enum breakpoint_type type)
221 struct target_list *head;
223 if (type == BKPT_SOFT) {
224 head = list_first_entry(target->smp_targets, struct target_list, lh);
225 return breakpoint_add_internal(head->target, address, length, type);
228 foreach_smp_target(head, target->smp_targets) {
229 struct target *curr = head->target;
230 int retval = breakpoint_add_internal(curr, address, length, type);
231 if (retval != ERROR_OK)
237 return breakpoint_add_internal(target, address, length, type);
241 int context_breakpoint_add(struct target *target,
244 enum breakpoint_type type)
247 struct target_list *head;
249 foreach_smp_target(head, target->smp_targets) {
250 struct target *curr = head->target;
251 int retval = context_breakpoint_add_internal(curr, asid, length, type);
252 if (retval != ERROR_OK)
258 return context_breakpoint_add_internal(target, asid, length, type);
262 int hybrid_breakpoint_add(struct target *target,
263 target_addr_t address,
266 enum breakpoint_type type)
269 struct target_list *head;
271 foreach_smp_target(head, target->smp_targets) {
272 struct target *curr = head->target;
273 int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
274 if (retval != ERROR_OK)
280 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
283 /* free up a breakpoint */
284 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
286 struct breakpoint *breakpoint = target->breakpoints;
287 struct breakpoint **breakpoint_p = &target->breakpoints;
291 if (breakpoint == breakpoint_to_remove)
293 breakpoint_p = &breakpoint->next;
294 breakpoint = breakpoint->next;
300 retval = target_remove_breakpoint(target, breakpoint);
302 LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
303 (*breakpoint_p) = breakpoint->next;
304 free(breakpoint->orig_instr);
308 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
310 struct breakpoint *breakpoint = target->breakpoints;
313 if ((breakpoint->address == address) ||
314 (breakpoint->address == 0 && breakpoint->asid == address))
316 breakpoint = breakpoint->next;
320 breakpoint_free(target, breakpoint);
324 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
329 static void breakpoint_remove_all_internal(struct target *target)
331 struct breakpoint *breakpoint = target->breakpoints;
334 struct breakpoint *tmp = breakpoint;
335 breakpoint = breakpoint->next;
336 breakpoint_free(target, tmp);
340 void breakpoint_remove(struct target *target, target_addr_t address)
343 unsigned int num_breakpoints = 0;
344 struct target_list *head;
346 foreach_smp_target(head, target->smp_targets) {
347 struct target *curr = head->target;
348 num_breakpoints += breakpoint_remove_internal(curr, address);
350 if (!num_breakpoints)
351 LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
353 breakpoint_remove_internal(target, address);
357 void breakpoint_remove_all(struct target *target)
360 struct target_list *head;
362 foreach_smp_target(head, target->smp_targets) {
363 struct target *curr = head->target;
364 breakpoint_remove_all_internal(curr);
367 breakpoint_remove_all_internal(target);
371 static void breakpoint_clear_target_internal(struct target *target)
373 LOG_DEBUG("Delete all breakpoints for target: %s",
374 target_name(target));
375 while (target->breakpoints)
376 breakpoint_free(target, target->breakpoints);
379 void breakpoint_clear_target(struct target *target)
382 struct target_list *head;
384 foreach_smp_target(head, target->smp_targets) {
385 struct target *curr = head->target;
386 breakpoint_clear_target_internal(curr);
389 breakpoint_clear_target_internal(target);
393 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
395 struct breakpoint *breakpoint = target->breakpoints;
398 if (breakpoint->address == address)
400 breakpoint = breakpoint->next;
406 int watchpoint_add_internal(struct target *target, target_addr_t address,
407 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
409 struct watchpoint *watchpoint = target->watchpoints;
410 struct watchpoint **watchpoint_p = &target->watchpoints;
415 if (watchpoint->address == address) {
416 if (watchpoint->length != length
417 || watchpoint->value != value
418 || watchpoint->mask != mask
419 || watchpoint->rw != rw) {
420 LOG_ERROR("address " TARGET_ADDR_FMT
421 " already has watchpoint %d",
422 address, watchpoint->unique_id);
426 /* ignore duplicate watchpoint */
429 watchpoint_p = &watchpoint->next;
430 watchpoint = watchpoint->next;
433 (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
434 (*watchpoint_p)->address = address;
435 (*watchpoint_p)->length = length;
436 (*watchpoint_p)->value = value;
437 (*watchpoint_p)->mask = mask;
438 (*watchpoint_p)->rw = rw;
439 (*watchpoint_p)->unique_id = bpwp_unique_id++;
441 retval = target_add_watchpoint(target, *watchpoint_p);
445 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
446 reason = "resource not available";
448 case ERROR_TARGET_NOT_HALTED:
449 reason = "target running";
452 reason = "unrecognized error";
454 LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
455 watchpoint_rw_strings[(*watchpoint_p)->rw],
458 *watchpoint_p = NULL;
462 LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
463 " of length 0x%8.8" PRIx32 " (WPID: %d)",
465 watchpoint_rw_strings[(*watchpoint_p)->rw],
466 (*watchpoint_p)->address,
467 (*watchpoint_p)->length,
468 (*watchpoint_p)->unique_id);
473 int watchpoint_add(struct target *target, target_addr_t address,
474 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
477 struct target_list *head;
479 foreach_smp_target(head, target->smp_targets) {
480 struct target *curr = head->target;
481 int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
482 if (retval != ERROR_OK)
488 return watchpoint_add_internal(target, address, length, rw, value,
493 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
495 struct watchpoint *watchpoint = target->watchpoints;
496 struct watchpoint **watchpoint_p = &target->watchpoints;
500 if (watchpoint == watchpoint_to_remove)
502 watchpoint_p = &watchpoint->next;
503 watchpoint = watchpoint->next;
508 retval = target_remove_watchpoint(target, watchpoint);
509 LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
510 (*watchpoint_p) = watchpoint->next;
514 int watchpoint_remove_internal(struct target *target, target_addr_t address)
516 struct watchpoint *watchpoint = target->watchpoints;
519 if (watchpoint->address == address)
521 watchpoint = watchpoint->next;
525 watchpoint_free(target, watchpoint);
529 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
534 void watchpoint_remove(struct target *target, target_addr_t address)
537 unsigned int num_watchpoints = 0;
538 struct target_list *head;
540 foreach_smp_target(head, target->smp_targets) {
541 struct target *curr = head->target;
542 num_watchpoints += watchpoint_remove_internal(curr, address);
544 if (num_watchpoints == 0)
545 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
547 watchpoint_remove_internal(target, address);
551 void watchpoint_clear_target(struct target *target)
553 LOG_DEBUG("Delete all watchpoints for target: %s",
554 target_name(target));
555 while (target->watchpoints)
556 watchpoint_free(target, target->watchpoints);
559 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
560 target_addr_t *address)
563 struct watchpoint *hit_watchpoint;
565 retval = target_hit_watchpoint(target, &hit_watchpoint);
566 if (retval != ERROR_OK)
569 *rw = hit_watchpoint->rw;
570 *address = hit_watchpoint->address;
572 LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
573 hit_watchpoint->address,
574 hit_watchpoint->unique_id);