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