]> git.sur5r.net Git - openocd/blob - src/target/breakpoints.c
flash/nrf5: support for nRF52840 Q1AAC0
[openocd] / 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 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_DEBUG("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
64                                 address, breakpoint->unique_id);
65                         return ERROR_OK;
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 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_DEBUG("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
128                                 asid, breakpoint->unique_id);
129                         return -1;
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 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_DEBUG("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
180                                 asid, breakpoint->unique_id);
181                         return -1;
182                 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
183                         LOG_DEBUG("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
184                                 address, breakpoint->unique_id);
185                         return -1;
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 int context_breakpoint_add(struct target *target,
245         uint32_t asid,
246         uint32_t length,
247         enum breakpoint_type type)
248 {
249         int retval = ERROR_OK;
250         if (target->smp) {
251                 struct target_list *head;
252                 struct target *curr;
253                 head = target->head;
254                 while (head != (struct target_list *)NULL) {
255                         curr = head->target;
256                         retval = context_breakpoint_add_internal(curr, asid, length, type);
257                         if (retval != ERROR_OK)
258                                 return retval;
259                         head = head->next;
260                 }
261                 return retval;
262         } else
263                 return context_breakpoint_add_internal(target, asid, length, type);
264 }
265 int hybrid_breakpoint_add(struct target *target,
266         target_addr_t address,
267         uint32_t asid,
268         uint32_t length,
269         enum breakpoint_type type)
270 {
271         int retval = ERROR_OK;
272         if (target->smp) {
273                 struct target_list *head;
274                 struct target *curr;
275                 head = target->head;
276                 while (head != (struct target_list *)NULL) {
277                         curr = head->target;
278                         retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
279                         if (retval != ERROR_OK)
280                                 return retval;
281                         head = head->next;
282                 }
283                 return retval;
284         } else
285                 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
286 }
287
288 /* free up a breakpoint */
289 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
290 {
291         struct breakpoint *breakpoint = target->breakpoints;
292         struct breakpoint **breakpoint_p = &target->breakpoints;
293         int retval;
294
295         while (breakpoint) {
296                 if (breakpoint == breakpoint_to_remove)
297                         break;
298                 breakpoint_p = &breakpoint->next;
299                 breakpoint = breakpoint->next;
300         }
301
302         if (breakpoint == NULL)
303                 return;
304
305         retval = target_remove_breakpoint(target, breakpoint);
306
307         LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
308         (*breakpoint_p) = breakpoint->next;
309         free(breakpoint->orig_instr);
310         free(breakpoint);
311 }
312
313 int breakpoint_remove_internal(struct target *target, target_addr_t address)
314 {
315         struct breakpoint *breakpoint = target->breakpoints;
316
317         while (breakpoint) {
318                 if ((breakpoint->address == address) ||
319                     (breakpoint->address == 0 && breakpoint->asid == address))
320                         break;
321                 breakpoint = breakpoint->next;
322         }
323
324         if (breakpoint) {
325                 breakpoint_free(target, breakpoint);
326                 return 1;
327         } else {
328                 if (!target->smp)
329                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
330                 return 0;
331         }
332 }
333 void breakpoint_remove(struct target *target, target_addr_t address)
334 {
335         int found = 0;
336         if (target->smp) {
337                 struct target_list *head;
338                 struct target *curr;
339                 head = target->head;
340                 while (head != (struct target_list *)NULL) {
341                         curr = head->target;
342                         found += breakpoint_remove_internal(curr, address);
343                         head = head->next;
344                 }
345                 if (found == 0)
346                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
347         } else
348                 breakpoint_remove_internal(target, address);
349 }
350
351 void breakpoint_clear_target_internal(struct target *target)
352 {
353         LOG_DEBUG("Delete all breakpoints for target: %s",
354                 target_name(target));
355         while (target->breakpoints != NULL)
356                 breakpoint_free(target, target->breakpoints);
357 }
358
359 void breakpoint_clear_target(struct target *target)
360 {
361         if (target->smp) {
362                 struct target_list *head;
363                 struct target *curr;
364                 head = target->head;
365                 while (head != (struct target_list *)NULL) {
366                         curr = head->target;
367                         breakpoint_clear_target_internal(curr);
368                         head = head->next;
369                 }
370         } else
371                 breakpoint_clear_target_internal(target);
372
373 }
374
375 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
376 {
377         struct breakpoint *breakpoint = target->breakpoints;
378
379         while (breakpoint) {
380                 if (breakpoint->address == address)
381                         return breakpoint;
382                 breakpoint = breakpoint->next;
383         }
384
385         return NULL;
386 }
387
388 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
389         enum watchpoint_rw rw, uint32_t value, uint32_t mask)
390 {
391         struct watchpoint *watchpoint = target->watchpoints;
392         struct watchpoint **watchpoint_p = &target->watchpoints;
393         int retval;
394         const char *reason;
395
396         while (watchpoint) {
397                 if (watchpoint->address == address) {
398                         if (watchpoint->length != length
399                                 || watchpoint->value != value
400                                 || watchpoint->mask != mask
401                                 || watchpoint->rw != rw) {
402                                 LOG_ERROR("address " TARGET_ADDR_FMT
403                                         " already has watchpoint %d",
404                                         address, watchpoint->unique_id);
405                                 return ERROR_FAIL;
406                         }
407
408                         /* ignore duplicate watchpoint */
409                         return ERROR_OK;
410                 }
411                 watchpoint_p = &watchpoint->next;
412                 watchpoint = watchpoint->next;
413         }
414
415         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
416         (*watchpoint_p)->address = address;
417         (*watchpoint_p)->length = length;
418         (*watchpoint_p)->value = value;
419         (*watchpoint_p)->mask = mask;
420         (*watchpoint_p)->rw = rw;
421         (*watchpoint_p)->unique_id = bpwp_unique_id++;
422
423         retval = target_add_watchpoint(target, *watchpoint_p);
424         switch (retval) {
425                 case ERROR_OK:
426                         break;
427                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
428                         reason = "resource not available";
429                         goto bye;
430                 case ERROR_TARGET_NOT_HALTED:
431                         reason = "target running";
432                         goto bye;
433                 default:
434                         reason = "unrecognized error";
435 bye:
436                         LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
437                                 watchpoint_rw_strings[(*watchpoint_p)->rw],
438                                 address, reason);
439                         free(*watchpoint_p);
440                         *watchpoint_p = NULL;
441                         return retval;
442         }
443
444         LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
445                 " of length 0x%8.8" PRIx32 " (WPID: %d)",
446                 watchpoint_rw_strings[(*watchpoint_p)->rw],
447                 (*watchpoint_p)->address,
448                 (*watchpoint_p)->length,
449                 (*watchpoint_p)->unique_id);
450
451         return ERROR_OK;
452 }
453
454 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
455 {
456         struct watchpoint *watchpoint = target->watchpoints;
457         struct watchpoint **watchpoint_p = &target->watchpoints;
458         int retval;
459
460         while (watchpoint) {
461                 if (watchpoint == watchpoint_to_remove)
462                         break;
463                 watchpoint_p = &watchpoint->next;
464                 watchpoint = watchpoint->next;
465         }
466
467         if (watchpoint == NULL)
468                 return;
469         retval = target_remove_watchpoint(target, watchpoint);
470         LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
471         (*watchpoint_p) = watchpoint->next;
472         free(watchpoint);
473 }
474
475 void watchpoint_remove(struct target *target, target_addr_t address)
476 {
477         struct watchpoint *watchpoint = target->watchpoints;
478
479         while (watchpoint) {
480                 if (watchpoint->address == address)
481                         break;
482                 watchpoint = watchpoint->next;
483         }
484
485         if (watchpoint)
486                 watchpoint_free(target, watchpoint);
487         else
488                 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
489 }
490
491 void watchpoint_clear_target(struct target *target)
492 {
493         LOG_DEBUG("Delete all watchpoints for target: %s",
494                 target_name(target));
495         while (target->watchpoints != NULL)
496                 watchpoint_free(target, target->watchpoints);
497 }
498
499 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
500                    target_addr_t *address)
501 {
502         int retval;
503         struct watchpoint *hit_watchpoint;
504
505         retval = target_hit_watchpoint(target, &hit_watchpoint);
506         if (retval != ERROR_OK)
507                 return ERROR_FAIL;
508
509         *rw = hit_watchpoint->rw;
510         *address = hit_watchpoint->address;
511
512         LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
513                 hit_watchpoint->address,
514                 hit_watchpoint->unique_id);
515
516         return ERROR_OK;
517 }