Add Breakpoint/Watchpoint unique ID to help debug hardware debug register leakage
[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(target_t *target, uint32_t address, uint32_t length, enum breakpoint_type type)
46 {
47         breakpoint_t *breakpoint = target->breakpoints;
48         breakpoint_t **breakpoint_p = &target->breakpoints;
49         int retval;
50         int n;
51
52         n = 0;
53         while (breakpoint)
54         {
55                 n++;
56                 if (breakpoint->address == address){
57                         LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %d)", 
58                                   address, breakpoint->unique_id );
59                         return ERROR_OK;
60                 }
61                 breakpoint_p = &breakpoint->next;
62                 breakpoint = breakpoint->next;
63         }
64
65         (*breakpoint_p) = malloc(sizeof(breakpoint_t));
66         (*breakpoint_p)->address = address;
67         (*breakpoint_p)->length = length;
68         (*breakpoint_p)->type = type;
69         (*breakpoint_p)->set = 0;
70         (*breakpoint_p)->orig_instr = malloc(length);
71         (*breakpoint_p)->next = NULL;
72         (*breakpoint_p)->unique_id = bpwp_unique_id++;
73
74         if ((retval = target_add_breakpoint(target, *breakpoint_p)) != ERROR_OK)
75         {
76                 switch (retval)
77                 {
78                         case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
79                                 LOG_INFO("can't add %s breakpoint, resource not available (BPID=%d)", 
80                                          breakpoint_type_strings[(*breakpoint_p)->type],
81                                          (*breakpoint_p)->unique_id );
82                                 
83                                 free((*breakpoint_p)->orig_instr);
84                                 free(*breakpoint_p);
85                                 *breakpoint_p = NULL;
86                                 return retval;
87                                 break;
88                         case ERROR_TARGET_NOT_HALTED:
89                                 LOG_INFO("can't add breakpoint while target is running (BPID: %d)",
90                                                  (*breakpoint_p)->unique_id );                                           
91                                 free((*breakpoint_p)->orig_instr);
92                                 free(*breakpoint_p);
93                                 *breakpoint_p = NULL;
94                                 return retval;
95                                 break;
96                         default:
97                                 break;
98                 }
99         }
100
101         LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)",
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 /* free up a breakpoint */
110 static void breakpoint_free(target_t *target, breakpoint_t *breakpoint_remove)
111 {
112         breakpoint_t *breakpoint = target->breakpoints;
113         breakpoint_t **breakpoint_p = &target->breakpoints;
114
115         while (breakpoint)
116         {
117                 if (breakpoint == breakpoint_remove)
118                         break;
119                 breakpoint_p = &breakpoint->next;
120                 breakpoint = breakpoint->next;
121         }
122
123         if (breakpoint == NULL)
124                 return;
125
126         target_remove_breakpoint(target, breakpoint);
127
128         LOG_DEBUG("BPID: %d", breakpoint->unique_id );
129         (*breakpoint_p) = breakpoint->next;
130         free(breakpoint->orig_instr);
131         free(breakpoint);
132 }
133
134 void breakpoint_remove(target_t *target, uint32_t address)
135 {
136         breakpoint_t *breakpoint = target->breakpoints;
137         breakpoint_t **breakpoint_p = &target->breakpoints;
138
139         while (breakpoint)
140         {
141                 if (breakpoint->address == address)
142                         break;
143                 breakpoint_p = &breakpoint->next;
144                 breakpoint = breakpoint->next;
145         }
146
147         if (breakpoint)
148         {
149                 breakpoint_free(target, breakpoint);
150         }
151         else
152         {
153                 LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
154         }
155 }
156
157 void breakpoint_clear_target(target_t *target)
158 {
159         breakpoint_t *breakpoint;
160         LOG_DEBUG("Delete all breakpoints for target: %s", target_get_name( target ));
161         while ((breakpoint = target->breakpoints) != NULL)
162         {
163                 breakpoint_free(target, breakpoint);
164         }
165 }
166
167 breakpoint_t* breakpoint_find(target_t *target, uint32_t address)
168 {
169         breakpoint_t *breakpoint = target->breakpoints;
170
171         while (breakpoint)
172         {
173                 if (breakpoint->address == address)
174                         return breakpoint;
175                 breakpoint = breakpoint->next;
176         }
177
178         return NULL;
179 }
180
181 int watchpoint_add(target_t *target, uint32_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
182 {
183         watchpoint_t *watchpoint = target->watchpoints;
184         watchpoint_t **watchpoint_p = &target->watchpoints;
185         int retval;
186
187         while (watchpoint)
188         {
189                 if (watchpoint->address == address)
190                         return ERROR_OK;
191                 watchpoint_p = &watchpoint->next;
192                 watchpoint = watchpoint->next;
193         }
194
195         (*watchpoint_p) = malloc(sizeof(watchpoint_t));
196         (*watchpoint_p)->address = address;
197         (*watchpoint_p)->length = length;
198         (*watchpoint_p)->value = value;
199         (*watchpoint_p)->mask = mask;
200         (*watchpoint_p)->rw = rw;
201         (*watchpoint_p)->set = 0;
202         (*watchpoint_p)->next = NULL;
203         (*watchpoint_p)->unique_id = bpwp_unique_id++;
204
205         if ((retval = target_add_watchpoint(target, *watchpoint_p)) != ERROR_OK)
206         {
207                 switch (retval)
208                 {
209                         case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
210                                 LOG_INFO("can't add %s watchpoint, resource not available (WPID: %d)", 
211                                          watchpoint_rw_strings[(*watchpoint_p)->rw],
212                                          (*watchpoint_p)->unique_id );
213                                 free (*watchpoint_p);
214                                 *watchpoint_p = NULL;
215                                 return retval;
216                                 break;
217                         case ERROR_TARGET_NOT_HALTED:
218                                 LOG_INFO("can't add watchpoint while target is running (WPID: %d)",
219                                                  (*watchpoint_p)->unique_id );
220                                 free (*watchpoint_p);
221                                 *watchpoint_p = NULL;
222                                 return retval;
223                                 break;
224                         default:
225                                 LOG_ERROR("unknown error");
226                                 exit(-1);
227                                 break;
228                 }
229         }
230
231         LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32 " of length 0x%8.8x (WPID: %d)",
232                           watchpoint_rw_strings[(*watchpoint_p)->rw],
233                           (*watchpoint_p)->address, 
234                           (*watchpoint_p)->length,
235                           (*watchpoint_p)->unique_id );
236
237         return ERROR_OK;
238 }
239
240 static void watchpoint_free(target_t *target, watchpoint_t *watchpoint_remove)
241 {
242         watchpoint_t *watchpoint = target->watchpoints;
243         watchpoint_t **watchpoint_p = &target->watchpoints;
244
245         while (watchpoint)
246         {
247                 if (watchpoint == watchpoint_remove)
248                         break;
249                 watchpoint_p = &watchpoint->next;
250                 watchpoint = watchpoint->next;
251         }
252
253         if (watchpoint == NULL)
254                 return;
255         target_remove_watchpoint(target, watchpoint);
256         LOG_DEBUG("WPID: %d", watchpoint->unique_id );
257         (*watchpoint_p) = watchpoint->next;
258         free(watchpoint);
259 }
260
261 void watchpoint_remove(target_t *target, uint32_t address)
262 {
263         watchpoint_t *watchpoint = target->watchpoints;
264         watchpoint_t **watchpoint_p = &target->watchpoints;
265
266         while (watchpoint)
267         {
268                 if (watchpoint->address == address)
269                         break;
270                 watchpoint_p = &watchpoint->next;
271                 watchpoint = watchpoint->next;
272         }
273
274         if (watchpoint)
275         {
276                 watchpoint_free(target, watchpoint);
277         }
278         else
279         {
280                 LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
281         }
282 }
283
284 void watchpoint_clear_target(target_t *target)
285 {
286         watchpoint_t *watchpoint;
287         LOG_DEBUG("Delete all watchpoints for target: %s", target_get_name( target ));
288         while ((watchpoint = target->watchpoints) != NULL)
289         {
290                 watchpoint_free(target, watchpoint);
291         }
292 }