dsp5680xx - fix jtag debug request failure handling
[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, 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                 if (type == BKPT_SOFT)
232                         return(breakpoint_add_internal(head->target, address,length, type));
233
234                 while(head != (struct target_list*)NULL)
235                 {
236                         curr = head->target;
237                         retval = breakpoint_add_internal(curr, address,length, type);
238                         if (retval != ERROR_OK) return retval;
239                         head = head->next;
240                 }
241                 return retval;
242         }
243         else
244                 return(breakpoint_add_internal(target, address, length, type));
245
246 }
247 int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type)
248 {
249
250         int retval = ERROR_OK;
251         if (target->smp)
252         {
253                 struct target_list *head;
254                 struct target *curr;
255                 head = target->head;
256                 while(head != (struct target_list*)NULL)
257                 {
258                         curr = head->target;
259                         retval = context_breakpoint_add_internal(curr, asid,length, type);
260                         if (retval != ERROR_OK) return retval;
261                         head = head->next;
262                 }
263                 return retval;
264         }
265         else
266                 return(context_breakpoint_add_internal(target, asid, length, type));
267
268 }
269 int hybrid_breakpoint_add(struct target *target, uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type)
270 {
271
272         int retval = ERROR_OK;
273         if (target->smp)
274         {
275                 struct target_list *head;
276                 struct target *curr;
277                 head = target->head;
278                 while(head != (struct target_list*)NULL)
279                 {
280                         curr = head->target;
281                         retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
282                         if (retval != ERROR_OK) return retval;
283                         head = head->next;
284                 }
285                 return retval;
286         }
287         else
288                 return(hybrid_breakpoint_add_internal(target, address, asid, length, type));
289
290 }
291
292 /* free up a breakpoint */
293 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
294 {
295         struct breakpoint *breakpoint = target->breakpoints;
296         struct breakpoint **breakpoint_p = &target->breakpoints;
297         int retval;
298
299         while (breakpoint)
300         {
301                 if (breakpoint == breakpoint_to_remove)
302                         break;
303                 breakpoint_p = &breakpoint->next;
304                 breakpoint = breakpoint->next;
305         }
306
307         if (breakpoint == NULL)
308                 return;
309
310         retval = target_remove_breakpoint(target, breakpoint);
311
312         LOG_DEBUG("free BPID: %d --> %d", breakpoint->unique_id, retval);
313         (*breakpoint_p) = breakpoint->next;
314         free(breakpoint->orig_instr);
315         free(breakpoint);
316 }
317
318 int breakpoint_remove_internal(struct target *target, uint32_t address)
319 {
320         struct breakpoint *breakpoint = target->breakpoints;
321
322         while (breakpoint)
323         {
324                 if ((breakpoint->address == address) && (breakpoint->asid == 0))
325                         break;
326                 else if ((breakpoint->address == 0) && (breakpoint->asid == address))
327                         break;
328                 else if ((breakpoint->address == address) && (breakpoint->asid != 0))
329                         break;
330                 breakpoint = breakpoint->next;
331         }
332
333         if (breakpoint)
334         {
335                 breakpoint_free(target, breakpoint);
336                 return 1;
337         }
338         else
339         {
340                 if (!target->smp)
341                         LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
342                 return 0;
343         }
344 }
345 void breakpoint_remove(struct target *target, uint32_t address)
346 {
347         int found = 0;
348         if (target->smp)
349         {
350                 struct target_list *head;
351                 struct target *curr;
352                 head = target->head;
353                 while(head != (struct target_list*)NULL)
354                 {
355                         curr = head->target;
356                         found += breakpoint_remove_internal(curr, address);
357                         head = head->next;
358                 }
359                 if (found == 0)
360                         LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address);
361         }
362         else  breakpoint_remove_internal(target, address);
363 }
364
365 void breakpoint_clear_target_internal(struct target *target)
366 {
367         struct breakpoint *breakpoint;
368
369         LOG_DEBUG("Delete all breakpoints for target: %s",
370                         target_name(target));
371         while ((breakpoint = target->breakpoints) != NULL)
372         {
373                 breakpoint_free(target, breakpoint);
374         }
375 }
376
377 void breakpoint_clear_target(struct target *target)
378 {
379         if (target->smp)
380         {
381                 struct target_list *head;
382                 struct target *curr;
383                 head = target->head;
384                 while(head != (struct target_list*)NULL)
385                 {
386                         curr = head->target;
387                         breakpoint_clear_target_internal(curr);
388                         head = head->next;
389                 }
390         }
391         else breakpoint_clear_target_internal(target);
392
393 }
394
395
396 struct breakpoint* breakpoint_find(struct target *target, uint32_t address)
397 {
398         struct breakpoint *breakpoint = target->breakpoints;
399
400         while (breakpoint)
401         {
402                 if (breakpoint->address == address)
403                         return breakpoint;
404                 breakpoint = breakpoint->next;
405         }
406
407         return NULL;
408 }
409
410 int watchpoint_add(struct target *target, uint32_t address, uint32_t length,
411                 enum watchpoint_rw rw, uint32_t value, uint32_t mask)
412 {
413         struct watchpoint *watchpoint = target->watchpoints;
414         struct watchpoint **watchpoint_p = &target->watchpoints;
415         int retval;
416         char *reason;
417
418         while (watchpoint)
419         {
420                 if (watchpoint->address == address) {
421                         if (watchpoint->length != length
422                                         || watchpoint->value != value
423                                         || watchpoint->mask != mask
424                                         || watchpoint->rw != rw) {
425                                 LOG_ERROR("address 0x%8.8" PRIx32
426                                                 "already has watchpoint %d",
427                                                 address, watchpoint->unique_id);
428                                 return ERROR_FAIL;
429                         }
430
431                         /* ignore duplicate watchpoint */
432                         return ERROR_OK;
433                 }
434                 watchpoint_p = &watchpoint->next;
435                 watchpoint = watchpoint->next;
436         }
437
438         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
439         (*watchpoint_p)->address = address;
440         (*watchpoint_p)->length = length;
441         (*watchpoint_p)->value = value;
442         (*watchpoint_p)->mask = mask;
443         (*watchpoint_p)->rw = rw;
444         (*watchpoint_p)->unique_id = bpwp_unique_id++;
445
446         retval = target_add_watchpoint(target, *watchpoint_p);
447         switch (retval) {
448         case ERROR_OK:
449                 break;
450         case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
451                 reason = "resource not available";
452                 goto bye;
453         case ERROR_TARGET_NOT_HALTED:
454                 reason = "target running";
455                 goto bye;
456         default:
457                 reason = "unrecognized error";
458 bye:
459                 LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s",
460                                 watchpoint_rw_strings[(*watchpoint_p)->rw],
461                                 address, reason);
462                 free (*watchpoint_p);
463                 *watchpoint_p = NULL;
464                 return retval;
465         }
466
467         LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32
468                         " of length 0x%8.8" PRIx32 " (WPID: %d)",
469                         watchpoint_rw_strings[(*watchpoint_p)->rw],
470                         (*watchpoint_p)->address,
471                         (*watchpoint_p)->length,
472                         (*watchpoint_p)->unique_id);
473
474         return ERROR_OK;
475 }
476
477 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
478 {
479         struct watchpoint *watchpoint = target->watchpoints;
480         struct watchpoint **watchpoint_p = &target->watchpoints;
481         int retval;
482
483         while (watchpoint)
484         {
485                 if (watchpoint == watchpoint_to_remove)
486                         break;
487                 watchpoint_p = &watchpoint->next;
488                 watchpoint = watchpoint->next;
489         }
490
491         if (watchpoint == NULL)
492                 return;
493         retval = target_remove_watchpoint(target, watchpoint);
494         LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
495         (*watchpoint_p) = watchpoint->next;
496         free(watchpoint);
497 }
498
499 void watchpoint_remove(struct target *target, uint32_t address)
500 {
501         struct watchpoint *watchpoint = target->watchpoints;
502
503         while (watchpoint)
504         {
505                 if (watchpoint->address == address)
506                         break;
507                 watchpoint = watchpoint->next;
508         }
509
510         if (watchpoint)
511         {
512                 watchpoint_free(target, watchpoint);
513         }
514         else
515         {
516                 LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address);
517         }
518 }
519
520 void watchpoint_clear_target(struct target *target)
521 {
522         struct watchpoint *watchpoint;
523
524         LOG_DEBUG("Delete all watchpoints for target: %s",
525                         target_name(target));
526         while ((watchpoint = target->watchpoints) != NULL)
527         {
528                 watchpoint_free(target, watchpoint);
529         }
530 }