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