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