target/breakpoints: Remove dead code and cleanup
[fw/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 static 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
54         while (breakpoint) {
55                 if (breakpoint->address == address) {
56                         /* FIXME don't assume "same address" means "same
57                          * breakpoint" ... check all the parameters before
58                          * succeeding.
59                          */
60                         LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
61                                 address, breakpoint->unique_id);
62                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
63                 }
64                 breakpoint_p = &breakpoint->next;
65                 breakpoint = breakpoint->next;
66         }
67
68         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
69         (*breakpoint_p)->address = address;
70         (*breakpoint_p)->asid = 0;
71         (*breakpoint_p)->length = length;
72         (*breakpoint_p)->type = type;
73         (*breakpoint_p)->set = 0;
74         (*breakpoint_p)->orig_instr = malloc(length);
75         (*breakpoint_p)->next = NULL;
76         (*breakpoint_p)->unique_id = bpwp_unique_id++;
77
78         retval = target_add_breakpoint(target, *breakpoint_p);
79         switch (retval) {
80                 case ERROR_OK:
81                         break;
82                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
83                         reason = "resource not available";
84                         goto fail;
85                 case ERROR_TARGET_NOT_HALTED:
86                         reason = "target running";
87                         goto fail;
88                 default:
89                         reason = "unknown reason";
90 fail:
91                         LOG_ERROR("can't add breakpoint: %s", reason);
92                         free((*breakpoint_p)->orig_instr);
93                         free(*breakpoint_p);
94                         *breakpoint_p = NULL;
95                         return retval;
96         }
97
98         LOG_DEBUG("added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
99                 breakpoint_type_strings[(*breakpoint_p)->type],
100                 (*breakpoint_p)->address, (*breakpoint_p)->length,
101                 (*breakpoint_p)->unique_id);
102
103         return ERROR_OK;
104 }
105
106 static int context_breakpoint_add_internal(struct target *target,
107         uint32_t asid,
108         uint32_t length,
109         enum breakpoint_type type)
110 {
111         struct breakpoint *breakpoint = target->breakpoints;
112         struct breakpoint **breakpoint_p = &target->breakpoints;
113         int retval;
114
115         while (breakpoint) {
116                 if (breakpoint->asid == asid) {
117                         /* FIXME don't assume "same address" means "same
118                          * breakpoint" ... check all the parameters before
119                          * succeeding.
120                          */
121                         LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
122                                 asid, breakpoint->unique_id);
123                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
124                 }
125                 breakpoint_p = &breakpoint->next;
126                 breakpoint = breakpoint->next;
127         }
128
129         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
130         (*breakpoint_p)->address = 0;
131         (*breakpoint_p)->asid = asid;
132         (*breakpoint_p)->length = length;
133         (*breakpoint_p)->type = type;
134         (*breakpoint_p)->set = 0;
135         (*breakpoint_p)->orig_instr = malloc(length);
136         (*breakpoint_p)->next = NULL;
137         (*breakpoint_p)->unique_id = bpwp_unique_id++;
138         retval = target_add_context_breakpoint(target, *breakpoint_p);
139         if (retval != ERROR_OK) {
140                 LOG_ERROR("could not add breakpoint");
141                 free((*breakpoint_p)->orig_instr);
142                 free(*breakpoint_p);
143                 *breakpoint_p = NULL;
144                 return retval;
145         }
146
147         LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
148                 breakpoint_type_strings[(*breakpoint_p)->type],
149                 (*breakpoint_p)->asid, (*breakpoint_p)->length,
150                 (*breakpoint_p)->unique_id);
151
152         return ERROR_OK;
153 }
154
155 static int hybrid_breakpoint_add_internal(struct target *target,
156         target_addr_t address,
157         uint32_t asid,
158         uint32_t length,
159         enum breakpoint_type type)
160 {
161         struct breakpoint *breakpoint = target->breakpoints;
162         struct breakpoint **breakpoint_p = &target->breakpoints;
163         int retval;
164
165         while (breakpoint) {
166                 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
167                         /* FIXME don't assume "same address" means "same
168                          * breakpoint" ... check all the parameters before
169                          * succeeding.
170                          */
171                         LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
172                                 asid, breakpoint->unique_id);
173                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
174                 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
175                         LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
176                                 address, breakpoint->unique_id);
177                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
178
179                 }
180                 breakpoint_p = &breakpoint->next;
181                 breakpoint = breakpoint->next;
182         }
183         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
184         (*breakpoint_p)->address = address;
185         (*breakpoint_p)->asid = asid;
186         (*breakpoint_p)->length = length;
187         (*breakpoint_p)->type = type;
188         (*breakpoint_p)->set = 0;
189         (*breakpoint_p)->orig_instr = malloc(length);
190         (*breakpoint_p)->next = NULL;
191         (*breakpoint_p)->unique_id = bpwp_unique_id++;
192
193
194         retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
195         if (retval != ERROR_OK) {
196                 LOG_ERROR("could not add breakpoint");
197                 free((*breakpoint_p)->orig_instr);
198                 free(*breakpoint_p);
199                 *breakpoint_p = NULL;
200                 return retval;
201         }
202         LOG_DEBUG(
203                 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
204                 breakpoint_type_strings[(*breakpoint_p)->type],
205                 (*breakpoint_p)->address,
206                 (*breakpoint_p)->length,
207                 (*breakpoint_p)->unique_id);
208
209         return ERROR_OK;
210 }
211
212 int breakpoint_add(struct target *target,
213         target_addr_t address,
214         uint32_t length,
215         enum breakpoint_type type)
216 {
217         int retval = ERROR_OK;
218         if (target->smp) {
219                 struct target_list *head;
220                 struct target *curr;
221                 head = target->head;
222                 if (type == BKPT_SOFT)
223                         return breakpoint_add_internal(head->target, address, length, type);
224
225                 while (head != (struct target_list *)NULL) {
226                         curr = head->target;
227                         retval = breakpoint_add_internal(curr, address, length, type);
228                         if (retval != ERROR_OK)
229                                 return retval;
230                         head = head->next;
231                 }
232                 return retval;
233         } else {
234                 return breakpoint_add_internal(target, address, length, type);
235         }
236 }
237
238 int context_breakpoint_add(struct target *target,
239         uint32_t asid,
240         uint32_t length,
241         enum breakpoint_type type)
242 {
243         int retval = ERROR_OK;
244         if (target->smp) {
245                 struct target_list *head;
246                 struct target *curr;
247                 head = target->head;
248                 while (head != (struct target_list *)NULL) {
249                         curr = head->target;
250                         retval = context_breakpoint_add_internal(curr, asid, length, type);
251                         if (retval != ERROR_OK)
252                                 return retval;
253                         head = head->next;
254                 }
255                 return retval;
256         } else {
257                 return context_breakpoint_add_internal(target, asid, length, type);
258         }
259 }
260
261 int hybrid_breakpoint_add(struct target *target,
262         target_addr_t address,
263         uint32_t asid,
264         uint32_t length,
265         enum breakpoint_type type)
266 {
267         int retval = ERROR_OK;
268         if (target->smp) {
269                 struct target_list *head;
270                 struct target *curr;
271                 head = target->head;
272                 while (head != (struct target_list *)NULL) {
273                         curr = head->target;
274                         retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
275                         if (retval != ERROR_OK)
276                                 return retval;
277                         head = head->next;
278                 }
279                 return retval;
280         } else
281                 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
282 }
283
284 /* free up a breakpoint */
285 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
286 {
287         struct breakpoint *breakpoint = target->breakpoints;
288         struct breakpoint **breakpoint_p = &target->breakpoints;
289         int retval;
290
291         while (breakpoint) {
292                 if (breakpoint == breakpoint_to_remove)
293                         break;
294                 breakpoint_p = &breakpoint->next;
295                 breakpoint = breakpoint->next;
296         }
297
298         if (!breakpoint)
299                 return;
300
301         retval = target_remove_breakpoint(target, breakpoint);
302
303         LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
304         (*breakpoint_p) = breakpoint->next;
305         free(breakpoint->orig_instr);
306         free(breakpoint);
307 }
308
309 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
310 {
311         struct breakpoint *breakpoint = target->breakpoints;
312
313         while (breakpoint) {
314                 if ((breakpoint->address == address) ||
315                     (breakpoint->address == 0 && breakpoint->asid == address))
316                         break;
317                 breakpoint = breakpoint->next;
318         }
319
320         if (breakpoint) {
321                 breakpoint_free(target, breakpoint);
322                 return 1;
323         } else {
324                 if (!target->smp)
325                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
326                 return 0;
327         }
328 }
329
330 static void breakpoint_remove_all_internal(struct target *target)
331 {
332         struct breakpoint *breakpoint = target->breakpoints;
333
334         while (breakpoint) {
335                 struct breakpoint *tmp = breakpoint;
336                 breakpoint = breakpoint->next;
337                 breakpoint_free(target, tmp);
338         }
339 }
340
341 void breakpoint_remove(struct target *target, target_addr_t address)
342 {
343         if (target->smp) {
344                 unsigned int num_breakpoints = 0;
345                 struct target_list *head;
346                 struct target *curr;
347                 head = target->head;
348                 while (head != (struct target_list *)NULL) {
349                         curr = head->target;
350                         num_breakpoints += breakpoint_remove_internal(curr, address);
351                         head = head->next;
352                 }
353                 if (!num_breakpoints)
354                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
355         } else {
356                 breakpoint_remove_internal(target, address);
357         }
358 }
359
360 void breakpoint_remove_all(struct target *target)
361 {
362         if (target->smp) {
363                 struct target_list *head;
364                 struct target *curr;
365                 head = target->head;
366                 while (head != (struct target_list *)NULL) {
367                         curr = head->target;
368                         breakpoint_remove_all_internal(curr);
369                         head = head->next;
370                 }
371         } else {
372                 breakpoint_remove_all_internal(target);
373         }
374 }
375
376 static void breakpoint_clear_target_internal(struct target *target)
377 {
378         LOG_DEBUG("Delete all breakpoints for target: %s",
379                 target_name(target));
380         while (target->breakpoints != NULL)
381                 breakpoint_free(target, target->breakpoints);
382 }
383
384 void breakpoint_clear_target(struct target *target)
385 {
386         if (target->smp) {
387                 struct target_list *head;
388                 struct target *curr;
389                 head = target->head;
390                 while (head != (struct target_list *)NULL) {
391                         curr = head->target;
392                         breakpoint_clear_target_internal(curr);
393                         head = head->next;
394                 }
395         } else {
396                 breakpoint_clear_target_internal(target);
397         }
398 }
399
400 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
401 {
402         struct breakpoint *breakpoint = target->breakpoints;
403
404         while (breakpoint) {
405                 if (breakpoint->address == address)
406                         return breakpoint;
407                 breakpoint = breakpoint->next;
408         }
409
410         return NULL;
411 }
412
413 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
414         enum watchpoint_rw rw, uint32_t value, uint32_t mask)
415 {
416         struct watchpoint *watchpoint = target->watchpoints;
417         struct watchpoint **watchpoint_p = &target->watchpoints;
418         int retval;
419         const char *reason;
420
421         while (watchpoint) {
422                 if (watchpoint->address == address) {
423                         if (watchpoint->length != length
424                                 || watchpoint->value != value
425                                 || watchpoint->mask != mask
426                                 || watchpoint->rw != rw) {
427                                 LOG_ERROR("address " TARGET_ADDR_FMT
428                                         " already has watchpoint %d",
429                                         address, watchpoint->unique_id);
430                                 return ERROR_FAIL;
431                         }
432
433                         /* ignore duplicate watchpoint */
434                         return ERROR_OK;
435                 }
436                 watchpoint_p = &watchpoint->next;
437                 watchpoint = watchpoint->next;
438         }
439
440         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
441         (*watchpoint_p)->address = address;
442         (*watchpoint_p)->length = length;
443         (*watchpoint_p)->value = value;
444         (*watchpoint_p)->mask = mask;
445         (*watchpoint_p)->rw = rw;
446         (*watchpoint_p)->unique_id = bpwp_unique_id++;
447
448         retval = target_add_watchpoint(target, *watchpoint_p);
449         switch (retval) {
450                 case ERROR_OK:
451                         break;
452                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
453                         reason = "resource not available";
454                         goto bye;
455                 case ERROR_TARGET_NOT_HALTED:
456                         reason = "target running";
457                         goto bye;
458                 default:
459                         reason = "unrecognized error";
460 bye:
461                         LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
462                                 watchpoint_rw_strings[(*watchpoint_p)->rw],
463                                 address, reason);
464                         free(*watchpoint_p);
465                         *watchpoint_p = NULL;
466                         return retval;
467         }
468
469         LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
470                 " of length 0x%8.8" PRIx32 " (WPID: %d)",
471                 watchpoint_rw_strings[(*watchpoint_p)->rw],
472                 (*watchpoint_p)->address,
473                 (*watchpoint_p)->length,
474                 (*watchpoint_p)->unique_id);
475
476         return ERROR_OK;
477 }
478
479 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
480 {
481         struct watchpoint *watchpoint = target->watchpoints;
482         struct watchpoint **watchpoint_p = &target->watchpoints;
483         int retval;
484
485         while (watchpoint) {
486                 if (watchpoint == watchpoint_to_remove)
487                         break;
488                 watchpoint_p = &watchpoint->next;
489                 watchpoint = watchpoint->next;
490         }
491
492         if (!watchpoint)
493                 return;
494         retval = target_remove_watchpoint(target, watchpoint);
495         LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
496         (*watchpoint_p) = watchpoint->next;
497         free(watchpoint);
498 }
499
500 void watchpoint_remove(struct target *target, target_addr_t address)
501 {
502         struct watchpoint *watchpoint = target->watchpoints;
503
504         while (watchpoint) {
505                 if (watchpoint->address == address)
506                         break;
507                 watchpoint = watchpoint->next;
508         }
509
510         if (watchpoint)
511                 watchpoint_free(target, watchpoint);
512         else
513                 LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
514 }
515
516 void watchpoint_clear_target(struct target *target)
517 {
518         LOG_DEBUG("Delete all watchpoints for target: %s",
519                 target_name(target));
520         while (target->watchpoints != NULL)
521                 watchpoint_free(target, target->watchpoints);
522 }
523
524 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
525                    target_addr_t *address)
526 {
527         int retval;
528         struct watchpoint *hit_watchpoint;
529
530         retval = target_hit_watchpoint(target, &hit_watchpoint);
531         if (retval != ERROR_OK)
532                 return ERROR_FAIL;
533
534         *rw = hit_watchpoint->rw;
535         *address = hit_watchpoint->address;
536
537         LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
538                 hit_watchpoint->address,
539                 hit_watchpoint->unique_id);
540
541         return ERROR_OK;
542 }