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