openocd: remove last NULL comparisons
[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
54         while (breakpoint) {
55                 if (breakpoint->address == address) {
56                         /* FIXME don't assume "same address" means "same
57                          * breakpoint" ... check all the parameters before
58                          * succeeding.
59                          */
60                         LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
61                                 address, breakpoint->unique_id);
62                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
63                 }
64                 breakpoint_p = &breakpoint->next;
65                 breakpoint = breakpoint->next;
66         }
67
68         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
69         (*breakpoint_p)->address = address;
70         (*breakpoint_p)->asid = 0;
71         (*breakpoint_p)->length = length;
72         (*breakpoint_p)->type = type;
73         (*breakpoint_p)->set = 0;
74         (*breakpoint_p)->orig_instr = malloc(length);
75         (*breakpoint_p)->next = NULL;
76         (*breakpoint_p)->unique_id = bpwp_unique_id++;
77
78         retval = target_add_breakpoint(target, *breakpoint_p);
79         switch (retval) {
80                 case ERROR_OK:
81                         break;
82                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
83                         reason = "resource not available";
84                         goto fail;
85                 case ERROR_TARGET_NOT_HALTED:
86                         reason = "target running";
87                         goto fail;
88                 default:
89                         reason = "unknown reason";
90 fail:
91                         LOG_ERROR("can't add breakpoint: %s", reason);
92                         free((*breakpoint_p)->orig_instr);
93                         free(*breakpoint_p);
94                         *breakpoint_p = NULL;
95                         return retval;
96         }
97
98         LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT
99                         " of length 0x%8.8x, (BPID: %" PRIu32 ")",
100                 target->coreid,
101                 breakpoint_type_strings[(*breakpoint_p)->type],
102                 (*breakpoint_p)->address, (*breakpoint_p)->length,
103                 (*breakpoint_p)->unique_id);
104
105         return ERROR_OK;
106 }
107
108 static int context_breakpoint_add_internal(struct target *target,
109         uint32_t asid,
110         uint32_t length,
111         enum breakpoint_type type)
112 {
113         struct breakpoint *breakpoint = target->breakpoints;
114         struct breakpoint **breakpoint_p = &target->breakpoints;
115         int retval;
116
117         while (breakpoint) {
118                 if (breakpoint->asid == asid) {
119                         /* FIXME don't assume "same address" means "same
120                          * breakpoint" ... check all the parameters before
121                          * succeeding.
122                          */
123                         LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
124                                 asid, breakpoint->unique_id);
125                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
126                 }
127                 breakpoint_p = &breakpoint->next;
128                 breakpoint = breakpoint->next;
129         }
130
131         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
132         (*breakpoint_p)->address = 0;
133         (*breakpoint_p)->asid = asid;
134         (*breakpoint_p)->length = length;
135         (*breakpoint_p)->type = type;
136         (*breakpoint_p)->set = 0;
137         (*breakpoint_p)->orig_instr = malloc(length);
138         (*breakpoint_p)->next = NULL;
139         (*breakpoint_p)->unique_id = bpwp_unique_id++;
140         retval = target_add_context_breakpoint(target, *breakpoint_p);
141         if (retval != ERROR_OK) {
142                 LOG_ERROR("could not add breakpoint");
143                 free((*breakpoint_p)->orig_instr);
144                 free(*breakpoint_p);
145                 *breakpoint_p = NULL;
146                 return retval;
147         }
148
149         LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")",
150                 breakpoint_type_strings[(*breakpoint_p)->type],
151                 (*breakpoint_p)->asid, (*breakpoint_p)->length,
152                 (*breakpoint_p)->unique_id);
153
154         return ERROR_OK;
155 }
156
157 static int hybrid_breakpoint_add_internal(struct target *target,
158         target_addr_t address,
159         uint32_t asid,
160         uint32_t length,
161         enum breakpoint_type type)
162 {
163         struct breakpoint *breakpoint = target->breakpoints;
164         struct breakpoint **breakpoint_p = &target->breakpoints;
165         int retval;
166
167         while (breakpoint) {
168                 if ((breakpoint->asid == asid) && (breakpoint->address == address)) {
169                         /* FIXME don't assume "same address" means "same
170                          * breakpoint" ... check all the parameters before
171                          * succeeding.
172                          */
173                         LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")",
174                                 asid, breakpoint->unique_id);
175                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
176                 } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) {
177                         LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")",
178                                 address, breakpoint->unique_id);
179                         return ERROR_TARGET_DUPLICATE_BREAKPOINT;
180
181                 }
182                 breakpoint_p = &breakpoint->next;
183                 breakpoint = breakpoint->next;
184         }
185         (*breakpoint_p) = malloc(sizeof(struct breakpoint));
186         (*breakpoint_p)->address = address;
187         (*breakpoint_p)->asid = asid;
188         (*breakpoint_p)->length = length;
189         (*breakpoint_p)->type = type;
190         (*breakpoint_p)->set = 0;
191         (*breakpoint_p)->orig_instr = malloc(length);
192         (*breakpoint_p)->next = NULL;
193         (*breakpoint_p)->unique_id = bpwp_unique_id++;
194
195
196         retval = target_add_hybrid_breakpoint(target, *breakpoint_p);
197         if (retval != ERROR_OK) {
198                 LOG_ERROR("could not add breakpoint");
199                 free((*breakpoint_p)->orig_instr);
200                 free(*breakpoint_p);
201                 *breakpoint_p = NULL;
202                 return retval;
203         }
204         LOG_DEBUG(
205                 "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")",
206                 breakpoint_type_strings[(*breakpoint_p)->type],
207                 (*breakpoint_p)->address,
208                 (*breakpoint_p)->length,
209                 (*breakpoint_p)->unique_id);
210
211         return ERROR_OK;
212 }
213
214 int breakpoint_add(struct target *target,
215         target_addr_t address,
216         uint32_t length,
217         enum breakpoint_type type)
218 {
219         int retval = ERROR_OK;
220         if (target->smp) {
221                 struct target_list *head;
222                 struct target *curr;
223                 head = target->head;
224                 if (type == BKPT_SOFT)
225                         return breakpoint_add_internal(head->target, address, length, type);
226
227                 while (head) {
228                         curr = head->target;
229                         retval = breakpoint_add_internal(curr, address, length, type);
230                         if (retval != ERROR_OK)
231                                 return retval;
232                         head = head->next;
233                 }
234                 return retval;
235         } else {
236                 return breakpoint_add_internal(target, address, length, type);
237         }
238 }
239
240 int context_breakpoint_add(struct target *target,
241         uint32_t asid,
242         uint32_t length,
243         enum breakpoint_type type)
244 {
245         int retval = ERROR_OK;
246         if (target->smp) {
247                 struct target_list *head;
248                 struct target *curr;
249                 head = target->head;
250                 while (head) {
251                         curr = head->target;
252                         retval = context_breakpoint_add_internal(curr, asid, length, type);
253                         if (retval != ERROR_OK)
254                                 return retval;
255                         head = head->next;
256                 }
257                 return retval;
258         } else {
259                 return context_breakpoint_add_internal(target, asid, length, type);
260         }
261 }
262
263 int hybrid_breakpoint_add(struct target *target,
264         target_addr_t address,
265         uint32_t asid,
266         uint32_t length,
267         enum breakpoint_type type)
268 {
269         int retval = ERROR_OK;
270         if (target->smp) {
271                 struct target_list *head;
272                 struct target *curr;
273                 head = target->head;
274                 while (head) {
275                         curr = head->target;
276                         retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
277                         if (retval != ERROR_OK)
278                                 return retval;
279                         head = head->next;
280                 }
281                 return retval;
282         } else
283                 return hybrid_breakpoint_add_internal(target, address, asid, length, type);
284 }
285
286 /* free up a breakpoint */
287 static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove)
288 {
289         struct breakpoint *breakpoint = target->breakpoints;
290         struct breakpoint **breakpoint_p = &target->breakpoints;
291         int retval;
292
293         while (breakpoint) {
294                 if (breakpoint == breakpoint_to_remove)
295                         break;
296                 breakpoint_p = &breakpoint->next;
297                 breakpoint = breakpoint->next;
298         }
299
300         if (!breakpoint)
301                 return;
302
303         retval = target_remove_breakpoint(target, breakpoint);
304
305         LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval);
306         (*breakpoint_p) = breakpoint->next;
307         free(breakpoint->orig_instr);
308         free(breakpoint);
309 }
310
311 static int breakpoint_remove_internal(struct target *target, target_addr_t address)
312 {
313         struct breakpoint *breakpoint = target->breakpoints;
314
315         while (breakpoint) {
316                 if ((breakpoint->address == address) ||
317                     (breakpoint->address == 0 && breakpoint->asid == address))
318                         break;
319                 breakpoint = breakpoint->next;
320         }
321
322         if (breakpoint) {
323                 breakpoint_free(target, breakpoint);
324                 return 1;
325         } else {
326                 if (!target->smp)
327                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
328                 return 0;
329         }
330 }
331
332 static void breakpoint_remove_all_internal(struct target *target)
333 {
334         struct breakpoint *breakpoint = target->breakpoints;
335
336         while (breakpoint) {
337                 struct breakpoint *tmp = breakpoint;
338                 breakpoint = breakpoint->next;
339                 breakpoint_free(target, tmp);
340         }
341 }
342
343 void breakpoint_remove(struct target *target, target_addr_t address)
344 {
345         if (target->smp) {
346                 unsigned int num_breakpoints = 0;
347                 struct target_list *head;
348                 struct target *curr;
349                 head = target->head;
350                 while (head) {
351                         curr = head->target;
352                         num_breakpoints += breakpoint_remove_internal(curr, address);
353                         head = head->next;
354                 }
355                 if (!num_breakpoints)
356                         LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
357         } else {
358                 breakpoint_remove_internal(target, address);
359         }
360 }
361
362 void breakpoint_remove_all(struct target *target)
363 {
364         if (target->smp) {
365                 struct target_list *head;
366                 struct target *curr;
367                 head = target->head;
368                 while (head) {
369                         curr = head->target;
370                         breakpoint_remove_all_internal(curr);
371                         head = head->next;
372                 }
373         } else {
374                 breakpoint_remove_all_internal(target);
375         }
376 }
377
378 static void breakpoint_clear_target_internal(struct target *target)
379 {
380         LOG_DEBUG("Delete all breakpoints for target: %s",
381                 target_name(target));
382         while (target->breakpoints)
383                 breakpoint_free(target, target->breakpoints);
384 }
385
386 void breakpoint_clear_target(struct target *target)
387 {
388         if (target->smp) {
389                 struct target_list *head;
390                 struct target *curr;
391                 head = target->head;
392                 while (head) {
393                         curr = head->target;
394                         breakpoint_clear_target_internal(curr);
395                         head = head->next;
396                 }
397         } else {
398                 breakpoint_clear_target_internal(target);
399         }
400 }
401
402 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
403 {
404         struct breakpoint *breakpoint = target->breakpoints;
405
406         while (breakpoint) {
407                 if (breakpoint->address == address)
408                         return breakpoint;
409                 breakpoint = breakpoint->next;
410         }
411
412         return NULL;
413 }
414
415 int watchpoint_add_internal(struct target *target, target_addr_t address,
416                 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
417 {
418         struct watchpoint *watchpoint = target->watchpoints;
419         struct watchpoint **watchpoint_p = &target->watchpoints;
420         int retval;
421         const char *reason;
422
423         while (watchpoint) {
424                 if (watchpoint->address == address) {
425                         if (watchpoint->length != length
426                                 || watchpoint->value != value
427                                 || watchpoint->mask != mask
428                                 || watchpoint->rw != rw) {
429                                 LOG_ERROR("address " TARGET_ADDR_FMT
430                                         " already has watchpoint %d",
431                                         address, watchpoint->unique_id);
432                                 return ERROR_FAIL;
433                         }
434
435                         /* ignore duplicate watchpoint */
436                         return ERROR_OK;
437                 }
438                 watchpoint_p = &watchpoint->next;
439                 watchpoint = watchpoint->next;
440         }
441
442         (*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
443         (*watchpoint_p)->address = address;
444         (*watchpoint_p)->length = length;
445         (*watchpoint_p)->value = value;
446         (*watchpoint_p)->mask = mask;
447         (*watchpoint_p)->rw = rw;
448         (*watchpoint_p)->unique_id = bpwp_unique_id++;
449
450         retval = target_add_watchpoint(target, *watchpoint_p);
451         switch (retval) {
452                 case ERROR_OK:
453                         break;
454                 case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
455                         reason = "resource not available";
456                         goto bye;
457                 case ERROR_TARGET_NOT_HALTED:
458                         reason = "target running";
459                         goto bye;
460                 default:
461                         reason = "unrecognized error";
462 bye:
463                         LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
464                                 watchpoint_rw_strings[(*watchpoint_p)->rw],
465                                 address, reason);
466                         free(*watchpoint_p);
467                         *watchpoint_p = NULL;
468                         return retval;
469         }
470
471         LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT
472                         " of length 0x%8.8" PRIx32 " (WPID: %d)",
473                 target->coreid,
474                 watchpoint_rw_strings[(*watchpoint_p)->rw],
475                 (*watchpoint_p)->address,
476                 (*watchpoint_p)->length,
477                 (*watchpoint_p)->unique_id);
478
479         return ERROR_OK;
480 }
481
482 int watchpoint_add(struct target *target, target_addr_t address,
483                 uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
484 {
485         int retval = ERROR_OK;
486         if (target->smp) {
487                 struct target_list *head;
488                 struct target *curr;
489                 head = target->head;
490
491                 while (head != (struct target_list *)NULL) {
492                         curr = head->target;
493                         retval = watchpoint_add_internal(curr, address, length, rw, value,
494                                         mask);
495                         if (retval != ERROR_OK)
496                                 return retval;
497                         head = head->next;
498                 }
499                 return retval;
500         } else {
501                 return watchpoint_add_internal(target, address, length, rw, value,
502                                 mask);
503         }
504 }
505
506 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
507 {
508         struct watchpoint *watchpoint = target->watchpoints;
509         struct watchpoint **watchpoint_p = &target->watchpoints;
510         int retval;
511
512         while (watchpoint) {
513                 if (watchpoint == watchpoint_to_remove)
514                         break;
515                 watchpoint_p = &watchpoint->next;
516                 watchpoint = watchpoint->next;
517         }
518
519         if (!watchpoint)
520                 return;
521         retval = target_remove_watchpoint(target, watchpoint);
522         LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
523         (*watchpoint_p) = watchpoint->next;
524         free(watchpoint);
525 }
526
527 int watchpoint_remove_internal(struct target *target, target_addr_t address)
528 {
529         struct watchpoint *watchpoint = target->watchpoints;
530
531         while (watchpoint) {
532                 if (watchpoint->address == address)
533                         break;
534                 watchpoint = watchpoint->next;
535         }
536
537         if (watchpoint) {
538                 watchpoint_free(target, watchpoint);
539                 return 1;
540         } else {
541                 if (!target->smp)
542                         LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
543                 return 0;
544         }
545 }
546
547 void watchpoint_remove(struct target *target, target_addr_t address)
548 {
549         if (target->smp) {
550                 unsigned int num_watchpoints = 0;
551                 struct target_list *head;
552                 struct target *curr;
553                 head = target->head;
554                 while (head) {
555                         curr = head->target;
556                         num_watchpoints += watchpoint_remove_internal(curr, address);
557                         head = head->next;
558                 }
559                 if (num_watchpoints == 0)
560                         LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
561         } else {
562                 watchpoint_remove_internal(target, address);
563         }
564 }
565
566 void watchpoint_clear_target(struct target *target)
567 {
568         LOG_DEBUG("Delete all watchpoints for target: %s",
569                 target_name(target));
570         while (target->watchpoints)
571                 watchpoint_free(target, target->watchpoints);
572 }
573
574 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
575                    target_addr_t *address)
576 {
577         int retval;
578         struct watchpoint *hit_watchpoint;
579
580         retval = target_hit_watchpoint(target, &hit_watchpoint);
581         if (retval != ERROR_OK)
582                 return ERROR_FAIL;
583
584         *rw = hit_watchpoint->rw;
585         *address = hit_watchpoint->address;
586
587         LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
588                 hit_watchpoint->address,
589                 hit_watchpoint->unique_id);
590
591         return ERROR_OK;
592 }