1 /* radare2 - LGPL - Copyright 2009-2020 - pancake */
2 
3 #include <r_bp.h>
4 #include <config.h>
5 
6 R_LIB_VERSION (r_bp);
7 
8 static struct r_bp_plugin_t *bp_static_plugins[] =
9 	{ R_BP_STATIC_PLUGINS };
10 
r_bp_item_free(RBreakpointItem * b)11 static void r_bp_item_free (RBreakpointItem *b) {
12 	free (b->name);
13 	free (b->bbytes);
14 	free (b->obytes);
15 	free (b->module_name);
16 	free (b->data);
17 	free (b->cond);
18 	free (b);
19 }
20 
r_bp_new(void)21 R_API RBreakpoint *r_bp_new(void) {
22 	int i;
23 	RBreakpointPlugin *static_plugin;
24 	RBreakpoint *bp = R_NEW0 (RBreakpoint);
25 	if (!bp) {
26 		return NULL;
27 	}
28 	bp->bps_idx_count = 16;
29 	bp->bps_idx = R_NEWS0 (RBreakpointItem*, bp->bps_idx_count);
30 	bp->stepcont = R_BP_CONT_NORMAL;
31 	bp->traces = r_bp_traptrace_new ();
32 	bp->cb_printf = (PrintfCallback)printf;
33 	bp->bps = r_list_newf ((RListFree)r_bp_item_free);
34 	bp->plugins = r_list_newf ((RListFree)free);
35 	bp->nhwbps = 0;
36 	for (i = 0; bp_static_plugins[i]; i++) {
37 		static_plugin = R_NEW (RBreakpointPlugin);
38 		memcpy (static_plugin, bp_static_plugins[i],
39 			sizeof (RBreakpointPlugin));
40 		r_bp_plugin_add (bp, static_plugin);
41 	}
42 	memset (&bp->iob, 0, sizeof (bp->iob));
43 	return bp;
44 }
45 
r_bp_free(RBreakpoint * bp)46 R_API RBreakpoint *r_bp_free(RBreakpoint *bp) {
47 	r_list_free (bp->bps);
48 	r_list_free (bp->plugins);
49 	r_list_free (bp->traces);
50 	free (bp->bps_idx);
51 	free (bp);
52 	return NULL;
53 }
54 
r_bp_get_bytes(RBreakpoint * bp,ut8 * buf,int len,int endian,int idx)55 R_API int r_bp_get_bytes(RBreakpoint *bp, ut8 *buf, int len, int endian, int idx) {
56 	int i;
57 	struct r_bp_arch_t *b;
58 	if (bp->cur) {
59 		// find matching size breakpoint
60 repeat:
61 		for (i = 0; i < bp->cur->nbps; i++) {
62 			b = &bp->cur->bps[i];
63 			if (bp->cur->bps[i].bits) {
64 				if (bp->bits != bp->cur->bps[i].bits) {
65 					continue;
66 				}
67 			}
68 			if (bp->cur->bps[i].length == len && bp->cur->bps[i].endian == endian) {
69 				memcpy (buf, b->bytes, b->length);
70 				return b->length;
71 			}
72 		}
73 		if (len != 4) {
74 			len = 4;
75 			goto repeat;
76 		}
77 		/* if not found try to pad with the first one */
78 		b = &bp->cur->bps[0];
79 		if (len % b->length) {
80 			eprintf ("No matching bpsize\n");
81 			return 0;
82 		}
83 		for (i = 0; i < len; i++) {
84 			memcpy (buf + i, b->bytes, b->length);
85 		}
86 		return b->length;
87 	}
88 	return 0;
89 }
90 
r_bp_get_at(RBreakpoint * bp,ut64 addr)91 R_API RBreakpointItem *r_bp_get_at(RBreakpoint *bp, ut64 addr) {
92 	RListIter *iter;
93 	RBreakpointItem *b;
94 	r_list_foreach(bp->bps, iter, b) {
95 		if (b->addr == addr) {
96 			return b;
97 		}
98 	}
99 	return NULL;
100 }
101 
inRange(RBreakpointItem * b,ut64 addr)102 static inline bool inRange(RBreakpointItem *b, ut64 addr) {
103 	return (addr >= b->addr && addr < (b->addr + b->size));
104 }
105 
matchProt(RBreakpointItem * b,int perm)106 static inline bool matchProt(RBreakpointItem *b, int perm) {
107 	return (!perm || (perm && b->perm));
108 }
109 
r_bp_get_in(RBreakpoint * bp,ut64 addr,int perm)110 R_API RBreakpointItem *r_bp_get_in(RBreakpoint *bp, ut64 addr, int perm) {
111 	RBreakpointItem *b;
112 	RListIter *iter;
113 	r_list_foreach (bp->bps, iter, b) {
114 		// eprintf ("---ataddr--- 0x%08"PFMT64x" %d %d %x\n", b->addr, b->size, b->recoil, b->perm);
115 		// Check addr within range and provided perm matches (or null)
116 		if (inRange (b, addr) && matchProt (b, perm)) {
117 			return b;
118 		}
119 	}
120 	return NULL;
121 }
122 
r_bp_enable(RBreakpoint * bp,ut64 addr,int set,int count)123 R_API RBreakpointItem *r_bp_enable(RBreakpoint *bp, ut64 addr, int set, int count) {
124 	RBreakpointItem *b = r_bp_get_in (bp, addr, 0);
125 	if (b) {
126 		b->enabled = set;
127 		b->togglehits = count;
128 		return b;
129 	}
130 	return NULL;
131 }
132 
r_bp_enable_all(RBreakpoint * bp,int set)133 R_API int r_bp_enable_all(RBreakpoint *bp, int set) {
134 	RListIter *iter;
135 	RBreakpointItem *b;
136 	r_list_foreach (bp->bps, iter, b) {
137 		b->enabled = set;
138 	}
139 	return true;
140 }
141 
r_bp_stepy_continuation(RBreakpoint * bp)142 R_API int r_bp_stepy_continuation(RBreakpoint *bp) {
143 	// TODO: implement
144 	return bp->stepcont;
145 }
146 
unlinkBreakpoint(RBreakpoint * bp,RBreakpointItem * b)147 static void unlinkBreakpoint(RBreakpoint *bp, RBreakpointItem *b) {
148 	int i;
149 	for (i = 0; i < bp->bps_idx_count; i++) {
150 		if (bp->bps_idx[i] == b) {
151 			bp->bps_idx[i] = NULL;
152 		}
153 	}
154 	r_list_delete_data (bp->bps, b);
155 }
156 
157 /* TODO: detect overlapping of breakpoints */
r_bp_add(RBreakpoint * bp,const ut8 * obytes,ut64 addr,int size,int hw,int perm)158 static RBreakpointItem *r_bp_add(RBreakpoint *bp, const ut8 *obytes, ut64 addr, int size, int hw, int perm) {
159 	int ret;
160 	RBreakpointItem *b;
161 	if (addr == UT64_MAX || size < 1) {
162 		return NULL;
163 	}
164 	if (r_bp_get_in (bp, addr, perm)) {
165 		eprintf ("Breakpoint already set at this address.\n");
166 		return NULL;
167 	}
168 	b = r_bp_item_new (bp);
169 	if (!b) {
170 		return NULL;
171 	}
172 	b->addr = addr + bp->delta;
173 	if (bp->baddr > addr) {
174 		eprintf ("base addr should not be larger than the breakpoint address.\n");
175 	}
176 	if (bp->bpinmaps && !r_bp_is_valid (bp, b)) {
177 		eprintf ("WARNING: Breakpoint won't be placed since it's not in a valid map.\n"
178 			 "You can bypass this check by setting dbg.bpinmaps to false.\n");
179 	}
180 	b->delta = addr - bp->baddr;
181 	b->size = size;
182 	b->enabled = true;
183 	b->perm = perm;
184 	b->hw = hw;
185 	// NOTE: for hw breakpoints there are no bytes to save/restore
186 	if (!hw) {
187 		b->bbytes = calloc (size + 16, 1);
188 		if (!b->bbytes) {
189 			return NULL;
190 		}
191 		if (obytes) {
192 			b->obytes = malloc (size);
193 			if (!b->obytes) {
194 				free (b->bbytes);
195 				return NULL;
196 			}
197 			memcpy (b->obytes, obytes, size);
198 		} else {
199 			b->obytes = NULL;
200 		}
201 		ret = r_bp_get_bytes (bp, b->bbytes, size, bp->endian, 0);
202 		if (ret != size) {
203 			eprintf ("Cannot get breakpoint bytes. No architecture selected?\n");
204 		}
205 	}
206 	bp->nbps++;
207 	r_list_append (bp->bps, b);
208 	return b;
209 }
210 
r_bp_add_fault(RBreakpoint * bp,ut64 addr,int size,int perm)211 R_API int r_bp_add_fault(RBreakpoint *bp, ut64 addr, int size, int perm) {
212 	// TODO
213 	return false;
214 }
215 
r_bp_add_sw(RBreakpoint * bp,ut64 addr,int size,int perm)216 R_API RBreakpointItem* r_bp_add_sw(RBreakpoint *bp, ut64 addr, int size, int perm) {
217 	RBreakpointItem *item;
218 	ut8 *bytes;
219 	if (size < 1) {
220 		size = 1;
221 	}
222 	if (!(bytes = calloc (1, size))) {
223 		return NULL;
224 	}
225 	memset (bytes, 0, size);
226 	if (bp->iob.read_at) {
227 		bp->iob.read_at (bp->iob.io, addr, bytes, size);
228 	}
229 	item = r_bp_add (bp, bytes, addr, size, R_BP_TYPE_SW, perm);
230 	free (bytes);
231 	return item;
232 }
233 
r_bp_add_hw(RBreakpoint * bp,ut64 addr,int size,int perm)234 R_API RBreakpointItem* r_bp_add_hw(RBreakpoint *bp, ut64 addr, int size, int perm) {
235 	return r_bp_add (bp, NULL, addr, size, R_BP_TYPE_HW, perm);
236 }
237 
r_bp_del_all(RBreakpoint * bp)238 R_API int r_bp_del_all(RBreakpoint *bp) {
239 	int i;
240 	if (!r_list_empty (bp->bps)) {
241 		r_list_purge (bp->bps);
242 		for (i = 0; i < bp->bps_idx_count; i++) {
243 			bp->bps_idx[i] = NULL;
244 		}
245 		return true;
246 	}
247 	return false;
248 }
249 
r_bp_del(RBreakpoint * bp,ut64 addr)250 R_API int r_bp_del(RBreakpoint *bp, ut64 addr) {
251 	RListIter *iter;
252 	RBreakpointItem *b;
253 	/* No _safe loop necessary because we return immediately after the delete. */
254 	r_list_foreach (bp->bps, iter, b) {
255 		if (b->addr == addr) {
256 			unlinkBreakpoint (bp, b);
257 			// r_list_delete (bp->bps, iter);
258 			return true;
259 		}
260 	}
261 	return false;
262 }
263 
r_bp_set_trace(RBreakpoint * bp,ut64 addr,int set)264 R_API int r_bp_set_trace(RBreakpoint *bp, ut64 addr, int set) {
265 	RBreakpointItem *b = r_bp_get_in (bp, addr, 0);
266 	if (b) {
267 		b->trace = set;
268 		return true;
269 	}
270 	return false;
271 }
272 
r_bp_set_trace_all(RBreakpoint * bp,int set)273 R_API int r_bp_set_trace_all(RBreakpoint *bp, int set) {
274 	RListIter *iter;
275 	RBreakpointItem *b;
276 	r_list_foreach (bp->bps, iter, b) {
277 		b->trace = set;
278 	}
279 	return true;
280 }
281 
282 // TODO: deprecate
r_bp_list(RBreakpoint * bp,int rad)283 R_API int r_bp_list(RBreakpoint *bp, int rad) {
284 	int n = 0;
285 	RBreakpointItem *b;
286 	RListIter *iter;
287 	PJ *pj = NULL;
288 	if (rad == 'j') {
289 		pj = pj_new ();
290 		if (!pj) {
291 			return 0;
292 		}
293 		pj_a (pj);
294 	}
295 	//eprintf ("Breakpoint list:\n");
296 	r_list_foreach (bp->bps, iter, b) {
297 		if (pj) {
298 			pj_o (pj);
299 			pj_kN (pj, "addr", b->addr);
300 			pj_ki (pj, "size", b->size);
301 			pj_ks (pj, "perm", r_str_rwx_i (b->perm & 7)); /* filter out R_BP_PROT_ACCESS */
302 			pj_kb (pj, "hw", b->hw);
303 			pj_kb (pj, "trace", b->trace);
304 			pj_kb (pj, "enabled", b->enabled);
305 			pj_kb (pj, "valid", r_bp_is_valid (bp, b));
306 			pj_ks (pj, "data", r_str_get (b->data));
307 			pj_ks (pj, "cond", r_str_get (b->cond));
308 			pj_end (pj);
309 		} else if (rad) {
310 			if (b->module_name) {
311 				bp->cb_printf ("dbm %s %"PFMT64d"\n", b->module_name, b->module_delta);
312 			} else {
313 				bp->cb_printf ("db 0x%08"PFMT64x"\n", b->addr);
314 			}
315 		} else {
316 			bp->cb_printf ("0x%08"PFMT64x" - 0x%08"PFMT64x \
317 				" %d %c%c%c %s %s %s %s cmd=\"%s\" cond=\"%s\" " \
318 				"name=\"%s\" module=\"%s\"\n",
319 				b->addr, b->addr + b->size, b->size,
320 				((b->perm & R_BP_PROT_READ) | (b->perm & R_BP_PROT_ACCESS)) ? 'r' : '-',
321 				((b->perm & R_BP_PROT_WRITE)| (b->perm & R_BP_PROT_ACCESS)) ? 'w' : '-',
322 				(b->perm & R_BP_PROT_EXEC) ? 'x' : '-',
323 				b->hw ? "hw": "sw",
324 				b->trace ? "trace" : "break",
325 				b->enabled ? "enabled" : "disabled",
326 				r_bp_is_valid (bp, b) ? "valid" : "invalid",
327 				r_str_get (b->data),
328 				r_str_get (b->cond),
329 				r_str_get (b->name),
330 				r_str_get (b->module_name));
331 		}
332 		n++;
333 	}
334 	if (pj) {
335 		pj_end (pj);
336 		bp->cb_printf ("%s\n", pj_string (pj));
337 		pj_free (pj);
338 	}
339 	return n;
340 }
341 
r_bp_item_new(RBreakpoint * bp)342 R_API RBreakpointItem *r_bp_item_new (RBreakpoint *bp) {
343 	int i, j;
344 	/* find empty slot */
345 	for (i = 0; i < bp->bps_idx_count; i++) {
346 		if (!bp->bps_idx[i]) {
347 			goto return_slot;
348 		}
349 	}
350 	/* allocate new slot */
351 	bp->bps_idx_count += 16; // allocate space for 16 more bps
352 	RBreakpointItem **newbps = realloc (bp->bps_idx, bp->bps_idx_count * sizeof (RBreakpointItem*));
353 	if (newbps) {
354 		bp->bps_idx = newbps;
355 	} else {
356 		bp->bps_idx_count -= 16; // allocate space for 16 more bps
357 	}
358 	for (j = i; j < bp->bps_idx_count; j++) {
359 		bp->bps_idx[j] = NULL;
360 	}
361 return_slot:
362 	/* empty slot */
363 	return (bp->bps_idx[i] = R_NEW0 (RBreakpointItem));
364 }
365 
r_bp_get_index(RBreakpoint * bp,int idx)366 R_API RBreakpointItem *r_bp_get_index(RBreakpoint *bp, int idx) {
367 	if (idx >= 0 && idx < bp->bps_idx_count) {
368 		return bp->bps_idx[idx];
369 	}
370 	return NULL;
371 }
372 
r_bp_get_index_at(RBreakpoint * bp,ut64 addr)373 R_API int r_bp_get_index_at (RBreakpoint *bp, ut64 addr) {
374 	int i;
375 	for (i = 0; i< bp->bps_idx_count; i++) {
376 		if (bp->bps_idx[i] && bp->bps_idx[i]->addr == addr) {
377 			return i;
378 		}
379 	}
380 	return -1;
381 }
382 
r_bp_del_index(RBreakpoint * bp,int idx)383 R_API int r_bp_del_index(RBreakpoint *bp, int idx) {
384 	if (idx >= 0 && idx < bp->bps_idx_count) {
385 		r_list_delete_data (bp->bps, bp->bps_idx[idx]);
386 		bp->bps_idx[idx] = 0;
387 		return true;
388 	}
389 	return false;
390 }
391 
r_bp_size(RBreakpoint * bp)392 R_API int r_bp_size(RBreakpoint *bp) {
393 	RBreakpointArch *bpa;
394 	int i, bpsize = 8;
395 	if (!bp || !bp->cur) {
396 		return 0;
397 	}
398 	for (i = 0; bp->cur->bps[i].bytes; i++) {
399 		bpa = &bp->cur->bps[i];
400 		if (bpa->bits && bpa->bits != bp->bits) {
401 			continue;
402 		}
403 		if (bpa->length < bpsize) {
404 			bpsize = bpa->length;
405 		}
406 	}
407 	return bpsize;
408 }
409 
410 // Check if the breakpoint is in a valid map
r_bp_is_valid(RBreakpoint * bp,RBreakpointItem * b)411 R_API bool r_bp_is_valid(RBreakpoint *bp, RBreakpointItem *b) {
412 	if (!bp->bpinmaps) {
413 		return true;
414 	}
415 
416 	return bp->corebind.isMapped (bp->corebind.core, b->addr, b->perm);
417 }
418