OpenOCD
breakpoints.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2005 by Dominic Rath *
5  * Dominic.Rath@gmx.de *
6  * *
7  * Copyright (C) ST-Ericsson SA 2011 *
8  * michel.jaouen@stericsson.com : smp minimum support *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include "target.h"
16 #include <helper/log.h>
17 #include "breakpoints.h"
18 #include "smp.h"
19 
23 };
24 
25 static const char * const breakpoint_type_strings[] = {
26  "hardware",
27  "software"
28 };
29 
30 static const char * const watchpoint_rw_strings[] = {
31  "read",
32  "write",
33  "access"
34 };
35 
36 /* monotonic counter/id-number for breakpoints and watch points */
37 static int bpwp_unique_id;
38 
41  unsigned int length,
42  enum breakpoint_type type)
43 {
45  struct breakpoint **breakpoint_p = &target->breakpoints;
46  const char *reason;
47  int retval;
48 
49  while (breakpoint) {
50  if (breakpoint->address == address) {
51  /* FIXME don't assume "same address" means "same
52  * breakpoint" ... check all the parameters before
53  * succeeding.
54  */
55  LOG_TARGET_ERROR(target, "Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
58  }
59  breakpoint_p = &breakpoint->next;
61  }
62 
63  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
64  (*breakpoint_p)->address = address;
65  (*breakpoint_p)->asid = 0;
66  (*breakpoint_p)->length = length;
67  (*breakpoint_p)->type = type;
68  (*breakpoint_p)->is_set = false;
69  (*breakpoint_p)->orig_instr = malloc(length);
70  (*breakpoint_p)->next = NULL;
71  (*breakpoint_p)->unique_id = bpwp_unique_id++;
72 
73  retval = target_add_breakpoint(target, *breakpoint_p);
74  switch (retval) {
75  case ERROR_OK:
76  break;
78  reason = "resource not available";
79  goto fail;
81  reason = "target running";
82  goto fail;
83  default:
84  reason = "unknown reason";
85 fail:
86  LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason);
87  free((*breakpoint_p)->orig_instr);
88  free(*breakpoint_p);
89  *breakpoint_p = NULL;
90  return retval;
91  }
92 
93  LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT
94  " of length 0x%8.8x, (BPID: %" PRIu32 ")",
95  breakpoint_type_strings[(*breakpoint_p)->type],
96  (*breakpoint_p)->address, (*breakpoint_p)->length,
97  (*breakpoint_p)->unique_id);
98 
99  return ERROR_OK;
100 }
101 
103  uint32_t asid,
104  unsigned int length,
105  enum breakpoint_type type)
106 {
108  struct breakpoint **breakpoint_p = &target->breakpoints;
109  int retval;
110 
111  while (breakpoint) {
112  if (breakpoint->asid == asid) {
113  /* FIXME don't assume "same address" means "same
114  * breakpoint" ... check all the parameters before
115  * succeeding.
116  */
117  LOG_TARGET_ERROR(target, "Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
120  }
121  breakpoint_p = &breakpoint->next;
123  }
124 
125  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
126  (*breakpoint_p)->address = 0;
127  (*breakpoint_p)->asid = asid;
128  (*breakpoint_p)->length = length;
129  (*breakpoint_p)->type = type;
130  (*breakpoint_p)->is_set = false;
131  (*breakpoint_p)->orig_instr = malloc(length);
132  (*breakpoint_p)->next = NULL;
133  (*breakpoint_p)->unique_id = bpwp_unique_id++;
134  retval = target_add_context_breakpoint(target, *breakpoint_p);
135  if (retval != ERROR_OK) {
136  LOG_TARGET_ERROR(target, "could not add breakpoint");
137  free((*breakpoint_p)->orig_instr);
138  free(*breakpoint_p);
139  *breakpoint_p = NULL;
140  return retval;
141  }
142 
143  LOG_TARGET_DEBUG(target, "added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
144  breakpoint_type_strings[(*breakpoint_p)->type],
145  (*breakpoint_p)->asid, (*breakpoint_p)->length,
146  (*breakpoint_p)->unique_id);
147 
148  return ERROR_OK;
149 }
150 
153  uint32_t asid,
154  unsigned int length,
155  enum breakpoint_type type)
156 {
158  struct breakpoint **breakpoint_p = &target->breakpoints;
159  int retval;
160 
161  while (breakpoint) {
162  if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
163  /* FIXME don't assume "same address" means "same
164  * breakpoint" ... check all the parameters before
165  * succeeding.
166  */
167  LOG_TARGET_ERROR(target, "Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
170  } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
171  LOG_TARGET_ERROR(target, "Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
174 
175  }
176  breakpoint_p = &breakpoint->next;
178  }
179  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
180  (*breakpoint_p)->address = address;
181  (*breakpoint_p)->asid = asid;
182  (*breakpoint_p)->length = length;
183  (*breakpoint_p)->type = type;
184  (*breakpoint_p)->is_set = false;
185  (*breakpoint_p)->orig_instr = malloc(length);
186  (*breakpoint_p)->next = NULL;
187  (*breakpoint_p)->unique_id = bpwp_unique_id++;
188 
189 
190  retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
191  if (retval != ERROR_OK) {
192  LOG_TARGET_ERROR(target, "could not add breakpoint");
193  free((*breakpoint_p)->orig_instr);
194  free(*breakpoint_p);
195  *breakpoint_p = NULL;
196  return retval;
197  }
199  "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
200  breakpoint_type_strings[(*breakpoint_p)->type],
201  (*breakpoint_p)->address,
202  (*breakpoint_p)->length,
203  (*breakpoint_p)->unique_id);
204 
205  return ERROR_OK;
206 }
207 
210  unsigned int length,
211  enum breakpoint_type type)
212 {
213  if (target->smp) {
214  struct target_list *head;
215 
216  if (type == BKPT_SOFT) {
219  }
220 
222  struct target *curr = head->target;
223  int retval = breakpoint_add_internal(curr, address, length, type);
224  if (retval != ERROR_OK)
225  return retval;
226  }
227 
228  return ERROR_OK;
229  } else {
231  }
232 }
233 
235  uint32_t asid,
236  unsigned int length,
237  enum breakpoint_type type)
238 {
239  if (target->smp) {
240  struct target_list *head;
241 
243  struct target *curr = head->target;
244  int retval = context_breakpoint_add_internal(curr, asid, length, type);
245  if (retval != ERROR_OK)
246  return retval;
247  }
248 
249  return ERROR_OK;
250  } else {
252  }
253 }
254 
257  uint32_t asid,
258  unsigned int length,
259  enum breakpoint_type type)
260 {
261  if (target->smp) {
262  struct target_list *head;
263 
265  struct target *curr = head->target;
266  int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
267  if (retval != ERROR_OK)
268  return retval;
269  }
270 
271  return ERROR_OK;
272  } else
274 }
275 
276 /* free up a breakpoint */
277 static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
278 {
280  struct breakpoint **breakpoint_p = &target->breakpoints;
281  int retval;
282 
283  while (breakpoint) {
284  if (breakpoint == breakpoint_to_remove)
285  break;
286  breakpoint_p = &breakpoint->next;
288  }
289 
290  if (!breakpoint)
291  return ERROR_OK;
292 
294  if (retval != ERROR_OK) {
295  LOG_TARGET_ERROR(target, "could not remove breakpoint #%d on this target",
296  breakpoint->number);
297  return retval;
298  }
299 
300  LOG_TARGET_DEBUG(target, "free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
301  (*breakpoint_p) = breakpoint->next;
302  free(breakpoint->orig_instr);
303  free(breakpoint);
304 
305  return ERROR_OK;
306 }
307 
309 {
311 
312  while (breakpoint) {
313  if ((breakpoint->address == address) ||
314  (breakpoint->address == 0 && breakpoint->asid == address))
315  break;
317  }
318 
319  if (breakpoint) {
321  } else {
323  }
324 }
325 
327 {
328  LOG_TARGET_DEBUG(target, "Delete all breakpoints");
329 
331  int retval = ERROR_OK;
332 
333  while (breakpoint) {
334  struct breakpoint *tmp = breakpoint;
336  int status = breakpoint_free(target, tmp);
337  if (status != ERROR_OK)
338  retval = status;
339  }
340 
341  return retval;
342 }
343 
345 {
346  int retval = ERROR_OK;
347  unsigned int num_found_breakpoints = 0;
348  if (target->smp) {
349  struct target_list *head;
350 
352  struct target *curr = head->target;
354 
356  num_found_breakpoints++;
357 
358  if (status != ERROR_OK) {
359  LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
360  retval = status;
361  }
362  }
363  }
364 
365  } else {
367 
368  if (retval != ERROR_BREAKPOINT_NOT_FOUND) {
369  num_found_breakpoints++;
370 
371  if (retval != ERROR_OK)
372  LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address);
373  }
374  }
375 
376  if (num_found_breakpoints == 0) {
377  LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address);
379  }
380 
381  return retval;
382 }
383 
384 static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
385 {
387  struct watchpoint **watchpoint_p = &target->watchpoints;
388  int retval;
389 
390  while (watchpoint) {
391  if (watchpoint == watchpoint_to_remove)
392  break;
393  watchpoint_p = &watchpoint->next;
395  }
396 
397  if (!watchpoint)
398  return ERROR_OK;
400  if (retval != ERROR_OK) {
401  LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target",
402  watchpoint->number);
403  return retval;
404  }
405 
406  LOG_TARGET_DEBUG(target, "free WPID: %d --> %d", watchpoint->unique_id, retval);
407  (*watchpoint_p) = watchpoint->next;
408  free(watchpoint);
409 
410  return ERROR_OK;
411 }
412 
414 {
415  LOG_TARGET_DEBUG(target, "Delete all watchpoints");
416 
418  int retval = ERROR_OK;
419 
420  while (watchpoint) {
421  struct watchpoint *tmp = watchpoint;
423  int status = watchpoint_free(target, tmp);
424  if (status != ERROR_OK)
425  retval = status;
426  }
427 
428  return retval;
429 }
430 
432 {
433  assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT);
434  int retval = ERROR_OK;
435  if (target->smp) {
436  struct target_list *head;
437 
439  struct target *curr = head->target;
440 
441  int status = ERROR_OK;
442  if (bp_wp == BREAKPOINT)
444  else
446 
447  if (status != ERROR_OK)
448  retval = status;
449  }
450  } else {
451  if (bp_wp == BREAKPOINT)
453  else
455  }
456 
457  return retval;
458 }
459 
461 {
463 }
464 
466 {
468 }
469 
471 {
473 
474  while (breakpoint) {
475  if (breakpoint->address == address)
476  return breakpoint;
478  }
479 
480  return NULL;
481 }
482 
484  unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
485 {
487  struct watchpoint **watchpoint_p = &target->watchpoints;
488  int retval;
489  const char *reason;
490 
491  while (watchpoint) {
492  if (watchpoint->address == address) {
493  if (watchpoint->length != length
494  || watchpoint->value != value
495  || watchpoint->mask != mask
496  || watchpoint->rw != rw) {
498  " already has watchpoint %d",
500  return ERROR_FAIL;
501  }
502 
503  /* ignore duplicate watchpoint */
504  return ERROR_OK;
505  }
506  watchpoint_p = &watchpoint->next;
508  }
509 
510  (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
511  (*watchpoint_p)->address = address;
512  (*watchpoint_p)->length = length;
513  (*watchpoint_p)->value = value;
514  (*watchpoint_p)->mask = mask;
515  (*watchpoint_p)->rw = rw;
516  (*watchpoint_p)->unique_id = bpwp_unique_id++;
517 
518  retval = target_add_watchpoint(target, *watchpoint_p);
519  switch (retval) {
520  case ERROR_OK:
521  break;
523  reason = "resource not available";
524  goto bye;
526  reason = "target running";
527  goto bye;
528  default:
529  reason = "unrecognized error";
530 bye:
531  LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
532  watchpoint_rw_strings[(*watchpoint_p)->rw],
533  address, reason);
534  free(*watchpoint_p);
535  *watchpoint_p = NULL;
536  return retval;
537  }
538 
539  LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT
540  " of length 0x%8.8x (WPID: %d)",
541  watchpoint_rw_strings[(*watchpoint_p)->rw],
542  (*watchpoint_p)->address,
543  (*watchpoint_p)->length,
544  (*watchpoint_p)->unique_id);
545 
546  return ERROR_OK;
547 }
548 
550  unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
551 {
552  if (target->smp) {
553  struct target_list *head;
554 
556  struct target *curr = head->target;
557  int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
558  if (retval != ERROR_OK)
559  return retval;
560  }
561 
562  return ERROR_OK;
563  } else {
564  return watchpoint_add_internal(target, address, length, rw, value,
565  mask);
566  }
567 }
568 
570 {
572 
573  while (watchpoint) {
574  if (watchpoint->address == address)
575  break;
577  }
578 
579  if (watchpoint) {
581  } else {
583  }
584 }
585 
587 {
588  int retval = ERROR_OK;
589  unsigned int num_found_watchpoints = 0;
590  if (target->smp) {
591  struct target_list *head;
592 
594  struct target *curr = head->target;
596 
598  num_found_watchpoints++;
599 
600  if (status != ERROR_OK) {
601  LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
602  retval = status;
603  }
604  }
605  }
606  } else {
608 
609  if (retval != ERROR_WATCHPOINT_NOT_FOUND) {
610  num_found_watchpoints++;
611 
612  if (retval != ERROR_OK)
613  LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address);
614  }
615  }
616 
617  if (num_found_watchpoints == 0) {
618  LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address);
620  }
621 
622  return retval;
623 }
624 
627 {
628  int retval;
629  struct watchpoint *hit_watchpoint;
630 
631  retval = target_hit_watchpoint(target, &hit_watchpoint);
632  if (retval != ERROR_OK)
633  return ERROR_FAIL;
634 
635  *rw = hit_watchpoint->rw;
636  *address = hit_watchpoint->address;
637 
638  LOG_TARGET_DEBUG(target, "Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
639  hit_watchpoint->address,
640  hit_watchpoint->unique_id);
641 
642  return ERROR_OK;
643 }
static const char *const watchpoint_rw_strings[]
Definition: breakpoints.c:30
int watchpoint_add(struct target *target, target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
Definition: breakpoints.c:549
static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp)
Definition: breakpoints.c:431
static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
Definition: breakpoints.c:384
static int breakpoint_add_internal(struct target *target, target_addr_t address, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:39
int breakpoint_remove(struct target *target, target_addr_t address)
Definition: breakpoints.c:344
static int watchpoint_add_internal(struct target *target, target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
Definition: breakpoints.c:483
int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address)
Definition: breakpoints.c:625
static int breakpoint_remove_internal(struct target *target, target_addr_t address)
Definition: breakpoints.c:308
static int context_breakpoint_add_internal(struct target *target, uint32_t asid, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:102
int watchpoint_remove(struct target *target, target_addr_t address)
Definition: breakpoints.c:586
int breakpoint_add(struct target *target, target_addr_t address, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:208
static int bpwp_unique_id
Definition: breakpoints.c:37
breakpoint_watchpoint
Definition: breakpoints.c:20
@ WATCHPOINT
Definition: breakpoints.c:22
@ BREAKPOINT
Definition: breakpoints.c:21
static const char *const breakpoint_type_strings[]
Definition: breakpoints.c:25
int context_breakpoint_add(struct target *target, uint32_t asid, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:234
static int watchpoint_remove_internal(struct target *target, target_addr_t address)
Definition: breakpoints.c:569
static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
Definition: breakpoints.c:277
int watchpoint_remove_all(struct target *target)
Definition: breakpoints.c:465
int breakpoint_remove_all(struct target *target)
Definition: breakpoints.c:460
static int hybrid_breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t asid, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:151
static int breakpoint_remove_all_internal(struct target *target)
Definition: breakpoints.c:326
int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, unsigned int length, enum breakpoint_type type)
Definition: breakpoints.c:255
static int watchpoint_remove_all_internal(struct target *target)
Definition: breakpoints.c:413
struct breakpoint * breakpoint_find(struct target *target, target_addr_t address)
Definition: breakpoints.c:470
breakpoint_type
Definition: breakpoints.h:17
@ BKPT_SOFT
Definition: breakpoints.h:19
#define ERROR_WATCHPOINT_NOT_FOUND
Definition: breakpoints.h:88
#define ERROR_BREAKPOINT_NOT_FOUND
Definition: breakpoints.h:87
watchpoint_rw
Definition: breakpoints.h:22
uint32_t address
Starting address. Sector aligned.
Definition: dw-spi-helper.h:0
uint8_t type
Definition: esp_usb_jtag.c:0
uint8_t length
Definition: esp_usb_jtag.c:1
#define list_first_entry(ptr, type, member)
Definition: list.h:131
#define ERROR_FAIL
Definition: log.h:174
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:162
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:150
#define ERROR_OK
Definition: log.h:168
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__((unused))
Definition: opcodes.h:117
uint8_t mask
Definition: parport.c:70
#define foreach_smp_target(pos, head)
Definition: smp.h:15
struct breakpoint * next
Definition: breakpoints.h:34
uint8_t * orig_instr
Definition: breakpoints.h:33
uint32_t unique_id
Definition: breakpoints.h:35
unsigned int number
Definition: breakpoints.h:32
uint32_t asid
Definition: breakpoints.h:28
target_addr_t address
Definition: breakpoints.h:27
struct target * target
Definition: target.h:217
Definition: target.h:119
struct list_head * smp_targets
Definition: target.h:191
struct breakpoint * breakpoints
Definition: target.h:162
unsigned int smp
Definition: target.h:190
struct watchpoint * watchpoints
Definition: target.h:163
uint64_t mask
Definition: breakpoints.h:44
enum watchpoint_rw rw
Definition: breakpoints.h:46
struct watchpoint * next
Definition: breakpoints.h:49
unsigned int length
Definition: breakpoints.h:43
uint64_t value
Definition: breakpoints.h:45
int unique_id
Definition: breakpoints.h:50
unsigned int number
Definition: breakpoints.h:48
target_addr_t address
Definition: breakpoints.h:42
int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
Add the watchpoint for target.
Definition: target.c:1339
int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
Remove the breakpoint for target.
Definition: target.c:1333
int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the ContextID & IVA breakpoint for target.
Definition: target.c:1323
int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the breakpoint for target.
Definition: target.c:1303
int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
Find out the just hit watchpoint for target.
Definition: target.c:1353
int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
Remove the watchpoint for target.
Definition: target.c:1348
int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the ContextID breakpoint for target.
Definition: target.c:1313
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:786
#define ERROR_TARGET_DUPLICATE_BREAKPOINT
Definition: target.h:794
#define ERROR_TARGET_RESOURCE_NOT_AVAILABLE
Definition: target.h:790
#define TARGET_ADDR_FMT
Definition: types.h:286
uint64_t target_addr_t
Definition: types.h:279
#define NULL
Definition: usb.h:16
uint8_t status[4]
Definition: vdebug.c:17