3ab1464e8b8db27dab7eb2f3cb9f6cd830598fe1
[fw/openocd] / src / target / breakpoints.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "target.h"
25 #include "log.h"
26 #include "breakpoints.h"
27
28
29 static char *breakpoint_type_strings[] =
30 {
31         "hardware",
32         "software"
33 };
34
35 static char *watchpoint_rw_strings[] =
36 {
37         "read",
38         "write",
39         "access"
40 };
41
42 // monotonic counter/id-number for breakpoints and watch points
43 static int bpwp_unique_id;
44
45 int breakpoint_add(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type)
46 {
47         struct breakpoint *breakpoint = target->breakpoints;
48         struct breakpoint **breakpoint_p = &target->breakpoints;
49         char *reason;
50         int retval;
51         int n;
52
53         n = 0;
54         while (breakpoint)
55         {
56                 n++;
57                 if (breakpoint->address == address) {
58                         /* FIXME don't assume "same address" means "same
59                          * breakpoint" ... check all the parameters before
60                          * succeeding.
61                          */
62                         LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %d)",
63                                   address, breakpoint->unique_id );
64                         return ERROR_OK;
65                 }
66                 breakpoint_p = &breakpoint->next;
67                 breakpoint = breakpoint->next;
68         }
69
70         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
71         (*breakpoint_p)->address = address;
72         (*breakpoint_p)->length = length;
73         (*breakpoint_p)->type = type;
74         (*breakpoint_p)->set = 0;
75         (*breakpoint_p)->orig_instr = malloc(length);
76         (*breakpoint_p)->next = NULL;
77         (*breakpoint_p)->unique_id = bpwp_unique_id++;
78
79         retval = target_add_breakpoint(target, *breakpoint_p);
80         switch (retval) {
81         case ERROR_OK:
82                 break;
83         case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
84                 reason = "resource not available";
85                 goto fail;
86         case ERROR_TARGET_NOT_HALTED:
87                 reason = "target running";
88                 goto fail;
89         default:
90                 reason = "unknown reason";
91 fail:
92                 LOG_ERROR("can't add breakpoint: %s", reason);
93                 free((*breakpoint_p)->orig_instr);
94                 free(*breakpoint_p);
95                 *breakpoint_p = NULL;
96                 return retval;
97         }
98
99         LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
100                           breakpoint_type_strings[(*breakpoint_p)->type],
101                           (*breakpoint_p)->address, (*breakpoint_p)->length,
102                           (*breakpoint_p)->unique_id  );
103
104         return ERROR_OK;
105 }
106
107 /* free up a breakpoint */
108 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_remove)
109 {
110         struct breakpoint *breakpoint = target->breakpoints;
111         struct breakpoint **breakpoint_p = &target->breakpoints;
112
113         while (breakpoint)
114         {
115                 if (breakpoint == breakpoint_remove)
116                         break;
117                 breakpoint_p = &breakpoint->next;
118                 breakpoint = breakpoint->next;
119         }
120
121         if (breakpoint == NULL)
122                 return;
123
124         target_remove_breakpoint(target, breakpoint);
125
126         LOG_DEBUG("BPID: %d", breakpoint->unique_id );
127         (*breakpoint_p) = breakpoint->next;
128         free(breakpoint->orig_instr);
129         free(breakpoint);
130 }
131
132 void breakpoint_remove(struct target *target, uint32_t address)
133 {
134         struct breakpoint *breakpoint = target->breakpoints;
135         struct breakpoint **breakpoint_p = &target->breakpoints;
136
137         while (breakpoint)
138         {
139                 if (breakpoint->address == address)
140                         break;
141                 breakpoint_p = &breakpoint->next;
142                 breakpoint = breakpoint->next;
143         }
144
145         if (breakpoint)
146         {
147                 breakpoint_free(target, breakpoint);
148         }
149         else
150         {
151                 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
152         }
153 }
154
155 void breakpoint_clear_target(struct target *target)
156 {
157         struct breakpoint *breakpoint;
158         LOG_DEBUG("Delete all breakpoints for target: %s", target_get_name( target ));
159         while ((breakpoint = target->breakpoints) != NULL)
160         {
161                 breakpoint_free(target, breakpoint);
162         }
163 }
164
165 struct breakpoint* breakpoint_find(struct target *target, uint32_t address)
166 {
167         struct breakpoint *breakpoint = target->breakpoints;
168
169         while (breakpoint)
170         {
171                 if (breakpoint->address == address)
172                         return breakpoint;
173                 breakpoint = breakpoint->next;
174         }
175
176         return NULL;
177 }
178
179 int watchpoint_add(struct target *target, uint32_t address, uint32_t length,
180                 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
181 {
182         struct watchpoint *watchpoint = target->watchpoints;
183         struct watchpoint **watchpoint_p = &target->watchpoints;
184         int retval;
185         char *reason;
186
187         while (watchpoint)
188         {
189                 if (watchpoint->address == address) {
190                         if (watchpoint->length != length
191                                         || watchpoint->value != value
192                                         || watchpoint->mask != mask
193                                         || watchpoint->rw != rw) {
194                                 LOG_ERROR("address 0x%8.8" PRIx32
195                                                 "already has watchpoint %d",
196                                                 address, watchpoint->unique_id);
197                                 return ERROR_FAIL;
198                         }
199
200                         /* ignore duplicate watchpoint */
201                         return ERROR_OK;
202                 }
203                 watchpoint_p = &watchpoint->next;
204                 watchpoint = watchpoint->next;
205         }
206
207         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
208         (*watchpoint_p)->address = address;
209         (*watchpoint_p)->length = length;
210         (*watchpoint_p)->value = value;
211         (*watchpoint_p)->mask = mask;
212         (*watchpoint_p)->rw = rw;
213         (*watchpoint_p)->unique_id = bpwp_unique_id++;
214
215         retval = target_add_watchpoint(target, *watchpoint_p);
216         switch (retval) {
217         case ERROR_OK:
218                 break;
219         case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
220                 reason = "resource not available";
221                 goto bye;
222         case ERROR_TARGET_NOT_HALTED:
223                 reason = "target running";
224                 goto bye;
225         default:
226                 reason = "unrecognized error";
227 bye:
228                 LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
229                          watchpoint_rw_strings[(*watchpoint_p)->rw],
230                          address, reason);
231                 free (*watchpoint_p);
232                 *watchpoint_p = NULL;
233                 return retval;
234         }
235
236         LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32
237                         " of length 0x%8.8" PRIx32 " (WPID: %d)",
238                         watchpoint_rw_strings[(*watchpoint_p)->rw],
239                         (*watchpoint_p)->address,
240                         (*watchpoint_p)->length,
241                         (*watchpoint_p)->unique_id );
242
243         return ERROR_OK;
244 }
245
246 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_remove)
247 {
248         struct watchpoint *watchpoint = target->watchpoints;
249         struct watchpoint **watchpoint_p = &target->watchpoints;
250
251         while (watchpoint)
252         {
253                 if (watchpoint == watchpoint_remove)
254                         break;
255                 watchpoint_p = &watchpoint->next;
256                 watchpoint = watchpoint->next;
257         }
258
259         if (watchpoint == NULL)
260                 return;
261         target_remove_watchpoint(target, watchpoint);
262         LOG_DEBUG("WPID: %d", watchpoint->unique_id );
263         (*watchpoint_p) = watchpoint->next;
264         free(watchpoint);
265 }
266
267 void watchpoint_remove(struct target *target, uint32_t address)
268 {
269         struct watchpoint *watchpoint = target->watchpoints;
270         struct watchpoint **watchpoint_p = &target->watchpoints;
271
272         while (watchpoint)
273         {
274                 if (watchpoint->address == address)
275                         break;
276                 watchpoint_p = &watchpoint->next;
277                 watchpoint = watchpoint->next;
278         }
279
280         if (watchpoint)
281         {
282                 watchpoint_free(target, watchpoint);
283         }
284         else
285         {
286                 LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
287         }
288 }
289
290 void watchpoint_clear_target(struct target *target)
291 {
292         struct watchpoint *watchpoint;
293         LOG_DEBUG("Delete all watchpoints for target: %s", target_get_name( target ));
294         while ((watchpoint = target->watchpoints) != NULL)
295         {
296                 watchpoint_free(target, watchpoint);
297         }
298 }