]> git.sur5r.net Git - openocd/blob - src/target/breakpoints.c
target/cortex_m: avoid dwt comparator overflow
[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) && (breakpoint->asid == 0))
319                         break;
320                 else if ((breakpoint->address == 0) && (breakpoint->asid == address))
321                         break;
322                 else if ((breakpoint->address == address) && (breakpoint->asid != 0))
323                         break;
324                 breakpoint = breakpoint->next;
325         }
326
327         if (breakpoint) {
328                 breakpoint_free(target, breakpoint);
329                 return 1;
330         } else {
331                 if (!target->smp)
332                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
333                 return 0;
334         }
335 }
336 void breakpoint_remove(struct target *target, target_addr_t address)
337 {
338         int found = 0;
339         if (target->smp) {
340                 struct target_list *head;
341                 struct target *curr;
342                 head = target->head;
343                 while (head != (struct target_list *)NULL) {
344                         curr = head->target;
345                         found += breakpoint_remove_internal(curr, address);
346                         head = head->next;
347                 }
348                 if (found == 0)
349                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
350         } else
351                 breakpoint_remove_internal(target, address);
352 }
353
354 void breakpoint_clear_target_internal(struct target *target)
355 {
356         LOG_DEBUG("Delete all breakpoints for target: %s",
357                 target_name(target));
358         while (target->breakpoints != NULL)
359                 breakpoint_free(target, target->breakpoints);
360 }
361
362 void breakpoint_clear_target(struct target *target)
363 {
364         if (target->smp) {
365                 struct target_list *head;
366                 struct target *curr;
367                 head = target->head;
368                 while (head != (struct target_list *)NULL) {
369                         curr = head->target;
370                         breakpoint_clear_target_internal(curr);
371                         head = head->next;
372                 }
373         } else
374                 breakpoint_clear_target_internal(target);
375
376 }
377
378 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
379 {
380         struct breakpoint *breakpoint = target->breakpoints;
381
382         while (breakpoint) {
383                 if (breakpoint->address == address)
384                         return breakpoint;
385                 breakpoint = breakpoint->next;
386         }
387
388         return NULL;
389 }
390
391 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
392         enum watchpoint_rw rw, uint32_t value, uint32_t mask)
393 {
394         struct watchpoint *watchpoint = target->watchpoints;
395         struct watchpoint **watchpoint_p = &target->watchpoints;
396         int retval;
397         const char *reason;
398
399         while (watchpoint) {
400                 if (watchpoint->address == address) {
401                         if (watchpoint->length != length
402                                 || watchpoint->value != value
403                                 || watchpoint->mask != mask
404                                 || watchpoint->rw != rw) {
405                                 LOG_ERROR("address " TARGET_ADDR_FMT
406                                         " already has watchpoint %d",
407                                         address, watchpoint->unique_id);
408                                 return ERROR_FAIL;
409                         }
410
411                         /* ignore duplicate watchpoint */
412                         return ERROR_OK;
413                 }
414                 watchpoint_p = &watchpoint->next;
415                 watchpoint = watchpoint->next;
416         }
417
418         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
419         (*watchpoint_p)->address = address;
420         (*watchpoint_p)->length = length;
421         (*watchpoint_p)->value = value;
422         (*watchpoint_p)->mask = mask;
423         (*watchpoint_p)->rw = rw;
424         (*watchpoint_p)->unique_id = bpwp_unique_id++;
425
426         retval = target_add_watchpoint(target, *watchpoint_p);
427         switch (retval) {
428                 case ERROR_OK:
429                         break;
430                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
431                         reason = "resource not available";
432                         goto bye;
433                 case ERROR_TARGET_NOT_HALTED:
434                         reason = "target running";
435                         goto bye;
436                 default:
437                         reason = "unrecognized error";
438 bye:
439                         LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
440                                 watchpoint_rw_strings[(*watchpoint_p)->rw],
441                                 address, reason);
442                         free(*watchpoint_p);
443                         *watchpoint_p = NULL;
444                         return retval;
445         }
446
447         LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
448                 " of length 0x%8.8" PRIx32 " (WPID: %d)",
449                 watchpoint_rw_strings[(*watchpoint_p)->rw],
450                 (*watchpoint_p)->address,
451                 (*watchpoint_p)->length,
452                 (*watchpoint_p)->unique_id);
453
454         return ERROR_OK;
455 }
456
457 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
458 {
459         struct watchpoint *watchpoint = target->watchpoints;
460         struct watchpoint **watchpoint_p = &target->watchpoints;
461         int retval;
462
463         while (watchpoint) {
464                 if (watchpoint == watchpoint_to_remove)
465                         break;
466                 watchpoint_p = &watchpoint->next;
467                 watchpoint = watchpoint->next;
468         }
469
470         if (watchpoint == NULL)
471                 return;
472         retval = target_remove_watchpoint(target, watchpoint);
473         LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
474         (*watchpoint_p) = watchpoint->next;
475         free(watchpoint);
476 }
477
478 void watchpoint_remove(struct target *target, target_addr_t address)
479 {
480         struct watchpoint *watchpoint = target->watchpoints;
481
482         while (watchpoint) {
483                 if (watchpoint->address == address)
484                         break;
485                 watchpoint = watchpoint->next;
486         }
487
488         if (watchpoint)
489                 watchpoint_free(target, watchpoint);
490         else
491                 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
492 }
493
494 void watchpoint_clear_target(struct target *target)
495 {
496         LOG_DEBUG("Delete all watchpoints for target: %s",
497                 target_name(target));
498         while (target->watchpoints != NULL)
499                 watchpoint_free(target, target->watchpoints);
500 }
501
502 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
503                    target_addr_t *address)
504 {
505         int retval;
506         struct watchpoint *hit_watchpoint;
507
508         retval = target_hit_watchpoint(target, &hit_watchpoint);
509         if (retval != ERROR_OK)
510                 return ERROR_FAIL;
511
512         *rw = hit_watchpoint->rw;
513         *address = hit_watchpoint->address;
514
515         LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
516                 hit_watchpoint->address,
517                 hit_watchpoint->unique_id);
518
519         return ERROR_OK;
520 }