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 
20 static const char * const breakpoint_type_strings[] = {
21  "hardware",
22  "software"
23 };
24 
25 static const char * const watchpoint_rw_strings[] = {
26  "read",
27  "write",
28  "access"
29 };
30 
31 /* monotonic counter/id-number for breakpoints and watch points */
32 static int bpwp_unique_id;
33 
35  target_addr_t address,
36  uint32_t length,
37  enum breakpoint_type type)
38 {
40  struct breakpoint **breakpoint_p = &target->breakpoints;
41  const char *reason;
42  int retval;
43 
44  while (breakpoint) {
45  if (breakpoint->address == address) {
46  /* FIXME don't assume "same address" means "same
47  * breakpoint" ... check all the parameters before
48  * succeeding.
49  */
50  LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
53  }
54  breakpoint_p = &breakpoint->next;
56  }
57 
58  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
59  (*breakpoint_p)->address = address;
60  (*breakpoint_p)->asid = 0;
61  (*breakpoint_p)->length = length;
62  (*breakpoint_p)->type = type;
63  (*breakpoint_p)->is_set = false;
64  (*breakpoint_p)->orig_instr = malloc(length);
65  (*breakpoint_p)->next = NULL;
66  (*breakpoint_p)->unique_id = bpwp_unique_id++;
67 
68  retval = target_add_breakpoint(target, *breakpoint_p);
69  switch (retval) {
70  case ERROR_OK:
71  break;
73  reason = "resource not available";
74  goto fail;
76  reason = "target running";
77  goto fail;
78  default:
79  reason = "unknown reason";
80 fail:
81  LOG_ERROR("can't add breakpoint: %s", reason);
82  free((*breakpoint_p)->orig_instr);
83  free(*breakpoint_p);
84  *breakpoint_p = NULL;
85  return retval;
86  }
87 
88  LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
89  " of length 0x%8.8x, (BPID: %" PRIu32 ")",
90  target->coreid,
91  breakpoint_type_strings[(*breakpoint_p)->type],
92  (*breakpoint_p)->address, (*breakpoint_p)->length,
93  (*breakpoint_p)->unique_id);
94 
95  return ERROR_OK;
96 }
97 
99  uint32_t asid,
100  uint32_t length,
101  enum breakpoint_type type)
102 {
104  struct breakpoint **breakpoint_p = &target->breakpoints;
105  int retval;
106 
107  while (breakpoint) {
108  if (breakpoint->asid == asid) {
109  /* FIXME don't assume "same address" means "same
110  * breakpoint" ... check all the parameters before
111  * succeeding.
112  */
113  LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
116  }
117  breakpoint_p = &breakpoint->next;
119  }
120 
121  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
122  (*breakpoint_p)->address = 0;
123  (*breakpoint_p)->asid = asid;
124  (*breakpoint_p)->length = length;
125  (*breakpoint_p)->type = type;
126  (*breakpoint_p)->is_set = false;
127  (*breakpoint_p)->orig_instr = malloc(length);
128  (*breakpoint_p)->next = NULL;
129  (*breakpoint_p)->unique_id = bpwp_unique_id++;
130  retval = target_add_context_breakpoint(target, *breakpoint_p);
131  if (retval != ERROR_OK) {
132  LOG_ERROR("could not add breakpoint");
133  free((*breakpoint_p)->orig_instr);
134  free(*breakpoint_p);
135  *breakpoint_p = NULL;
136  return retval;
137  }
138 
139  LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
140  breakpoint_type_strings[(*breakpoint_p)->type],
141  (*breakpoint_p)->asid, (*breakpoint_p)->length,
142  (*breakpoint_p)->unique_id);
143 
144  return ERROR_OK;
145 }
146 
149  uint32_t asid,
150  uint32_t length,
151  enum breakpoint_type type)
152 {
154  struct breakpoint **breakpoint_p = &target->breakpoints;
155  int retval;
156 
157  while (breakpoint) {
158  if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
159  /* FIXME don't assume "same address" means "same
160  * breakpoint" ... check all the parameters before
161  * succeeding.
162  */
163  LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
166  } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
167  LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
170 
171  }
172  breakpoint_p = &breakpoint->next;
174  }
175  (*breakpoint_p) = malloc(sizeof(struct breakpoint));
176  (*breakpoint_p)->address = address;
177  (*breakpoint_p)->asid = asid;
178  (*breakpoint_p)->length = length;
179  (*breakpoint_p)->type = type;
180  (*breakpoint_p)->is_set = false;
181  (*breakpoint_p)->orig_instr = malloc(length);
182  (*breakpoint_p)->next = NULL;
183  (*breakpoint_p)->unique_id = bpwp_unique_id++;
184 
185 
186  retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
187  if (retval != ERROR_OK) {
188  LOG_ERROR("could not add breakpoint");
189  free((*breakpoint_p)->orig_instr);
190  free(*breakpoint_p);
191  *breakpoint_p = NULL;
192  return retval;
193  }
194  LOG_DEBUG(
195  "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
196  breakpoint_type_strings[(*breakpoint_p)->type],
197  (*breakpoint_p)->address,
198  (*breakpoint_p)->length,
199  (*breakpoint_p)->unique_id);
200 
201  return ERROR_OK;
202 }
203 
206  uint32_t length,
207  enum breakpoint_type type)
208 {
209  if (target->smp) {
210  struct target_list *head;
211 
212  if (type == BKPT_SOFT) {
214  return breakpoint_add_internal(head->target, address, length, type);
215  }
216 
218  struct target *curr = head->target;
219  int retval = breakpoint_add_internal(curr, address, length, type);
220  if (retval != ERROR_OK)
221  return retval;
222  }
223 
224  return ERROR_OK;
225  } else {
226  return breakpoint_add_internal(target, address, length, type);
227  }
228 }
229 
231  uint32_t asid,
232  uint32_t length,
233  enum breakpoint_type type)
234 {
235  if (target->smp) {
236  struct target_list *head;
237 
239  struct target *curr = head->target;
240  int retval = context_breakpoint_add_internal(curr, asid, length, type);
241  if (retval != ERROR_OK)
242  return retval;
243  }
244 
245  return ERROR_OK;
246  } else {
248  }
249 }
250 
252  target_addr_t address,
253  uint32_t asid,
254  uint32_t length,
255  enum breakpoint_type type)
256 {
257  if (target->smp) {
258  struct target_list *head;
259 
261  struct target *curr = head->target;
262  int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
263  if (retval != ERROR_OK)
264  return retval;
265  }
266 
267  return ERROR_OK;
268  } else
269  return hybrid_breakpoint_add_internal(target, address, asid, length, type);
270 }
271 
272 /* free up a breakpoint */
273 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
274 {
276  struct breakpoint **breakpoint_p = &target->breakpoints;
277  int retval;
278 
279  while (breakpoint) {
280  if (breakpoint == breakpoint_to_remove)
281  break;
282  breakpoint_p = &breakpoint->next;
284  }
285 
286  if (!breakpoint)
287  return;
288 
290 
291  LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
292  (*breakpoint_p) = breakpoint->next;
293  free(breakpoint->orig_instr);
294  free(breakpoint);
295 }
296 
298 {
300 
301  while (breakpoint) {
302  if ((breakpoint->address == address) ||
303  (breakpoint->address == 0 && breakpoint->asid == address))
304  break;
306  }
307 
308  if (breakpoint) {
310  return 1;
311  } else {
312  if (!target->smp)
313  LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
314  return 0;
315  }
316 }
317 
319 {
321 
322  while (breakpoint) {
323  struct breakpoint *tmp = breakpoint;
325  breakpoint_free(target, tmp);
326  }
327 }
328 
330 {
331  if (target->smp) {
332  unsigned int num_breakpoints = 0;
333  struct target_list *head;
334 
336  struct target *curr = head->target;
337  num_breakpoints += breakpoint_remove_internal(curr, address);
338  }
339  if (!num_breakpoints)
340  LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
341  } else {
343  }
344 }
345 
347 {
348  if (target->smp) {
349  struct target_list *head;
350 
352  struct target *curr = head->target;
354  }
355  } else {
357  }
358 }
359 
361 {
362  LOG_DEBUG("Delete all breakpoints for target: %s",
364  while (target->breakpoints)
366 }
367 
369 {
370  if (target->smp) {
371  struct target_list *head;
372 
374  struct target *curr = head->target;
376  }
377  } else {
379  }
380 }
381 
383 {
385 
386  while (breakpoint) {
387  if (breakpoint->address == address)
388  return breakpoint;
390  }
391 
392  return NULL;
393 }
394 
396  uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
397 {
399  struct watchpoint **watchpoint_p = &target->watchpoints;
400  int retval;
401  const char *reason;
402 
403  while (watchpoint) {
404  if (watchpoint->address == address) {
405  if (watchpoint->length != length
406  || watchpoint->value != value
407  || watchpoint->mask != mask
408  || watchpoint->rw != rw) {
409  LOG_ERROR("address " TARGET_ADDR_FMT
410  " already has watchpoint %d",
412  return ERROR_FAIL;
413  }
414 
415  /* ignore duplicate watchpoint */
416  return ERROR_OK;
417  }
418  watchpoint_p = &watchpoint->next;
420  }
421 
422  (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
423  (*watchpoint_p)->address = address;
424  (*watchpoint_p)->length = length;
425  (*watchpoint_p)->value = value;
426  (*watchpoint_p)->mask = mask;
427  (*watchpoint_p)->rw = rw;
428  (*watchpoint_p)->unique_id = bpwp_unique_id++;
429 
430  retval = target_add_watchpoint(target, *watchpoint_p);
431  switch (retval) {
432  case ERROR_OK:
433  break;
435  reason = "resource not available";
436  goto bye;
438  reason = "target running";
439  goto bye;
440  default:
441  reason = "unrecognized error";
442 bye:
443  LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
444  watchpoint_rw_strings[(*watchpoint_p)->rw],
445  address, reason);
446  free(*watchpoint_p);
447  *watchpoint_p = NULL;
448  return retval;
449  }
450 
451  LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
452  " of length 0x%8.8" PRIx32 " (WPID: %d)",
453  target->coreid,
454  watchpoint_rw_strings[(*watchpoint_p)->rw],
455  (*watchpoint_p)->address,
456  (*watchpoint_p)->length,
457  (*watchpoint_p)->unique_id);
458 
459  return ERROR_OK;
460 }
461 
463  uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
464 {
465  if (target->smp) {
466  struct target_list *head;
467 
469  struct target *curr = head->target;
470  int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
471  if (retval != ERROR_OK)
472  return retval;
473  }
474 
475  return ERROR_OK;
476  } else {
477  return watchpoint_add_internal(target, address, length, rw, value,
478  mask);
479  }
480 }
481 
482 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
483 {
485  struct watchpoint **watchpoint_p = &target->watchpoints;
486  int retval;
487 
488  while (watchpoint) {
489  if (watchpoint == watchpoint_to_remove)
490  break;
491  watchpoint_p = &watchpoint->next;
493  }
494 
495  if (!watchpoint)
496  return;
498  LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
499  (*watchpoint_p) = watchpoint->next;
500  free(watchpoint);
501 }
502 
504 {
506 
507  while (watchpoint) {
508  if (watchpoint->address == address)
509  break;
511  }
512 
513  if (watchpoint) {
515  return 1;
516  } else {
517  if (!target->smp)
518  LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
519  return 0;
520  }
521 }
522 
524 {
525  if (target->smp) {
526  unsigned int num_watchpoints = 0;
527  struct target_list *head;
528 
530  struct target *curr = head->target;
531  num_watchpoints += watchpoint_remove_internal(curr, address);
532  }
533  if (num_watchpoints == 0)
534  LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
535  } else {
537  }
538 }
539 
541 {
542  LOG_DEBUG("Delete all watchpoints for target: %s",
544  while (target->watchpoints)
546 }
547 
549  target_addr_t *address)
550 {
551  int retval;
552  struct watchpoint *hit_watchpoint;
553 
554  retval = target_hit_watchpoint(target, &hit_watchpoint);
555  if (retval != ERROR_OK)
556  return ERROR_FAIL;
557 
558  *rw = hit_watchpoint->rw;
559  *address = hit_watchpoint->address;
560 
561  LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
562  hit_watchpoint->address,
563  hit_watchpoint->unique_id);
564 
565  return ERROR_OK;
566 }
static const char *const watchpoint_rw_strings[]
Definition: breakpoints.c:25
void watchpoint_clear_target(struct target *target)
Definition: breakpoints.c:540
void breakpoint_remove_all(struct target *target)
Definition: breakpoints.c:346
void breakpoint_clear_target(struct target *target)
Definition: breakpoints.c:368
static void breakpoint_clear_target_internal(struct target *target)
Definition: breakpoints.c:360
int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address)
Definition: breakpoints.c:548
static int hybrid_breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:147
static int breakpoint_remove_internal(struct target *target, target_addr_t address)
Definition: breakpoints.c:297
static int context_breakpoint_add_internal(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:98
int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:251
static int bpwp_unique_id
Definition: breakpoints.c:32
static const char *const breakpoint_type_strings[]
Definition: breakpoints.c:20
static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
Definition: breakpoints.c:482
static int watchpoint_remove_internal(struct target *target, target_addr_t address)
Definition: breakpoints.c:503
static int watchpoint_add_internal(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
Definition: breakpoints.c:395
int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:230
void watchpoint_remove(struct target *target, target_addr_t address)
Definition: breakpoints.c:523
void breakpoint_remove(struct target *target, target_addr_t address)
Definition: breakpoints.c:329
int breakpoint_add(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:204
static int breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type)
Definition: breakpoints.c:34
int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
Definition: breakpoints.c:462
static void breakpoint_remove_all_internal(struct target *target)
Definition: breakpoints.c:318
struct breakpoint * breakpoint_find(struct target *target, target_addr_t address)
Definition: breakpoints.c:382
static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
Definition: breakpoints.c:273
breakpoint_type
Definition: breakpoints.h:17
@ BKPT_SOFT
Definition: breakpoints.h:19
watchpoint_rw
Definition: breakpoints.h:22
int mask
Definition: esirisc.c:1698
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)
list_first_entry - get the first element from a list
Definition: list.h:537
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:155
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__((unused))
Definition: opcodes.h:117
#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
uint32_t asid
Definition: breakpoints.h:28
target_addr_t address
Definition: breakpoints.h:27
struct target * target
Definition: target.h:215
Definition: target.h:120
int32_t coreid
Definition: target.h:125
int smp
Definition: target.h:192
struct list_head * smp_targets
Definition: target.h:193
struct breakpoint * breakpoints
Definition: target.h:164
struct watchpoint * watchpoints
Definition: target.h:165
enum watchpoint_rw rw
Definition: breakpoints.h:44
uint32_t mask
Definition: breakpoints.h:42
struct watchpoint * next
Definition: breakpoints.h:47
int unique_id
Definition: breakpoints.h:48
uint32_t value
Definition: breakpoints.h:43
uint32_t length
Definition: breakpoints.h:41
target_addr_t address
Definition: breakpoints.h:40
int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
Add the watchpoint for target.
Definition: target.c:1398
int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
Remove the breakpoint for target.
Definition: target.c:1392
int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the ContextID & IVA breakpoint for target.
Definition: target.c:1382
int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the breakpoint for target.
Definition: target.c:1362
int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
Find out the just hit watchpoint for target.
Definition: target.c:1412
int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
Remove the watchpoint for target.
Definition: target.c:1407
int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint)
Add the ContextID breakpoint for target.
Definition: target.c:1372
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:792
#define ERROR_TARGET_DUPLICATE_BREAKPOINT
Definition: target.h:800
static const char * target_name(struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:234
#define ERROR_TARGET_RESOURCE_NOT_AVAILABLE
Definition: target.h:796
#define TARGET_ADDR_FMT
Definition: types.h:342
uint64_t target_addr_t
Definition: types.h:335
#define NULL
Definition: usb.h:16