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 
breakpoint_add_internal(struct target * target,target_addr_t address,uint32_t length,enum breakpoint_type type)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 
context_breakpoint_add_internal(struct target * target,uint32_t asid,uint32_t length,enum breakpoint_type type)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 
hybrid_breakpoint_add_internal(struct target * target,target_addr_t address,uint32_t asid,uint32_t length,enum breakpoint_type type)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 
breakpoint_add(struct target * target,target_addr_t address,uint32_t length,enum breakpoint_type type)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 
context_breakpoint_add(struct target * target,uint32_t asid,uint32_t length,enum breakpoint_type type)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 
hybrid_breakpoint_add(struct target * target,target_addr_t address,uint32_t asid,uint32_t length,enum breakpoint_type type)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 */
breakpoint_free(struct target * target,struct breakpoint * breakpoint_to_remove)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 
breakpoint_remove_internal(struct target * target,target_addr_t address)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 
breakpoint_remove_all_internal(struct target * target)336 static void breakpoint_remove_all_internal(struct target *target)
337 {
338 	struct breakpoint *breakpoint = target->breakpoints;
339 
340 	while (breakpoint) {
341 		struct breakpoint *tmp = breakpoint;
342 		breakpoint = breakpoint->next;
343 		breakpoint_free(target, tmp);
344 	}
345 }
346 
breakpoint_remove(struct target * target,target_addr_t address)347 void breakpoint_remove(struct target *target, target_addr_t address)
348 {
349 	int found = 0;
350 	if (target->smp) {
351 		struct target_list *head;
352 		struct target *curr;
353 		head = target->head;
354 		while (head != (struct target_list *)NULL) {
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 " TARGET_ADDR_FMT " found", address);
361 	} else
362 		breakpoint_remove_internal(target, address);
363 }
364 
breakpoint_remove_all(struct target * target)365 void breakpoint_remove_all(struct target *target)
366 {
367 	if (target->smp) {
368 		struct target_list *head;
369 		struct target *curr;
370 		head = target->head;
371 		while (head != (struct target_list *)NULL) {
372 			curr = head->target;
373 			breakpoint_remove_all_internal(curr);
374 			head = head->next;
375 		}
376 	} else {
377 		breakpoint_remove_all_internal(target);
378 	}
379 }
380 
breakpoint_clear_target_internal(struct target * target)381 static void breakpoint_clear_target_internal(struct target *target)
382 {
383 	LOG_DEBUG("Delete all breakpoints for target: %s",
384 		target_name(target));
385 	while (target->breakpoints != NULL)
386 		breakpoint_free(target, target->breakpoints);
387 }
388 
breakpoint_clear_target(struct target * target)389 void breakpoint_clear_target(struct target *target)
390 {
391 	if (target->smp) {
392 		struct target_list *head;
393 		struct target *curr;
394 		head = target->head;
395 		while (head != (struct target_list *)NULL) {
396 			curr = head->target;
397 			breakpoint_clear_target_internal(curr);
398 			head = head->next;
399 		}
400 	} else
401 		breakpoint_clear_target_internal(target);
402 
403 }
404 
breakpoint_find(struct target * target,target_addr_t address)405 struct breakpoint *breakpoint_find(struct target *target, target_addr_t address)
406 {
407 	struct breakpoint *breakpoint = target->breakpoints;
408 
409 	while (breakpoint) {
410 		if (breakpoint->address == address)
411 			return breakpoint;
412 		breakpoint = breakpoint->next;
413 	}
414 
415 	return NULL;
416 }
417 
watchpoint_add(struct target * target,target_addr_t address,uint32_t length,enum watchpoint_rw rw,uint32_t value,uint32_t mask)418 int watchpoint_add(struct target *target, target_addr_t address, uint32_t length,
419 	enum watchpoint_rw rw, uint32_t value, uint32_t mask)
420 {
421 	struct watchpoint *watchpoint = target->watchpoints;
422 	struct watchpoint **watchpoint_p = &target->watchpoints;
423 	int retval;
424 	const char *reason;
425 
426 	while (watchpoint) {
427 		if (watchpoint->address == address) {
428 			if (watchpoint->length != length
429 				|| watchpoint->value != value
430 				|| watchpoint->mask != mask
431 				|| watchpoint->rw != rw) {
432 				LOG_ERROR("address " TARGET_ADDR_FMT
433 					" already has watchpoint %d",
434 					address, watchpoint->unique_id);
435 				return ERROR_FAIL;
436 			}
437 
438 			/* ignore duplicate watchpoint */
439 			return ERROR_OK;
440 		}
441 		watchpoint_p = &watchpoint->next;
442 		watchpoint = watchpoint->next;
443 	}
444 
445 	(*watchpoint_p) = calloc(1, sizeof(struct watchpoint));
446 	(*watchpoint_p)->address = address;
447 	(*watchpoint_p)->length = length;
448 	(*watchpoint_p)->value = value;
449 	(*watchpoint_p)->mask = mask;
450 	(*watchpoint_p)->rw = rw;
451 	(*watchpoint_p)->unique_id = bpwp_unique_id++;
452 
453 	retval = target_add_watchpoint(target, *watchpoint_p);
454 	switch (retval) {
455 		case ERROR_OK:
456 			break;
457 		case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
458 			reason = "resource not available";
459 			goto bye;
460 		case ERROR_TARGET_NOT_HALTED:
461 			reason = "target running";
462 			goto bye;
463 		default:
464 			reason = "unrecognized error";
465 bye:
466 			LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s",
467 				watchpoint_rw_strings[(*watchpoint_p)->rw],
468 				address, reason);
469 			free(*watchpoint_p);
470 			*watchpoint_p = NULL;
471 			return retval;
472 	}
473 
474 	LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT
475 		" of length 0x%8.8" PRIx32 " (WPID: %d)",
476 		watchpoint_rw_strings[(*watchpoint_p)->rw],
477 		(*watchpoint_p)->address,
478 		(*watchpoint_p)->length,
479 		(*watchpoint_p)->unique_id);
480 
481 	return ERROR_OK;
482 }
483 
watchpoint_free(struct target * target,struct watchpoint * watchpoint_to_remove)484 static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove)
485 {
486 	struct watchpoint *watchpoint = target->watchpoints;
487 	struct watchpoint **watchpoint_p = &target->watchpoints;
488 	int retval;
489 
490 	while (watchpoint) {
491 		if (watchpoint == watchpoint_to_remove)
492 			break;
493 		watchpoint_p = &watchpoint->next;
494 		watchpoint = watchpoint->next;
495 	}
496 
497 	if (watchpoint == NULL)
498 		return;
499 	retval = target_remove_watchpoint(target, watchpoint);
500 	LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval);
501 	(*watchpoint_p) = watchpoint->next;
502 	free(watchpoint);
503 }
504 
watchpoint_remove(struct target * target,target_addr_t address)505 void watchpoint_remove(struct target *target, target_addr_t address)
506 {
507 	struct watchpoint *watchpoint = target->watchpoints;
508 
509 	while (watchpoint) {
510 		if (watchpoint->address == address)
511 			break;
512 		watchpoint = watchpoint->next;
513 	}
514 
515 	if (watchpoint)
516 		watchpoint_free(target, watchpoint);
517 	else
518 		LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address);
519 }
520 
watchpoint_clear_target(struct target * target)521 void watchpoint_clear_target(struct target *target)
522 {
523 	LOG_DEBUG("Delete all watchpoints for target: %s",
524 		target_name(target));
525 	while (target->watchpoints != NULL)
526 		watchpoint_free(target, target->watchpoints);
527 }
528 
watchpoint_hit(struct target * target,enum watchpoint_rw * rw,target_addr_t * address)529 int watchpoint_hit(struct target *target, enum watchpoint_rw *rw,
530 		   target_addr_t *address)
531 {
532 	int retval;
533 	struct watchpoint *hit_watchpoint;
534 
535 	retval = target_hit_watchpoint(target, &hit_watchpoint);
536 	if (retval != ERROR_OK)
537 		return ERROR_FAIL;
538 
539 	*rw = hit_watchpoint->rw;
540 	*address = hit_watchpoint->address;
541 
542 	LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)",
543 		hit_watchpoint->address,
544 		hit_watchpoint->unique_id);
545 
546 	return ERROR_OK;
547 }
548