1 /* radare - LGPL - Copyright 2009-2020 - pancake, nibble */
2
3 #include <r_types.h>
4 #include <r_list.h>
5 #include <r_flag.h>
6 #include <r_core.h>
7 #include <r_bin.h>
8 #include <ht_uu.h>
9 #include <r_util/r_graph_drawable.h>
10
11 #include <string.h>
12
13 HEAPTYPE (ut64);
14
15 // used to speedup strcmp with rconfig.get in loops
16 enum {
17 R2_ARCH_THUMB,
18 R2_ARCH_ARM32,
19 R2_ARCH_ARM64,
20 R2_ARCH_MIPS
21 };
22 // 128M
23 #define MAX_SCAN_SIZE 0x7ffffff
24
loganal(ut64 from,ut64 to,int depth)25 static void loganal(ut64 from, ut64 to, int depth) {
26 r_cons_clear_line (1);
27 eprintf ("0x%08"PFMT64x" > 0x%08"PFMT64x" %d\r", from, to, depth);
28 }
29
cmpsize(const void * a,const void * b)30 static int cmpsize (const void *a, const void *b) {
31 ut64 as = r_anal_function_linear_size ((RAnalFunction *) a);
32 ut64 bs = r_anal_function_linear_size ((RAnalFunction *) b);
33 return (as> bs)? 1: (as< bs)? -1: 0;
34 }
35
cmpfcncc(const void * _a,const void * _b)36 static int cmpfcncc(const void *_a, const void *_b) {
37 RAnalFunction *a = (RAnalFunction *)_a;
38 RAnalFunction *b = (RAnalFunction *)_b;
39 ut64 as = r_anal_function_complexity (a);
40 ut64 bs = r_anal_function_complexity (b);
41 return (as > bs)? 1: (as < bs)? -1: 0;
42 }
43
cmpedges(const void * _a,const void * _b)44 static int cmpedges(const void *_a, const void *_b) {
45 const RAnalFunction *a = _a, *b = _b;
46 int as, bs;
47 r_anal_function_count_edges (a, &as);
48 r_anal_function_count_edges (b, &bs);
49 return (as > bs)? 1: (as < bs)? -1: 0;
50 }
51
cmpframe(const void * _a,const void * _b)52 static int cmpframe(const void *_a, const void *_b) {
53 const RAnalFunction *a = _a, *b = _b;
54 int as = a->maxstack;
55 int bs = b->maxstack;
56 return (as > bs)? 1: (as < bs)? -1: 0;
57 }
58
cmpxrefs(const void * _a,const void * _b)59 static int cmpxrefs(const void *_a, const void *_b) {
60 const RAnalFunction *a = _a, *b = _b;
61 int as = a->meta.numrefs;
62 int bs = b->meta.numrefs;
63 return (as > bs)? 1: (as < bs)? -1: 0;
64 }
65
cmpname(const void * _a,const void * _b)66 static int cmpname(const void *_a, const void *_b) {
67 const RAnalFunction *a = _a, *b = _b;
68 int as = strcmp (a->name, b->name);
69 int bs = strcmp (b->name, a->name);
70 return (as > bs)? 1: (as < bs)? -1: 0;
71 }
72
cmpcalls(const void * _a,const void * _b)73 static int cmpcalls(const void *_a, const void *_b) {
74 const RAnalFunction *a = _a, *b = _b;
75 int as = a->meta.numcallrefs;
76 int bs = b->meta.numcallrefs;
77 return (as > bs)? 1: (as < bs)? -1: 0;
78 }
79
cmpnbbs(const void * _a,const void * _b)80 static int cmpnbbs(const void *_a, const void *_b) {
81 const RAnalFunction *a = _a, *b = _b;
82 ut64 as = r_list_length (a->bbs);
83 ut64 bs = r_list_length (b->bbs);
84 return (as> bs)? 1: (as< bs)? -1: 0;
85 }
86
cmpaddr(const void * _a,const void * _b)87 static int cmpaddr(const void *_a, const void *_b) {
88 const RAnalFunction *a = _a, *b = _b;
89 return (a->addr > b->addr)? 1: (a->addr < b->addr)? -1: 0;
90 }
91
get_function_name(RCore * core,ut64 addr)92 static char *get_function_name(RCore *core, ut64 addr) {
93 RBinFile *bf = r_bin_cur (core->bin);
94 if (bf && bf->o) {
95 RBinSymbol *sym = ht_up_find (bf->o->addr2klassmethod, addr, NULL);
96 if (sym && sym->classname && sym->name) {
97 return r_str_newf ("method.%s.%s", sym->classname, sym->name);
98 }
99 }
100 RFlagItem *flag = r_core_flag_get_by_spaces (core->flags, addr);
101 return (flag && flag->name) ? strdup (flag->name) : NULL;
102 }
103
104 static RCore *mycore = NULL;
105
106 // XXX: copypaste from anal/data.c
107 #define MINLEN 1
is_string(const ut8 * buf,int size,int * len)108 static int is_string(const ut8 *buf, int size, int *len) {
109 int i, fakeLen = 0;
110 if (size < 1) {
111 return 0;
112 }
113 if (!len) {
114 len = &fakeLen;
115 }
116 if (size > 3 && buf[0] && !buf[1] && buf[2] && !buf[3]) {
117 *len = 1; // XXX: TODO: Measure wide string length
118 return 2; // is wide
119 }
120 for (i = 0; i < size; i++) {
121 if (!buf[i] && i > MINLEN) {
122 *len = i;
123 return 1;
124 }
125 if (buf[i] == 10 || buf[i] == 13 || buf[i] == 9) {
126 continue;
127 }
128 if (buf[i] < 32 || buf[i] > 127) {
129 // not ascii text
130 return 0;
131 }
132 if (!IS_PRINTABLE (buf[i])) {
133 *len = i;
134 return 0;
135 }
136 }
137 *len = i;
138 return 1;
139 }
140
is_string_at(RCore * core,ut64 addr,int * olen)141 static char *is_string_at(RCore *core, ut64 addr, int *olen) {
142 ut8 rstr[128] = {0};
143 int ret = 0, len = 0;
144 ut8 *str = calloc (256, 1);
145 if (!str) {
146 if (olen) {
147 *olen = 0;
148 }
149 return NULL;
150 }
151 r_io_read_at (core->io, addr, str, 255);
152
153 str[255] = 0;
154 if (is_string (str, 256, &len)) {
155 if (olen) {
156 *olen = len;
157 }
158 return (char*) str;
159 }
160
161 ut64 *cstr = (ut64*)str;
162 ut64 lowptr = cstr[0];
163 if (lowptr >> 32) { // must be pa mode only
164 lowptr &= UT32_MAX;
165 }
166 // cstring
167 if (cstr[0] == 0 && cstr[1] < 0x1000) {
168 ut64 ptr = cstr[2];
169 if (ptr >> 32) { // must be pa mode only
170 ptr &= UT32_MAX;
171 }
172 if (ptr) {
173 r_io_read_at (core->io, ptr, rstr, sizeof (rstr));
174 rstr[127] = 0;
175 ret = is_string (rstr, 128, &len);
176 if (ret) {
177 strcpy ((char*) str, (char*) rstr);
178 if (olen) {
179 *olen = len;
180 }
181 return (char*) str;
182 }
183 }
184 } else {
185 // pstring
186 r_io_read_at (core->io, lowptr, rstr, sizeof (rstr));
187 rstr[127] = 0;
188 ret = is_string (rstr, sizeof (rstr), &len);
189 if (ret) {
190 strcpy ((char*) str, (char*) rstr);
191 if (olen) {
192 *olen = len;
193 }
194 return (char*) str;
195 }
196 }
197 // check if current section have no exec bit
198 if (len < 1) {
199 ret = 0;
200 free (str);
201 len = -1;
202 } else if (olen) {
203 *olen = len;
204 }
205 // NOTE: coverity says that ret is always 0 here, so str is dead code
206 return ret? (char *)str: NULL;
207 }
208
209 /* returns the R_ANAL_ADDR_TYPE_* of the address 'addr' */
r_core_anal_address(RCore * core,ut64 addr)210 R_API ut64 r_core_anal_address(RCore *core, ut64 addr) {
211 ut64 types = 0;
212 RRegSet *rs = NULL;
213 if (!core) {
214 return 0;
215 }
216 if (core->dbg && core->dbg->reg) {
217 rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
218 }
219 if (rs) {
220 RRegItem *r;
221 RListIter *iter;
222 r_list_foreach (rs->regs, iter, r) {
223 if (r->type == R_REG_TYPE_GPR) {
224 ut64 val = r_reg_getv(core->dbg->reg, r->name);
225 if (addr == val) {
226 types |= R_ANAL_ADDR_TYPE_REG;
227 break;
228 }
229 }
230 }
231 }
232 if (r_flag_get_i (core->flags, addr)) {
233 types |= R_ANAL_ADDR_TYPE_FLAG;
234 }
235 if (r_anal_get_fcn_in (core->anal, addr, 0)) {
236 types |= R_ANAL_ADDR_TYPE_FUNC;
237 }
238 // check registers
239 if (core->bin && core->dbg && r_config_get_i (core->config, "cfg.debug")) {
240 RDebugMap *map;
241 RListIter *iter;
242 // use 'dm'
243 // XXX: this line makes r2 debugging MUCH slower
244 // r_debug_map_sync (core->dbg);
245 r_list_foreach (core->dbg->maps, iter, map) {
246 if (addr >= map->addr && addr < map->addr_end) {
247 if (map->name && map->name[0] == '/') {
248 if (core->io && core->io->desc &&
249 core->io->desc->name &&
250 !strcmp (map->name,
251 core->io->desc->name)) {
252 types |= R_ANAL_ADDR_TYPE_PROGRAM;
253 } else {
254 types |= R_ANAL_ADDR_TYPE_LIBRARY;
255 }
256 }
257 if (map->perm & R_PERM_X) {
258 types |= R_ANAL_ADDR_TYPE_EXEC;
259 }
260 if (map->perm & R_PERM_R) {
261 types |= R_ANAL_ADDR_TYPE_READ;
262 }
263 if (map->perm & R_PERM_W) {
264 types |= R_ANAL_ADDR_TYPE_WRITE;
265 }
266 // find function
267 if (map->name && strstr (map->name, "heap")) {
268 types |= R_ANAL_ADDR_TYPE_HEAP;
269 }
270 if (map->name && strstr (map->name, "stack")) {
271 types |= R_ANAL_ADDR_TYPE_STACK;
272 }
273 break;
274 }
275 }
276 } else {
277 int _perm = -1;
278 if (core->io) {
279 // sections
280 void **it;
281 r_pvector_foreach (&core->io->maps, it) {
282 RIOMap *s = *it;
283 if (addr >= s->itv.addr && addr < (s->itv.addr + s->itv.size)) {
284 // sections overlap, so we want to get the one with lower perms
285 _perm = (_perm != -1) ? R_MIN (_perm, s->perm) : s->perm;
286 // TODO: we should identify which maps come from the program or other
287 //types |= R_ANAL_ADDR_TYPE_PROGRAM;
288 // find function those sections should be created by hand or esil init
289 if (s->name && strstr (s->name, "heap")) {
290 types |= R_ANAL_ADDR_TYPE_HEAP;
291 }
292 if (s->name && strstr (s->name, "stack")) {
293 types |= R_ANAL_ADDR_TYPE_STACK;
294 }
295 }
296 }
297 }
298 if (_perm != -1) {
299 if (_perm & R_PERM_X) {
300 types |= R_ANAL_ADDR_TYPE_EXEC;
301 }
302 if (_perm & R_PERM_R) {
303 types |= R_ANAL_ADDR_TYPE_READ;
304 }
305 if (_perm & R_PERM_W) {
306 types |= R_ANAL_ADDR_TYPE_WRITE;
307 }
308 }
309 }
310
311 // check if it's ascii
312 if (addr != 0) {
313 int not_ascii = 0;
314 int i, failed_sequence, dir, on;
315 for (i = 0; i < 8; i++) {
316 ut8 n = (addr >> (i * 8)) & 0xff;
317 if (n && !IS_PRINTABLE (n)) {
318 not_ascii = 1;
319 }
320 }
321 if (!not_ascii) {
322 types |= R_ANAL_ADDR_TYPE_ASCII;
323 }
324 failed_sequence = 0;
325 dir = on = -1;
326 for (i = 0; i < 8; i++) {
327 ut8 n = (addr >> (i * 8)) & 0xff;
328 if (on != -1) {
329 if (dir == -1) {
330 dir = (n > on)? 1: -1;
331 }
332 if (n == on + dir) {
333 // ok
334 } else {
335 failed_sequence = 1;
336 break;
337 }
338 }
339 on = n;
340 }
341 if (!failed_sequence) {
342 types |= R_ANAL_ADDR_TYPE_SEQUENCE;
343 }
344 }
345 return types;
346 }
347
blacklisted_word(char * name)348 static bool blacklisted_word(char* name) {
349 const char * list[] = {
350 "__stack_chk_guard",
351 "__stderrp",
352 "__stdinp",
353 "__stdoutp",
354 "_DefaultRuneLocale"
355 };
356 int i;
357 for (i = 0; i < sizeof (list) / sizeof (list[0]); i++) {
358 if (strstr (name, list[i])) { return true; }
359 }
360 return false;
361 }
362
anal_fcn_autoname(RCore * core,RAnalFunction * fcn,int dump,int mode)363 static char *anal_fcn_autoname(RCore *core, RAnalFunction *fcn, int dump, int mode) {
364 int use_getopt = 0;
365 int use_isatty = 0;
366 PJ *pj = NULL;
367 char *do_call = NULL;
368 RAnalRef *ref;
369 RListIter *iter;
370 RList *refs = r_anal_function_get_refs (fcn);
371 if (mode == 'j') {
372 // start a new JSON object
373 pj = r_core_pj_new (core);
374 pj_a (pj);
375 }
376 if (refs) {
377 r_list_foreach (refs, iter, ref) {
378 RFlagItem *f = r_flag_get_i (core->flags, ref->addr);
379 if (f) {
380 // If dump is true, print all strings referenced by the function
381 if (dump) {
382 // take only strings flags
383 if (!strncmp (f->name, "str.", 4)) {
384 if (mode == 'j') {
385 // add new json item
386 pj_o (pj);
387 pj_kn (pj, "addr", ref->at);
388 pj_kn (pj, "ref", ref->addr);
389 pj_ks (pj, "flag", f->name);
390 pj_end (pj);
391 } else {
392 r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s\n", ref->at, ref->addr, f->name);
393 }
394 }
395 } else if (do_call) { // break if a proper autoname found and not in dump mode
396 break;
397 }
398 // enter only if a candidate name hasn't found yet
399 if (!do_call) {
400 if (blacklisted_word (f->name)) {
401 continue;
402 }
403 if (strstr (f->name, ".isatty")) {
404 use_isatty = 1;
405 }
406 if (strstr (f->name, ".getopt")) {
407 use_getopt = 1;
408 }
409 if (!strncmp (f->name, "method.", 7)) {
410 free (do_call);
411 do_call = strdup (f->name + 7);
412 continue;
413 }
414 if (!strncmp (f->name, "str.", 4)) {
415 free (do_call);
416 do_call = strdup (f->name + 4);
417 continue;
418 }
419 if (!strncmp (f->name, "sym.imp.", 8)) {
420 free (do_call);
421 do_call = strdup (f->name + 8);
422 continue;
423 }
424 if (!strncmp (f->name, "reloc.", 6)) {
425 free (do_call);
426 do_call = strdup (f->name + 6);
427 continue;
428 }
429 }
430 }
431 }
432 r_list_free (refs);
433 }
434 if (mode == 'j') {
435 pj_end (pj);
436 }
437 if (pj) {
438 r_cons_printf ("%s\n", pj_string (pj));
439 pj_free (pj);
440 }
441 // TODO: append counter if name already exists
442 if (use_getopt) {
443 RFlagItem *item = r_flag_get (core->flags, "main");
444 free (do_call);
445 // if referenced from entrypoint. this should be main
446 if (item && item->offset == fcn->addr) {
447 return strdup ("main"); // main?
448 }
449 return strdup ("parse_args"); // main?
450 }
451 if (use_isatty) {
452 char *ret = r_str_newf ("sub.setup_tty_%s_%"PFMT64x, do_call, fcn->addr);
453 free (do_call);
454 return ret;
455 }
456 if (do_call) {
457 char *ret = r_str_newf ("sub.%s_%"PFMT64x, do_call, fcn->addr);
458 free (do_call);
459 return ret;
460 }
461 return NULL;
462 }
463
464 /*this only autoname those function that start with fcn.* or sym.func.* */
r_core_anal_autoname_all_fcns(RCore * core)465 R_API void r_core_anal_autoname_all_fcns(RCore *core) {
466 RListIter *it;
467 RAnalFunction *fcn;
468
469 r_list_foreach (core->anal->fcns, it, fcn) {
470 if (!strncmp (fcn->name, "fcn.", 4) || !strncmp (fcn->name, "sym.func.", 9)) {
471 RFlagItem *item = r_flag_get (core->flags, fcn->name);
472 if (item) {
473 char *name = anal_fcn_autoname (core, fcn, 0, 0);
474 if (name) {
475 r_flag_rename (core->flags, item, name);
476 free (fcn->name);
477 fcn->name = name;
478 }
479 } else {
480 // there should always be a flag for a function
481 r_warn_if_reached ();
482 }
483 }
484 }
485 }
486
487 /* reads .gopclntab section in go binaries to recover function names
488 and adds them as sym.go.* flags */
r_core_anal_autoname_all_golang_fcns(RCore * core)489 R_API void r_core_anal_autoname_all_golang_fcns(RCore *core) {
490 RList* section_list = r_bin_get_sections (core->bin);
491 RListIter *iter;
492 const char* oldstr = NULL;
493 RBinSection *section;
494 ut64 gopclntab = 0;
495 r_list_foreach (section_list, iter, section) {
496 if (strstr (section->name, ".gopclntab")) {
497 gopclntab = section->vaddr;
498 break;
499 }
500 }
501 if (!gopclntab) {
502 oldstr = r_print_rowlog (core->print, "Could not find .gopclntab section");
503 r_print_rowlog_done (core->print, oldstr);
504 return;
505 }
506 int ptr_size = core->anal->bits / 8;
507 ut64 offset = gopclntab + 2 * ptr_size;
508 ut64 size_offset = gopclntab + 3 * ptr_size ;
509 ut8 temp_size[4] = {0};
510 if (!r_io_nread_at (core->io, size_offset, temp_size, 4)) {
511 return;
512 }
513 ut32 size = r_read_le32 (temp_size);
514 int num_syms = 0;
515 //r_cons_print ("[x] Reading .gopclntab...\n");
516 r_flag_space_push (core->flags, R_FLAGS_FS_SYMBOLS);
517 while (offset < gopclntab + size) {
518 ut8 temp_delta[4] = {0};
519 ut8 temp_func_addr[4] = {0};
520 ut8 temp_func_name[4] = {0};
521 if (!r_io_nread_at (core->io, offset + ptr_size, temp_delta, 4)) {
522 break;
523 }
524 ut32 delta = r_read_le32 (temp_delta);
525 ut64 func_offset = gopclntab + delta;
526 if (!r_io_nread_at (core->io, func_offset, temp_func_addr, 4) ||
527 !r_io_nread_at (core->io, func_offset + ptr_size, temp_func_name, 4)) {
528 break;
529 }
530 ut32 func_addr = r_read_le32 (temp_func_addr);
531 ut32 func_name_offset = r_read_le32 (temp_func_name);
532 ut8 func_name[64] = {0};
533 r_io_read_at (core->io, gopclntab + func_name_offset, func_name, 63);
534 if (func_name[0] == 0xff) {
535 break;
536 }
537 r_name_filter ((char *)func_name, 0);
538 //r_cons_printf ("[x] Found symbol %s at 0x%x\n", func_name, func_addr);
539 r_flag_set (core->flags, sdb_fmt ("sym.go.%s", func_name), func_addr, 1);
540 offset += 2 * ptr_size;
541 num_syms++;
542 }
543 r_flag_space_pop (core->flags);
544 if (num_syms) {
545 oldstr = r_print_rowlog (core->print, sdb_fmt ("Found %d symbols and saved them at sym.go.*", num_syms));
546 r_print_rowlog_done (core->print, oldstr);
547 } else {
548 oldstr = r_print_rowlog (core->print, "Found no symbols.");
549 r_print_rowlog_done (core->print, oldstr);
550 }
551 }
552
553 /* suggest a name for the function at the address 'addr'.
554 * If dump is true, every strings associated with the function is printed */
r_core_anal_fcn_autoname(RCore * core,ut64 addr,int dump,int mode)555 R_API char *r_core_anal_fcn_autoname(RCore *core, ut64 addr, int dump, int mode) {
556 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
557 if (fcn) {
558 return anal_fcn_autoname (core, fcn, dump, mode);
559 }
560 return NULL;
561 }
562
next_append(ut64 * next,int * nexti,ut64 v)563 static ut64 *next_append(ut64 *next, int *nexti, ut64 v) {
564 ut64 *tmp_next = realloc (next, sizeof (ut64) * (1 + *nexti));
565 if (!tmp_next) {
566 return NULL;
567 }
568 next = tmp_next;
569 next[*nexti] = v;
570 (*nexti)++;
571 return next;
572 }
573
r_anal_set_stringrefs(RCore * core,RAnalFunction * fcn)574 static void r_anal_set_stringrefs(RCore *core, RAnalFunction *fcn) {
575 RListIter *iter;
576 RAnalRef *ref;
577 RList *refs = r_anal_function_get_refs (fcn);
578 r_list_foreach (refs, iter, ref) {
579 if (ref->type == R_ANAL_REF_TYPE_DATA &&
580 r_bin_is_string (core->bin, ref->addr)) {
581 r_anal_xrefs_set (core->anal, ref->at, ref->addr, R_ANAL_REF_TYPE_STRING);
582 }
583 }
584 r_list_free (refs);
585 }
586
r_anal_try_get_fcn(RCore * core,RAnalRef * ref,int fcndepth,int refdepth)587 static bool r_anal_try_get_fcn(RCore *core, RAnalRef *ref, int fcndepth, int refdepth) {
588 if (!refdepth) {
589 return false;
590 }
591 RIOMap *map = r_io_map_get (core->io, ref->addr);
592 if (!map) {
593 return false;
594 }
595
596 if (map->perm & R_PERM_X) {
597 ut8 buf[64];
598 r_io_read_at (core->io, ref->addr, buf, sizeof (buf));
599 bool looksLikeAFunction = r_anal_check_fcn (core->anal, buf, sizeof (buf), ref->addr, r_io_map_begin (map),
600 r_io_map_end (map));
601 if (looksLikeAFunction) {
602 if (core->anal->limit) {
603 if (ref->addr < core->anal->limit->from ||
604 ref->addr > core->anal->limit->to) {
605 return 1;
606 }
607 }
608 r_core_anal_fcn (core, ref->addr, ref->at, ref->type, fcndepth - 1);
609 }
610 } else {
611 ut64 offs = 0;
612 ut64 sz = core->anal->bits >> 3;
613 RAnalRef ref1;
614 ref1.type = R_ANAL_REF_TYPE_DATA;
615 ref1.at = ref->addr;
616 ref1.addr = 0;
617 ut32 i32;
618 ut16 i16;
619 ut8 i8;
620 ut64 offe = offs + 1024;
621 for (offs = 0; offs < offe; offs += sz, ref1.at += sz) {
622 ut8 bo[8];
623 r_io_read_at (core->io, ref->addr + offs, bo, R_MIN (sizeof (bo), sz));
624 bool be = core->anal->big_endian;
625 switch (sz) {
626 case 1:
627 i8 = r_read_ble8 (bo);
628 ref1.addr = (ut64)i8;
629 break;
630 case 2:
631 i16 = r_read_ble16 (bo, be);
632 ref1.addr = (ut64)i16;
633 break;
634 case 4:
635 i32 = r_read_ble32 (bo, be);
636 ref1.addr = (ut64)i32;
637 break;
638 case 8:
639 ref1.addr = r_read_ble64 (bo, be);
640 break;
641 }
642 r_anal_try_get_fcn (core, &ref1, fcndepth, refdepth - 1);
643 }
644 }
645 return 1;
646 }
647
r_anal_analyze_fcn_refs(RCore * core,RAnalFunction * fcn,int depth)648 static int r_anal_analyze_fcn_refs(RCore *core, RAnalFunction *fcn, int depth) {
649 RListIter *iter;
650 RAnalRef *ref;
651 RList *refs = r_anal_function_get_refs (fcn);
652
653 r_list_foreach (refs, iter, ref) {
654 if (ref->addr == UT64_MAX) {
655 continue;
656 }
657 switch (ref->type) {
658 case R_ANAL_REF_TYPE_DATA:
659 if (core->anal->opt.followdatarefs) {
660 r_anal_try_get_fcn (core, ref, depth, 2);
661 }
662 break;
663 case R_ANAL_REF_TYPE_CODE:
664 case R_ANAL_REF_TYPE_CALL:
665 r_core_anal_fcn (core, ref->addr, ref->at, ref->type, depth - 1);
666 break;
667 default:
668 break;
669 }
670 // TODO: fix memleak here, fcn not freed even though it is
671 // added in core->anal->fcns which is freed in r_anal_free()
672 }
673 r_list_free (refs);
674 return 1;
675 }
676
function_rename(RFlag * flags,RAnalFunction * fcn)677 static void function_rename(RFlag *flags, RAnalFunction *fcn) {
678 const char *locname = "loc.";
679 const size_t locsize = strlen (locname);
680 char *fcnname = fcn->name;
681
682 if (strncmp (fcn->name, locname, locsize) == 0) {
683 const char *fcnpfx, *restofname;
684 RFlagItem *f;
685
686 fcn->type = R_ANAL_FCN_TYPE_FCN;
687 fcnpfx = r_anal_fcntype_tostring (fcn->type);
688 restofname = fcn->name + locsize;
689 fcn->name = r_str_newf ("%s.%s", fcnpfx, restofname);
690
691 f = r_flag_get_i (flags, fcn->addr);
692 r_flag_rename (flags, f, fcn->name);
693
694 free (fcnname);
695 }
696 }
697
autoname_imp_trampoline(RCore * core,RAnalFunction * fcn)698 static void autoname_imp_trampoline(RCore *core, RAnalFunction *fcn) {
699 if (r_list_length (fcn->bbs) == 1 && ((RAnalBlock *) r_list_first (fcn->bbs))->ninstr == 1) {
700 RList *refs = r_anal_function_get_refs (fcn);
701 if (refs && r_list_length (refs) == 1) {
702 RAnalRef *ref = r_list_first (refs);
703 if (ref->type != R_ANAL_REF_TYPE_CALL) { /* Some fcns don't return */
704 RFlagItem *flg = r_flag_get_i (core->flags, ref->addr);
705 if (flg && r_str_startswith (flg->name, "sym.imp.")) {
706 R_FREE (fcn->name);
707 fcn->name = r_str_newf ("sub.%s", flg->name + 8);
708 }
709 }
710 }
711 r_list_free (refs);
712 }
713 }
714
set_fcn_name_from_flag(RAnalFunction * fcn,RFlagItem * f,const char * fcnpfx)715 static void set_fcn_name_from_flag(RAnalFunction *fcn, RFlagItem *f, const char *fcnpfx) {
716 bool nameChanged = false;
717 if (f && f->name) {
718 if (!strncmp (fcn->name, "loc.", 4) || !strncmp (fcn->name, "fcn.", 4)) {
719 r_anal_function_rename (fcn, f->name);
720 nameChanged = true;
721 } else if (strncmp (f->name, "sect", 4)) {
722 r_anal_function_rename (fcn, f->name);
723 nameChanged = true;
724 }
725 }
726 if (!nameChanged) {
727 r_anal_function_rename (fcn, sdb_fmt ("%s.%08" PFMT64x, fcnpfx, fcn->addr));
728 }
729 }
730
is_entry_flag(RFlagItem * f)731 static bool is_entry_flag(RFlagItem *f) {
732 return f->space && !strcmp (f->space->name, R_FLAGS_FS_SYMBOLS) && r_str_startswith (f->name, "entry.");
733 }
734
__core_anal_fcn(RCore * core,ut64 at,ut64 from,int reftype,int depth)735 static int __core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth) {
736 if (depth < 0) {
737 // printf ("Too deep for 0x%08"PFMT64x"\n", at);
738 // r_sys_backtrace ();
739 return false;
740 }
741 int has_next = r_config_get_i (core->config, "anal.hasnext");
742 RAnalHint *hint = NULL;
743 int i, nexti = 0;
744 ut64 *next = NULL;
745 int fcnlen;
746 RAnalFunction *fcn = r_anal_function_new (core->anal);
747 r_warn_if_fail (fcn);
748 const char *fcnpfx = r_config_get (core->config, "anal.fcnprefix");
749 if (!fcnpfx) {
750 fcnpfx = "fcn";
751 }
752 const char *cc = r_anal_cc_default (core->anal);
753 if (!cc) {
754 if (r_anal_cc_once (core->anal)) {
755 eprintf ("Warning: set your favourite calling convention in `e anal.cc=?`\n");
756 }
757 cc = "reg";
758 }
759 fcn->cc = r_str_constpool_get (&core->anal->constpool, cc);
760 r_warn_if_fail (fcn->cc);
761 hint = r_anal_hint_get (core->anal, at);
762 if (hint && hint->bits == 16) {
763 // expand 16bit for function
764 fcn->bits = 16;
765 } else {
766 fcn->bits = core->anal->bits;
767 }
768 fcn->addr = at;
769 fcn->name = get_function_name (core, at);
770
771 if (!fcn->name) {
772 fcn->name = r_str_newf ("%s.%08"PFMT64x, fcnpfx, at);
773 }
774 r_anal_fcn_invalidate_read_ahead_cache ();
775 do {
776 RFlagItem *f;
777 ut64 delta = r_anal_function_linear_size (fcn);
778 if (!r_io_is_valid_offset (core->io, at + delta, !core->anal->opt.noncode)) {
779 goto error;
780 }
781 if (r_cons_is_breaked ()) {
782 break;
783 }
784 fcnlen = r_anal_fcn (core->anal, fcn, at + delta, core->anal->opt.bb_max_size, reftype);
785 if (core->anal->opt.searchstringrefs) {
786 r_anal_set_stringrefs (core, fcn);
787 }
788 if (fcnlen == 0) {
789 if (core->anal->verbose) {
790 eprintf ("Analyzed function size is 0 at 0x%08"PFMT64x"\n", at + delta);
791 }
792 goto error;
793 }
794 if (fcnlen < 0) {
795 switch (fcnlen) {
796 case R_ANAL_RET_ERROR:
797 case R_ANAL_RET_NEW:
798 case R_ANAL_RET_DUP:
799 case R_ANAL_RET_END:
800 break;
801 default:
802 eprintf ("Oops. Negative fcnsize at 0x%08"PFMT64x" (%d)\n", at, fcnlen);
803 continue;
804 }
805 }
806 f = r_core_flag_get_by_spaces (core->flags, fcn->addr);
807 set_fcn_name_from_flag (fcn, f, fcnpfx);
808
809 if (fcnlen == R_ANAL_RET_ERROR ||
810 (fcnlen == R_ANAL_RET_END && !r_anal_function_realsize (fcn))) { /* Error analyzing function */
811 if (core->anal->opt.followbrokenfcnsrefs) {
812 r_anal_analyze_fcn_refs (core, fcn, depth);
813 }
814 goto error;
815 } else if (fcnlen == R_ANAL_RET_END) { /* Function analysis complete */
816 f = r_core_flag_get_by_spaces (core->flags, fcn->addr);
817 if (f && f->name && strncmp (f->name, "sect", 4)) { /* Check if it's already flagged */
818 char *new_name = strdup (f->name);
819 if (is_entry_flag (f)) {
820 RListIter *iter;
821 RBinSymbol *sym;
822 const RList *syms = r_bin_get_symbols (core->bin);
823 ut64 baddr = r_config_get_i (core->config, "bin.baddr");
824 r_list_foreach (syms, iter, sym) {
825 if ((sym->paddr + baddr) == fcn->addr && !strcmp (sym->type, R_BIN_TYPE_FUNC_STR)) {
826 free (new_name);
827 new_name = r_str_newf ("sym.%s", sym->name);
828 break;
829 }
830 }
831 }
832 free (fcn->name);
833 fcn->name = new_name;
834 } else {
835 R_FREE (fcn->name);
836 const char *fcnpfx = r_anal_fcntype_tostring (fcn->type);
837 if (!fcnpfx || !*fcnpfx || !strcmp (fcnpfx, "fcn")) {
838 fcnpfx = r_config_get (core->config, "anal.fcnprefix");
839 }
840 fcn->name = r_str_newf ("%s.%08"PFMT64x, fcnpfx, fcn->addr);
841 autoname_imp_trampoline (core, fcn);
842 /* Add flag */
843 r_flag_space_push (core->flags, R_FLAGS_FS_FUNCTIONS);
844 r_flag_set (core->flags, fcn->name, fcn->addr, r_anal_function_linear_size (fcn));
845 r_flag_space_pop (core->flags);
846 }
847
848 /* New function: Add initial xref */
849 if (from != UT64_MAX) {
850 r_anal_xrefs_set (core->anal, from, fcn->addr, reftype);
851 }
852 // XXX: this is wrong. See CID 1134565
853 r_anal_add_function (core->anal, fcn);
854 if (has_next) {
855 ut64 addr = r_anal_function_max_addr (fcn);
856 RIOMap *map = r_io_map_get (core->io, addr);
857 // only get next if found on an executable section
858 if (!map || (map && map->perm & R_PERM_X)) {
859 for (i = 0; i < nexti; i++) {
860 if (next[i] == addr) {
861 break;
862 }
863 }
864 if (i == nexti) {
865 ut64 at = r_anal_function_max_addr (fcn);
866 while (true) {
867 ut64 size;
868 RAnalMetaItem *mi = r_meta_get_at (core->anal, at, R_META_TYPE_ANY, &size);
869 if (!mi) {
870 break;
871 }
872 at += size;
873 }
874 // TODO: ensure next address is function after padding (nop or trap or wat)
875 // XXX noisy for test cases because we want to clear the stderr
876 r_cons_clear_line (1);
877 loganal (fcn->addr, at, 10000 - depth);
878 next = next_append (next, &nexti, at);
879 }
880 }
881 }
882 if (!r_anal_analyze_fcn_refs (core, fcn, depth)) {
883 goto error;
884 }
885 }
886 } while (fcnlen != R_ANAL_RET_END);
887 r_list_free (core->anal->leaddrs);
888 core->anal->leaddrs = NULL;
889 if (has_next) {
890 for (i = 0; i < nexti; i++) {
891 if (!next[i] || r_anal_get_fcn_in (core->anal, next[i], 0)) {
892 continue;
893 }
894 r_core_anal_fcn (core, next[i], from, 0, depth - 1);
895 }
896 free (next);
897 }
898 if (core->anal->cur && core->anal->cur->arch && !strcmp (core->anal->cur->arch, "x86")) {
899 r_anal_function_check_bp_use (fcn);
900 if (fcn && !fcn->bp_frame) {
901 r_anal_function_delete_vars_by_kind (fcn, R_ANAL_VAR_KIND_BPV);
902 }
903 }
904 r_anal_hint_free (hint);
905 return true;
906
907 error:
908 r_list_free (core->anal->leaddrs);
909 core->anal->leaddrs = NULL;
910 // ugly hack to free fcn
911 if (fcn) {
912 if (!r_anal_function_realsize (fcn) || fcn->addr == UT64_MAX) {
913 r_anal_function_free (fcn);
914 fcn = NULL;
915 } else {
916 // TODO: mark this function as not properly analyzed
917 if (!fcn->name) {
918 // XXX dupped code.
919 fcn->name = r_str_newf (
920 "%s.%08" PFMT64x,
921 r_anal_fcntype_tostring (fcn->type),
922 at);
923 /* Add flag */
924 r_flag_space_push (core->flags, R_FLAGS_FS_FUNCTIONS);
925 r_flag_set (core->flags, fcn->name, at, r_anal_function_linear_size (fcn));
926 r_flag_space_pop (core->flags);
927 }
928 r_anal_add_function (core->anal, fcn);
929 }
930 if (fcn && has_next) {
931 ut64 newaddr = r_anal_function_max_addr (fcn);
932 RIOMap *map = r_io_map_get (core->io, newaddr);
933 if (!map || (map && (map->perm & R_PERM_X))) {
934 next = next_append (next, &nexti, newaddr);
935 for (i = 0; i < nexti; i++) {
936 if (!next[i]) {
937 continue;
938 }
939 r_core_anal_fcn (core, next[i], next[i], 0, depth - 1);
940 }
941 free (next);
942 }
943 }
944 }
945 if (fcn && core->anal->cur && core->anal->cur->arch && !strcmp (core->anal->cur->arch, "x86")) {
946 r_anal_function_check_bp_use (fcn);
947 if (!fcn->bp_frame) {
948 r_anal_function_delete_vars_by_kind (fcn, R_ANAL_VAR_KIND_BPV);
949 }
950 }
951 r_anal_hint_free (hint);
952 return false;
953 }
954
get_title(ut64 addr)955 static char *get_title(ut64 addr) {
956 return r_str_newf ("0x%"PFMT64x, addr);
957 }
958
959 /* decode and return the RAnalOp at the address addr */
r_core_anal_op(RCore * core,ut64 addr,int mask)960 R_API RAnalOp* r_core_anal_op(RCore *core, ut64 addr, int mask) {
961 int len;
962 ut8 buf[32];
963 ut8 *ptr;
964
965 r_return_val_if_fail (core, NULL);
966 if (addr == UT64_MAX) {
967 return NULL;
968 }
969 RAnalOp *op = R_NEW0 (RAnalOp);
970 if (!op) {
971 return NULL;
972 }
973 int delta = (addr - core->offset);
974 int minopsz = 8;
975 if (delta > 0 && delta + minopsz < core->blocksize && addr >= core->offset && addr + 16 < core->offset + core->blocksize) {
976 ptr = core->block + delta;
977 len = core->blocksize - delta;
978 if (len < 1) {
979 goto err_op;
980 }
981 } else {
982 if (!r_io_read_at (core->io, addr, buf, sizeof (buf))) {
983 goto err_op;
984 }
985 ptr = buf;
986 len = sizeof (buf);
987 }
988 if (r_anal_op (core->anal, op, addr, ptr, len, mask) < 1) {
989 goto err_op;
990 }
991 // TODO This code block must be deleted when all the anal plugs support disasm
992 if (!op->mnemonic && mask & R_ANAL_OP_MASK_DISASM) {
993 RAsmOp asmop;
994 if (core->anal->verbose) {
995 eprintf ("WARNING: Implement RAnalOp.MASK_DISASM for current anal.arch. Using the sluggish RAsmOp fallback for now.\n");
996 }
997 r_asm_set_pc (core->rasm, addr);
998 r_asm_op_init (&asmop);
999 if (r_asm_disassemble (core->rasm, &asmop, ptr, len) > 0) {
1000 op->mnemonic = strdup (r_strbuf_get (&asmop.buf_asm));
1001 }
1002 r_asm_op_fini (&asmop);
1003 }
1004 return op;
1005 err_op:
1006 free (op);
1007 return NULL;
1008 }
1009
1010 // Node for tree-sorting anal hints or collecting hint records at a single addr
1011 typedef struct {
1012 RBNode rb;
1013 ut64 addr;
1014 enum {
1015 HINT_NODE_ADDR,
1016 HINT_NODE_ARCH,
1017 HINT_NODE_BITS
1018 } type;
1019 union {
1020 const RVector/*<const RAnalAddrHintRecord>*/ *addr_hints;
1021 const char *arch;
1022 int bits;
1023 };
1024 } HintNode;
1025
print_hint_h_format(HintNode * node)1026 static void print_hint_h_format(HintNode *node) {
1027 switch (node->type) {
1028 case HINT_NODE_ADDR: {
1029 const RAnalAddrHintRecord *record;
1030 r_vector_foreach (node->addr_hints, record) {
1031 switch (record->type) {
1032 case R_ANAL_ADDR_HINT_TYPE_IMMBASE:
1033 r_cons_printf (" immbase=%d", record->immbase);
1034 break;
1035 case R_ANAL_ADDR_HINT_TYPE_JUMP:
1036 r_cons_printf (" jump=0x%08"PFMT64x, record->jump);
1037 break;
1038 case R_ANAL_ADDR_HINT_TYPE_FAIL:
1039 r_cons_printf (" fail=0x%08"PFMT64x, record->fail);
1040 break;
1041 case R_ANAL_ADDR_HINT_TYPE_STACKFRAME:
1042 r_cons_printf (" stackframe=0x%"PFMT64x, record->stackframe);
1043 break;
1044 case R_ANAL_ADDR_HINT_TYPE_PTR:
1045 r_cons_printf (" ptr=0x%"PFMT64x, record->ptr);
1046 break;
1047 case R_ANAL_ADDR_HINT_TYPE_NWORD:
1048 r_cons_printf (" nword=%d", record->nword);
1049 break;
1050 case R_ANAL_ADDR_HINT_TYPE_RET:
1051 r_cons_printf (" ret=0x%08"PFMT64x, record->retval);
1052 break;
1053 case R_ANAL_ADDR_HINT_TYPE_NEW_BITS:
1054 r_cons_printf (" newbits=%d", record->newbits);
1055 break;
1056 case R_ANAL_ADDR_HINT_TYPE_SIZE:
1057 r_cons_printf (" size=%"PFMT64u, record->size);
1058 break;
1059 case R_ANAL_ADDR_HINT_TYPE_SYNTAX:
1060 r_cons_printf (" syntax='%s'", record->syntax);
1061 break;
1062 case R_ANAL_ADDR_HINT_TYPE_OPTYPE: {
1063 const char *type = r_anal_optype_to_string (record->optype);
1064 if (type) {
1065 r_cons_printf (" type='%s'", type);
1066 }
1067 break;
1068 }
1069 case R_ANAL_ADDR_HINT_TYPE_OPCODE:
1070 r_cons_printf (" opcode='%s'", record->opcode);
1071 break;
1072 case R_ANAL_ADDR_HINT_TYPE_TYPE_OFFSET:
1073 r_cons_printf (" offset='%s'", record->type_offset);
1074 break;
1075 case R_ANAL_ADDR_HINT_TYPE_ESIL:
1076 r_cons_printf (" esil='%s'", record->esil);
1077 break;
1078 case R_ANAL_ADDR_HINT_TYPE_HIGH:
1079 r_cons_printf (" high=true");
1080 break;
1081 case R_ANAL_ADDR_HINT_TYPE_VAL:
1082 r_cons_printf (" val=0x%08"PFMT64x, record->val);
1083 break;
1084 }
1085 }
1086 break;
1087 }
1088 case HINT_NODE_ARCH:
1089 if (node->arch) {
1090 r_cons_printf (" arch='%s'", node->arch);
1091 } else {
1092 r_cons_print (" arch=RESET");
1093 }
1094 break;
1095 case HINT_NODE_BITS:
1096 if (node->bits) {
1097 r_cons_printf (" bits=%d", node->bits);
1098 } else {
1099 r_cons_print (" bits=RESET");
1100 }
1101 break;
1102 }
1103 }
1104
1105 // if mode == 'j', pj must be an existing PJ!
hint_node_print(HintNode * node,int mode,PJ * pj)1106 static void hint_node_print(HintNode *node, int mode, PJ *pj) {
1107 switch (mode) {
1108 case '*':
1109 #define HINTCMD_ADDR(hint,fmt,x) r_cons_printf (fmt" @ 0x%"PFMT64x"\n", x, (hint)->addr)
1110 switch (node->type) {
1111 case HINT_NODE_ADDR: {
1112 const RAnalAddrHintRecord *record;
1113 r_vector_foreach (node->addr_hints, record) {
1114 switch (record->type) {
1115 case R_ANAL_ADDR_HINT_TYPE_IMMBASE:
1116 HINTCMD_ADDR (node, "ahi %d", record->immbase);
1117 break;
1118 case R_ANAL_ADDR_HINT_TYPE_JUMP:
1119 HINTCMD_ADDR (node, "ahc 0x%"PFMT64x, record->jump);
1120 break;
1121 case R_ANAL_ADDR_HINT_TYPE_FAIL:
1122 HINTCMD_ADDR (node, "ahf 0x%"PFMT64x, record->fail);
1123 break;
1124 case R_ANAL_ADDR_HINT_TYPE_STACKFRAME:
1125 HINTCMD_ADDR (node, "ahF 0x%"PFMT64x, record->stackframe);
1126 break;
1127 case R_ANAL_ADDR_HINT_TYPE_PTR:
1128 HINTCMD_ADDR (node, "ahp 0x%"PFMT64x, record->ptr);
1129 break;
1130 case R_ANAL_ADDR_HINT_TYPE_NWORD:
1131 // no command for this
1132 break;
1133 case R_ANAL_ADDR_HINT_TYPE_RET:
1134 HINTCMD_ADDR (node, "ahr 0x%"PFMT64x, record->retval);
1135 break;
1136 case R_ANAL_ADDR_HINT_TYPE_NEW_BITS:
1137 // no command for this
1138 break;
1139 case R_ANAL_ADDR_HINT_TYPE_SIZE:
1140 HINTCMD_ADDR (node, "ahs 0x%"PFMT64x, record->size);
1141 break;
1142 case R_ANAL_ADDR_HINT_TYPE_SYNTAX:
1143 HINTCMD_ADDR (node, "ahS %s", record->syntax); // TODO: escape for newcmd
1144 break;
1145 case R_ANAL_ADDR_HINT_TYPE_OPTYPE: {
1146 const char *type = r_anal_optype_to_string (record->optype);
1147 if (type) {
1148 HINTCMD_ADDR (node, "aho %s", type); // TODO: escape for newcmd
1149 }
1150 break;
1151 }
1152 case R_ANAL_ADDR_HINT_TYPE_OPCODE:
1153 HINTCMD_ADDR (node, "ahd %s", record->opcode);
1154 break;
1155 case R_ANAL_ADDR_HINT_TYPE_TYPE_OFFSET:
1156 HINTCMD_ADDR (node, "aht %s", record->type_offset); // TODO: escape for newcmd
1157 break;
1158 case R_ANAL_ADDR_HINT_TYPE_ESIL:
1159 HINTCMD_ADDR (node, "ahe %s", record->esil); // TODO: escape for newcmd
1160 break;
1161 case R_ANAL_ADDR_HINT_TYPE_HIGH:
1162 r_cons_printf ("ahh @ 0x%"PFMT64x"\n", node->addr);
1163 break;
1164 case R_ANAL_ADDR_HINT_TYPE_VAL:
1165 // no command for this
1166 break;
1167 }
1168 }
1169 break;
1170 }
1171 case HINT_NODE_ARCH:
1172 HINTCMD_ADDR (node, "aha %s", r_str_get_fail (node->arch, "0"));
1173 break;
1174 case HINT_NODE_BITS:
1175 HINTCMD_ADDR (node, "ahb %d", node->bits);
1176 break;
1177 }
1178 #undef HINTCMD_ADDR
1179 break;
1180 case 'j':
1181 switch (node->type) {
1182 case HINT_NODE_ADDR: {
1183 const RAnalAddrHintRecord *record;
1184 r_vector_foreach (node->addr_hints, record) {
1185 switch (record->type) {
1186 case R_ANAL_ADDR_HINT_TYPE_IMMBASE:
1187 pj_ki (pj, "immbase", record->immbase);
1188 break;
1189 case R_ANAL_ADDR_HINT_TYPE_JUMP:
1190 pj_kn (pj, "jump", record->jump);
1191 break;
1192 case R_ANAL_ADDR_HINT_TYPE_FAIL:
1193 pj_kn (pj, "fail", record->fail);
1194 break;
1195 case R_ANAL_ADDR_HINT_TYPE_STACKFRAME:
1196 pj_kn (pj, "stackframe", record->stackframe);
1197 break;
1198 case R_ANAL_ADDR_HINT_TYPE_PTR:
1199 pj_kn (pj, "ptr", record->ptr);
1200 break;
1201 case R_ANAL_ADDR_HINT_TYPE_NWORD:
1202 pj_ki (pj, "nword", record->nword);
1203 break;
1204 case R_ANAL_ADDR_HINT_TYPE_RET:
1205 pj_kn (pj, "ret", record->retval);
1206 break;
1207 case R_ANAL_ADDR_HINT_TYPE_NEW_BITS:
1208 pj_ki (pj, "newbits", record->newbits);
1209 break;
1210 case R_ANAL_ADDR_HINT_TYPE_SIZE:
1211 pj_kn (pj, "size", record->size);
1212 break;
1213 case R_ANAL_ADDR_HINT_TYPE_SYNTAX:
1214 pj_ks (pj, "syntax", record->syntax);
1215 break;
1216 case R_ANAL_ADDR_HINT_TYPE_OPTYPE: {
1217 const char *type = r_anal_optype_to_string (record->optype);
1218 if (type) {
1219 pj_ks (pj, "type", type);
1220 }
1221 break;
1222 }
1223 case R_ANAL_ADDR_HINT_TYPE_OPCODE:
1224 pj_ks (pj, "opcode", record->opcode);
1225 break;
1226 case R_ANAL_ADDR_HINT_TYPE_TYPE_OFFSET:
1227 pj_ks (pj, "offset", record->type_offset);
1228 break;
1229 case R_ANAL_ADDR_HINT_TYPE_ESIL:
1230 pj_ks (pj, "esil", record->esil);
1231 break;
1232 case R_ANAL_ADDR_HINT_TYPE_HIGH:
1233 pj_kb (pj, "high", true);
1234 break;
1235 case R_ANAL_ADDR_HINT_TYPE_VAL:
1236 pj_kn (pj, "val", record->val);
1237 break;
1238 }
1239 }
1240 break;
1241 }
1242 case HINT_NODE_ARCH:
1243 if (node->arch) {
1244 pj_ks (pj, "arch", node->arch);
1245 } else {
1246 pj_knull (pj, "arch");
1247 }
1248 break;
1249 case HINT_NODE_BITS:
1250 pj_ki (pj, "bits", node->bits);
1251 break;
1252 }
1253 break;
1254 default:
1255 print_hint_h_format (node);
1256 break;
1257 }
1258 }
1259
hint_node_free(RBNode * node,void * user)1260 void hint_node_free(RBNode *node, void *user) {
1261 free (container_of (node, HintNode, rb));
1262 }
1263
hint_node_cmp(const void * incoming,const RBNode * in_tree,void * user)1264 int hint_node_cmp(const void *incoming, const RBNode *in_tree, void *user) {
1265 ut64 ia = *(ut64 *)incoming;
1266 ut64 ta = container_of (in_tree, const HintNode, rb)->addr;
1267 if (ia < ta) {
1268 return -1;
1269 } else if (ia > ta) {
1270 return 1;
1271 }
1272 return 0;
1273 }
1274
print_addr_hint_cb(ut64 addr,const RVector * records,void * user)1275 bool print_addr_hint_cb(ut64 addr, const RVector/*<const RAnalAddrHintRecord>*/ *records, void *user) {
1276 HintNode *node = R_NEW0 (HintNode);
1277 if (!node) {
1278 return false;
1279 }
1280 node->addr = addr;
1281 node->type = HINT_NODE_ADDR;
1282 node->addr_hints = records;
1283 r_rbtree_insert (user, &addr, &node->rb, hint_node_cmp, NULL);
1284 return true;
1285 }
1286
print_arch_hint_cb(ut64 addr,R_NULLABLE const char * arch,void * user)1287 bool print_arch_hint_cb(ut64 addr, R_NULLABLE const char *arch, void *user) {
1288 HintNode *node = R_NEW0 (HintNode);
1289 if (!node) {
1290 return false;
1291 }
1292 node->addr = addr;
1293 node->type = HINT_NODE_ARCH;
1294 node->arch = arch;
1295 r_rbtree_insert (user, &addr, &node->rb, hint_node_cmp, NULL);
1296 return true;
1297 }
1298
print_bits_hint_cb(ut64 addr,int bits,void * user)1299 bool print_bits_hint_cb(ut64 addr, int bits, void *user) {
1300 HintNode *node = R_NEW0 (HintNode);
1301 if (!node) {
1302 return false;
1303 }
1304 node->addr = addr;
1305 node->type = HINT_NODE_BITS;
1306 node->bits = bits;
1307 r_rbtree_insert (user, &addr, &node->rb, hint_node_cmp, NULL);
1308 return true;
1309 }
1310
print_hint_tree(RBTree tree,int mode)1311 static void print_hint_tree(RBTree tree, int mode) {
1312 PJ *pj = NULL;
1313 if (mode == 'j') {
1314 pj = pj_new ();
1315 pj_a (pj);
1316 }
1317 #define END_ADDR \
1318 if (pj) { \
1319 pj_end (pj); \
1320 } else if (mode != '*') { \
1321 r_cons_newline (); \
1322 }
1323 RBIter it;
1324 HintNode *node;
1325 ut64 last_addr = 0;
1326 bool in_addr = false;
1327 r_rbtree_foreach (tree, it, node, HintNode, rb) {
1328 if (!in_addr || last_addr != node->addr) {
1329 if (in_addr) {
1330 END_ADDR
1331 }
1332 in_addr = true;
1333 last_addr = node->addr;
1334 if (pj) {
1335 pj_o (pj);
1336 pj_kn (pj, "addr", node->addr);
1337 } else if (mode != '*') {
1338 r_cons_printf (" 0x%08"PFMT64x" =>", node->addr);
1339 }
1340 }
1341 hint_node_print (node, mode, pj);
1342 }
1343 if (in_addr) {
1344 END_ADDR
1345 }
1346 #undef BEGIN_ADDR
1347 #undef END_ADDR
1348 if (pj) {
1349 pj_end (pj);
1350 r_cons_printf ("%s\n", pj_string (pj));
1351 pj_free (pj);
1352 }
1353 }
1354
r_core_anal_hint_list(RAnal * a,int mode)1355 R_API void r_core_anal_hint_list(RAnal *a, int mode) {
1356 RBTree tree = NULL;
1357 // Collect all hints in the tree to sort them
1358 r_anal_arch_hints_foreach (a, print_arch_hint_cb, &tree);
1359 r_anal_bits_hints_foreach (a, print_bits_hint_cb, &tree);
1360 r_anal_addr_hints_foreach (a, print_addr_hint_cb, &tree);
1361 print_hint_tree (tree, mode);
1362 r_rbtree_free (tree, hint_node_free, NULL);
1363 }
1364
r_core_anal_hint_print(RAnal * a,ut64 addr,int mode)1365 R_API void r_core_anal_hint_print(RAnal* a, ut64 addr, int mode) {
1366 RBTree tree = NULL;
1367 ut64 hint_addr = UT64_MAX;
1368 const char *arch = r_anal_hint_arch_at(a, addr, &hint_addr);
1369 if (hint_addr != UT64_MAX) {
1370 print_arch_hint_cb (hint_addr, arch, &tree);
1371 }
1372 int bits = r_anal_hint_bits_at (a, addr, &hint_addr);
1373 if (hint_addr != UT64_MAX) {
1374 print_bits_hint_cb (hint_addr, bits, &tree);
1375 }
1376 const RVector *addr_hints = r_anal_addr_hints_at (a, addr);
1377 if (addr_hints) {
1378 print_addr_hint_cb (addr, addr_hints, &tree);
1379 }
1380 print_hint_tree (tree, mode);
1381 r_rbtree_free (tree, hint_node_free, NULL);
1382 }
1383
core_anal_graph_label(RCore * core,RAnalBlock * bb,int opts)1384 static char *core_anal_graph_label(RCore *core, RAnalBlock *bb, int opts) {
1385 int is_html = r_cons_singleton ()->is_html;
1386 int is_json = opts & R_CORE_ANAL_JSON;
1387 char cmd[1024], file[1024], *cmdstr = NULL, *filestr = NULL, *str = NULL;
1388 int line = 0, oline = 0, idx = 0;
1389 ut64 at;
1390
1391 if (opts & R_CORE_ANAL_GRAPHLINES) {
1392 for (at = bb->addr; at < bb->addr + bb->size; at += 2) {
1393 r_bin_addr2line (core->bin, at, file, sizeof (file) - 1, &line);
1394 if (line != 0 && line != oline && strcmp (file, "??")) {
1395 filestr = r_file_slurp_line (file, line, 0);
1396 if (filestr) {
1397 int flen = strlen (filestr);
1398 cmdstr = realloc (cmdstr, idx + flen + 8);
1399 memcpy (cmdstr + idx, filestr, flen);
1400 idx += flen;
1401 if (is_json) {
1402 strcpy (cmdstr + idx, "\\n");
1403 idx += 2;
1404 } else if (is_html) {
1405 strcpy (cmdstr + idx, "<br />");
1406 idx += 6;
1407 } else {
1408 strcpy (cmdstr + idx, "\\l");
1409 idx += 2;
1410 }
1411 free (filestr);
1412 }
1413 }
1414 oline = line;
1415 }
1416 } else if (opts & R_CORE_ANAL_STAR) {
1417 snprintf (cmd, sizeof (cmd), "pdb %"PFMT64u" @ 0x%08" PFMT64x, bb->size, bb->addr);
1418 str = r_core_cmd_str (core, cmd);
1419 } else if (opts & R_CORE_ANAL_GRAPHBODY) {
1420 const bool scrColor = r_config_get (core->config, "scr.color");
1421 const bool scrUtf8 = r_config_get (core->config, "scr.utf8");
1422 r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
1423 r_config_set (core->config, "scr.utf8", "false");
1424 snprintf (cmd, sizeof (cmd), "pD %"PFMT64u" @ 0x%08" PFMT64x, bb->size, bb->addr);
1425 cmdstr = r_core_cmd_str (core, cmd);
1426 r_config_set_i (core->config, "scr.color", scrColor);
1427 r_config_set_i (core->config, "scr.utf8", scrUtf8);
1428 }
1429 if (cmdstr) {
1430 str = r_str_escape_dot (cmdstr);
1431 free (cmdstr);
1432 }
1433 return str;
1434 }
1435
palColorFor(const char * k)1436 static char *palColorFor(const char *k) {
1437 if (!r_cons_singleton ()) {
1438 return NULL;
1439 }
1440 RColor rcolor = r_cons_pal_get (k);
1441 return r_cons_rgb_tostring (rcolor.r, rcolor.g, rcolor.b);
1442 }
1443
core_anal_color_curr_node(RCore * core,RAnalBlock * bbi)1444 static void core_anal_color_curr_node(RCore *core, RAnalBlock *bbi) {
1445 bool color_current = r_config_get_i (core->config, "graph.gv.current");
1446 char *pal_curr = palColorFor ("graph.current");
1447 bool current = r_anal_block_contains (bbi, core->offset);
1448
1449 if (current && color_current) {
1450 r_cons_printf ("\t\"0x%08"PFMT64x"\" ", bbi->addr);
1451 r_cons_printf ("\t[fillcolor=%s style=filled shape=box];\n", pal_curr);
1452 }
1453 free (pal_curr);
1454 }
1455
core_anal_graph_construct_edges(RCore * core,RAnalFunction * fcn,int opts,PJ * pj,Sdb * DB)1456 static int core_anal_graph_construct_edges(RCore *core, RAnalFunction *fcn, int opts, PJ *pj, Sdb *DB) {
1457 RAnalBlock *bbi;
1458 RListIter *iter;
1459 int is_keva = opts & R_CORE_ANAL_KEYVALUE;
1460 int is_star = opts & R_CORE_ANAL_STAR;
1461 int is_json = opts & R_CORE_ANAL_JSON;
1462 int is_html = r_cons_singleton ()->is_html;
1463 char *pal_jump = palColorFor ("graph.true");
1464 char *pal_fail = palColorFor ("graph.false");
1465 char *pal_trfa = palColorFor ("graph.trufae");
1466 int nodes = 0;
1467 r_list_foreach (fcn->bbs, iter, bbi) {
1468 if (bbi->jump != UT64_MAX) {
1469 nodes++;
1470 if (is_keva) {
1471 char key[128];
1472 char val[128];
1473 snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".to", bbi->addr);
1474 if (bbi->fail != UT64_MAX) {
1475 snprintf (val, sizeof (val), "0x%08"PFMT64x, bbi->jump);
1476 } else {
1477 snprintf (val, sizeof (val), "0x%08"PFMT64x ",0x%08"PFMT64x,
1478 bbi->jump, bbi->fail);
1479 }
1480 // bb.<addr>.to=<jump>,<fail>
1481 sdb_set (DB, key, val, 0);
1482 } else if (is_html) {
1483 r_cons_printf ("<div class=\"connector _0x%08"PFMT64x" _0x%08"PFMT64x"\">\n"
1484 " <img class=\"connector-end\" src=\"img/arrow.gif\" /></div>\n",
1485 bbi->addr, bbi->jump);
1486 } else if (!is_json && !is_keva) {
1487 if (is_star) {
1488 char *from = get_title (bbi->addr);
1489 char *to = get_title (bbi->jump);
1490 r_cons_printf ("age %s %s\n", from, to);
1491 free(from);
1492 free(to);
1493 } else {
1494 r_cons_printf (" \"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" "
1495 "[color=\"%s\"];\n", bbi->addr, bbi->jump,
1496 bbi->fail != -1 ? pal_jump : pal_trfa);
1497 core_anal_color_curr_node (core, bbi);
1498 }
1499 }
1500 }
1501 if (bbi->fail != -1) {
1502 nodes++;
1503 if (is_html) {
1504 r_cons_printf ("<div class=\"connector _0x%08"PFMT64x" _0x%08"PFMT64x"\">\n"
1505 " <img class=\"connector-end\" src=\"img/arrow.gif\"/></div>\n",
1506 bbi->addr, bbi->fail);
1507 } else if (!is_keva && !is_json) {
1508 if (is_star) {
1509 char *from = get_title (bbi->addr);
1510 char *to = get_title (bbi->fail);
1511 r_cons_printf ("age %s %s\n", from, to);
1512 free(from);
1513 free(to);
1514 } else {
1515 r_cons_printf (" \"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" "
1516 "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail);
1517 core_anal_color_curr_node (core, bbi);
1518 }
1519 }
1520 }
1521 if (bbi->switch_op) {
1522 RAnalCaseOp *caseop;
1523 RListIter *iter;
1524
1525 if (bbi->fail != UT64_MAX) {
1526 if (is_html) {
1527 r_cons_printf ("<div class=\"connector _0x%08"PFMT64x" _0x%08"PFMT64x"\">\n"
1528 " <img class=\"connector-end\" src=\"img/arrow.gif\"/></div>\n",
1529 bbi->addr, bbi->fail);
1530 } else if (!is_keva && !is_json) {
1531 if (is_star) {
1532 char *from = get_title (bbi->addr);
1533 char *to = get_title (bbi->fail);
1534 r_cons_printf ("age %s %s\n", from, to);
1535 free(from);
1536 free(to);
1537 } else {
1538 r_cons_printf (" \"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" "
1539 "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail);
1540 core_anal_color_curr_node (core, bbi);
1541 }
1542 }
1543 }
1544 r_list_foreach (bbi->switch_op->cases, iter, caseop) {
1545 nodes++;
1546 if (is_keva) {
1547 char key[128];
1548 snprintf (key, sizeof (key),
1549 "bb.0x%08"PFMT64x".switch.%"PFMT64d,
1550 bbi->addr, caseop->value);
1551 sdb_num_set (DB, key, caseop->jump, 0);
1552 snprintf (key, sizeof (key),
1553 "bb.0x%08"PFMT64x".switch", bbi->addr);
1554 sdb_array_add_num (DB, key, caseop->value, 0);
1555 } else if (is_html) {
1556 r_cons_printf ("<div class=\"connector _0x%08"PFMT64x" _0x%08"PFMT64x"\">\n"
1557 " <img class=\"connector-end\" src=\"img/arrow.gif\"/></div>\n",
1558 caseop->addr, caseop->jump);
1559 } else if (!is_json && !is_keva) {
1560 if (is_star) {
1561 char *from = get_title (caseop->addr);
1562 char *to = get_title (caseop->jump);
1563 r_cons_printf ("age %s %s\n", from ,to);
1564 free(from);
1565 free(to);
1566 } else {
1567 r_cons_printf (" \"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " \
1568 "[color2=\"%s\"];\n", caseop->addr, caseop->jump, pal_fail);
1569 core_anal_color_curr_node (core, bbi);
1570 }
1571 }
1572 }
1573 }
1574 }
1575 free(pal_jump);
1576 free(pal_fail);
1577 free(pal_trfa);
1578 return nodes;
1579 }
1580
core_anal_graph_construct_nodes(RCore * core,RAnalFunction * fcn,int opts,PJ * pj,Sdb * DB)1581 static int core_anal_graph_construct_nodes(RCore *core, RAnalFunction *fcn, int opts, PJ *pj, Sdb *DB) {
1582 RAnalBlock *bbi;
1583 RListIter *iter;
1584 int is_keva = opts & R_CORE_ANAL_KEYVALUE;
1585 int is_star = opts & R_CORE_ANAL_STAR;
1586 int is_json = opts & R_CORE_ANAL_JSON;
1587 int is_html = r_cons_singleton ()->is_html;
1588 int left = 300;
1589 int top = 0;
1590
1591 int is_json_format_disasm = opts & R_CORE_ANAL_JSON_FORMAT_DISASM;
1592 char *pal_curr = palColorFor ("graph.current");
1593 char *pal_traced = palColorFor ("graph.traced");
1594 char *pal_box4 = palColorFor ("graph.box4");
1595 const char *font = r_config_get (core->config, "graph.font");
1596 bool color_current = r_config_get_i (core->config, "graph.gv.current");
1597 char *str;
1598 int nodes = 0;
1599 r_list_foreach (fcn->bbs, iter, bbi) {
1600 if (is_keva) {
1601 char key[128];
1602 sdb_array_push_num (DB, "bbs", bbi->addr, 0);
1603 snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".size", bbi->addr);
1604 sdb_num_set (DB, key, bbi->size, 0); // bb.<addr>.size=<num>
1605 } else if (is_json) {
1606 RDebugTracepoint *t = r_debug_trace_get (core->dbg, bbi->addr);
1607 ut8 *buf = malloc (bbi->size);
1608 pj_o (pj);
1609 pj_kn (pj, "offset", bbi->addr);
1610 pj_kn (pj, "size", bbi->size);
1611 if (bbi->jump != UT64_MAX) {
1612 pj_kn (pj, "jump", bbi->jump);
1613 }
1614 if (bbi->fail != -1) {
1615 pj_kn (pj, "fail", bbi->fail);
1616 }
1617 if (bbi->switch_op) {
1618 RAnalSwitchOp *op = bbi->switch_op;
1619 pj_k (pj, "switchop");
1620 pj_o (pj);
1621 pj_kn (pj, "offset", op->addr);
1622 pj_kn (pj, "defval", op->def_val);
1623 pj_kn (pj, "maxval", op->max_val);
1624 pj_kn (pj, "minval", op->min_val);
1625 pj_k (pj, "cases");
1626 pj_a (pj);
1627 RAnalCaseOp *case_op;
1628 RListIter *case_iter;
1629 r_list_foreach (op->cases, case_iter, case_op) {
1630 pj_o (pj);
1631 pj_kn (pj, "offset", case_op->addr);
1632 pj_kn (pj, "value", case_op->value);
1633 pj_kn (pj, "jump", case_op->jump);
1634 pj_end (pj);
1635 }
1636 pj_end (pj);
1637 pj_end (pj);
1638 }
1639 if (t) {
1640 pj_k (pj, "trace");
1641 pj_o (pj);
1642 pj_ki (pj, "count", t->count);
1643 pj_ki (pj, "times", t->times);
1644 pj_end (pj);
1645 }
1646 if (bbi->color.r || bbi->color.g || bbi->color.b) {
1647 char *s = r_cons_rgb_tostring (bbi->color.r, bbi->color.g, bbi->color.b);
1648 pj_ks (pj, "color", s);
1649 free (s);
1650 }
1651 pj_k (pj, "ops");
1652 pj_a (pj);
1653 if (buf) {
1654 r_io_read_at (core->io, bbi->addr, buf, bbi->size);
1655 if (is_json_format_disasm) {
1656 r_core_print_disasm (core->print, core, bbi->addr, buf, bbi->size, bbi->size, 0, 1, true, pj, NULL);
1657 } else {
1658 r_core_print_disasm_json (core, bbi->addr, buf, bbi->size, 0, pj);
1659 }
1660 free (buf);
1661 } else {
1662 eprintf ("cannot allocate %"PFMT64u" byte(s)\n", bbi->size);
1663 }
1664 pj_end (pj);
1665 pj_end (pj);
1666 continue;
1667 }
1668 if ((str = core_anal_graph_label (core, bbi, opts))) {
1669 if (opts & R_CORE_ANAL_GRAPHDIFF) {
1670 const char *difftype = bbi->diff? (\
1671 bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "lightgray":
1672 bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "yellow": "red"): "orange";
1673 const char *diffname = bbi->diff? (\
1674 bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "match":
1675 bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "unmatch": "new"): "unk";
1676 if (is_keva) {
1677 sdb_set (DB, "diff", diffname, 0);
1678 sdb_set (DB, "label", str, 0);
1679 } else if (!is_json) {
1680 nodes++;
1681 RConfigHold *hc = r_config_hold_new (core->config);
1682 r_config_hold (hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines",
1683 "asm.cmt.right", "asm.lines.fcn", "asm.bytes", NULL);
1684 RDiff *d = r_diff_new ();
1685 r_config_set_i (core->config, "scr.utf8", 0);
1686 r_config_set_i (core->config, "asm.offset", 0);
1687 r_config_set_i (core->config, "asm.lines", 0);
1688 r_config_set_i (core->config, "asm.cmt.right", 0);
1689 r_config_set_i (core->config, "asm.lines.fcn", 0);
1690 r_config_set_i (core->config, "asm.bytes", 0);
1691 if (!is_star) {
1692 r_config_set_i (core->config, "scr.color", 0); // disable color for dot
1693 }
1694
1695 if (bbi->diff && bbi->diff->type != R_ANAL_DIFF_TYPE_MATCH && core->c2) {
1696 RCore *c = core->c2;
1697 RConfig *oc = c->config;
1698 char *str = r_core_cmd_strf (core, "pdb @ 0x%08"PFMT64x, bbi->addr);
1699 c->config = core->config;
1700 // XXX. the bbi->addr doesnt needs to be in the same address in core2
1701 char *str2 = r_core_cmd_strf (c, "pdb @ 0x%08"PFMT64x, bbi->diff->addr);
1702 char *diffstr = r_diff_buffers_to_string (d,
1703 (const ut8*)str, strlen (str),
1704 (const ut8*)str2, strlen (str2));
1705
1706 if (diffstr) {
1707 char *nl = strchr (diffstr, '\n');
1708 if (nl) {
1709 nl = strchr (nl + 1, '\n');
1710 if (nl) {
1711 nl = strchr (nl + 1, '\n');
1712 if (nl) {
1713 r_str_cpy (diffstr, nl + 1);
1714 }
1715 }
1716 }
1717 }
1718
1719 if (is_star) {
1720 char *title = get_title (bbi->addr);
1721 char *body_b64 = r_base64_encode_dyn (diffstr, -1);
1722 if (!title || !body_b64) {
1723 free (body_b64);
1724 free (title);
1725 r_diff_free (d);
1726 return false;
1727 }
1728 body_b64 = r_str_prepend (body_b64, "base64:");
1729 r_cons_printf ("agn %s %s %d\n", title, body_b64, bbi->diff->type);
1730 free (body_b64);
1731 free (title);
1732 } else {
1733 diffstr = r_str_replace (diffstr, "\n", "\\l", 1);
1734 diffstr = r_str_replace (diffstr, "\"", "'", 1);
1735 r_cons_printf(" \"0x%08"PFMT64x"\" [fillcolor=\"%s\","
1736 "color=\"black\", fontname=\"%s\","
1737 " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n",
1738 bbi->addr, difftype, diffstr, font, fcn->name,
1739 bbi->addr);
1740 }
1741 free (diffstr);
1742 c->config = oc;
1743 } else {
1744 if (is_star) {
1745 char *title = get_title (bbi->addr);
1746 char *body_b64 = r_base64_encode_dyn (str, -1);
1747 int color = (bbi && bbi->diff) ? bbi->diff->type : 0;
1748 if (!title || !body_b64) {
1749 free (body_b64);
1750 free (title);
1751 r_diff_free (d);
1752 return false;
1753 }
1754 body_b64 = r_str_prepend (body_b64, "base64:");
1755 r_cons_printf ("agn %s %s %d\n", title, body_b64, color);
1756 free (body_b64);
1757 free (title);
1758 } else {
1759 r_cons_printf(" \"0x%08"PFMT64x"\" [fillcolor=\"%s\","
1760 "color=\"black\", fontname=\"%s\","
1761 " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n",
1762 bbi->addr, difftype, str, font, fcn->name, bbi->addr);
1763 }
1764 }
1765 r_diff_free (d);
1766 r_config_set_i (core->config, "scr.color", 1);
1767 r_config_hold_free (hc);
1768 }
1769 } else {
1770 if (is_html) {
1771 nodes++;
1772 r_cons_printf ("<p class=\"block draggable\" style=\""
1773 "top: %dpx; left: %dpx; width: 400px;\" id=\""
1774 "_0x%08"PFMT64x"\">\n%s</p>\n",
1775 top, left, bbi->addr, str);
1776 left = left? 0: 600;
1777 if (!left) {
1778 top += 250;
1779 }
1780 } else if (!is_json && !is_keva) {
1781 bool current = r_anal_block_contains (bbi, core->offset);
1782 const char *label_color = bbi->traced
1783 ? pal_traced
1784 : (current && color_current)
1785 ? pal_curr
1786 : pal_box4;
1787 const char *fill_color = ((current && color_current) || label_color == pal_traced)? pal_traced: "white";
1788 nodes++;
1789 if (is_star) {
1790 char *title = get_title (bbi->addr);
1791 char *body_b64 = r_base64_encode_dyn (str, -1);
1792 int color = (bbi && bbi->diff) ? bbi->diff->type : 0;
1793 if (!title || !body_b64) {
1794 free (body_b64);
1795 free (title);
1796 return false;
1797 }
1798 body_b64 = r_str_prepend (body_b64, "base64:");
1799 r_cons_printf ("agn %s %s %d\n", title, body_b64, color);
1800 free (body_b64);
1801 free (title);
1802 } else {
1803 r_cons_printf ("\t\"0x%08"PFMT64x"\" ["
1804 "URL=\"%s/0x%08"PFMT64x"\", fillcolor=\"%s\","
1805 "color=\"%s\", fontname=\"%s\","
1806 "label=\"%s\"]\n",
1807 bbi->addr, fcn->name, bbi->addr,
1808 fill_color, label_color, font, str);
1809 }
1810 }
1811 }
1812 free (str);
1813 }
1814 }
1815 return nodes;
1816 }
1817
core_anal_graph_nodes(RCore * core,RAnalFunction * fcn,int opts,PJ * pj)1818 static int core_anal_graph_nodes(RCore *core, RAnalFunction *fcn, int opts, PJ *pj) {
1819 int is_json = opts & R_CORE_ANAL_JSON;
1820 int is_keva = opts & R_CORE_ANAL_KEYVALUE;
1821 int nodes = 0;
1822 Sdb *DB = NULL;
1823 char *pal_jump = palColorFor ("graph.true");
1824 char *pal_fail = palColorFor ("graph.false");
1825 char *pal_trfa = palColorFor ("graph.trufae");
1826 char *pal_curr = palColorFor ("graph.current");
1827 char *pal_traced = palColorFor ("graph.traced");
1828 char *pal_box4 = palColorFor ("graph.box4");
1829 if (!fcn || !fcn->bbs) {
1830 eprintf ("No fcn\n");
1831 return -1;
1832 }
1833
1834 if (is_keva) {
1835 char ns[64];
1836 DB = sdb_ns (core->anal->sdb, "graph", 1);
1837 snprintf (ns, sizeof (ns), "fcn.0x%08"PFMT64x, fcn->addr);
1838 DB = sdb_ns (DB, ns, 1);
1839 }
1840
1841 if (is_keva) {
1842 char *ename = sdb_encode ((const ut8*)fcn->name, -1);
1843 sdb_set (DB, "name", fcn->name, 0);
1844 sdb_set (DB, "ename", ename, 0);
1845 free (ename);
1846 sdb_num_set (DB, "size", r_anal_function_linear_size (fcn), 0);
1847 if (fcn->maxstack > 0) {
1848 sdb_num_set (DB, "stack", fcn->maxstack, 0);
1849 }
1850 sdb_set (DB, "pos", "0,0", 0); // needs to run layout
1851 sdb_set (DB, "type", r_anal_fcntype_tostring (fcn->type), 0);
1852 } else if (is_json) {
1853 // TODO: show vars, refs and xrefs
1854 char *fcn_name_escaped = r_str_escape_utf8_for_json (fcn->name, -1);
1855 pj_o (pj);
1856 pj_ks (pj, "name", r_str_getf (fcn_name_escaped));
1857 free (fcn_name_escaped);
1858 pj_kn (pj, "offset", fcn->addr);
1859 pj_ki (pj, "ninstr", fcn->ninstr);
1860 pj_ki (pj, "nargs",
1861 r_anal_var_count (core->anal, fcn, 'r', 1) +
1862 r_anal_var_count (core->anal, fcn, 's', 1) +
1863 r_anal_var_count (core->anal, fcn, 'b', 1));
1864 pj_ki (pj, "nlocals",
1865 r_anal_var_count (core->anal, fcn, 'r', 0) +
1866 r_anal_var_count (core->anal, fcn, 's', 0) +
1867 r_anal_var_count (core->anal, fcn, 'b', 0));
1868 pj_kn (pj, "size", r_anal_function_linear_size (fcn));
1869 pj_ki (pj, "stack", fcn->maxstack);
1870 pj_ks (pj, "type", r_anal_fcntype_tostring (fcn->type));
1871 pj_k (pj, "blocks");
1872 pj_a (pj);
1873 }
1874 nodes += core_anal_graph_construct_nodes (core, fcn, opts, pj, DB);
1875 nodes += core_anal_graph_construct_edges (core, fcn, opts, pj, DB);
1876 if (is_json) {
1877 pj_end (pj);
1878 pj_end (pj);
1879 }
1880 free (pal_jump);
1881 free (pal_fail);
1882 free (pal_trfa);
1883 free (pal_curr);
1884 free (pal_traced);
1885 free (pal_box4);
1886 return nodes;
1887 }
1888
1889 /* seek basic block that contains address addr or just addr if there's no such
1890 * basic block */
r_core_anal_bb_seek(RCore * core,ut64 addr)1891 R_API bool r_core_anal_bb_seek(RCore *core, ut64 addr) {
1892 ut64 bbaddr = r_anal_get_bbaddr (core->anal, addr);
1893 if (bbaddr != UT64_MAX) {
1894 r_core_seek (core, bbaddr, false);
1895 return true;
1896 }
1897 return false;
1898 }
1899
r_core_anal_esil_fcn(RCore * core,ut64 at,ut64 from,int reftype,int depth)1900 R_API int r_core_anal_esil_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth) {
1901 const char *esil;
1902 eprintf ("TODO\n");
1903 while (1) {
1904 // TODO: Implement the proper logic for doing esil analysis
1905 RAnalOp *op = r_core_anal_op (core, at, R_ANAL_OP_MASK_ESIL);
1906 if (!op) {
1907 break;
1908 }
1909 esil = R_STRBUF_SAFEGET (&op->esil);
1910 eprintf ("0x%08"PFMT64x" %d %s\n", at, op->size, esil);
1911 // at += op->size;
1912 // esilIsRet()
1913 // esilIsCall()
1914 // esilIsJmp()
1915 r_anal_op_free (op);
1916 break;
1917 }
1918 return 0;
1919 }
1920
find_sym_flag(const void * a1,const void * a2)1921 static int find_sym_flag(const void *a1, const void *a2) {
1922 const RFlagItem *f = (const RFlagItem *)a2;
1923 return f->space && !strcmp (f->space->name, R_FLAGS_FS_SYMBOLS)? 0: 1;
1924 }
1925
is_skippable_addr(RCore * core,ut64 addr)1926 static bool is_skippable_addr(RCore *core, ut64 addr) {
1927 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
1928 if (!fcn) {
1929 return false;
1930 }
1931 if (fcn->addr == addr) {
1932 return true;
1933 }
1934 const RList *flags = r_flag_get_list (core->flags, addr);
1935 return !(flags && r_list_find (flags, fcn, find_sym_flag));
1936 }
1937
1938 // XXX: This function takes sometimes forever
1939 /* analyze a RAnalFunction at the address 'at'.
1940 * If the function has been already analyzed, it adds a
1941 * reference to that fcn */
r_core_anal_fcn(RCore * core,ut64 at,ut64 from,int reftype,int depth)1942 R_API int r_core_anal_fcn(RCore *core, ut64 at, ut64 from, int reftype, int depth) {
1943 if (from == UT64_MAX && is_skippable_addr (core, at)) {
1944 if (core->anal->verbose) {
1945 eprintf ("Message: Invalid address for function 0x%08"PFMT64x"\n", at);
1946 }
1947 return 0;
1948 }
1949
1950 const bool use_esil = r_config_get_i (core->config, "anal.esil");
1951 RAnalFunction *fcn;
1952
1953 //update bits based on the core->offset otherwise we could have the
1954 //last value set and blow everything up
1955 r_core_seek_arch_bits (core, at);
1956
1957 if (core->io->va) {
1958 if (!r_io_is_valid_offset (core->io, at, !core->anal->opt.noncode)) {
1959 if (core->anal->verbose) {
1960 eprintf ("Warning: Address not mapped or not executable at 0x%08"PFMT64x"\n", at);
1961 }
1962 return false;
1963 }
1964 }
1965 if (r_config_get_i (core->config, "anal.a2f")) {
1966 r_core_cmd0 (core, ".a2f");
1967 return 0;
1968 }
1969 if (use_esil) {
1970 return r_core_anal_esil_fcn (core, at, from, reftype, depth);
1971 }
1972
1973 if ((from != UT64_MAX && !at) || at == UT64_MAX) {
1974 eprintf ("Invalid address from 0x%08"PFMT64x"\n", from);
1975 return false;
1976 }
1977 if (depth < 0) {
1978 if (core->anal->verbose) {
1979 eprintf ("Warning: anal depth reached\n");
1980 }
1981 return false;
1982 }
1983 if (r_cons_is_breaked ()) {
1984 return false;
1985 }
1986 fcn = r_anal_get_fcn_in (core->anal, at, 0);
1987 if (fcn) {
1988 if (fcn->addr == at) {
1989 // if the function was already analyzed as a "loc.",
1990 // convert it to function and rename it to "fcn.",
1991 // because we found a call to this address
1992 if (reftype == R_ANAL_REF_TYPE_CALL && fcn->type == R_ANAL_FCN_TYPE_LOC) {
1993 function_rename (core->flags, fcn);
1994 }
1995
1996 return 0; // already analyzed function
1997 }
1998 if (r_anal_function_contains (fcn, from)) { // inner function
1999 RList *l = r_anal_xrefs_get (core->anal, from);
2000 if (l && !r_list_empty (l)) {
2001 r_list_free (l);
2002 return true;
2003 }
2004 r_list_free (l);
2005
2006 // we should analyze and add code ref otherwise aaa != aac
2007 if (from != UT64_MAX) {
2008 r_anal_xrefs_set (core->anal, from, at, reftype);
2009 }
2010 return true;
2011 }
2012 }
2013 if (__core_anal_fcn (core, at, from, reftype, depth - 1)) {
2014 // split function if overlaps
2015 if (fcn) {
2016 r_anal_function_resize (fcn, at - fcn->addr);
2017 }
2018 return true;
2019 }
2020 return false;
2021 }
2022
2023 /* if addr is 0, remove all functions
2024 * otherwise remove the function addr falls into */
r_core_anal_fcn_clean(RCore * core,ut64 addr)2025 R_API int r_core_anal_fcn_clean(RCore *core, ut64 addr) {
2026 RAnalFunction *fcni;
2027 RListIter *iter, *iter_tmp;
2028
2029 if (!addr) {
2030 r_list_purge (core->anal->fcns);
2031 if (!(core->anal->fcns = r_list_new ())) {
2032 return false;
2033 }
2034 } else {
2035 r_list_foreach_safe (core->anal->fcns, iter, iter_tmp, fcni) {
2036 if (r_anal_function_contains (fcni, addr)) {
2037 r_anal_function_delete (fcni);
2038 }
2039 }
2040 }
2041 return true;
2042 }
2043
r_core_print_bb_custom(RCore * core,RAnalFunction * fcn)2044 R_API int r_core_print_bb_custom(RCore *core, RAnalFunction *fcn) {
2045 RAnalBlock *bb;
2046 RListIter *iter;
2047 if (!fcn) {
2048 return false;
2049 }
2050
2051 RConfigHold *hc = r_config_hold_new (core->config);
2052 r_config_hold (hc, "scr.color", "scr.utf8", "asm.marks", "asm.offset", "asm.lines",
2053 "asm.cmt.right", "asm.cmt.col", "asm.lines.fcn", "asm.bytes", NULL);
2054 /*r_config_set_i (core->config, "scr.color", 0);*/
2055 r_config_set_i (core->config, "scr.utf8", 0);
2056 r_config_set_i (core->config, "asm.marks", 0);
2057 r_config_set_i (core->config, "asm.offset", 0);
2058 r_config_set_i (core->config, "asm.lines", 0);
2059 r_config_set_i (core->config, "asm.cmt.right", 0);
2060 r_config_set_i (core->config, "asm.cmt.col", 0);
2061 r_config_set_i (core->config, "asm.lines.fcn", 0);
2062 r_config_set_i (core->config, "asm.bytes", 0);
2063
2064 r_list_foreach (fcn->bbs, iter, bb) {
2065 if (bb->addr == UT64_MAX) {
2066 continue;
2067 }
2068 char *title = get_title (bb->addr);
2069 char *body = r_core_cmd_strf (core, "pdb @ 0x%08"PFMT64x, bb->addr);
2070 char *body_b64 = r_base64_encode_dyn (body, -1);
2071 if (!title || !body || !body_b64) {
2072 free (body_b64);
2073 free (body);
2074 free (title);
2075 r_config_hold_restore (hc);
2076 r_config_hold_free (hc);
2077 return false;
2078 }
2079 body_b64 = r_str_prepend (body_b64, "base64:");
2080 r_cons_printf ("agn %s %s\n", title, body_b64);
2081 free (body);
2082 free (body_b64);
2083 free (title);
2084 }
2085
2086 r_config_hold_restore (hc);
2087 r_config_hold_free (hc);
2088
2089 r_list_foreach (fcn->bbs, iter, bb) {
2090 if (bb->addr == UT64_MAX) {
2091 continue;
2092 }
2093 char *u = get_title (bb->addr), *v = NULL;
2094 if (bb->jump != UT64_MAX) {
2095 v = get_title (bb->jump);
2096 r_cons_printf ("age %s %s\n", u, v);
2097 free (v);
2098 }
2099 if (bb->fail != UT64_MAX) {
2100 v = get_title (bb->fail);
2101 r_cons_printf ("age %s %s\n", u, v);
2102 free (v);
2103 }
2104 if (bb->switch_op) {
2105 RListIter *it;
2106 RAnalCaseOp *cop;
2107 r_list_foreach (bb->switch_op->cases, it, cop) {
2108 v = get_title (cop->addr);
2109 r_cons_printf ("age %s %s\n", u, v);
2110 free (v);
2111 }
2112 }
2113 free (u);
2114 }
2115 return true;
2116 }
2117
2118 #define USE_ID 1
r_core_print_bb_gml(RCore * core,RAnalFunction * fcn)2119 R_API int r_core_print_bb_gml(RCore *core, RAnalFunction *fcn) {
2120 RAnalBlock *bb;
2121 RListIter *iter;
2122 if (!fcn) {
2123 return false;
2124 }
2125 int id = 0;
2126 HtUUOptions opt = { 0 };
2127 HtUU *ht = ht_uu_new_opt (&opt);
2128
2129 r_cons_printf ("graph\n[\n" "hierarchic 1\n" "label \"\"\n" "directed 1\n");
2130
2131 r_list_foreach (fcn->bbs, iter, bb) {
2132 RFlagItem *flag = r_flag_get_i (core->flags, bb->addr);
2133 char *msg = flag? strdup (flag->name): r_str_newf ("0x%08"PFMT64x, bb->addr);
2134 #if USE_ID
2135 ht_uu_insert (ht, bb->addr, id);
2136 r_cons_printf (" node [\n"
2137 " id %d\n"
2138 " label \"%s\"\n"
2139 " ]\n", id, msg);
2140 id++;
2141 #else
2142 r_cons_printf (" node [\n"
2143 " id %"PFMT64d"\n"
2144 " label \"%s\"\n"
2145 " ]\n", bb->addr, msg);
2146 #endif
2147 free (msg);
2148 }
2149
2150 r_list_foreach (fcn->bbs, iter, bb) {
2151 if (bb->addr == UT64_MAX) {
2152 continue;
2153 }
2154
2155 #if USE_ID
2156 if (bb->jump != UT64_MAX) {
2157 bool found;
2158 int i = ht_uu_find (ht, bb->addr, &found);
2159 if (found) {
2160 int i2 = ht_uu_find (ht, bb->jump, &found);
2161 if (found) {
2162 r_cons_printf (" edge [\n"
2163 " source %d\n"
2164 " target %d\n"
2165 " ]\n", i, i2);
2166 }
2167 }
2168 }
2169 if (bb->fail != UT64_MAX) {
2170 bool found;
2171 int i = ht_uu_find (ht, bb->addr, &found);
2172 if (found) {
2173 int i2 = ht_uu_find (ht, bb->fail, &found);
2174 if (found) {
2175 r_cons_printf (" edge [\n"
2176 " source %d\n"
2177 " target %d\n"
2178 " ]\n", i, i2);
2179 }
2180 }
2181 }
2182 if (bb->switch_op) {
2183 RListIter *it;
2184 RAnalCaseOp *cop;
2185 r_list_foreach (bb->switch_op->cases, it, cop) {
2186 bool found;
2187 int i = ht_uu_find (ht, bb->addr, &found);
2188 if (found) {
2189 int i2 = ht_uu_find (ht, cop->addr, &found);
2190 if (found) {
2191 r_cons_printf (" edge [\n"
2192 " source %d\n"
2193 " target %d\n"
2194 " ]\n", i, i2);
2195 }
2196 }
2197 }
2198 }
2199 #else
2200 if (bb->jump != UT64_MAX) {
2201 r_cons_printf (" edge [\n"
2202 " source %"PFMT64d"\n"
2203 " target %"PFMT64d"\n"
2204 " ]\n", bb->addr, bb->jump
2205 );
2206 }
2207 if (bb->fail != UT64_MAX) {
2208 r_cons_printf (" edge [\n"
2209 " source %"PFMT64d"\n"
2210 " target %"PFMT64d"\n"
2211 " ]\n", bb->addr, bb->fail
2212 );
2213 }
2214 if (bb->switch_op) {
2215 RListIter *it;
2216 RAnalCaseOp *cop;
2217 r_list_foreach (bb->switch_op->cases, it, cop) {
2218 r_cons_printf (" edge [\n"
2219 " source %"PFMT64d"\n"
2220 " target %"PFMT64d"\n"
2221 " ]\n", bb->addr, cop->addr
2222 );
2223 }
2224 }
2225 #endif
2226 }
2227 r_cons_printf ("]\n");
2228 ht_uu_free (ht);
2229 return true;
2230 }
2231
r_core_anal_datarefs(RCore * core,ut64 addr)2232 R_API void r_core_anal_datarefs(RCore *core, ut64 addr) {
2233 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, -1);
2234 if (fcn) {
2235 bool found = false;
2236 const char *me = fcn->name;
2237 RListIter *iter;
2238 RAnalRef *ref;
2239 RList *refs = r_anal_function_get_refs (fcn);
2240 r_list_foreach (refs, iter, ref) {
2241 RBinObject *obj = r_bin_cur_object (core->bin);
2242 RBinSection *binsec = r_bin_get_section_at (obj, ref->addr, true);
2243 if (binsec && binsec->is_data) {
2244 if (!found) {
2245 r_cons_printf ("agn %s\n", me);
2246 found = true;
2247 }
2248 RFlagItem *item = r_flag_get_i (core->flags, ref->addr);
2249 const char *dst = item? item->name: sdb_fmt ("0x%08"PFMT64x, ref->addr);
2250 r_cons_printf ("agn %s\n", dst);
2251 r_cons_printf ("age %s %s\n", me, dst);
2252 }
2253 }
2254 r_list_free (refs);
2255 } else {
2256 eprintf ("Not in a function. Use 'df' to define it.\n");
2257 }
2258 }
2259
r_core_anal_coderefs(RCore * core,ut64 addr)2260 R_API void r_core_anal_coderefs(RCore *core, ut64 addr) {
2261 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, -1);
2262 if (fcn) {
2263 const char *me = fcn->name;
2264 RListIter *iter;
2265 RAnalRef *ref;
2266 RList *refs = r_anal_function_get_refs (fcn);
2267 r_cons_printf ("agn %s\n", me);
2268 r_list_foreach (refs, iter, ref) {
2269 RFlagItem *item = r_flag_get_i (core->flags, ref->addr);
2270 const char *dst = item? item->name: sdb_fmt ("0x%08"PFMT64x, ref->addr);
2271 r_cons_printf ("agn %s\n", dst);
2272 r_cons_printf ("age %s %s\n", me, dst);
2273 }
2274 r_list_free (refs);
2275 } else {
2276 eprintf("Not in a function. Use 'df' to define it.\n");
2277 }
2278 }
2279
add_single_addr_xrefs(RCore * core,ut64 addr,RGraph * graph)2280 static void add_single_addr_xrefs(RCore *core, ut64 addr, RGraph *graph) {
2281 r_return_if_fail (graph);
2282 RFlagItem *f = r_flag_get_at (core->flags, addr, false);
2283 char *me = (f && f->offset == addr)
2284 ? r_str_new (f->name)
2285 : r_str_newf ("0x%" PFMT64x, addr);
2286
2287 RGraphNode *curr_node = r_graph_add_node_info (graph, me, NULL, addr);
2288 R_FREE (me);
2289 if (!curr_node) {
2290 return;
2291 }
2292 RListIter *iter;
2293 RAnalRef *ref;
2294 RList *list = r_anal_xrefs_get (core->anal, addr);
2295 r_list_foreach (list, iter, ref) {
2296 RFlagItem *item = r_flag_get_i (core->flags, ref->addr);
2297 char *src = item? r_str_new (item->name): r_str_newf ("0x%08" PFMT64x, ref->addr);
2298 RGraphNode *reference_from = r_graph_add_node_info (graph, src, NULL, ref->addr);
2299 free (src);
2300 r_graph_add_edge (graph, reference_from, curr_node);
2301 }
2302 r_list_free (list);
2303 }
2304
r_core_anal_importxrefs(RCore * core)2305 R_API RGraph *r_core_anal_importxrefs(RCore *core) {
2306 RBinInfo *info = r_bin_get_info (core->bin);
2307 RBinObject *obj = r_bin_cur_object (core->bin);
2308 bool lit = info? info->has_lit: false;
2309 bool va = core->io->va || r_config_get_i (core->config, "cfg.debug");
2310
2311 RListIter *iter;
2312 RBinImport *imp;
2313 if (!obj) {
2314 return NULL;
2315 }
2316 RGraph *graph = r_graph_new ();
2317 if (!graph) {
2318 return NULL;
2319 }
2320 r_list_foreach (obj->imports, iter, imp) {
2321 ut64 addr = lit ? r_core_bin_impaddr (core->bin, va, imp->name): 0;
2322 if (addr) {
2323 add_single_addr_xrefs (core, addr, graph);
2324 } else {
2325 r_graph_add_node_info (graph, imp->name, NULL, 0);
2326 }
2327 }
2328 return graph;
2329 }
2330
r_core_anal_codexrefs(RCore * core,ut64 addr)2331 R_API RGraph *r_core_anal_codexrefs(RCore *core, ut64 addr) {
2332 RGraph *graph = r_graph_new ();
2333 if (!graph) {
2334 return NULL;
2335 }
2336 add_single_addr_xrefs (core, addr, graph);
2337 return graph;
2338 }
2339
RAnalRef_cmp(const RAnalRef * ref1,const RAnalRef * ref2)2340 static int RAnalRef_cmp(const RAnalRef* ref1, const RAnalRef* ref2) {
2341 return ref1->addr != ref2->addr;
2342 }
2343
r_core_anal_callgraph(RCore * core,ut64 addr,int fmt)2344 R_API void r_core_anal_callgraph(RCore *core, ut64 addr, int fmt) {
2345 const char *font = r_config_get (core->config, "graph.font");
2346 int is_html = r_cons_singleton ()->is_html;
2347 bool refgraph = r_config_get_i (core->config, "graph.refs");
2348 RListIter *iter, *iter2;
2349 int usenames = r_config_get_i (core->config, "graph.json.usenames");;
2350 RAnalFunction *fcni;
2351 RAnalRef *fcnr;
2352 PJ *pj = NULL;
2353
2354 ut64 from = r_config_get_i (core->config, "graph.from");
2355 ut64 to = r_config_get_i (core->config, "graph.to");
2356
2357 switch (fmt) {
2358 case R_GRAPH_FORMAT_JSON:
2359 pj = pj_new ();
2360 if (!pj) {
2361 return;
2362 }
2363 pj_a (pj);
2364 break;
2365 case R_GRAPH_FORMAT_GML:
2366 case R_GRAPH_FORMAT_GMLFCN:
2367 r_cons_printf ("graph\n[\n"
2368 "hierarchic 1\n"
2369 "label \"\"\n"
2370 "directed 1\n");
2371 break;
2372 case R_GRAPH_FORMAT_DOT:
2373 if (!is_html) {
2374 const char * gv_edge = r_config_get (core->config, "graph.gv.edge");
2375 char * gv_node = strdup (r_config_get (core->config, "graph.gv.node"));
2376 const char * gv_grph = r_config_get (core->config, "graph.gv.graph");
2377 const char * gv_spline = r_config_get (core->config, "graph.gv.spline");
2378 if (!gv_edge || !*gv_edge) {
2379 gv_edge = "arrowhead=\"normal\" style=bold weight=2";
2380 }
2381 if (!gv_node || !*gv_node) {
2382 const char *font = r_config_get (core->config, "graph.font");
2383 free (gv_node);
2384 gv_node = r_str_newf ("penwidth=4 fillcolor=white style=filled fontname=\"%s Bold\" fontsize=14 shape=box", font);
2385 }
2386 if (!gv_grph || !*gv_grph) {
2387 gv_grph = "bgcolor=azure";
2388 }
2389 if (!gv_spline || !*gv_spline) {
2390 // ortho for bbgraph and curved for callgraph
2391 gv_spline = "splines=\"curved\"";
2392 }
2393 r_cons_printf ("digraph code {\n"
2394 "rankdir=LR;\n"
2395 "outputorder=edgesfirst;\n"
2396 "graph [%s fontname=\"%s\" %s];\n"
2397 "node [%s];\n"
2398 "edge [%s];\n", gv_grph, font, gv_spline,
2399 gv_node, gv_edge);
2400 free (gv_node);
2401 }
2402 break;
2403 }
2404 ut64 base = UT64_MAX;
2405 int iteration = 0;
2406 repeat:
2407 r_list_foreach (core->anal->fcns, iter, fcni) {
2408 if (base == UT64_MAX) {
2409 base = fcni->addr;
2410 }
2411 if (from != UT64_MAX && fcni->addr < from) {
2412 continue;
2413 }
2414 if (to != UT64_MAX && fcni->addr > to) {
2415 continue;
2416 }
2417 if (addr != UT64_MAX && addr != fcni->addr) {
2418 continue;
2419 }
2420 RList *refs = r_anal_function_get_refs (fcni);
2421 RList *calls = r_list_new ();
2422 // TODO: maybe fcni->calls instead ?
2423 r_list_foreach (refs, iter2, fcnr) {
2424 // TODO: tail calll jumps are also calls
2425 if (fcnr->type == 'C' && r_list_find(calls, fcnr, (RListComparator)RAnalRef_cmp) == NULL) {
2426 r_list_append (calls, fcnr);
2427 }
2428 }
2429 if (r_list_empty(calls)) {
2430 r_list_free (refs);
2431 r_list_free (calls);
2432 continue;
2433 }
2434 switch (fmt) {
2435 case R_GRAPH_FORMAT_NO:
2436 r_cons_printf ("0x%08"PFMT64x"\n", fcni->addr);
2437 break;
2438 case R_GRAPH_FORMAT_GML:
2439 case R_GRAPH_FORMAT_GMLFCN: {
2440 RFlagItem *flag = r_flag_get_i (core->flags, fcni->addr);
2441 if (iteration == 0) {
2442 char *msg = flag? strdup (flag->name): r_str_newf ("0x%08"PFMT64x, fcni->addr);
2443 r_cons_printf (" node [\n"
2444 " id %"PFMT64d"\n"
2445 " label \"%s\"\n"
2446 " ]\n", fcni->addr - base, msg);
2447 free (msg);
2448 }
2449 break;
2450 }
2451 case R_GRAPH_FORMAT_JSON:
2452 pj_o (pj);
2453 if (usenames) {
2454 pj_ks (pj, "name", fcni->name);
2455 } else {
2456 char fcni_addr[20];
2457 snprintf (fcni_addr, sizeof (fcni_addr) - 1, "0x%08" PFMT64x, fcni->addr);
2458 pj_ks (pj, "name", fcni_addr);
2459 }
2460 pj_kn (pj, "size", r_anal_function_linear_size (fcni));
2461 pj_ka (pj, "imports");
2462 break;
2463 case R_GRAPH_FORMAT_DOT:
2464 r_cons_printf (" \"0x%08"PFMT64x"\" "
2465 "[label=\"%s\""
2466 " URL=\"%s/0x%08"PFMT64x"\"];\n",
2467 fcni->addr, fcni->name,
2468 fcni->name, fcni->addr);
2469 }
2470 r_list_foreach (calls, iter2, fcnr) {
2471 // TODO: display only code or data refs?
2472 RFlagItem *flag = r_flag_get_i (core->flags, fcnr->addr);
2473 char *fcnr_name = (flag && flag->name) ? flag->name : r_str_newf ("unk.0x%"PFMT64x, fcnr->addr);
2474 switch (fmt) {
2475 case R_GRAPH_FORMAT_GMLFCN:
2476 if (iteration == 0) {
2477 r_cons_printf (" node [\n"
2478 " id %"PFMT64d"\n"
2479 " label \"%s\"\n"
2480 " ]\n", fcnr->addr - base, fcnr_name);
2481 r_cons_printf (" edge [\n"
2482 " source %"PFMT64d"\n"
2483 " target %"PFMT64d"\n"
2484 " ]\n", fcni->addr-base, fcnr->addr-base);
2485 }
2486 case R_GRAPH_FORMAT_GML:
2487 if (iteration != 0) {
2488 r_cons_printf (" edge [\n"
2489 " source %"PFMT64d"\n"
2490 " target %"PFMT64d"\n"
2491 " ]\n", fcni->addr-base, fcnr->addr-base); //, "#000000"
2492 }
2493 break;
2494 case R_GRAPH_FORMAT_DOT:
2495 r_cons_printf (" \"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" "
2496 "[color=\"%s\" URL=\"%s/0x%08"PFMT64x"\"];\n",
2497 //"[label=\"%s\" color=\"%s\" URL=\"%s/0x%08"PFMT64x"\"];\n",
2498 fcni->addr, fcnr->addr, //, fcnr_name,
2499 "#61afef",
2500 fcnr_name, fcnr->addr);
2501 r_cons_printf (" \"0x%08"PFMT64x"\" "
2502 "[label=\"%s\""
2503 " URL=\"%s/0x%08"PFMT64x"\"];\n",
2504 fcnr->addr, fcnr_name,
2505 fcnr_name, fcnr->addr);
2506 break;
2507 case R_GRAPH_FORMAT_JSON:
2508 if (usenames) {
2509 pj_s (pj, fcnr_name);
2510 } else {
2511 char fcnr_addr[20];
2512 snprintf (fcnr_addr, sizeof (fcnr_addr) - 1, "0x%08" PFMT64x, fcnr->addr);
2513 pj_s (pj, fcnr_addr);
2514 }
2515 break;
2516 default:
2517 if (refgraph || fcnr->type == R_ANAL_REF_TYPE_CALL) {
2518 // TODO: avoid recreating nodes unnecessarily
2519 r_cons_printf ("agn %s\n", fcni->name);
2520 r_cons_printf ("agn %s\n", fcnr_name);
2521 r_cons_printf ("age %s %s\n", fcni->name, fcnr_name);
2522 } else {
2523 r_cons_printf ("# - 0x%08"PFMT64x" (%c)\n", fcnr->addr, fcnr->type);
2524 }
2525 }
2526 if (!(flag && flag->name)) {
2527 free(fcnr_name);
2528 }
2529 }
2530 r_list_free (refs);
2531 r_list_free (calls);
2532 if (fmt == R_GRAPH_FORMAT_JSON) {
2533 pj_end (pj);
2534 pj_end (pj);
2535 }
2536 }
2537 if (iteration == 0 && fmt == R_GRAPH_FORMAT_GML) {
2538 iteration++;
2539 goto repeat;
2540 }
2541 if (iteration == 0 && fmt == R_GRAPH_FORMAT_GMLFCN) {
2542 iteration++;
2543 }
2544 switch (fmt) {
2545 case R_GRAPH_FORMAT_GML:
2546 case R_GRAPH_FORMAT_GMLFCN:
2547 case R_GRAPH_FORMAT_JSON:
2548 pj_end (pj);
2549 r_cons_println (pj_string (pj));
2550 pj_free (pj);
2551 break;
2552 case R_GRAPH_FORMAT_DOT:
2553 r_cons_printf ("}\n");
2554 break;
2555 }
2556 }
2557
fcn_list_bbs(RAnalFunction * fcn)2558 static void fcn_list_bbs(RAnalFunction *fcn) {
2559 RAnalBlock *bbi;
2560 RListIter *iter;
2561
2562 r_list_foreach (fcn->bbs, iter, bbi) {
2563 r_cons_printf ("afb+ 0x%08" PFMT64x " 0x%08" PFMT64x " %" PFMT64u " ",
2564 fcn->addr, bbi->addr, bbi->size);
2565 r_cons_printf ("0x%08"PFMT64x" ", bbi->jump);
2566 r_cons_printf ("0x%08"PFMT64x, bbi->fail);
2567 if (bbi->diff) {
2568 if (bbi->diff->type == R_ANAL_DIFF_TYPE_MATCH) {
2569 r_cons_printf (" m");
2570 } else if (bbi->diff->type == R_ANAL_DIFF_TYPE_UNMATCH) {
2571 r_cons_printf (" u");
2572 } else {
2573 r_cons_printf (" n");
2574 }
2575 }
2576 r_cons_printf ("\n");
2577 }
2578 }
2579
r_core_anal_fcn_list_size(RCore * core)2580 R_API ut64 r_core_anal_fcn_list_size(RCore *core) {
2581 RAnalFunction *fcn;
2582 RListIter *iter;
2583 ut64 total = 0;
2584
2585 r_list_foreach (core->anal->fcns, iter, fcn) {
2586 total += r_anal_function_realsize (fcn);
2587 }
2588 r_cons_printf ("%"PFMT64u"\n", total);
2589 return total;
2590 }
2591
2592 /* Fill out metadata struct of functions */
fcnlist_gather_metadata(RAnal * anal,RList * fcns)2593 static int fcnlist_gather_metadata(RAnal *anal, RList *fcns) {
2594 RListIter *iter;
2595 RAnalFunction *fcn;
2596 RList *xrefs;
2597
2598 r_list_foreach (fcns, iter, fcn) {
2599 // Count the number of references and number of calls
2600 RListIter *callrefiter;
2601 RAnalRef *ref;
2602 RList *refs = r_anal_function_get_refs (fcn);
2603 int numcallrefs = 0;
2604 r_list_foreach (refs, callrefiter, ref) {
2605 if (ref->type == R_ANAL_REF_TYPE_CALL) {
2606 numcallrefs++;
2607 }
2608 }
2609 r_list_free (refs);
2610 fcn->meta.numcallrefs = numcallrefs;
2611 xrefs = r_anal_xrefs_get (anal, fcn->addr);
2612 fcn->meta.numrefs = xrefs? xrefs->length: 0;
2613 r_list_free (xrefs);
2614 }
2615 // TODO: Determine sgnc, sgec
2616 return 0;
2617 }
2618
r_core_anal_fcn_name(RCore * core,RAnalFunction * fcn)2619 R_API char *r_core_anal_fcn_name(RCore *core, RAnalFunction *fcn) {
2620 bool demangle = r_config_get_i (core->config, "bin.demangle");
2621 const char *lang = demangle ? r_config_get (core->config, "bin.lang") : NULL;
2622 bool keep_lib = r_config_get_i (core->config, "bin.demangle.libs");
2623 char *name = strdup (r_str_get (fcn->name));
2624 if (demangle) {
2625 char *tmp = r_bin_demangle (core->bin->cur, lang, name, fcn->addr, keep_lib);
2626 if (tmp) {
2627 free (name);
2628 name = tmp;
2629 }
2630 }
2631 return name;
2632 }
2633
2634 #define FCN_LIST_VERBOSE_ENTRY "%s0x%0*"PFMT64x" %4"PFMT64d" %5d %5d %5d %4d 0x%0*"PFMT64x" %5"PFMT64d" 0x%0*"PFMT64x" %5d %4d %6d %4d %5d %s%s\n"
fcn_print_verbose(RCore * core,RAnalFunction * fcn,bool use_color)2635 static int fcn_print_verbose(RCore *core, RAnalFunction *fcn, bool use_color) {
2636 char *name = r_core_anal_fcn_name (core, fcn);
2637 int ebbs = 0;
2638 int addrwidth = 8;
2639 const char *color = "";
2640 const char *color_end = "";
2641 if (use_color) {
2642 color_end = Color_RESET;
2643 if (strstr (name, "sym.imp.")) {
2644 color = Color_YELLOW;
2645 } else if (strstr (name, "sym.")) {
2646 color = Color_GREEN;
2647 } else if (strstr (name, "sub.")) {
2648 color = Color_MAGENTA;
2649 }
2650 }
2651
2652 if (core->anal->bits == 64) {
2653 addrwidth = 16;
2654 }
2655
2656 r_cons_printf (FCN_LIST_VERBOSE_ENTRY, color,
2657 addrwidth, fcn->addr,
2658 r_anal_function_realsize (fcn),
2659 r_list_length (fcn->bbs),
2660 r_anal_function_count_edges (fcn, &ebbs),
2661 r_anal_function_complexity (fcn),
2662 r_anal_function_cost (fcn),
2663 addrwidth, r_anal_function_min_addr (fcn),
2664 r_anal_function_linear_size (fcn),
2665 addrwidth, r_anal_function_max_addr (fcn),
2666 fcn->meta.numcallrefs,
2667 r_anal_var_count (core->anal, fcn, 's', 0) +
2668 r_anal_var_count (core->anal, fcn, 'b', 0) +
2669 r_anal_var_count (core->anal, fcn, 'r', 0),
2670 r_anal_var_count (core->anal, fcn, 's', 1) +
2671 r_anal_var_count (core->anal, fcn, 'b', 1) +
2672 r_anal_var_count (core->anal, fcn, 'r', 1),
2673 fcn->meta.numrefs,
2674 fcn->maxstack,
2675 name,
2676 color_end);
2677 free (name);
2678 return 0;
2679 }
2680
fcn_list_verbose(RCore * core,RList * fcns,const char * sortby)2681 static int fcn_list_verbose(RCore *core, RList *fcns, const char *sortby) {
2682 bool use_color = r_config_get_i (core->config, "scr.color");
2683 int headeraddr_width = 10;
2684 char *headeraddr = "==========";
2685
2686 if (core->anal->bits == 64) {
2687 headeraddr_width = 18;
2688 headeraddr = "==================";
2689 }
2690
2691 if (sortby) {
2692 if (!strcmp (sortby, "size")) {
2693 r_list_sort (fcns, cmpsize);
2694 } else if (!strcmp (sortby, "addr")) {
2695 r_list_sort (fcns, cmpaddr);
2696 } else if (!strcmp (sortby, "cc")) {
2697 r_list_sort (fcns, cmpfcncc);
2698 } else if (!strcmp (sortby, "edges")) {
2699 r_list_sort (fcns, cmpedges);
2700 } else if (!strcmp (sortby, "calls")) {
2701 r_list_sort (fcns, cmpcalls);
2702 } else if (strstr (sortby, "name")) {
2703 r_list_sort (fcns, cmpname);
2704 } else if (strstr (sortby, "frame")) {
2705 r_list_sort (fcns, cmpframe);
2706 } else if (strstr (sortby, "ref")) {
2707 r_list_sort (fcns, cmpxrefs);
2708 } else if (!strcmp (sortby, "nbbs")) {
2709 r_list_sort (fcns, cmpnbbs);
2710 }
2711 }
2712
2713 r_cons_printf ("%-*s %4s %5s %5s %5s %4s %*s range %-*s %s %s %s %s %s %s\n",
2714 headeraddr_width, "address", "size", "nbbs", "edges", "cc", "cost",
2715 headeraddr_width, "min bound", headeraddr_width, "max bound", "calls",
2716 "locals", "args", "xref", "frame", "name");
2717 r_cons_printf ("%s ==== ===== ===== ===== ==== %s ===== %s ===== ====== ==== ==== ===== ====\n",
2718 headeraddr, headeraddr, headeraddr);
2719 RListIter *iter;
2720 RAnalFunction *fcn;
2721 r_list_foreach (fcns, iter, fcn) {
2722 fcn_print_verbose (core, fcn, use_color);
2723 }
2724
2725 return 0;
2726 }
2727
__fcn_print_default(RCore * core,RAnalFunction * fcn,bool quiet)2728 static void __fcn_print_default(RCore *core, RAnalFunction *fcn, bool quiet) {
2729 if (quiet) {
2730 r_cons_printf ("0x%08"PFMT64x" ", fcn->addr);
2731 } else {
2732 char *msg, *name = r_core_anal_fcn_name (core, fcn);
2733 ut64 realsize = r_anal_function_realsize (fcn);
2734 ut64 size = r_anal_function_linear_size (fcn);
2735 if (realsize == size) {
2736 msg = r_str_newf ("%-12"PFMT64u, size);
2737 } else {
2738 msg = r_str_newf ("%-4"PFMT64u" -> %-4"PFMT64u, size, realsize);
2739 }
2740 r_cons_printf ("0x%08"PFMT64x" %4d %4s %s\n",
2741 fcn->addr, r_list_length (fcn->bbs), msg, name);
2742 free (name);
2743 free (msg);
2744 }
2745 }
2746
fcn_list_default(RCore * core,RList * fcns,bool quiet)2747 static int fcn_list_default(RCore *core, RList *fcns, bool quiet) {
2748 RListIter *iter;
2749 RAnalFunction *fcn;
2750 r_list_foreach (fcns, iter, fcn) {
2751 __fcn_print_default (core, fcn, quiet);
2752 if (quiet) {
2753 r_cons_newline ();
2754 }
2755 }
2756 return 0;
2757 }
2758
2759 // for a given function returns an RList of all functions that were called in it
r_core_anal_fcn_get_calls(RCore * core,RAnalFunction * fcn)2760 R_API RList *r_core_anal_fcn_get_calls (RCore *core, RAnalFunction *fcn) {
2761 RAnalRef *refi;
2762 RListIter *iter, *iter2;
2763
2764 // get all references from this function
2765 RList *refs = r_anal_function_get_refs (fcn);
2766 // sanity check
2767 if (!r_list_empty (refs)) {
2768 // iterate over all the references and remove these which aren't of type call
2769 r_list_foreach_safe (refs, iter, iter2, refi) {
2770 if (refi->type != R_ANAL_REF_TYPE_CALL) {
2771 r_list_delete (refs, iter);
2772 }
2773 }
2774 }
2775 return refs;
2776 }
2777
2778 // Lists function names and their calls (uniqified)
fcn_print_makestyle(RCore * core,RList * fcns,char mode)2779 static int fcn_print_makestyle(RCore *core, RList *fcns, char mode) {
2780 RListIter *refiter;
2781 RListIter *fcniter;
2782 RAnalFunction *fcn;
2783 RAnalRef *refi;
2784 RList *refs = NULL;
2785 PJ *pj = NULL;
2786
2787 if (mode == 'j') {
2788 pj = r_core_pj_new (core);
2789 pj_a (pj);
2790 }
2791
2792 // Iterate over all functions
2793 r_list_foreach (fcns, fcniter, fcn) {
2794 // Get all refs for a function
2795 refs = r_core_anal_fcn_get_calls (core, fcn);
2796 // Uniquify the list by ref->addr
2797 refs = r_list_uniq (refs, (RListComparator)RAnalRef_cmp);
2798
2799 // don't enter for functions with 0 refs
2800 if (!r_list_empty (refs)) {
2801 if (pj) { // begin json output of function
2802 pj_o (pj);
2803 pj_ks (pj, "name", fcn->name);
2804 pj_kn (pj, "addr", fcn->addr);
2805 pj_k (pj, "calls");
2806 pj_a (pj);
2807 } else {
2808 r_cons_printf ("%s", fcn->name);
2809 }
2810
2811 if (mode == 'm') {
2812 r_cons_printf (":\n");
2813 } else if (mode == 'q') {
2814 r_cons_printf (" -> ");
2815 }
2816 // Iterate over all refs from a function
2817 r_list_foreach (refs, refiter, refi) {
2818 RFlagItem *f = r_flag_get_i (core->flags, refi->addr);
2819 char *dst = r_str_newf ((f? f->name: "0x%08"PFMT64x), refi->addr);
2820 if (pj) { // Append calee json item
2821 pj_o (pj);
2822 pj_ks (pj, "name", dst);
2823 pj_kn (pj, "addr", refi->addr);
2824 pj_end (pj); // close referenced item
2825 } else if (mode == 'q') {
2826 r_cons_printf ("%s ", dst);
2827 } else {
2828 r_cons_printf (" %s\n", dst);
2829 }
2830 }
2831 if (pj) {
2832 pj_end (pj); // close list of calls
2833 pj_end (pj); // close function item
2834 } else {
2835 r_cons_newline();
2836 }
2837 }
2838 }
2839
2840 if (mode == 'j') {
2841 pj_end (pj); // close json output
2842 r_cons_printf ("%s\n", pj_string (pj));
2843 }
2844 if (pj) {
2845 pj_free (pj);
2846 }
2847 return 0;
2848 }
2849
fcn_print_json(RCore * core,RAnalFunction * fcn,PJ * pj)2850 static int fcn_print_json(RCore *core, RAnalFunction *fcn, PJ *pj) {
2851 RListIter *iter;
2852 RAnalRef *refi;
2853 RList *refs, *xrefs;
2854 if (!pj) {
2855 return -1;
2856 }
2857 int ebbs = 0;
2858 pj_o (pj);
2859 pj_kn (pj, "offset", fcn->addr);
2860 char *name = r_core_anal_fcn_name (core, fcn);
2861 if (name) {
2862 pj_ks (pj, "name", name);
2863 }
2864 pj_kn (pj, "size", r_anal_function_linear_size (fcn));
2865 pj_ks (pj, "is-pure", r_str_bool (r_anal_function_purity (fcn)));
2866 pj_kn (pj, "realsz", r_anal_function_realsize (fcn));
2867 pj_kb (pj, "noreturn", fcn->is_noreturn);
2868 pj_ki (pj, "stackframe", fcn->maxstack);
2869 if (fcn->cc) {
2870 pj_ks (pj, "calltype", fcn->cc); // calling conventions
2871 }
2872 pj_ki (pj, "cost", r_anal_function_cost (fcn)); // execution cost
2873 pj_ki (pj, "cc", r_anal_function_complexity (fcn)); // cyclic cost
2874 pj_ki (pj, "bits", fcn->bits);
2875 pj_ks (pj, "type", r_anal_fcntype_tostring (fcn->type));
2876 pj_ki (pj, "nbbs", r_list_length (fcn->bbs));
2877 pj_ki (pj, "edges", r_anal_function_count_edges (fcn, &ebbs));
2878 pj_ki (pj, "ebbs", ebbs);
2879 {
2880 char *sig = r_core_cmd_strf (core, "afcf @ 0x%"PFMT64x, fcn->addr);
2881 if (sig) {
2882 r_str_trim (sig);
2883 pj_ks (pj, "signature", sig);
2884 free (sig);
2885 }
2886
2887 }
2888 pj_kn (pj, "minbound", r_anal_function_min_addr (fcn));
2889 pj_kn (pj, "maxbound", r_anal_function_max_addr (fcn));
2890
2891 int outdegree = 0;
2892 refs = r_anal_function_get_refs (fcn);
2893 if (!r_list_empty (refs)) {
2894 pj_k (pj, "callrefs");
2895 pj_a (pj);
2896 r_list_foreach (refs, iter, refi) {
2897 if (refi->type == R_ANAL_REF_TYPE_CALL) {
2898 outdegree++;
2899 }
2900 if (refi->type == R_ANAL_REF_TYPE_CODE ||
2901 refi->type == R_ANAL_REF_TYPE_CALL) {
2902 pj_o (pj);
2903 pj_kn (pj, "addr", refi->addr);
2904 pj_ks (pj, "type", r_anal_xrefs_type_tostring (refi->type));
2905 pj_kn (pj, "at", refi->at);
2906 pj_end (pj);
2907 }
2908 }
2909 pj_end (pj);
2910
2911 pj_k (pj, "datarefs");
2912 pj_a (pj);
2913 r_list_foreach (refs, iter, refi) {
2914 if (refi->type == R_ANAL_REF_TYPE_DATA) {
2915 pj_n (pj, refi->addr);
2916 }
2917 }
2918 pj_end (pj);
2919 }
2920 r_list_free (refs);
2921
2922 int indegree = 0;
2923 xrefs = r_anal_function_get_xrefs (fcn);
2924 if (!r_list_empty (xrefs)) {
2925 pj_k (pj, "codexrefs");
2926 pj_a (pj);
2927 r_list_foreach (xrefs, iter, refi) {
2928 if (refi->type == R_ANAL_REF_TYPE_CODE ||
2929 refi->type == R_ANAL_REF_TYPE_CALL) {
2930 indegree++;
2931 pj_o (pj);
2932 pj_kn (pj, "addr", refi->addr);
2933 pj_ks (pj, "type", r_anal_xrefs_type_tostring (refi->type));
2934 pj_kn (pj, "at", refi->at);
2935 pj_end (pj);
2936 }
2937 }
2938
2939 pj_end (pj);
2940 pj_k (pj, "dataxrefs");
2941 pj_a (pj);
2942
2943 r_list_foreach (xrefs, iter, refi) {
2944 if (refi->type == R_ANAL_REF_TYPE_DATA) {
2945 pj_n (pj, refi->addr);
2946 }
2947 }
2948 pj_end (pj);
2949 }
2950 r_list_free (xrefs);
2951
2952 pj_ki (pj, "indegree", indegree);
2953 pj_ki (pj, "outdegree", outdegree);
2954
2955 if (fcn->type == R_ANAL_FCN_TYPE_FCN || fcn->type == R_ANAL_FCN_TYPE_SYM) {
2956 pj_ki (pj, "nlocals", r_anal_var_count (core->anal, fcn, 'b', 0) +
2957 r_anal_var_count (core->anal, fcn, 'r', 0) +
2958 r_anal_var_count (core->anal, fcn, 's', 0));
2959 pj_ki (pj, "nargs", r_anal_var_count (core->anal, fcn, 'b', 1) +
2960 r_anal_var_count (core->anal, fcn, 'r', 1) +
2961 r_anal_var_count (core->anal, fcn, 's', 1));
2962
2963 pj_k (pj, "bpvars");
2964 r_anal_var_list_show (core->anal, fcn, 'b', 'j', pj);
2965 pj_k (pj, "spvars");
2966 r_anal_var_list_show (core->anal, fcn, 's', 'j', pj);
2967 pj_k (pj, "regvars");
2968 r_anal_var_list_show (core->anal, fcn, 'r', 'j', pj);
2969
2970 pj_ks (pj, "difftype", fcn->diff->type == R_ANAL_DIFF_TYPE_MATCH?"match":
2971 fcn->diff->type == R_ANAL_DIFF_TYPE_UNMATCH?"unmatch":"new");
2972 if (fcn->diff->addr != -1) {
2973 pj_kn (pj, "diffaddr", fcn->diff->addr);
2974 }
2975 if (fcn->diff->name) {
2976 pj_ks (pj, "diffname", fcn->diff->name);
2977 }
2978 }
2979 pj_end (pj);
2980 free (name);
2981 return 0;
2982 }
2983
fcn_list_json(RCore * core,RList * fcns,bool quiet)2984 static int fcn_list_json(RCore *core, RList *fcns, bool quiet) {
2985 RListIter *iter;
2986 RAnalFunction *fcn;
2987 PJ *pj = r_core_pj_new (core);
2988 if (!pj) {
2989 return -1;
2990 }
2991 pj_a (pj);
2992 r_list_foreach (fcns, iter, fcn) {
2993 if (quiet) {
2994 pj_n (pj, fcn->addr);
2995 } else {
2996 fcn_print_json (core, fcn, pj);
2997 }
2998 }
2999 pj_end (pj);
3000 r_cons_println (pj_string (pj));
3001 pj_free (pj);
3002 return 0;
3003 }
3004
fcn_list_verbose_json(RCore * core,RList * fcns)3005 static int fcn_list_verbose_json(RCore *core, RList *fcns) {
3006 return fcn_list_json (core, fcns, false);
3007 }
3008
fcn_print_detail(RCore * core,RAnalFunction * fcn)3009 static int fcn_print_detail(RCore *core, RAnalFunction *fcn) {
3010 const char *defaultCC = r_anal_cc_default (core->anal);
3011 char *name = r_core_anal_fcn_name (core, fcn);
3012 r_cons_printf ("\"f %s %"PFMT64u" 0x%08"PFMT64x"\"\n", name, r_anal_function_linear_size (fcn), fcn->addr);
3013 r_cons_printf ("\"af+ 0x%08"PFMT64x" %s %c %c\"\n",
3014 fcn->addr, name, //r_anal_fcn_size (fcn), name,
3015 fcn->type == R_ANAL_FCN_TYPE_LOC?'l':
3016 fcn->type == R_ANAL_FCN_TYPE_SYM?'s':
3017 fcn->type == R_ANAL_FCN_TYPE_IMP?'i':'f',
3018 fcn->diff->type == R_ANAL_DIFF_TYPE_MATCH?'m':
3019 fcn->diff->type == R_ANAL_DIFF_TYPE_UNMATCH?'u':'n');
3020 // FIXME: this command prints something annoying. Does it have important side-effects?
3021 fcn_list_bbs (fcn);
3022 if (fcn->bits != 0) {
3023 r_cons_printf ("afB %d @ 0x%08"PFMT64x"\n", fcn->bits, fcn->addr);
3024 }
3025 // FIXME command injection vuln here
3026 if (fcn->cc || defaultCC) {
3027 r_cons_printf ("afc %s @ 0x%08"PFMT64x"\n", fcn->cc?fcn->cc: defaultCC, fcn->addr);
3028 }
3029 if (fcn->folded) {
3030 r_cons_printf ("afF @ 0x%08"PFMT64x"\n", fcn->addr);
3031 }
3032 if (fcn) {
3033 /* show variables and arguments */
3034 r_core_cmdf (core, "afvb* @ 0x%"PFMT64x"\n", fcn->addr);
3035 r_core_cmdf (core, "afvr* @ 0x%"PFMT64x"\n", fcn->addr);
3036 r_core_cmdf (core, "afvs* @ 0x%"PFMT64x"\n", fcn->addr);
3037 }
3038 /* Show references */
3039 RListIter *refiter;
3040 RAnalRef *refi;
3041 RList *refs = r_anal_function_get_refs (fcn);
3042 r_list_foreach (refs, refiter, refi) {
3043 switch (refi->type) {
3044 case R_ANAL_REF_TYPE_CALL:
3045 r_cons_printf ("axC 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
3046 break;
3047 case R_ANAL_REF_TYPE_DATA:
3048 r_cons_printf ("axd 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
3049 break;
3050 case R_ANAL_REF_TYPE_CODE:
3051 r_cons_printf ("axc 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
3052 break;
3053 case R_ANAL_REF_TYPE_STRING:
3054 r_cons_printf ("axs 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
3055 break;
3056 case R_ANAL_REF_TYPE_NULL:
3057 default:
3058 r_cons_printf ("ax 0x%"PFMT64x" 0x%"PFMT64x"\n", refi->addr, refi->at);
3059 break;
3060 }
3061 }
3062 r_list_free (refs);
3063 /*Saving Function stack frame*/
3064 r_cons_printf ("afS %d @ 0x%"PFMT64x"\n", fcn->maxstack, fcn->addr);
3065 free (name);
3066 return 0;
3067 }
3068
is_fcn_traced(RDebugTrace * traced,RAnalFunction * fcn)3069 static bool is_fcn_traced(RDebugTrace *traced, RAnalFunction *fcn) {
3070 int tag = traced->tag;
3071 RListIter *iter;
3072 RDebugTracepoint *trace;
3073
3074 r_list_foreach (traced->traces, iter, trace) {
3075 if (!trace->tag || (tag & trace->tag)) {
3076 if (r_anal_function_contains (fcn, trace->addr)) {
3077 r_cons_printf ("\ntraced: %d\n", trace->times);
3078 return true;
3079 }
3080 }
3081 }
3082 return false;
3083 }
3084
fcn_print_legacy(RCore * core,RAnalFunction * fcn)3085 static int fcn_print_legacy(RCore *core, RAnalFunction *fcn) {
3086 RListIter *iter;
3087 RAnalRef *refi;
3088 RList *refs, *xrefs;
3089 int ebbs = 0;
3090 char *name = r_core_anal_fcn_name (core, fcn);
3091
3092 r_cons_printf ("#\noffset: 0x%08"PFMT64x"\nname: %s\nsize: %"PFMT64u,
3093 fcn->addr, name, r_anal_function_linear_size (fcn));
3094 r_cons_printf ("\nis-pure: %s", r_str_bool (r_anal_function_purity (fcn)));
3095 r_cons_printf ("\nrealsz: %" PFMT64d, r_anal_function_realsize (fcn));
3096 r_cons_printf ("\nstackframe: %d", fcn->maxstack);
3097 if (fcn->cc) {
3098 r_cons_printf ("\ncall-convention: %s", fcn->cc);
3099 }
3100 r_cons_printf ("\ncyclomatic-cost: %d", r_anal_function_cost (fcn));
3101 r_cons_printf ("\ncyclomatic-complexity: %d", r_anal_function_complexity (fcn));
3102 r_cons_printf ("\nbits: %d", fcn->bits);
3103 r_cons_printf ("\ntype: %s", r_anal_fcntype_tostring (fcn->type));
3104 if (fcn->type == R_ANAL_FCN_TYPE_FCN || fcn->type == R_ANAL_FCN_TYPE_SYM) {
3105 r_cons_printf (" [%s]",
3106 fcn->diff->type == R_ANAL_DIFF_TYPE_MATCH?"MATCH":
3107 fcn->diff->type == R_ANAL_DIFF_TYPE_UNMATCH?"UNMATCH":"NEW");
3108 }
3109 r_cons_printf ("\nnum-bbs: %d", r_list_length (fcn->bbs));
3110 r_cons_printf ("\nedges: %d", r_anal_function_count_edges (fcn, &ebbs));
3111 r_cons_printf ("\nend-bbs: %d", ebbs);
3112 r_cons_printf ("\ncall-refs:");
3113 int outdegree = 0;
3114 refs = r_anal_function_get_refs (fcn);
3115 r_list_foreach (refs, iter, refi) {
3116 if (refi->type == R_ANAL_REF_TYPE_CALL) {
3117 outdegree++;
3118 }
3119 if (refi->type == R_ANAL_REF_TYPE_CODE || refi->type == R_ANAL_REF_TYPE_CALL) {
3120 r_cons_printf (" 0x%08"PFMT64x" %c", refi->addr,
3121 refi->type == R_ANAL_REF_TYPE_CALL?'C':'J');
3122 }
3123 }
3124 r_cons_printf ("\ndata-refs:");
3125 r_list_foreach (refs, iter, refi) {
3126 // global or local?
3127 if (refi->type == R_ANAL_REF_TYPE_DATA) {
3128 r_cons_printf (" 0x%08"PFMT64x, refi->addr);
3129 }
3130 }
3131 r_list_free (refs);
3132
3133 int indegree = 0;
3134 r_cons_printf ("\ncode-xrefs:");
3135 xrefs = r_anal_function_get_xrefs (fcn);
3136 r_list_foreach (xrefs, iter, refi) {
3137 if (refi->type == R_ANAL_REF_TYPE_CODE || refi->type == R_ANAL_REF_TYPE_CALL) {
3138 indegree++;
3139 r_cons_printf (" 0x%08"PFMT64x" %c", refi->addr,
3140 refi->type == R_ANAL_REF_TYPE_CALL?'C':'J');
3141 }
3142 }
3143 r_cons_printf ("\nnoreturn: %s", r_str_bool (fcn->is_noreturn));
3144 r_cons_printf ("\nin-degree: %d", indegree);
3145 r_cons_printf ("\nout-degree: %d", outdegree);
3146 r_cons_printf ("\ndata-xrefs:");
3147 r_list_foreach (xrefs, iter, refi) {
3148 if (refi->type == R_ANAL_REF_TYPE_DATA) {
3149 r_cons_printf (" 0x%08"PFMT64x, refi->addr);
3150 }
3151 }
3152 r_list_free (xrefs);
3153
3154 if (fcn->type == R_ANAL_FCN_TYPE_FCN || fcn->type == R_ANAL_FCN_TYPE_SYM) {
3155 int args_count = r_anal_var_count (core->anal, fcn, 'b', 1);
3156 args_count += r_anal_var_count (core->anal, fcn, 's', 1);
3157 args_count += r_anal_var_count (core->anal, fcn, 'r', 1);
3158 int var_count = r_anal_var_count (core->anal, fcn, 'b', 0);
3159 var_count += r_anal_var_count (core->anal, fcn, 's', 0);
3160 var_count += r_anal_var_count (core->anal, fcn, 'r', 0);
3161
3162 r_cons_printf ("\nlocals: %d\nargs: %d\n", var_count, args_count);
3163 r_anal_var_list_show (core->anal, fcn, 'b', 0, NULL);
3164 r_anal_var_list_show (core->anal, fcn, 's', 0, NULL);
3165 r_anal_var_list_show (core->anal, fcn, 'r', 0, NULL);
3166 r_cons_printf ("diff: type: %s",
3167 fcn->diff->type == R_ANAL_DIFF_TYPE_MATCH?"match":
3168 fcn->diff->type == R_ANAL_DIFF_TYPE_UNMATCH?"unmatch":"new");
3169 if (fcn->diff->addr != -1) {
3170 r_cons_printf ("addr: 0x%"PFMT64x, fcn->diff->addr);
3171 }
3172 if (fcn->diff->name) {
3173 r_cons_printf ("function: %s", fcn->diff->name);
3174 }
3175 }
3176 free (name);
3177
3178 // traced
3179 if (core->dbg->trace->enabled) {
3180 is_fcn_traced (core->dbg->trace, fcn);
3181 }
3182 return 0;
3183 }
3184
fcn_list_detail(RCore * core,RList * fcns)3185 static int fcn_list_detail(RCore *core, RList *fcns) {
3186 RListIter *iter;
3187 RAnalFunction *fcn;
3188 r_list_foreach (fcns, iter, fcn) {
3189 fcn_print_detail (core, fcn);
3190 }
3191 r_cons_newline ();
3192 return 0;
3193 }
3194
fcn_list_table(RCore * core,const char * q,int fmt)3195 static int fcn_list_table(RCore *core, const char *q, int fmt) {
3196 RAnalFunction *fcn;
3197 RListIter *iter;
3198 RTable *t = r_core_table (core, "fcns");
3199 RTableColumnType *typeString = r_table_type ("string");
3200 RTableColumnType *typeNumber = r_table_type ("number");
3201 r_table_add_column (t, typeNumber, "addr", 0);
3202 r_table_add_column (t, typeNumber, "size", 0);
3203 r_table_add_column (t, typeString, "name", 0);
3204 r_table_add_column (t, typeNumber, "nbbs", 0);
3205 r_table_add_column (t, typeNumber, "xref", 0);
3206 r_table_add_column (t, typeNumber, "calls", 0);
3207 r_table_add_column (t, typeNumber, "cc", 0);
3208 r_list_foreach (core->anal->fcns, iter, fcn) {
3209 const char *fcnAddr = sdb_fmt ("0x%08"PFMT64x, fcn->addr);
3210 const char *fcnSize = sdb_fmt ("%"PFMT64u, r_anal_function_linear_size (fcn));
3211 const char *nbbs = sdb_fmt ("%d", r_list_length (fcn->bbs)); // r_anal_fcn_size (fcn));
3212 RList *xrefs = r_anal_function_get_xrefs (fcn);
3213 char xref[128], ccstr[128];
3214 snprintf (xref, sizeof (xref), "%d", r_list_length (xrefs));
3215 r_list_free (xrefs);
3216
3217 RList * calls = r_core_anal_fcn_get_calls (core, fcn);
3218 // Uniquify the list by ref->addr
3219 calls = r_list_uniq (calls, (RListComparator)RAnalRef_cmp);
3220 const char *callstr = sdb_fmt ("%d", r_list_length (calls));
3221 r_list_free (calls);
3222 snprintf (ccstr, sizeof (ccstr), "%d", r_anal_function_complexity (fcn));
3223
3224 r_table_add_row (t, fcnAddr, fcnSize, fcn->name, nbbs, xref, callstr, ccstr, NULL);
3225 }
3226 if (r_table_query (t, q)) {
3227 char *s = (fmt== 'j')
3228 ? r_table_tojson (t)
3229 : r_table_tostring (t);
3230 r_cons_printf ("%s\n", s);
3231 free (s);
3232 }
3233 r_table_free (t);
3234 return 0;
3235 }
3236
fcn_list_legacy(RCore * core,RList * fcns)3237 static int fcn_list_legacy(RCore *core, RList *fcns) {
3238 RListIter *iter;
3239 RAnalFunction *fcn;
3240 r_list_foreach (fcns, iter, fcn) {
3241 fcn_print_legacy (core, fcn);
3242 }
3243 r_cons_newline ();
3244 return 0;
3245 }
3246
r_core_anal_fcn_list(RCore * core,const char * input,const char * rad)3247 R_API int r_core_anal_fcn_list(RCore *core, const char *input, const char *rad) {
3248 char temp[64];
3249 r_return_val_if_fail (core && core->anal, 0);
3250 if (r_list_empty (core->anal->fcns)) {
3251 return 0;
3252 }
3253 if (*rad == '.') {
3254 RList *fcns = r_anal_get_functions_in (core->anal, core->offset);
3255 if (!fcns || r_list_empty (fcns)) {
3256 eprintf ("No functions at current address.\n");
3257 r_list_free (fcns);
3258 return -1;
3259 }
3260 fcn_list_default (core, fcns, false);
3261 r_list_free (fcns);
3262 return 0;
3263 }
3264
3265 if (rad && (*rad == 'l' || *rad == 'j')) {
3266 fcnlist_gather_metadata (core->anal, core->anal->fcns);
3267 }
3268
3269 const char *name = input;
3270 ut64 addr = core->offset;
3271 if (input && *input) {
3272 name = input + 1;
3273 addr = r_num_math (core->num, name);
3274 }
3275
3276 RList *fcns = r_list_newf (NULL);
3277 if (!fcns) {
3278 return -1;
3279 }
3280 RListIter *iter;
3281 RAnalFunction *fcn;
3282 r_list_foreach (core->anal->fcns, iter, fcn) {
3283 if (!input || r_anal_function_contains (fcn, addr) || (!strcmp (name, fcn->name))) {
3284 r_list_append (fcns, fcn);
3285 }
3286 }
3287
3288 // r_list_sort (fcns, &cmpfcn);
3289 if (!rad) {
3290 fcn_list_default (core, fcns, false);
3291 r_list_free (fcns);
3292 return 0;
3293 }
3294 switch (*rad) {
3295 case '+':
3296 r_core_anal_fcn_list_size (core);
3297 break;
3298 case '=': { // afl=
3299 r_list_sort (fcns, cmpaddr);
3300 RList *flist = r_list_newf ((RListFree) r_listinfo_free);
3301 if (!flist) {
3302 r_list_free (fcns);
3303 return -1;
3304 }
3305 ls_foreach (fcns, iter, fcn) {
3306 RInterval inter = {r_anal_function_min_addr (fcn), r_anal_function_linear_size (fcn) };
3307 RListInfo *info = r_listinfo_new (r_core_anal_fcn_name (core, fcn), inter, inter, -1, sdb_itoa (fcn->bits, temp, 10));
3308 if (!info) {
3309 break;
3310 }
3311 r_list_append (flist, info);
3312 }
3313 RTable *table = r_core_table (core, "functions");
3314 r_table_visual_list (table, flist, core->offset, core->blocksize,
3315 r_cons_get_size (NULL), r_config_get_i (core->config, "scr.color"));
3316 r_cons_printf ("\n%s\n", r_table_tostring (table));
3317 r_table_free (table);
3318 r_list_free (flist);
3319 break;
3320 }
3321 case ',': // "afl," "afl,j"
3322 case 't': // "aflt" "afltj"
3323 if (rad[1] == 'j') {
3324 fcn_list_table (core, r_str_trim_head_ro (rad + 2), 'j');
3325 } else {
3326 fcn_list_table (core, r_str_trim_head_ro (rad + 1), rad[1]);
3327 }
3328 break;
3329 case 'l': // "afll" "afllj"
3330 if (rad[1] == 'j') {
3331 fcn_list_verbose_json (core, fcns);
3332 } else {
3333 char *sp = strchr (rad, ' ');
3334 fcn_list_verbose (core, fcns, sp?sp+1: NULL);
3335 }
3336 break;
3337 case 'q':
3338 if (rad[1] == 'j') {
3339 fcn_list_json (core, fcns, true);
3340 } else {
3341 fcn_list_default (core, fcns, true);
3342 }
3343 break;
3344 case 'j':
3345 fcn_list_json (core, fcns, false);
3346 break;
3347 case '*':
3348 fcn_list_detail (core, fcns);
3349 break;
3350 case 'm': // "aflm"
3351 {
3352 char mode = 'm';
3353 if (rad[1] != 0) {
3354 if (rad[1] == 'j') { // "aflmj"
3355 mode = 'j';
3356 } else if (rad[1] == 'q') { // "aflmq"
3357 mode = 'q';
3358 }
3359 }
3360 fcn_print_makestyle (core, fcns, mode);
3361 break;
3362 }
3363 case 1:
3364 fcn_list_legacy (core, fcns);
3365 break;
3366 default:
3367 fcn_list_default (core, fcns, false);
3368 break;
3369 }
3370 r_list_free (fcns);
3371 return 0;
3372 }
3373
3374 static RList *recurse_bb(RCore *core, ut64 addr, RAnalBlock *dest);
3375
recurse(RCore * core,RAnalBlock * from,RAnalBlock * dest)3376 static RList *recurse(RCore *core, RAnalBlock *from, RAnalBlock *dest) {
3377 recurse_bb (core, from->jump, dest);
3378 recurse_bb (core, from->fail, dest);
3379
3380 /* same for all calls */
3381 // TODO: RAnalBlock must contain a linked list of calls
3382 return NULL;
3383 }
3384
recurse_bb(RCore * core,ut64 addr,RAnalBlock * dest)3385 static RList *recurse_bb(RCore *core, ut64 addr, RAnalBlock *dest) {
3386 RAnalBlock *bb = r_anal_bb_from_offset (core->anal, addr);
3387 if (bb == dest) {
3388 eprintf ("path found!");
3389 return NULL;
3390 }
3391 return recurse (core, bb, dest);
3392 }
3393
3394 #define REG_SET_SIZE (R_ANAL_CC_MAXARG + 2)
3395
3396 typedef struct {
3397 int count;
3398 RPVector reg_set;
3399 bool argonly;
3400 RAnalFunction *fcn;
3401 RCore *core;
3402 } BlockRecurseCtx;
3403
anal_block_on_exit(RAnalBlock * bb,BlockRecurseCtx * ctx)3404 static bool anal_block_on_exit(RAnalBlock *bb, BlockRecurseCtx *ctx) {
3405 int *cur_regset = r_pvector_pop (&ctx->reg_set);
3406 int *prev_regset = r_pvector_at (&ctx->reg_set, r_pvector_len (&ctx->reg_set) - 1);
3407 size_t i;
3408 for (i = 0; i < REG_SET_SIZE; i++) {
3409 if (!prev_regset[i] && cur_regset[i] == 1) {
3410 prev_regset[i] = 1;
3411 }
3412 }
3413 free (cur_regset);
3414 return true;
3415 }
3416
anal_block_cb(RAnalBlock * bb,BlockRecurseCtx * ctx)3417 static bool anal_block_cb(RAnalBlock *bb, BlockRecurseCtx *ctx) {
3418 if (r_cons_is_breaked ()) {
3419 return false;
3420 }
3421 if (bb->size < 1) {
3422 return true;
3423 }
3424 if (bb->size > ctx->core->anal->opt.bb_max_size) {
3425 return true;
3426 }
3427 int *parent_reg_set = r_pvector_at (&ctx->reg_set, r_pvector_len (&ctx->reg_set) - 1);
3428 int *reg_set = R_NEWS (int, REG_SET_SIZE);
3429 memcpy (reg_set, parent_reg_set, REG_SET_SIZE * sizeof (int));
3430 r_pvector_push (&ctx->reg_set, reg_set);
3431 RCore *core = ctx->core;
3432 RAnalFunction *fcn = ctx->fcn;
3433 fcn->stack = bb->parent_stackptr;
3434 ut64 pos = bb->addr;
3435 while (pos < bb->addr + bb->size) {
3436 if (r_cons_is_breaked ()) {
3437 break;
3438 }
3439 RAnalOp *op = r_core_anal_op (core, pos, R_ANAL_OP_MASK_ESIL | R_ANAL_OP_MASK_VAL | R_ANAL_OP_MASK_HINT);
3440 if (!op) {
3441 //eprintf ("Cannot get op\n");
3442 break;
3443 }
3444 r_anal_extract_rarg (core->anal, op, fcn, reg_set, &ctx->count);
3445 if (!ctx->argonly) {
3446 if (op->stackop == R_ANAL_STACK_INC) {
3447 fcn->stack += op->stackptr;
3448 } else if (op->stackop == R_ANAL_STACK_RESET) {
3449 fcn->stack = 0;
3450 }
3451 r_anal_extract_vars (core->anal, fcn, op);
3452 }
3453 int opsize = op->size;
3454 int optype = op->type;
3455 r_anal_op_free (op);
3456 if (opsize < 1) {
3457 break;
3458 }
3459 if (optype == R_ANAL_OP_TYPE_CALL) {
3460 size_t i;
3461 int max_count = fcn->cc ? r_anal_cc_max_arg (core->anal, fcn->cc) : 0;
3462 for (i = 0; i < max_count; i++) {
3463 reg_set[i] = 2;
3464 }
3465 }
3466 pos += opsize;
3467 }
3468 return true;
3469 }
3470
3471 // TODO: move this logic into the main anal loop
r_core_recover_vars(RCore * core,RAnalFunction * fcn,bool argonly)3472 R_API void r_core_recover_vars(RCore *core, RAnalFunction *fcn, bool argonly) {
3473 r_return_if_fail (core && core->anal && fcn);
3474 if (core->anal->opt.bb_max_size < 1) {
3475 return;
3476 }
3477 BlockRecurseCtx ctx = { 0, {{ 0 }}, argonly, fcn, core };
3478 r_pvector_init (&ctx.reg_set, free);
3479 int *reg_set = R_NEWS0 (int, REG_SET_SIZE);
3480 r_pvector_push (&ctx.reg_set, reg_set);
3481 int saved_stack = fcn->stack;
3482 RAnalBlock *first_bb = r_anal_get_block_at (fcn->anal, fcn->addr);
3483 r_anal_block_recurse_depth_first (first_bb, (RAnalBlockCb)anal_block_cb, (RAnalBlockCb)anal_block_on_exit, &ctx);
3484 r_pvector_fini (&ctx.reg_set);
3485 fcn->stack = saved_stack;
3486 }
3487
anal_path_exists(RCore * core,ut64 from,ut64 to,RList * bbs,int depth,HtUP * state,HtUP * avoid)3488 static bool anal_path_exists(RCore *core, ut64 from, ut64 to, RList *bbs, int depth, HtUP *state, HtUP *avoid) {
3489 r_return_val_if_fail (bbs, false);
3490 RAnalBlock *bb = r_anal_bb_from_offset (core->anal, from);
3491 RListIter *iter = NULL;
3492 RAnalRef *refi;
3493
3494 if (depth < 1) {
3495 eprintf ("going too deep\n");
3496 return false;
3497 }
3498
3499 if (!bb) {
3500 return false;
3501 }
3502
3503 ht_up_update (state, from, bb);
3504
3505 // try to find the target in the current function
3506 if (r_anal_block_contains (bb, to) ||
3507 ((!ht_up_find (avoid, bb->jump, NULL) &&
3508 !ht_up_find (state, bb->jump, NULL) &&
3509 anal_path_exists (core, bb->jump, to, bbs, depth - 1, state, avoid))) ||
3510 ((!ht_up_find (avoid, bb->fail, NULL) &&
3511 !ht_up_find (state, bb->fail, NULL) &&
3512 anal_path_exists (core, bb->fail, to, bbs, depth - 1, state, avoid)))) {
3513 r_list_prepend (bbs, bb);
3514 return true;
3515 }
3516
3517 // find our current function
3518 RAnalFunction *cur_fcn = r_anal_get_fcn_in (core->anal, from, 0);
3519
3520 // get call refs from current basic block and find a path from them
3521 if (cur_fcn) {
3522 RList *refs = r_anal_function_get_refs (cur_fcn);
3523 if (refs) {
3524 r_list_foreach (refs, iter, refi) {
3525 if (refi->type == R_ANAL_REF_TYPE_CALL) {
3526 if (r_anal_block_contains (bb, refi->at)) {
3527 if ((refi->at != refi->addr) && !ht_up_find (state, refi->addr, NULL) && anal_path_exists (core, refi->addr, to, bbs, depth - 1, state, avoid)) {
3528 r_list_prepend (bbs, bb);
3529 r_list_free (refs);
3530 return true;
3531 }
3532 }
3533 }
3534 }
3535 }
3536 r_list_free (refs);
3537 }
3538
3539 return false;
3540 }
3541
anal_graph_to(RCore * core,ut64 addr,int depth,HtUP * avoid)3542 static RList *anal_graph_to(RCore *core, ut64 addr, int depth, HtUP *avoid) {
3543 RAnalFunction *cur_fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
3544 RList *list = r_list_new ();
3545 HtUP *state = ht_up_new0 ();
3546
3547 if (!list || !state || !cur_fcn) {
3548 r_list_free (list);
3549 ht_up_free (state);
3550 return NULL;
3551 }
3552
3553 // forward search
3554 if (anal_path_exists (core, core->offset, addr, list, depth - 1, state, avoid)) {
3555 ht_up_free (state);
3556 return list;
3557 }
3558
3559 // backward search
3560 RList *xrefs = r_anal_xrefs_get (core->anal, cur_fcn->addr);
3561 if (xrefs) {
3562 RListIter *iter;
3563 RAnalRef *xref = NULL;
3564 r_list_foreach (xrefs, iter, xref) {
3565 if (xref->type == R_ANAL_REF_TYPE_CALL) {
3566 ut64 offset = core->offset;
3567 core->offset = xref->addr;
3568 r_list_free (list);
3569 list = anal_graph_to (core, addr, depth - 1, avoid);
3570 core->offset = offset;
3571 if (list && r_list_length (list)) {
3572 r_list_free (xrefs);
3573 ht_up_free (state);
3574 return list;
3575 }
3576 }
3577 }
3578 }
3579
3580 r_list_free (xrefs);
3581 ht_up_free (state);
3582 r_list_free (list);
3583 return NULL;
3584 }
3585
r_core_anal_graph_to(RCore * core,ut64 addr,int n)3586 R_API RList* r_core_anal_graph_to(RCore *core, ut64 addr, int n) {
3587 int depth = r_config_get_i (core->config, "anal.graph_depth");
3588 RList *path, *paths = r_list_new ();
3589 HtUP *avoid = ht_up_new0 ();
3590 while (n) {
3591 path = anal_graph_to (core, addr, depth, avoid);
3592 if (path) {
3593 r_list_append (paths, path);
3594 if (r_list_length (path) >= 2) {
3595 RAnalBlock *last = r_list_get_n (path, r_list_length (path) - 2);
3596 ht_up_update (avoid, last->addr, last);
3597 n--;
3598 continue;
3599 }
3600 }
3601 // no more path found
3602 break;
3603 }
3604 ht_up_free (avoid);
3605 return paths;
3606 }
3607
r_core_anal_graph(RCore * core,ut64 addr,int opts)3608 R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) {
3609 ut64 from = r_config_get_i (core->config, "graph.from");
3610 ut64 to = r_config_get_i (core->config, "graph.to");
3611 const char *font = r_config_get (core->config, "graph.font");
3612 int is_html = r_cons_singleton ()->is_html;
3613 int is_json = opts & R_CORE_ANAL_JSON;
3614 int is_json_format_disasm = opts & R_CORE_ANAL_JSON_FORMAT_DISASM;
3615 int is_keva = opts & R_CORE_ANAL_KEYVALUE;
3616 int is_star = opts & R_CORE_ANAL_STAR;
3617 RConfigHold *hc;
3618 RAnalFunction *fcni;
3619 RListIter *iter;
3620 int nodes = 0;
3621 PJ *pj = NULL;
3622
3623 if (!addr) {
3624 addr = core->offset;
3625 }
3626 if (r_list_empty (core->anal->fcns)) {
3627 return false;
3628 }
3629 hc = r_config_hold_new (core->config);
3630 if (!hc) {
3631 return false;
3632 }
3633
3634 r_config_hold (hc, "asm.lines", "asm.bytes", "asm.dwarf", NULL);
3635 //opts |= R_CORE_ANAL_GRAPHBODY;
3636 r_config_set_i (core->config, "asm.lines", 0);
3637 r_config_set_i (core->config, "asm.dwarf", 0);
3638 if (!is_json_format_disasm) {
3639 r_config_hold (hc, "asm.bytes", NULL);
3640 r_config_set_i (core->config, "asm.bytes", 0);
3641 }
3642 if (!is_html && !is_json && !is_keva && !is_star) {
3643 const char * gv_edge = r_config_get (core->config, "graph.gv.edge");
3644 const char * gv_node = r_config_get (core->config, "graph.gv.node");
3645 const char * gv_spline = r_config_get (core->config, "graph.gv.spline");
3646 if (!gv_edge || !*gv_edge) {
3647 gv_edge = "arrowhead=\"normal\"";
3648 }
3649 if (!gv_node || !*gv_node) {
3650 gv_node = "fillcolor=gray style=filled shape=box";
3651 }
3652 if (!gv_spline || !*gv_spline) {
3653 gv_spline = "splines=\"ortho\"";
3654 }
3655 r_cons_printf ("digraph code {\n"
3656 "\tgraph [bgcolor=azure fontsize=8 fontname=\"%s\" %s];\n"
3657 "\tnode [%s];\n"
3658 "\tedge [%s];\n", font, gv_spline, gv_node, gv_edge);
3659 }
3660 if (is_json) {
3661 pj = r_core_pj_new (core);
3662 if (!pj) {
3663 r_config_hold_restore (hc);
3664 r_config_hold_free (hc);
3665 return false;
3666 }
3667 pj_a (pj);
3668 }
3669 r_list_foreach (core->anal->fcns, iter, fcni) {
3670 if (fcni->type & (R_ANAL_FCN_TYPE_SYM | R_ANAL_FCN_TYPE_FCN |
3671 R_ANAL_FCN_TYPE_LOC) &&
3672 (addr == UT64_MAX || r_anal_get_fcn_in (core->anal, addr, 0) == fcni)) {
3673 if (addr == UT64_MAX && (from != UT64_MAX && to != UT64_MAX)) {
3674 if (fcni->addr < from || fcni->addr > to) {
3675 continue;
3676 }
3677 }
3678 nodes += core_anal_graph_nodes (core, fcni, opts, pj);
3679 if (addr != UT64_MAX) {
3680 break;
3681 }
3682 }
3683 }
3684 if (!nodes) {
3685 if (!is_html && !is_json && !is_keva) {
3686 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
3687 if (is_star) {
3688 char *name = get_title(fcn ? fcn->addr: addr);
3689 r_cons_printf ("agn %s;", name);
3690 } else {
3691 r_cons_printf ("\t\"0x%08"PFMT64x"\";\n", fcn? fcn->addr: addr);
3692 }
3693 }
3694 }
3695 if (!is_keva && !is_html && !is_json && !is_star && !is_json_format_disasm) {
3696 r_cons_printf ("}\n");
3697 }
3698 if (is_json) {
3699 pj_end (pj);
3700 r_cons_printf ("%s\n", pj_string (pj));
3701 pj_free (pj);
3702 }
3703 r_config_hold_restore (hc);
3704 r_config_hold_free (hc);
3705 return true;
3706 }
3707
core_anal_followptr(RCore * core,int type,ut64 at,ut64 ptr,ut64 ref,int code,int depth)3708 static int core_anal_followptr(RCore *core, int type, ut64 at, ut64 ptr, ut64 ref, int code, int depth) {
3709 // SLOW Operation try to reduce as much as possible
3710 if (!ptr) {
3711 return false;
3712 }
3713 if (ref == UT64_MAX || ptr == ref) {
3714 const RAnalRefType t = code? type? type: R_ANAL_REF_TYPE_CODE: R_ANAL_REF_TYPE_DATA;
3715 r_anal_xrefs_set (core->anal, at, ptr, t);
3716 return true;
3717 }
3718 if (depth < 1) {
3719 return false;
3720 }
3721 int wordsize = (int)(core->anal->bits / 8);
3722 ut64 dataptr;
3723 if (!r_io_read_i (core->io, ptr, &dataptr, wordsize, false)) {
3724 // eprintf ("core_anal_followptr: Cannot read word at destination\n");
3725 return false;
3726 }
3727 return core_anal_followptr (core, type, at, dataptr, ref, code, depth - 1);
3728 }
3729
opiscall(RCore * core,RAnalOp * aop,ut64 addr,const ut8 * buf,int len,int arch)3730 static bool opiscall(RCore *core, RAnalOp *aop, ut64 addr, const ut8* buf, int len, int arch) {
3731 switch (arch) {
3732 case R2_ARCH_ARM64:
3733 aop->size = 4;
3734 //addr should be aligned by 4 in aarch64
3735 if (addr % 4) {
3736 char diff = addr % 4;
3737 addr = addr - diff;
3738 buf = buf - diff;
3739 }
3740 //if is not bl do not analyze
3741 if (buf[3] == 0x94) {
3742 if (r_anal_op (core->anal, aop, addr, buf, len, R_ANAL_OP_MASK_BASIC)) {
3743 return true;
3744 }
3745 }
3746 break;
3747 default:
3748 aop->size = 1;
3749 if (r_anal_op (core->anal, aop, addr, buf, len, R_ANAL_OP_MASK_BASIC)) {
3750 switch (aop->type & R_ANAL_OP_TYPE_MASK) {
3751 case R_ANAL_OP_TYPE_CALL:
3752 case R_ANAL_OP_TYPE_CCALL:
3753 return true;
3754 }
3755 }
3756 break;
3757 }
3758 return false;
3759 }
3760
3761 // TODO(maskray) RAddrInterval API
3762 #define OPSZ 8
r_core_anal_search(RCore * core,ut64 from,ut64 to,ut64 ref,int mode)3763 R_API int r_core_anal_search(RCore *core, ut64 from, ut64 to, ut64 ref, int mode) {
3764 ut8 *buf = (ut8 *)malloc (core->blocksize);
3765 if (!buf) {
3766 return -1;
3767 }
3768 int ptrdepth = r_config_get_i (core->config, "anal.ptrdepth");
3769 int i, count = 0;
3770 RAnalOp op = R_EMPTY;
3771 ut64 at;
3772 char bckwrds, do_bckwrd_srch;
3773 int arch = -1;
3774 if (core->rasm->bits == 64) {
3775 // speedup search
3776 if (!strncmp (core->rasm->cur->name, "arm", 3)) {
3777 arch = R2_ARCH_ARM64;
3778 }
3779 }
3780 // TODO: get current section range here or gtfo
3781 // ???
3782 // XXX must read bytes correctly
3783 do_bckwrd_srch = bckwrds = core->search->bckwrds;
3784 if (!ref) {
3785 eprintf ("Null reference search is not supported\n");
3786 free (buf);
3787 return -1;
3788 }
3789 r_cons_break_push (NULL, NULL);
3790 if (core->blocksize > OPSZ) {
3791 if (bckwrds) {
3792 if (from + core->blocksize > to) {
3793 at = from;
3794 do_bckwrd_srch = false;
3795 } else {
3796 at = to - core->blocksize;
3797 }
3798 } else {
3799 at = from;
3800 }
3801 while ((!bckwrds && at < to) || bckwrds) {
3802 eprintf ("\r[0x%08"PFMT64x"-0x%08"PFMT64x"] ", at, to);
3803 if (r_cons_is_breaked ()) {
3804 break;
3805 }
3806 // TODO: this can be probably enhanced
3807 if (!r_io_read_at (core->io, at, buf, core->blocksize)) {
3808 eprintf ("Failed to read at 0x%08" PFMT64x "\n", at);
3809 break;
3810 }
3811 for (i = bckwrds ? (core->blocksize - OPSZ - 1) : 0;
3812 (!bckwrds && i < core->blocksize - OPSZ) ||
3813 (bckwrds && i > 0);
3814 bckwrds ? i-- : i++) {
3815 // TODO: honor anal.align
3816 if (r_cons_is_breaked ()) {
3817 break;
3818 }
3819 switch (mode) {
3820 case 'c':
3821 (void)opiscall (core, &op, at + i, buf + i, core->blocksize - i, arch);
3822 if (op.size < 1) {
3823 op.size = 1;
3824 }
3825 break;
3826 case 'r':
3827 case 'w':
3828 case 'x':
3829 {
3830 r_anal_op (core->anal, &op, at + i, buf + i, core->blocksize - i, R_ANAL_OP_MASK_BASIC);
3831 int mask = mode=='r' ? 1 : mode == 'w' ? 2: mode == 'x' ? 4: 0;
3832 if (op.direction == mask) {
3833 i += op.size;
3834 }
3835 r_anal_op_fini (&op);
3836 continue;
3837 }
3838 break;
3839 default:
3840 if (!r_anal_op (core->anal, &op, at + i, buf + i, core->blocksize - i, R_ANAL_OP_MASK_BASIC)) {
3841 r_anal_op_fini (&op);
3842 continue;
3843 }
3844 }
3845 switch (op.type) {
3846 case R_ANAL_OP_TYPE_JMP:
3847 case R_ANAL_OP_TYPE_CJMP:
3848 case R_ANAL_OP_TYPE_CALL:
3849 case R_ANAL_OP_TYPE_CCALL:
3850 if (op.jump != UT64_MAX &&
3851 core_anal_followptr (core, 'C', at + i, op.jump, ref, true, 0)) {
3852 count ++;
3853 }
3854 break;
3855 case R_ANAL_OP_TYPE_UCJMP:
3856 case R_ANAL_OP_TYPE_UJMP:
3857 case R_ANAL_OP_TYPE_IJMP:
3858 case R_ANAL_OP_TYPE_RJMP:
3859 case R_ANAL_OP_TYPE_IRJMP:
3860 case R_ANAL_OP_TYPE_MJMP:
3861 if (op.ptr != UT64_MAX &&
3862 core_anal_followptr (core, 'c', at + i, op.ptr, ref, true ,1)) {
3863 count ++;
3864 }
3865 break;
3866 case R_ANAL_OP_TYPE_UCALL:
3867 case R_ANAL_OP_TYPE_ICALL:
3868 case R_ANAL_OP_TYPE_RCALL:
3869 case R_ANAL_OP_TYPE_IRCALL:
3870 case R_ANAL_OP_TYPE_UCCALL:
3871 if (op.ptr != UT64_MAX &&
3872 core_anal_followptr (core, 'C', at + i, op.ptr, ref, true ,1)) {
3873 count ++;
3874 }
3875 break;
3876 default:
3877 {
3878 if (!r_anal_op (core->anal, &op, at + i, buf + i, core->blocksize - i, R_ANAL_OP_MASK_BASIC)) {
3879 r_anal_op_fini (&op);
3880 continue;
3881 }
3882 }
3883 if (op.ptr != UT64_MAX &&
3884 core_anal_followptr (core, 'd', at + i, op.ptr, ref, false, ptrdepth)) {
3885 count ++;
3886 }
3887 break;
3888 }
3889 if (op.size < 1) {
3890 op.size = 1;
3891 }
3892 i += op.size - 1;
3893 r_anal_op_fini (&op);
3894 }
3895 if (bckwrds) {
3896 if (!do_bckwrd_srch) {
3897 break;
3898 }
3899 if (at > from + core->blocksize - OPSZ) {
3900 at -= core->blocksize;
3901 } else {
3902 do_bckwrd_srch = false;
3903 at = from;
3904 }
3905 } else {
3906 at += core->blocksize - OPSZ;
3907 }
3908 }
3909 } else {
3910 eprintf ("error: block size too small\n");
3911 }
3912 r_cons_break_pop ();
3913 free (buf);
3914 r_anal_op_fini (&op);
3915 return count;
3916 }
3917
found_xref(RCore * core,ut64 at,ut64 xref_to,RAnalRefType type,PJ * pj,int rad,int cfg_debug,bool cfg_anal_strings)3918 static bool found_xref(RCore *core, ut64 at, ut64 xref_to, RAnalRefType type, PJ *pj, int rad, int cfg_debug, bool cfg_anal_strings) {
3919 // Validate the reference. If virtual addressing is enabled, we
3920 // allow only references to virtual addresses in order to reduce
3921 // the number of false positives. In debugger mode, the reference
3922 // must point to a mapped memory region.
3923 if (type == R_ANAL_REF_TYPE_NULL) {
3924 return false;
3925 }
3926 if (cfg_debug) {
3927 if (!r_debug_map_get (core->dbg, xref_to)) {
3928 return false;
3929 }
3930 } else if (core->io->va) {
3931 if (!r_io_is_valid_offset (core->io, xref_to, 0)) {
3932 return false;
3933 }
3934 }
3935 if (!rad) {
3936 if (cfg_anal_strings && type == R_ANAL_REF_TYPE_DATA) {
3937 int len = 0;
3938 char *str_string = is_string_at (core, xref_to, &len);
3939 if (str_string) {
3940 r_name_filter (str_string, -1);
3941 char *str_flagname = r_str_newf ("str.%s", str_string);
3942 r_flag_space_push (core->flags, R_FLAGS_FS_STRINGS);
3943 (void)r_flag_set (core->flags, str_flagname, xref_to, 1);
3944 r_flag_space_pop (core->flags);
3945 free (str_flagname);
3946 if (len > 0) {
3947 r_meta_set (core->anal, R_META_TYPE_STRING, xref_to,
3948 len, (const char *) str_string);
3949 }
3950 free (str_string);
3951 }
3952 }
3953 // Add to SDB
3954 if (xref_to) {
3955 r_anal_xrefs_set (core->anal, at, xref_to, type);
3956 }
3957 } else if (rad == 'j') {
3958 char *key = sdb_fmt ("0x%"PFMT64x, xref_to);
3959 char *value = sdb_fmt ("0x%"PFMT64x, at);
3960 pj_ks (pj, key, value);
3961 } else {
3962 int len = 0;
3963 // Display in radare commands format
3964 char *cmd;
3965 switch (type) {
3966 case R_ANAL_REF_TYPE_CODE: cmd = "axc"; break;
3967 case R_ANAL_REF_TYPE_CALL: cmd = "axC"; break;
3968 case R_ANAL_REF_TYPE_DATA: cmd = "axd"; break;
3969 default: cmd = "ax"; break;
3970 }
3971 r_cons_printf ("%s 0x%08"PFMT64x" 0x%08"PFMT64x"\n", cmd, xref_to, at);
3972 if (cfg_anal_strings && type == R_ANAL_REF_TYPE_DATA) {
3973 char *str_flagname = is_string_at (core, xref_to, &len);
3974 if (str_flagname) {
3975 ut64 str_addr = xref_to;
3976 r_name_filter (str_flagname, -1);
3977 r_cons_printf ("f str.%s=0x%"PFMT64x"\n", str_flagname, str_addr);
3978 r_cons_printf ("Cs %d @ 0x%"PFMT64x"\n", len, str_addr);
3979 free (str_flagname);
3980 }
3981 }
3982 }
3983 return true;
3984 }
3985
r_core_anal_search_xrefs(RCore * core,ut64 from,ut64 to,PJ * pj,int rad)3986 R_API int r_core_anal_search_xrefs(RCore *core, ut64 from, ut64 to, PJ *pj, int rad) {
3987 int cfg_debug = r_config_get_i (core->config, "cfg.debug");
3988 bool cfg_anal_strings = r_config_get_i (core->config, "anal.strings");
3989 ut64 at;
3990 int count = 0;
3991 const int bsz = 8096;
3992 RAnalOp op = { 0 };
3993
3994 if (from == to) {
3995 return -1;
3996 }
3997 if (from > to) {
3998 eprintf ("Invalid range (0x%"PFMT64x
3999 " >= 0x%"PFMT64x")\n", from, to);
4000 return -1;
4001 }
4002
4003 if (core->blocksize <= OPSZ) {
4004 eprintf ("Error: block size too small\n");
4005 return -1;
4006 }
4007 ut8 *buf = malloc (bsz);
4008 if (!buf) {
4009 eprintf ("Error: cannot allocate a block\n");
4010 return -1;
4011 }
4012 ut8 *block = malloc (bsz);
4013 if (!block) {
4014 eprintf ("Error: cannot allocate a temp block\n");
4015 free (buf);
4016 return -1;
4017 }
4018 r_cons_break_push (NULL, NULL);
4019 at = from;
4020 st64 asm_sub_varmin = r_config_get_i (core->config, "asm.sub.varmin");
4021 while (at < to && !r_cons_is_breaked ()) {
4022 int i = 0, ret = bsz;
4023 if (!r_io_is_valid_offset (core->io, at, R_PERM_X)) {
4024 break;
4025 }
4026 (void)r_io_read_at (core->io, at, buf, bsz);
4027 memset (block, -1, bsz);
4028 if (!memcmp (buf, block, bsz)) {
4029 // eprintf ("Error: skipping uninitialized block \n");
4030 at += ret;
4031 continue;
4032 }
4033 memset (block, 0, bsz);
4034 if (!memcmp (buf, block, bsz)) {
4035 // eprintf ("Error: skipping uninitialized block \n");
4036 at += ret;
4037 continue;
4038 }
4039 while (i < bsz && !r_cons_is_breaked ()) {
4040 ret = r_anal_op (core->anal, &op, at + i, buf + i, bsz - i, R_ANAL_OP_MASK_BASIC | R_ANAL_OP_MASK_HINT);
4041 ret = ret > 0 ? ret : 1;
4042 i += ret;
4043 if (ret <= 0 || i > bsz) {
4044 break;
4045 }
4046 // find references
4047 if ((st64)op.val > asm_sub_varmin && op.val != UT64_MAX && op.val != UT32_MAX) {
4048 if (found_xref (core, op.addr, op.val, R_ANAL_REF_TYPE_DATA, pj, rad, cfg_debug, cfg_anal_strings)) {
4049 count++;
4050 }
4051 }
4052 // find references
4053 if (op.ptr && op.ptr != UT64_MAX && op.ptr != UT32_MAX) {
4054 if (found_xref (core, op.addr, op.ptr, R_ANAL_REF_TYPE_DATA, pj, rad, cfg_debug, cfg_anal_strings)) {
4055 count++;
4056 }
4057 }
4058 // find references
4059 if (op.addr > 512 && op.disp > 512 && op.disp && op.disp != UT64_MAX) {
4060 if (found_xref (core, op.addr, op.disp, R_ANAL_REF_TYPE_DATA, pj, rad, cfg_debug, cfg_anal_strings)) {
4061 count++;
4062 }
4063 }
4064 switch (op.type) {
4065 case R_ANAL_OP_TYPE_JMP:
4066 case R_ANAL_OP_TYPE_CJMP:
4067 if (found_xref (core, op.addr, op.jump, R_ANAL_REF_TYPE_CODE, pj, rad, cfg_debug, cfg_anal_strings)) {
4068 count++;
4069 }
4070 break;
4071 case R_ANAL_OP_TYPE_CALL:
4072 case R_ANAL_OP_TYPE_CCALL:
4073 if (found_xref (core, op.addr, op.jump, R_ANAL_REF_TYPE_CALL, pj, rad, cfg_debug, cfg_anal_strings)) {
4074 count++;
4075 }
4076 break;
4077 case R_ANAL_OP_TYPE_UJMP:
4078 case R_ANAL_OP_TYPE_IJMP:
4079 case R_ANAL_OP_TYPE_RJMP:
4080 case R_ANAL_OP_TYPE_IRJMP:
4081 case R_ANAL_OP_TYPE_MJMP:
4082 case R_ANAL_OP_TYPE_UCJMP:
4083 count++;
4084 if (found_xref (core, op.addr, op.ptr, R_ANAL_REF_TYPE_CODE, pj, rad, cfg_debug, cfg_anal_strings)) {
4085 count++;
4086 }
4087 break;
4088 case R_ANAL_OP_TYPE_UCALL:
4089 case R_ANAL_OP_TYPE_ICALL:
4090 case R_ANAL_OP_TYPE_RCALL:
4091 case R_ANAL_OP_TYPE_IRCALL:
4092 case R_ANAL_OP_TYPE_UCCALL:
4093 if (found_xref (core, op.addr, op.ptr, R_ANAL_REF_TYPE_CALL, pj, rad, cfg_debug, cfg_anal_strings)) {
4094 count++;
4095 }
4096 break;
4097 default:
4098 break;
4099 }
4100 r_anal_op_fini (&op);
4101 }
4102 at += bsz;
4103 r_anal_op_fini (&op);
4104 }
4105 r_cons_break_pop ();
4106 free (buf);
4107 free (block);
4108 return count;
4109 }
4110
isValidSymbol(RBinSymbol * symbol)4111 static bool isValidSymbol(RBinSymbol *symbol) {
4112 if (symbol && symbol->type) {
4113 const char *type = symbol->type;
4114 return (symbol->paddr != UT64_MAX) && (!strcmp (type, R_BIN_TYPE_FUNC_STR) || !strcmp (type, R_BIN_TYPE_HIOS_STR) || !strcmp (type, R_BIN_TYPE_LOOS_STR) || !strcmp (type, R_BIN_TYPE_METH_STR) || !strcmp (type , R_BIN_TYPE_STATIC_STR));
4115 }
4116 return false;
4117 }
4118
isSkippable(RBinSymbol * s)4119 static bool isSkippable(RBinSymbol *s) {
4120 if (s && s->name && s->bind) {
4121 if (r_str_startswith (s->name, "radr://")) {
4122 return true;
4123 }
4124 if (!strcmp (s->name, "__mh_execute_header")) {
4125 return true;
4126 }
4127 if (!strcmp (s->bind, "NONE")) {
4128 if (s->is_imported && s->libname && strstr(s->libname, ".dll")) {
4129 return true;
4130 }
4131 }
4132 }
4133 return false;
4134 }
4135
r_core_anal_all(RCore * core)4136 R_API int r_core_anal_all(RCore *core) {
4137 RList *list;
4138 RListIter *iter;
4139 RFlagItem *item;
4140 RAnalFunction *fcni;
4141 RBinAddr *binmain;
4142 RBinAddr *entry;
4143 RBinSymbol *symbol;
4144 int depth = core->anal->opt.depth;
4145 bool anal_vars = r_config_get_i (core->config, "anal.vars");
4146
4147 /* Analyze Functions */
4148 /* Entries */
4149 item = r_flag_get (core->flags, "entry0");
4150 if (item) {
4151 r_core_anal_fcn (core, item->offset, -1, R_ANAL_REF_TYPE_NULL, depth - 1);
4152 r_core_cmdf (core, "afn entry0 0x%08"PFMT64x, item->offset);
4153 } else {
4154 r_core_cmd0 (core, "af");
4155 }
4156
4157 r_core_task_yield (&core->tasks);
4158
4159 r_cons_break_push (NULL, NULL);
4160 /* Symbols (Imports are already analyzed by rabin2 on init) */
4161 if ((list = r_bin_get_symbols (core->bin)) != NULL) {
4162 r_list_foreach (list, iter, symbol) {
4163 if (r_cons_is_breaked ()) {
4164 break;
4165 }
4166 // Stop analyzing PE imports further
4167 if (isSkippable (symbol)) {
4168 continue;
4169 }
4170 if (isValidSymbol (symbol)) {
4171 ut64 addr = r_bin_get_vaddr (core->bin, symbol->paddr,
4172 symbol->vaddr);
4173 r_core_anal_fcn (core, addr, -1, R_ANAL_REF_TYPE_NULL, depth - 1);
4174 }
4175 }
4176 }
4177 r_core_task_yield (&core->tasks);
4178 /* Main */
4179 if ((binmain = r_bin_get_sym (core->bin, R_BIN_SYM_MAIN))) {
4180 if (binmain->paddr != UT64_MAX) {
4181 ut64 addr = r_bin_get_vaddr (core->bin, binmain->paddr, binmain->vaddr);
4182 r_core_anal_fcn (core, addr, -1, R_ANAL_REF_TYPE_NULL, depth - 1);
4183 }
4184 }
4185 r_core_task_yield (&core->tasks);
4186 if ((list = r_bin_get_entries (core->bin))) {
4187 r_list_foreach (list, iter, entry) {
4188 if (entry->paddr == UT64_MAX) {
4189 continue;
4190 }
4191 ut64 addr = r_bin_get_vaddr (core->bin, entry->paddr, entry->vaddr);
4192 r_core_anal_fcn (core, addr, -1, R_ANAL_REF_TYPE_NULL, depth - 1);
4193 }
4194 }
4195 r_core_task_yield (&core->tasks);
4196 if (anal_vars) {
4197 /* Set fcn type to R_ANAL_FCN_TYPE_SYM for symbols */
4198 r_list_foreach_prev (core->anal->fcns, iter, fcni) {
4199 if (r_cons_is_breaked ()) {
4200 break;
4201 }
4202 r_core_recover_vars (core, fcni, true);
4203 if (!strncmp (fcni->name, "sym.", 4) || !strncmp (fcni->name, "main", 4)) {
4204 fcni->type = R_ANAL_FCN_TYPE_SYM;
4205 }
4206 }
4207 }
4208 r_cons_break_pop ();
4209 return true;
4210 }
4211
r_core_anal_data(RCore * core,ut64 addr,int count,int depth,int wordsize)4212 R_API int r_core_anal_data(RCore *core, ut64 addr, int count, int depth, int wordsize) {
4213 RAnalData *d;
4214 ut64 dstaddr = 0LL;
4215 ut8 *buf = core->block;
4216 int len = core->blocksize;
4217 int word = wordsize ? wordsize: core->rasm->bits / 8;
4218 char *str;
4219 int i, j;
4220
4221 count = R_MIN (count, len);
4222 buf = malloc (len + 1);
4223 if (!buf) {
4224 return false;
4225 }
4226 memset (buf, 0xff, len);
4227 r_io_read_at (core->io, addr, buf, len);
4228 buf[len - 1] = 0;
4229
4230 RConsPrintablePalette *pal = r_config_get_i (core->config, "scr.color")? &r_cons_singleton ()->context->pal: NULL;
4231 for (i = j = 0; j < count; j++) {
4232 if (i >= len) {
4233 r_io_read_at (core->io, addr + i, buf, len);
4234 buf[len] = 0;
4235 addr += i;
4236 i = 0;
4237 continue;
4238 }
4239 /* r_anal_data requires null-terminated buffer according to coverity */
4240 /* but it should not.. so this must be fixed in anal/data.c instead of */
4241 /* null terminating here */
4242 d = r_anal_data (core->anal, addr + i, buf + i, len - i, wordsize);
4243 str = r_anal_data_to_string (d, pal);
4244 r_cons_println (str);
4245
4246 if (d) {
4247 switch (d->type) {
4248 case R_ANAL_DATA_TYPE_POINTER:
4249 r_cons_printf ("`- ");
4250 dstaddr = r_mem_get_num (buf + i, word);
4251 if (depth > 0) {
4252 r_core_anal_data (core, dstaddr, 1, depth - 1, wordsize);
4253 }
4254 i += word;
4255 break;
4256 case R_ANAL_DATA_TYPE_STRING:
4257 buf[len-1] = 0;
4258 i += strlen ((const char*)buf + i) + 1;
4259 break;
4260 default:
4261 i += (d->len > 3)? d->len: word;
4262 break;
4263 }
4264 } else {
4265 i += word;
4266 }
4267 free (str);
4268 r_anal_data_free (d);
4269 }
4270 free (buf);
4271 return true;
4272 }
4273
4274 struct block_flags_stat_t {
4275 ut64 step;
4276 ut64 from;
4277 RCoreAnalStats *as;
4278 };
4279
block_flags_stat(RFlagItem * fi,void * user)4280 static bool block_flags_stat(RFlagItem *fi, void *user) {
4281 struct block_flags_stat_t *u = (struct block_flags_stat_t *)user;
4282 int piece = (fi->offset - u->from) / u->step;
4283 u->as->block[piece].flags++;
4284 return true;
4285 }
4286
4287 /* core analysis stats */
4288 /* stats --- colorful bar */
r_core_anal_get_stats(RCore * core,ut64 from,ut64 to,ut64 step)4289 R_API RCoreAnalStats* r_core_anal_get_stats(RCore *core, ut64 from, ut64 to, ut64 step) {
4290 RAnalFunction *F;
4291 RAnalBlock *B;
4292 RBinSymbol *S;
4293 RListIter *iter, *iter2;
4294 RCoreAnalStats *as = NULL;
4295 int piece, as_size, blocks;
4296 ut64 at;
4297
4298 if (from == to || from == UT64_MAX || to == UT64_MAX) {
4299 eprintf ("Cannot alloc for this range\n");
4300 return NULL;
4301 }
4302 as = R_NEW0 (RCoreAnalStats);
4303 if (!as) {
4304 return NULL;
4305 }
4306 if (step < 1) {
4307 step = 1;
4308 }
4309 blocks = (to - from) / step;
4310 as_size = (1 + blocks) * sizeof (RCoreAnalStatsItem);
4311 as->block = malloc (as_size);
4312 if (!as->block) {
4313 free (as);
4314 return NULL;
4315 }
4316 memset (as->block, 0, as_size);
4317 for (at = from; at < to; at += step) {
4318 RIOMap *map = r_io_map_get (core->io, at);
4319 piece = (at - from) / step;
4320 as->block[piece].perm = map ? map->perm: (core->io->desc ? core->io->desc->perm: 0);
4321 }
4322 // iter all flags
4323 struct block_flags_stat_t u = { .step = step, .from = from, .as = as };
4324 r_flag_foreach_range (core->flags, from, to + 1, block_flags_stat, &u);
4325 // iter all functions
4326 r_list_foreach (core->anal->fcns, iter, F) {
4327 if (F->addr < from || F->addr > to) {
4328 continue;
4329 }
4330 piece = (F->addr - from) / step;
4331 as->block[piece].functions++;
4332 ut64 last_piece = R_MIN ((F->addr + r_anal_function_linear_size (F) - 1) / step, blocks - 1);
4333 for (; piece <= last_piece; piece++) {
4334 as->block[piece].in_functions++;
4335 }
4336 // iter all basic blocks
4337 r_list_foreach (F->bbs, iter2, B) {
4338 if (B->addr < from || B->addr > to) {
4339 continue;
4340 }
4341 piece = (B->addr - from) / step;
4342 as->block[piece].blocks++;
4343 }
4344 }
4345 // iter all symbols
4346 r_list_foreach (r_bin_get_symbols (core->bin), iter, S) {
4347 if (S->vaddr < from || S->vaddr > to) {
4348 continue;
4349 }
4350 piece = (S->vaddr - from) / step;
4351 as->block[piece].symbols++;
4352 }
4353 RPVector *metas = to > from ? r_meta_get_all_intersect (core->anal, from, to - from, R_META_TYPE_ANY) : NULL;
4354 if (metas) {
4355 void **it;
4356 r_pvector_foreach (metas, it) {
4357 RIntervalNode *node = *it;
4358 RAnalMetaItem *mi = node->data;
4359 if (node->start < from || node->end > to) {
4360 continue;
4361 }
4362 piece = (node->start - from) / step;
4363 switch (mi->type) {
4364 case R_META_TYPE_STRING:
4365 as->block[piece].strings++;
4366 break;
4367 case R_META_TYPE_COMMENT:
4368 as->block[piece].comments++;
4369 break;
4370 default:
4371 break;
4372 }
4373 }
4374 r_pvector_free (metas);
4375 }
4376 return as;
4377 }
4378
r_core_anal_stats_free(RCoreAnalStats * s)4379 R_API void r_core_anal_stats_free(RCoreAnalStats *s) {
4380 if (s) {
4381 free (s->block);
4382 }
4383 free (s);
4384 }
4385
r_core_anal_cycles(RCore * core,int ccl)4386 R_API RList* r_core_anal_cycles(RCore *core, int ccl) {
4387 ut64 addr = core->offset;
4388 int depth = 0;
4389 RAnalOp *op = NULL;
4390 RAnalCycleFrame *prev = NULL, *cf = NULL;
4391 RAnalCycleHook *ch;
4392 RList *hooks = r_list_new ();
4393 if (!hooks) {
4394 return NULL;
4395 }
4396 cf = r_anal_cycle_frame_new ();
4397 r_cons_break_push (NULL, NULL);
4398 while (cf && !r_cons_is_breaked ()) {
4399 if ((op = r_core_anal_op (core, addr, R_ANAL_OP_MASK_BASIC)) && (op->cycles) && (ccl > 0)) {
4400 r_cons_clear_line (1);
4401 eprintf ("%i -- ", ccl);
4402 addr += op->size;
4403 switch (op->type) {
4404 case R_ANAL_OP_TYPE_JMP:
4405 addr = op->jump;
4406 ccl -= op->cycles;
4407 loganal (op->addr, addr, depth);
4408 break;
4409 case R_ANAL_OP_TYPE_UJMP:
4410 case R_ANAL_OP_TYPE_MJMP:
4411 case R_ANAL_OP_TYPE_UCALL:
4412 case R_ANAL_OP_TYPE_ICALL:
4413 case R_ANAL_OP_TYPE_RCALL:
4414 case R_ANAL_OP_TYPE_IRCALL:
4415 ch = R_NEW0 (RAnalCycleHook);
4416 ch->addr = op->addr;
4417 eprintf ("0x%08"PFMT64x" > ?\r", op->addr);
4418 ch->cycles = ccl;
4419 r_list_append (hooks, ch);
4420 ch = NULL;
4421 while (!ch && cf) {
4422 ch = r_list_pop (cf->hooks);
4423 if (ch) {
4424 addr = ch->addr;
4425 ccl = ch->cycles;
4426 free (ch);
4427 } else {
4428 r_anal_cycle_frame_free (cf);
4429 cf = prev;
4430 if (cf) {
4431 prev = cf->prev;
4432 }
4433 }
4434 }
4435 break;
4436 case R_ANAL_OP_TYPE_CJMP:
4437 ch = R_NEW0 (RAnalCycleHook);
4438 ch->addr = addr;
4439 ch->cycles = ccl - op->failcycles;
4440 r_list_push (cf->hooks, ch);
4441 ch = NULL;
4442 addr = op->jump;
4443 loganal (op->addr, addr, depth);
4444 break;
4445 case R_ANAL_OP_TYPE_UCJMP:
4446 case R_ANAL_OP_TYPE_UCCALL:
4447 ch = R_NEW0 (RAnalCycleHook);
4448 ch->addr = op->addr;
4449 ch->cycles = ccl;
4450 r_list_append (hooks, ch);
4451 ch = NULL;
4452 ccl -= op->failcycles;
4453 eprintf ("0x%08"PFMT64x" > ?\r", op->addr);
4454 break;
4455 case R_ANAL_OP_TYPE_CCALL:
4456 ch = R_NEW0 (RAnalCycleHook);
4457 ch->addr = addr;
4458 ch->cycles = ccl - op->failcycles;
4459 r_list_push (cf->hooks, ch);
4460 ch = NULL;
4461 case R_ANAL_OP_TYPE_CALL:
4462 if (op->addr != op->jump) { //no selfies
4463 cf->naddr = addr;
4464 prev = cf;
4465 cf = r_anal_cycle_frame_new ();
4466 cf->prev = prev;
4467 }
4468 ccl -= op->cycles;
4469 addr = op->jump;
4470 loganal (op->addr, addr, depth - 1);
4471 break;
4472 case R_ANAL_OP_TYPE_RET:
4473 ch = R_NEW0 (RAnalCycleHook);
4474 if (prev) {
4475 ch->addr = prev->naddr;
4476 ccl -= op->cycles;
4477 ch->cycles = ccl;
4478 r_list_push (prev->hooks, ch);
4479 eprintf ("0x%08"PFMT64x" < 0x%08"PFMT64x"\r", prev->naddr, op->addr);
4480 } else {
4481 ch->addr = op->addr;
4482 ch->cycles = ccl;
4483 r_list_append (hooks, ch);
4484 eprintf ("? < 0x%08"PFMT64x"\r", op->addr);
4485 }
4486 ch = NULL;
4487 while (!ch && cf) {
4488 ch = r_list_pop (cf->hooks);
4489 if (ch) {
4490 addr = ch->addr;
4491 ccl = ch->cycles;
4492 free (ch);
4493 } else {
4494 r_anal_cycle_frame_free (cf);
4495 cf = prev;
4496 if (cf) {
4497 prev = cf->prev;
4498 }
4499 }
4500 }
4501 break;
4502 case R_ANAL_OP_TYPE_CRET:
4503 ch = R_NEW0 (RAnalCycleHook);
4504 if (prev) {
4505 ch->addr = prev->naddr;
4506 ch->cycles = ccl - op->cycles;
4507 r_list_push (prev->hooks, ch);
4508 eprintf ("0x%08"PFMT64x" < 0x%08"PFMT64x"\r", prev->naddr, op->addr);
4509 } else {
4510 ch->addr = op->addr;
4511 ch->cycles = ccl - op->cycles;
4512 r_list_append (hooks, ch);
4513 eprintf ("? < 0x%08"PFMT64x"\r", op->addr);
4514 }
4515 ccl -= op->failcycles;
4516 break;
4517 default:
4518 ccl -= op->cycles;
4519 eprintf ("0x%08"PFMT64x"\r", op->addr);
4520 break;
4521 }
4522 } else {
4523 ch = R_NEW0 (RAnalCycleHook);
4524 if (!ch) {
4525 r_anal_cycle_frame_free (cf);
4526 r_list_free (hooks);
4527 return NULL;
4528 }
4529 ch->addr = addr;
4530 ch->cycles = ccl;
4531 r_list_append (hooks, ch);
4532 ch = NULL;
4533 while (!ch && cf) {
4534 ch = r_list_pop (cf->hooks);
4535 if (ch) {
4536 addr = ch->addr;
4537 ccl = ch->cycles;
4538 free (ch);
4539 } else {
4540 r_anal_cycle_frame_free (cf);
4541 cf = prev;
4542 if (cf) {
4543 prev = cf->prev;
4544 }
4545 }
4546 }
4547 }
4548 r_anal_op_free (op);
4549 }
4550 if (r_cons_is_breaked ()) {
4551 while (cf) {
4552 ch = r_list_pop (cf->hooks);
4553 while (ch) {
4554 free (ch);
4555 ch = r_list_pop (cf->hooks);
4556 }
4557 prev = cf->prev;
4558 r_anal_cycle_frame_free (cf);
4559 cf = prev;
4560 }
4561 }
4562 r_cons_break_pop ();
4563 return hooks;
4564 }
4565
r_core_anal_undefine(RCore * core,ut64 off)4566 R_API void r_core_anal_undefine(RCore *core, ut64 off) {
4567 RAnalFunction *f = r_anal_get_fcn_in (core->anal, off, -1);
4568 if (f) {
4569 if (!strncmp (f->name, "fcn.", 4)) {
4570 r_flag_unset_name (core->flags, f->name);
4571 }
4572 r_meta_del (core->anal, R_META_TYPE_ANY, r_anal_function_min_addr (f), r_anal_function_linear_size (f));
4573 }
4574 r_anal_fcn_del_locs (core->anal, off);
4575 r_anal_fcn_del (core->anal, off);
4576 }
4577
4578 /* Join function at addr2 into function at addr */
4579 // addr use to be core->offset
r_core_anal_fcn_merge(RCore * core,ut64 addr,ut64 addr2)4580 R_API void r_core_anal_fcn_merge(RCore *core, ut64 addr, ut64 addr2) {
4581 RListIter *iter;
4582 ut64 min = 0;
4583 ut64 max = 0;
4584 int first = 1;
4585 RAnalBlock *bb;
4586 RAnalFunction *f1 = r_anal_get_function_at (core->anal, addr);
4587 RAnalFunction *f2 = r_anal_get_function_at (core->anal, addr2);
4588 if (!f1 || !f2) {
4589 eprintf ("Cannot find function\n");
4590 return;
4591 }
4592 if (f1 == f2) {
4593 eprintf ("Cannot merge the same function\n");
4594 return;
4595 }
4596 // join all basic blocks from f1 into f2 if they are not
4597 // delete f2
4598 eprintf ("Merge 0x%08"PFMT64x" into 0x%08"PFMT64x"\n", addr, addr2);
4599 r_list_foreach (f1->bbs, iter, bb) {
4600 if (first) {
4601 min = bb->addr;
4602 max = bb->addr + bb->size;
4603 first = 0;
4604 } else {
4605 if (bb->addr < min) {
4606 min = bb->addr;
4607 }
4608 if (bb->addr + bb->size > max) {
4609 max = bb->addr + bb->size;
4610 }
4611 }
4612 }
4613 r_list_foreach (f2->bbs, iter, bb) {
4614 if (first) {
4615 min = bb->addr;
4616 max = bb->addr + bb->size;
4617 first = 0;
4618 } else {
4619 if (bb->addr < min) {
4620 min = bb->addr;
4621 }
4622 if (bb->addr + bb->size > max) {
4623 max = bb->addr + bb->size;
4624 }
4625 }
4626 r_anal_function_add_block (f1, bb);
4627 }
4628 // TODO: import data/code/refs
4629 r_anal_function_delete (f2);
4630 // update size
4631 r_anal_function_relocate (f2, R_MIN (addr, addr2));
4632 }
4633
4634 static bool esil_anal_stop = false;
cccb(void * u)4635 static void cccb(void *u) {
4636 esil_anal_stop = true;
4637 eprintf ("^C\n");
4638 }
4639
add_string_ref(RCore * core,ut64 xref_from,ut64 xref_to)4640 static void add_string_ref(RCore *core, ut64 xref_from, ut64 xref_to) {
4641 int len = 0;
4642 if (xref_to == UT64_MAX || !xref_to) {
4643 return;
4644 }
4645 if (!xref_from || xref_from == UT64_MAX) {
4646 xref_from = core->anal->esil->address;
4647 }
4648 char *str_flagname = is_string_at (core, xref_to, &len);
4649 if (str_flagname) {
4650 r_anal_xrefs_set (core->anal, xref_from, xref_to, R_ANAL_REF_TYPE_DATA);
4651 r_name_filter (str_flagname, -1);
4652 char *flagname = sdb_fmt ("str.%s", str_flagname);
4653 r_flag_space_push (core->flags, R_FLAGS_FS_STRINGS);
4654 r_flag_set (core->flags, flagname, xref_to, len);
4655 r_flag_space_pop (core->flags);
4656 r_meta_set (core->anal, 's', xref_to, len, str_flagname);
4657 free (str_flagname);
4658 }
4659 }
4660
4661
4662 // dup with isValidAddress wtf
myvalid(RIO * io,ut64 addr)4663 static bool myvalid(RIO *io, ut64 addr) {
4664 if (addr < 0x100) {
4665 return false;
4666 }
4667 if (addr == UT32_MAX || addr == UT64_MAX) { //the best of the best of the best :(
4668 return false;
4669 }
4670 if (!r_io_is_valid_offset (io, addr, 0)) {
4671 return false;
4672 }
4673 return true;
4674 }
4675
4676 typedef struct {
4677 RAnalOp *op;
4678 RAnalFunction *fcn;
4679 const char *spname;
4680 ut64 initial_sp;
4681 } EsilBreakCtx;
4682
reg_name_for_access(RAnalOp * op,RAnalVarAccessType type)4683 static const char *reg_name_for_access(RAnalOp* op, RAnalVarAccessType type) {
4684 if (type == R_ANAL_VAR_ACCESS_TYPE_WRITE) {
4685 if (op->dst && op->dst->reg) {
4686 return op->dst->reg->name;
4687 }
4688 } else {
4689 if (op->src[0] && op->src[0]->reg) {
4690 return op->src[0]->reg->name;
4691 }
4692 }
4693 return NULL;
4694 }
4695
delta_for_access(RAnalOp * op,RAnalVarAccessType type)4696 static ut64 delta_for_access(RAnalOp *op, RAnalVarAccessType type) {
4697 if (type == R_ANAL_VAR_ACCESS_TYPE_WRITE) {
4698 if (op->dst) {
4699 return op->dst->imm + op->dst->delta;
4700 }
4701 } else {
4702 if (op->src[1] && (op->src[1]->imm || op->src[1]->delta)) {
4703 return op->src[1]->imm + op->src[1]->delta;
4704 }
4705 if (op->src[0]) {
4706 return op->src[0]->imm + op->src[0]->delta;
4707 }
4708 }
4709 return 0;
4710 }
4711
handle_var_stack_access(RAnalEsil * esil,ut64 addr,RAnalVarAccessType type,int len)4712 static void handle_var_stack_access(RAnalEsil *esil, ut64 addr, RAnalVarAccessType type, int len) {
4713 EsilBreakCtx *ctx = esil->user;
4714 const char *regname = reg_name_for_access (ctx->op, type);
4715 if (ctx->fcn && regname) {
4716 ut64 spaddr = r_reg_getv (esil->anal->reg, ctx->spname);
4717 if (addr >= spaddr && addr < ctx->initial_sp) {
4718 int stack_off = addr - ctx->initial_sp;
4719 RAnalVar *var = r_anal_function_get_var (ctx->fcn, R_ANAL_VAR_KIND_SPV, stack_off);
4720 if (!var) {
4721 var = r_anal_function_get_var (ctx->fcn, R_ANAL_VAR_KIND_BPV, stack_off);
4722 }
4723 if (!var && stack_off >= -ctx->fcn->maxstack) {
4724 char *varname;
4725 varname = ctx->fcn->anal->opt.varname_stack
4726 ? r_str_newf ("var_%xh", R_ABS (stack_off))
4727 : r_anal_function_autoname_var (ctx->fcn, R_ANAL_VAR_KIND_SPV, "var", delta_for_access (ctx->op, type));
4728 var = r_anal_function_set_var (ctx->fcn, stack_off, R_ANAL_VAR_KIND_SPV, NULL, len, false, varname);
4729 free (varname);
4730 }
4731 if (var) {
4732 r_anal_var_set_access (var, regname, ctx->op->addr, type, delta_for_access (ctx->op, type));
4733 }
4734 }
4735 }
4736 }
4737
esilbreak_mem_write(RAnalEsil * esil,ut64 addr,const ut8 * buf,int len)4738 static int esilbreak_mem_write(RAnalEsil *esil, ut64 addr, const ut8 *buf, int len) {
4739 handle_var_stack_access (esil, addr, R_ANAL_VAR_ACCESS_TYPE_WRITE, len);
4740 return 1;
4741 }
4742
4743 /* TODO: move into RCore? */
4744 static ut64 esilbreak_last_read = UT64_MAX;
4745 static ut64 esilbreak_last_data = UT64_MAX;
4746
4747 static ut64 ntarget = UT64_MAX;
4748
4749 // TODO differentiate endian-aware mem_read with other reads; move ntarget handling to another function
esilbreak_mem_read(RAnalEsil * esil,ut64 addr,ut8 * buf,int len)4750 static int esilbreak_mem_read(RAnalEsil *esil, ut64 addr, ut8 *buf, int len) {
4751 ut8 str[128];
4752 if (addr != UT64_MAX) {
4753 esilbreak_last_read = addr;
4754 }
4755 handle_var_stack_access (esil, addr, R_ANAL_VAR_ACCESS_TYPE_READ, len);
4756 if (myvalid (mycore->io, addr) && r_io_read_at (mycore->io, addr, (ut8*)buf, len)) {
4757 ut64 refptr;
4758 bool trace = true;
4759 switch (len) {
4760 case 2:
4761 esilbreak_last_data = refptr = (ut64)r_read_ble16 (buf, esil->anal->big_endian);
4762 break;
4763 case 4:
4764 esilbreak_last_data = refptr = (ut64)r_read_ble32 (buf, esil->anal->big_endian);
4765 break;
4766 case 8:
4767 esilbreak_last_data = refptr = r_read_ble64 (buf, esil->anal->big_endian);
4768 break;
4769 default:
4770 trace = false;
4771 r_io_read_at (mycore->io, addr, (ut8*)buf, len);
4772 break;
4773 }
4774 // TODO incorrect
4775 bool validRef = false;
4776 if (trace && myvalid (mycore->io, refptr)) {
4777 if (ntarget == UT64_MAX || ntarget == refptr) {
4778 str[0] = 0;
4779 if (r_io_read_at (mycore->io, refptr, str, sizeof (str)) < 1) {
4780 //eprintf ("Invalid read\n");
4781 str[0] = 0;
4782 validRef = false;
4783 } else {
4784 r_anal_xrefs_set (mycore->anal, esil->address, refptr, R_ANAL_REF_TYPE_DATA);
4785 str[sizeof (str) - 1] = 0;
4786 add_string_ref (mycore, esil->address, refptr);
4787 esilbreak_last_data = UT64_MAX;
4788 validRef = true;
4789 }
4790 }
4791 }
4792
4793 /** resolve ptr */
4794 if (ntarget == UT64_MAX || ntarget == addr || (ntarget == UT64_MAX && !validRef)) {
4795 r_anal_xrefs_set (mycore->anal, esil->address, addr, R_ANAL_REF_TYPE_DATA);
4796 }
4797 }
4798 return 0; // fallback
4799 }
4800
esilbreak_reg_write(RAnalEsil * esil,const char * name,ut64 * val)4801 static int esilbreak_reg_write(RAnalEsil *esil, const char *name, ut64 *val) {
4802 if (!esil) {
4803 return 0;
4804 }
4805 RAnal *anal = esil->anal;
4806 EsilBreakCtx *ctx = esil->user;
4807 RAnalOp *op = ctx->op;
4808 RCore *core = anal->coreb.core;
4809 handle_var_stack_access (esil, *val, R_ANAL_VAR_ACCESS_TYPE_PTR, esil->anal->bits / 8);
4810 //specific case to handle blx/bx cases in arm through emulation
4811 // XXX this thing creates a lot of false positives
4812 ut64 at = *val;
4813 if (anal && anal->opt.armthumb) {
4814 if (anal->cur && anal->cur->arch && anal->bits < 33 &&
4815 strstr (anal->cur->arch, "arm") && !strcmp (name, "pc") && op) {
4816 switch (op->type) {
4817 case R_ANAL_OP_TYPE_UCALL: // BLX
4818 case R_ANAL_OP_TYPE_UJMP: // BX
4819 // maybe UJMP/UCALL is enough here
4820 if (!(*val & 1)) {
4821 r_anal_hint_set_bits (anal, *val, 32);
4822 } else {
4823 ut64 snv = r_reg_getv (anal->reg, "pc");
4824 if (snv != UT32_MAX && snv != UT64_MAX) {
4825 if (r_io_is_valid_offset (anal->iob.io, *val, 1)) {
4826 r_anal_hint_set_bits (anal, *val - 1, 16);
4827 }
4828 }
4829 }
4830 break;
4831 default:
4832 break;
4833 }
4834 }
4835 }
4836 if (core->rasm->bits == 32 && strstr (core->rasm->cur->name, "arm")) {
4837 if ((!(at & 1)) && r_io_is_valid_offset (anal->iob.io, at, 0)) { // !core->anal->opt.noncode)) {
4838 add_string_ref (anal->coreb.core, esil->address, at);
4839 }
4840 }
4841 return 0;
4842 }
4843
getpcfromstack(RCore * core,RAnalEsil * esil)4844 static void getpcfromstack(RCore *core, RAnalEsil *esil) {
4845 ut64 cur;
4846 ut64 addr;
4847 ut64 size;
4848 int idx;
4849 RAnalEsil esil_cpy;
4850 RAnalOp op = R_EMPTY;
4851 RAnalFunction *fcn = NULL;
4852 ut8 *buf = NULL;
4853 char *tmp_esil_str = NULL;
4854 int tmp_esil_str_len;
4855 const char *esilstr;
4856 const int maxaddrlen = 20;
4857 const char *spname = NULL;
4858 if (!esil) {
4859 return;
4860 }
4861
4862 memcpy (&esil_cpy, esil, sizeof (esil_cpy));
4863 addr = cur = esil_cpy.cur;
4864 fcn = r_anal_get_fcn_in (core->anal, addr, 0);
4865 if (!fcn) {
4866 return;
4867 }
4868
4869 size = r_anal_function_linear_size (fcn);
4870 if (size <= 0) {
4871 return;
4872 }
4873
4874 buf = malloc (size + 2);
4875 if (!buf) {
4876 perror ("malloc");
4877 return;
4878 }
4879
4880 r_io_read_at (core->io, addr, buf, size + 1);
4881
4882 // TODO Hardcoding for 2 instructions (mov e_p,[esp];ret). More work needed
4883 idx = 0;
4884 if (r_anal_op (core->anal, &op, cur, buf + idx, size - idx, R_ANAL_OP_MASK_ESIL) <= 0 ||
4885 op.size <= 0 ||
4886 (op.type != R_ANAL_OP_TYPE_MOV && op.type != R_ANAL_OP_TYPE_CMOV)) {
4887 goto err_anal_op;
4888 }
4889
4890 r_asm_set_pc (core->rasm, cur);
4891 esilstr = R_STRBUF_SAFEGET (&op.esil);
4892 if (!esilstr) {
4893 goto err_anal_op;
4894 }
4895 // Ugly code
4896 // This is a hack, since ESIL doesn't always preserve values pushed on the stack. That probably needs to be rectified
4897 spname = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
4898 if (!spname || !*spname) {
4899 goto err_anal_op;
4900 }
4901 tmp_esil_str_len = strlen (esilstr) + strlen (spname) + maxaddrlen;
4902 tmp_esil_str = (char*) malloc (tmp_esil_str_len);
4903 if (!tmp_esil_str) {
4904 goto err_anal_op;
4905 }
4906 tmp_esil_str[tmp_esil_str_len - 1] = '\0';
4907 snprintf (tmp_esil_str, tmp_esil_str_len - 1, "%s,[", spname);
4908 if (!*esilstr || (strncmp ( esilstr, tmp_esil_str, strlen (tmp_esil_str)))) {
4909 free (tmp_esil_str);
4910 goto err_anal_op;
4911 }
4912
4913 snprintf (tmp_esil_str, tmp_esil_str_len - 1, "%20" PFMT64u "%s", esil_cpy.old, &esilstr[strlen (spname) + 4]);
4914 r_str_trim (tmp_esil_str);
4915 idx += op.size;
4916 r_anal_esil_set_pc (&esil_cpy, cur);
4917 r_anal_esil_parse (&esil_cpy, tmp_esil_str);
4918 r_anal_esil_stack_free (&esil_cpy);
4919 free (tmp_esil_str);
4920
4921 cur = addr + idx;
4922 r_anal_op_fini (&op);
4923 if (r_anal_op (core->anal, &op, cur, buf + idx, size - idx, R_ANAL_OP_MASK_ESIL) <= 0 ||
4924 op.size <= 0 ||
4925 (op.type != R_ANAL_OP_TYPE_RET && op.type != R_ANAL_OP_TYPE_CRET)) {
4926 goto err_anal_op;
4927 }
4928 r_asm_set_pc (core->rasm, cur);
4929
4930 esilstr = R_STRBUF_SAFEGET (&op.esil);
4931 r_anal_esil_set_pc (&esil_cpy, cur);
4932 if (!esilstr || !*esilstr) {
4933 goto err_anal_op;
4934 }
4935 r_anal_esil_parse (&esil_cpy, esilstr);
4936 r_anal_esil_stack_free (&esil_cpy);
4937
4938 memcpy (esil, &esil_cpy, sizeof (esil_cpy));
4939
4940 err_anal_op:
4941 r_anal_op_fini (&op);
4942 free (buf);
4943 }
4944
4945 typedef struct {
4946 ut64 start_addr;
4947 ut64 end_addr;
4948 RAnalFunction *fcn;
4949 RAnalBlock *cur_bb;
4950 RList *bbl, *path, *switch_path;
4951 } IterCtx;
4952
find_bb(ut64 * addr,RAnalBlock * bb)4953 static int find_bb(ut64 *addr, RAnalBlock *bb) {
4954 return *addr != bb->addr;
4955 }
4956
get_next_i(IterCtx * ctx,size_t * next_i)4957 static inline bool get_next_i(IterCtx *ctx, size_t *next_i) {
4958 (*next_i)++;
4959 ut64 cur_addr = *next_i + ctx->start_addr;
4960 if (ctx->fcn) {
4961 if (!ctx->cur_bb) {
4962 ctx->path = r_list_new ();
4963 ctx->switch_path = r_list_new ();
4964 ctx->bbl = r_list_clone (ctx->fcn->bbs);
4965 ctx->cur_bb = r_anal_get_block_at (ctx->fcn->anal, ctx->fcn->addr);
4966 r_list_push (ctx->path, ctx->cur_bb);
4967 }
4968 RAnalBlock *bb = ctx->cur_bb;
4969 if (cur_addr >= bb->addr + bb->size) {
4970 r_reg_arena_push (ctx->fcn->anal->reg);
4971 RListIter *bbit = NULL;
4972 if (bb->switch_op) {
4973 RAnalCaseOp *cop = r_list_first (bb->switch_op->cases);
4974 bbit = r_list_find (ctx->bbl, &cop->jump, (RListComparator)find_bb);
4975 if (bbit) {
4976 r_list_push (ctx->switch_path, bb->switch_op->cases->head);
4977 }
4978 } else {
4979 bbit = r_list_find (ctx->bbl, &bb->jump, (RListComparator)find_bb);
4980 if (!bbit && bb->fail != UT64_MAX) {
4981 bbit = r_list_find (ctx->bbl, &bb->fail, (RListComparator)find_bb);
4982 }
4983 }
4984 if (!bbit) {
4985 RListIter *cop_it = r_list_last (ctx->switch_path);
4986 RAnalBlock *prev_bb = NULL;
4987 do {
4988 r_reg_arena_pop (ctx->fcn->anal->reg);
4989 prev_bb = r_list_pop (ctx->path);
4990 if (prev_bb->fail != UT64_MAX) {
4991 bbit = r_list_find (ctx->bbl, &prev_bb->fail, (RListComparator)find_bb);
4992 if (bbit) {
4993 r_reg_arena_push (ctx->fcn->anal->reg);
4994 r_list_push (ctx->path, prev_bb);
4995 }
4996 }
4997 if (!bbit && cop_it) {
4998 RAnalCaseOp *cop = cop_it->data;
4999 if (cop->jump == prev_bb->addr && cop_it->n) {
5000 cop = cop_it->n->data;
5001 r_list_pop (ctx->switch_path);
5002 r_list_push (ctx->switch_path, cop_it->n);
5003 cop_it = cop_it->n;
5004 bbit = r_list_find (ctx->bbl, &cop->jump, (RListComparator)find_bb);
5005 }
5006 }
5007 if (cop_it && !cop_it->n) {
5008 r_list_pop (ctx->switch_path);
5009 cop_it = r_list_last (ctx->switch_path);
5010 }
5011 } while (!bbit && !r_list_empty (ctx->path));
5012 }
5013 if (!bbit) {
5014 r_list_free (ctx->path);
5015 r_list_free (ctx->switch_path);
5016 r_list_free (ctx->bbl);
5017 return false;
5018 }
5019 ctx->cur_bb = bbit->data;
5020 r_list_push (ctx->path, ctx->cur_bb);
5021 r_list_delete (ctx->bbl, bbit);
5022 *next_i = ctx->cur_bb->addr - ctx->start_addr;
5023 }
5024 } else if (cur_addr >= ctx->end_addr) {
5025 return false;
5026 }
5027 return true;
5028 }
5029
r_core_anal_esil(RCore * core,const char * str,const char * target)5030 R_API void r_core_anal_esil(RCore *core, const char *str, const char *target) {
5031 bool cfg_anal_strings = r_config_get_i (core->config, "anal.strings");
5032 bool emu_lazy = r_config_get_i (core->config, "emu.lazy");
5033 bool gp_fixed = r_config_get_i (core->config, "anal.gpfixed");
5034 RAnalEsil *ESIL = core->anal->esil;
5035 ut64 refptr = 0LL;
5036 const char *pcname;
5037 RAnalOp op = R_EMPTY;
5038 ut8 *buf = NULL;
5039 bool end_address_set = false;
5040 int iend;
5041 int minopsize = 4; // XXX this depends on asm->mininstrsize
5042 bool archIsArm = false;
5043 ut64 addr = core->offset;
5044 ut64 start = addr;
5045 ut64 end = 0LL;
5046 ut64 cur;
5047
5048 mycore = core;
5049 if (!strcmp (str, "?")) {
5050 eprintf ("Usage: aae[f] [len] [addr] - analyze refs in function, section or len bytes with esil\n");
5051 eprintf (" aae $SS @ $S - analyze the whole section\n");
5052 eprintf (" aae $SS str.Hello @ $S - find references for str.Hellow\n");
5053 eprintf (" aaef - analyze functions discovered with esil\n");
5054 return;
5055 }
5056 #define CHECKREF(x) ((refptr && (x) == refptr) || !refptr)
5057 if (target) {
5058 const char *expr = r_str_trim_head_ro (target);
5059 if (*expr) {
5060 refptr = ntarget = r_num_math (core->num, expr);
5061 if (!refptr) {
5062 ntarget = refptr = addr;
5063 }
5064 } else {
5065 ntarget = UT64_MAX;
5066 refptr = 0LL;
5067 }
5068 } else {
5069 ntarget = UT64_MAX;
5070 refptr = 0LL;
5071 }
5072 RAnalFunction *fcn = NULL;
5073 if (!strcmp (str, "f")) {
5074 fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
5075 if (fcn) {
5076 start = r_anal_function_min_addr (fcn);
5077 addr = fcn->addr;
5078 end = r_anal_function_max_addr (fcn);
5079 end_address_set = true;
5080 }
5081 }
5082
5083 if (!end_address_set) {
5084 if (str[0] == ' ') {
5085 end = addr + r_num_math (core->num, str + 1);
5086 } else {
5087 RIOMap *map = r_io_map_get (core->io, addr);
5088 if (map) {
5089 end = r_io_map_end (map);
5090 } else {
5091 end = addr + core->blocksize;
5092 }
5093 }
5094 }
5095
5096 iend = end - start;
5097 if (iend < 0) {
5098 return;
5099 }
5100 if (iend > MAX_SCAN_SIZE) {
5101 eprintf ("Warning: Not going to analyze 0x%08"PFMT64x" bytes.\n", (ut64)iend);
5102 return;
5103 }
5104 buf = malloc ((size_t)iend + 2);
5105 if (!buf) {
5106 perror ("malloc");
5107 return;
5108 }
5109 esilbreak_last_read = UT64_MAX;
5110 r_io_read_at (core->io, start, buf, iend + 1);
5111 if (!ESIL) {
5112 r_core_cmd0 (core, "aei");
5113 ESIL = core->anal->esil;
5114 if (!ESIL) {
5115 eprintf ("ESIL not initialized\n");
5116 return;
5117 }
5118 r_core_cmd0 (core, "aeim");
5119 }
5120 EsilBreakCtx ctx = {
5121 &op,
5122 fcn,
5123 r_reg_get_name (core->anal->reg, R_REG_NAME_SP),
5124 r_reg_getv (core->anal->reg, ctx.spname)
5125 };
5126 ESIL->cb.hook_reg_write = &esilbreak_reg_write;
5127 //this is necessary for the hook to read the id of analop
5128 ESIL->user = &ctx;
5129 ESIL->cb.hook_mem_read = &esilbreak_mem_read;
5130 ESIL->cb.hook_mem_write = &esilbreak_mem_write;
5131
5132 if (fcn && fcn->reg_save_area) {
5133 r_reg_setv (core->anal->reg, ctx.spname, ctx.initial_sp - fcn->reg_save_area);
5134 }
5135 //eprintf ("Analyzing ESIL refs from 0x%"PFMT64x" - 0x%"PFMT64x"\n", addr, end);
5136 // TODO: backup/restore register state before/after analysis
5137 pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
5138 if (!pcname || !*pcname) {
5139 eprintf ("Cannot find program counter register in the current profile.\n");
5140 return;
5141 }
5142 esil_anal_stop = false;
5143 r_cons_break_push (cccb, core);
5144
5145 int arch = -1;
5146 if (!strcmp (core->anal->cur->arch, "arm")) {
5147 switch (core->anal->cur->bits) {
5148 case 64: arch = R2_ARCH_ARM64; break;
5149 case 32: arch = R2_ARCH_ARM32; break;
5150 case 16: arch = R2_ARCH_THUMB; break;
5151 }
5152 archIsArm = true;
5153 }
5154
5155 ut64 gp = r_config_get_i (core->config, "anal.gp");
5156 const char *gp_reg = NULL;
5157 if (!strcmp (core->anal->cur->arch, "mips")) {
5158 gp_reg = "gp";
5159 arch = R2_ARCH_MIPS;
5160 }
5161
5162 const char *sn = r_reg_get_name (core->anal->reg, R_REG_NAME_SN);
5163 if (!sn) {
5164 eprintf ("Warning: No SN reg alias for current architecture.\n");
5165 }
5166 r_reg_arena_push (core->anal->reg);
5167
5168 IterCtx ictx = { start, end, fcn, NULL};
5169 size_t i = addr - start;
5170 do {
5171 if (esil_anal_stop || r_cons_is_breaked ()) {
5172 break;
5173 }
5174 cur = start + i;
5175 if (!r_io_is_valid_offset (core->io, cur, 0)) {
5176 break;
5177 }
5178 {
5179 RPVector *list = r_meta_get_all_in (core->anal, cur, R_META_TYPE_ANY);
5180 void **it;
5181 r_pvector_foreach (list, it) {
5182 RIntervalNode *node = *it;
5183 RAnalMetaItem *meta = node->data;
5184 switch (meta->type) {
5185 case R_META_TYPE_DATA:
5186 case R_META_TYPE_STRING:
5187 case R_META_TYPE_FORMAT:
5188 i += 4;
5189 r_pvector_free (list);
5190 goto repeat;
5191 default:
5192 break;
5193 }
5194 }
5195 r_pvector_free (list);
5196 }
5197
5198 /* realign address if needed */
5199 r_core_seek_arch_bits (core, cur);
5200 int opalign = core->anal->pcalign;
5201 if (opalign > 0) {
5202 cur -= (cur % opalign);
5203 }
5204
5205 r_anal_op_fini (&op);
5206 r_asm_set_pc (core->rasm, cur);
5207 if (!r_anal_op (core->anal, &op, cur, buf + i, iend - i, R_ANAL_OP_MASK_ESIL | R_ANAL_OP_MASK_VAL | R_ANAL_OP_MASK_HINT)) {
5208 i += minopsize - 1; // XXX dupe in op.size below
5209 }
5210 // if (op.type & 0x80000000 || op.type == 0) {
5211 if (op.type == R_ANAL_OP_TYPE_ILL || op.type == R_ANAL_OP_TYPE_UNK) {
5212 // i += 2
5213 r_anal_op_fini (&op);
5214 continue;
5215 }
5216 //we need to check again i because buf+i may goes beyond its boundaries
5217 //because of i+= minopsize - 1
5218 if (i > iend) {
5219 break;
5220 }
5221 if (op.size < 1) {
5222 i += minopsize - 1;
5223 continue;
5224 }
5225 if (emu_lazy) {
5226 if (op.type & R_ANAL_OP_TYPE_REP) {
5227 i += op.size - 1;
5228 continue;
5229 }
5230 switch (op.type & R_ANAL_OP_TYPE_MASK) {
5231 case R_ANAL_OP_TYPE_JMP:
5232 case R_ANAL_OP_TYPE_CJMP:
5233 case R_ANAL_OP_TYPE_CALL:
5234 case R_ANAL_OP_TYPE_RET:
5235 case R_ANAL_OP_TYPE_ILL:
5236 case R_ANAL_OP_TYPE_NOP:
5237 case R_ANAL_OP_TYPE_UJMP:
5238 case R_ANAL_OP_TYPE_IO:
5239 case R_ANAL_OP_TYPE_LEAVE:
5240 case R_ANAL_OP_TYPE_CRYPTO:
5241 case R_ANAL_OP_TYPE_CPL:
5242 case R_ANAL_OP_TYPE_SYNC:
5243 case R_ANAL_OP_TYPE_SWI:
5244 case R_ANAL_OP_TYPE_CMP:
5245 case R_ANAL_OP_TYPE_ACMP:
5246 case R_ANAL_OP_TYPE_NULL:
5247 case R_ANAL_OP_TYPE_CSWI:
5248 case R_ANAL_OP_TYPE_TRAP:
5249 i += op.size - 1;
5250 continue;
5251 // those require write support
5252 case R_ANAL_OP_TYPE_PUSH:
5253 case R_ANAL_OP_TYPE_POP:
5254 i += op.size - 1;
5255 continue;
5256 }
5257 }
5258 if (sn && op.type == R_ANAL_OP_TYPE_SWI) {
5259 r_flag_space_set (core->flags, R_FLAGS_FS_SYSCALLS);
5260 int snv = (arch == R2_ARCH_THUMB)? op.val: (int)r_reg_getv (core->anal->reg, sn);
5261 RSyscallItem *si = r_syscall_get (core->anal->syscall, snv, -1);
5262 if (si) {
5263 // eprintf ("0x%08"PFMT64x" SYSCALL %-4d %s\n", cur, snv, si->name);
5264 r_flag_set_next (core->flags, sdb_fmt ("syscall.%s", si->name), cur, 1);
5265 } else {
5266 //todo were doing less filtering up top because we can't match against 80 on all platforms
5267 // might get too many of this path now..
5268 // eprintf ("0x%08"PFMT64x" SYSCALL %d\n", cur, snv);
5269 r_flag_set_next (core->flags, sdb_fmt ("syscall.%d", snv), cur, 1);
5270 }
5271 r_flag_space_set (core->flags, NULL);
5272 }
5273 const char *esilstr = R_STRBUF_SAFEGET (&op.esil);
5274 i += op.size - 1;
5275 if (!esilstr || !*esilstr) {
5276 continue;
5277 }
5278 r_anal_esil_set_pc (ESIL, cur);
5279 r_reg_setv (core->anal->reg, pcname, cur + op.size);
5280 if (gp_fixed && gp_reg) {
5281 r_reg_setv (core->anal->reg, gp_reg, gp);
5282 }
5283 (void)r_anal_esil_parse (ESIL, esilstr);
5284 // looks like ^C is handled by esil_parse !!!!
5285 //r_anal_esil_dumpstack (ESIL);
5286 //r_anal_esil_stack_free (ESIL);
5287 switch (op.type) {
5288 case R_ANAL_OP_TYPE_LEA:
5289 // arm64
5290 if (core->anal->cur && arch == R2_ARCH_ARM64) {
5291 if (CHECKREF (ESIL->cur)) {
5292 r_anal_xrefs_set (core->anal, cur, ESIL->cur, R_ANAL_REF_TYPE_STRING);
5293 }
5294 } else if ((target && op.ptr == ntarget) || !target) {
5295 if (CHECKREF (ESIL->cur)) {
5296 if (op.ptr && r_io_is_valid_offset (core->io, op.ptr, !core->anal->opt.noncode)) {
5297 r_anal_xrefs_set (core->anal, cur, op.ptr, R_ANAL_REF_TYPE_STRING);
5298 } else {
5299 r_anal_xrefs_set (core->anal, cur, ESIL->cur, R_ANAL_REF_TYPE_STRING);
5300 }
5301 }
5302 }
5303 if (cfg_anal_strings) {
5304 add_string_ref (core, op.addr, op.ptr);
5305 }
5306 break;
5307 case R_ANAL_OP_TYPE_ADD:
5308 /* TODO: test if this is valid for other archs too */
5309 if (core->anal->cur && archIsArm) {
5310 /* This code is known to work on Thumb, ARM and ARM64 */
5311 ut64 dst = ESIL->cur;
5312 if ((target && dst == ntarget) || !target) {
5313 if (CHECKREF (dst)) {
5314 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
5315 }
5316 }
5317 if (cfg_anal_strings) {
5318 add_string_ref (core, op.addr, dst);
5319 }
5320 } else if ((core->anal->bits == 32 && core->anal->cur && arch == R2_ARCH_MIPS)) {
5321 ut64 dst = ESIL->cur;
5322 if (!op.src[0] || !op.src[0]->reg || !op.src[0]->reg->name) {
5323 break;
5324 }
5325 if (!strcmp (op.src[0]->reg->name, "sp")) {
5326 break;
5327 }
5328 if (!strcmp (op.src[0]->reg->name, "zero")) {
5329 break;
5330 }
5331 if ((target && dst == ntarget) || !target) {
5332 if (dst > 0xffff && op.src[1] && (dst & 0xffff) == (op.src[1]->imm & 0xffff) && myvalid (mycore->io, dst)) {
5333 RFlagItem *f;
5334 char *str;
5335 if (CHECKREF (dst) || CHECKREF (cur)) {
5336 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
5337 if (cfg_anal_strings) {
5338 add_string_ref (core, op.addr, dst);
5339 }
5340 if ((f = r_core_flag_get_by_spaces (core->flags, dst))) {
5341 r_meta_set_string (core->anal, R_META_TYPE_COMMENT, cur, f->name);
5342 } else if ((str = is_string_at (mycore, dst, NULL))) {
5343 char *str2 = sdb_fmt ("esilref: '%s'", str);
5344 // HACK avoid format string inside string used later as format
5345 // string crashes disasm inside agf under some conditions.
5346 // https://github.com/radareorg/radare2/issues/6937
5347 r_str_replace_char (str2, '%', '&');
5348 r_meta_set_string (core->anal, R_META_TYPE_COMMENT, cur, str2);
5349 free (str);
5350 }
5351 }
5352 }
5353 }
5354 }
5355 break;
5356 case R_ANAL_OP_TYPE_LOAD:
5357 {
5358 ut64 dst = esilbreak_last_read;
5359 if (dst != UT64_MAX && CHECKREF (dst)) {
5360 if (myvalid (mycore->io, dst)) {
5361 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
5362 if (cfg_anal_strings) {
5363 add_string_ref (core, op.addr, dst);
5364 }
5365 }
5366 }
5367 dst = esilbreak_last_data;
5368 if (dst != UT64_MAX && CHECKREF (dst)) {
5369 if (myvalid (mycore->io, dst)) {
5370 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_DATA);
5371 if (cfg_anal_strings) {
5372 add_string_ref (core, op.addr, dst);
5373 }
5374 }
5375 }
5376 }
5377 break;
5378 case R_ANAL_OP_TYPE_JMP:
5379 {
5380 ut64 dst = op.jump;
5381 if (CHECKREF (dst)) {
5382 if (myvalid (core->io, dst)) {
5383 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_CODE);
5384 }
5385 }
5386 }
5387 break;
5388 case R_ANAL_OP_TYPE_CALL:
5389 {
5390 ut64 dst = op.jump;
5391 if (CHECKREF (dst)) {
5392 if (myvalid (core->io, dst)) {
5393 r_anal_xrefs_set (core->anal, cur, dst, R_ANAL_REF_TYPE_CALL);
5394 }
5395 ESIL->old = cur + op.size;
5396 getpcfromstack (core, ESIL);
5397 }
5398 }
5399 break;
5400 case R_ANAL_OP_TYPE_UJMP:
5401 case R_ANAL_OP_TYPE_UCALL:
5402 case R_ANAL_OP_TYPE_ICALL:
5403 case R_ANAL_OP_TYPE_RCALL:
5404 case R_ANAL_OP_TYPE_IRCALL:
5405 case R_ANAL_OP_TYPE_MJMP:
5406 {
5407 ut64 dst = core->anal->esil->jump_target;
5408 if (dst == 0 || dst == UT64_MAX) {
5409 dst = r_reg_getv (core->anal->reg, pcname);
5410 }
5411 if (CHECKREF (dst)) {
5412 if (myvalid (core->io, dst)) {
5413 RAnalRefType ref =
5414 (op.type & R_ANAL_OP_TYPE_MASK) == R_ANAL_OP_TYPE_UCALL
5415 ? R_ANAL_REF_TYPE_CALL
5416 : R_ANAL_REF_TYPE_CODE;
5417 r_anal_xrefs_set (core->anal, cur, dst, ref);
5418 r_core_anal_fcn (core, dst, UT64_MAX, R_ANAL_REF_TYPE_NULL, 1);
5419 // analyze function here
5420 #if 0
5421 if (op.type == R_ANAL_OP_TYPE_UCALL || op.type == R_ANAL_OP_TYPE_RCALL) {
5422 eprintf ("0x%08"PFMT64x" RCALL TO %llx\n", cur, dst);
5423 }
5424 #endif
5425 }
5426 }
5427 }
5428 break;
5429 default:
5430 break;
5431 }
5432 r_anal_esil_stack_free (ESIL);
5433 repeat:;
5434 } while (get_next_i (&ictx, &i));
5435 free (buf);
5436 ESIL->cb.hook_mem_read = NULL;
5437 ESIL->cb.hook_mem_write = NULL;
5438 ESIL->cb.hook_reg_write = NULL;
5439 ESIL->user = NULL;
5440 r_anal_op_fini (&op);
5441 r_cons_break_pop ();
5442 // restore register
5443 r_reg_arena_pop (core->anal->reg);
5444 }
5445
isValidAddress(RCore * core,ut64 addr)5446 static bool isValidAddress (RCore *core, ut64 addr) {
5447 // check if address is mapped
5448 RIOMap* map = r_io_map_get (core->io, addr);
5449 if (!map) {
5450 return false;
5451 }
5452 st64 fdsz = (st64)r_io_fd_size (core->io, map->fd);
5453 if (fdsz > 0 && map->delta > fdsz) {
5454 return false;
5455 }
5456 // check if associated file is opened
5457 RIODesc *desc = r_io_desc_get (core->io, map->fd);
5458 if (!desc) {
5459 return false;
5460 }
5461 // check if current map->fd is null://
5462 if (!strncmp (desc->name, "null://", 7)) {
5463 return false;
5464 }
5465 return true;
5466 }
5467
stringAt(RCore * core,ut64 addr)5468 static bool stringAt(RCore *core, ut64 addr) {
5469 ut8 buf[32];
5470 r_io_read_at (core->io, addr - 1, buf, sizeof (buf));
5471 // check if previous byte is a null byte, all strings, except pascal ones should be like this
5472 if (buf[0] != 0) {
5473 return false;
5474 }
5475 return is_string (buf + 1, 31, NULL);
5476 }
5477
r_core_search_value_in_range(RCore * core,RInterval search_itv,ut64 vmin,ut64 vmax,int vsize,inRangeCb cb,void * cb_user)5478 R_API int r_core_search_value_in_range(RCore *core, RInterval search_itv, ut64 vmin,
5479 ut64 vmax, int vsize, inRangeCb cb, void *cb_user) {
5480 int i, align = core->search->align, hitctr = 0;
5481 bool vinfun = r_config_get_i (core->config, "anal.vinfun");
5482 bool vinfunr = r_config_get_i (core->config, "anal.vinfunrange");
5483 bool analStrings = r_config_get_i (core->config, "anal.strings");
5484 mycore = core;
5485 ut8 buf[4096];
5486 ut64 v64, value = 0, size;
5487 ut64 from = search_itv.addr, to = r_itv_end (search_itv);
5488 ut32 v32;
5489 ut16 v16;
5490 if (from >= to) {
5491 eprintf ("Error: from must be lower than to\n");
5492 return -1;
5493 }
5494 bool maybeThumb = false;
5495 if (align && core->anal->cur && core->anal->cur->arch) {
5496 if (!strcmp (core->anal->cur->arch, "arm") && core->anal->bits != 64) {
5497 maybeThumb = true;
5498 }
5499 }
5500
5501 if (vmin >= vmax) {
5502 eprintf ("Error: vmin must be lower than vmax\n");
5503 return -1;
5504 }
5505 if (to == UT64_MAX) {
5506 eprintf ("Error: Invalid destination boundary\n");
5507 return -1;
5508 }
5509 r_cons_break_push (NULL, NULL);
5510
5511 if (!r_io_is_valid_offset (core->io, from, 0)) {
5512 return -1;
5513 }
5514 while (from < to) {
5515 size = R_MIN (to - from, sizeof (buf));
5516 memset (buf, 0xff, sizeof (buf)); // probably unnecessary
5517 if (r_cons_is_breaked ()) {
5518 goto beach;
5519 }
5520 bool res = r_io_read_at_mapped (core->io, from, buf, size);
5521 if (!res || !memcmp (buf, "\xff\xff\xff\xff", 4) || !memcmp (buf, "\x00\x00\x00\x00", 4)) {
5522 if (!isValidAddress (core, from)) {
5523 ut64 next = r_io_map_next_address (core->io, from);
5524 if (next == UT64_MAX) {
5525 from += sizeof (buf);
5526 } else {
5527 from += (next - from);
5528 }
5529 continue;
5530 }
5531 }
5532 for (i = 0; i <= (size - vsize); i++) {
5533 void *v = (buf + i);
5534 ut64 addr = from + i;
5535 if (r_cons_is_breaked ()) {
5536 goto beach;
5537 }
5538 if (align && (addr) % align) {
5539 continue;
5540 }
5541 int match = false;
5542 int left = size - i;
5543 if (vsize > left) {
5544 break;
5545 }
5546 switch (vsize) {
5547 case 1: value = *(ut8 *)v; match = (buf[i] >= vmin && buf[i] <= vmax); break;
5548 case 2: v16 = *(uut16 *)v; match = (v16 >= vmin && v16 <= vmax); value = v16; break;
5549 case 4: v32 = *(uut32 *)v; match = (v32 >= vmin && v32 <= vmax); value = v32; break;
5550 case 8: v64 = *(uut64 *)v; match = (v64 >= vmin && v64 <= vmax); value = v64; break;
5551 default: eprintf ("Unknown vsize %d\n", vsize); return -1;
5552 }
5553 if (match && !vinfun) {
5554 if (vinfunr) {
5555 if (r_anal_get_fcn_in_bounds (core->anal, addr, R_ANAL_FCN_TYPE_NULL)) {
5556 match = false;
5557 }
5558 } else {
5559 if (r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL)) {
5560 match = false;
5561 }
5562 }
5563 }
5564 if (match && value) {
5565 bool isValidMatch = true;
5566 if (align && (value % align)) {
5567 // ignored .. unless we are analyzing arm/thumb and lower bit is 1
5568 isValidMatch = false;
5569 if (maybeThumb && (value & 1)) {
5570 isValidMatch = true;
5571 }
5572 }
5573 if (isValidMatch) {
5574 cb (core, addr, value, vsize, cb_user);
5575 if (analStrings && stringAt (core, addr)) {
5576 add_string_ref (mycore, addr, value);
5577 }
5578 hitctr++;
5579 }
5580 }
5581 }
5582 if (size == to-from) {
5583 break;
5584 }
5585 from += size-vsize+1;
5586 }
5587 beach:
5588 r_cons_break_pop ();
5589 return hitctr;
5590 }
5591
5592
5593 typedef struct {
5594 dict visited;
5595 RList *path;
5596 RCore *core;
5597 ut64 from;
5598 RAnalBlock *fromBB;
5599 ut64 to;
5600 RAnalBlock *toBB;
5601 RAnalBlock *cur;
5602 bool followCalls;
5603 int followDepth;
5604 int count; // max number of results
5605 } RCoreAnalPaths;
5606
printAnalPaths(RCoreAnalPaths * p,PJ * pj)5607 static bool printAnalPaths(RCoreAnalPaths *p, PJ *pj) {
5608 RListIter *iter;
5609 RAnalBlock *path;
5610 if (pj) {
5611 pj_a (pj);
5612 } else {
5613 r_cons_printf ("pdb @@= ");
5614 }
5615
5616 r_list_foreach (p->path, iter, path) {
5617 if (pj) {
5618 pj_n (pj, path->addr);
5619 } else {
5620 r_cons_printf ("0x%08"PFMT64x" ", path->addr);
5621 }
5622 }
5623
5624 if(pj) {
5625 pj_end (pj);
5626 } else {
5627 r_cons_printf ("\n");
5628 }
5629 return (p->count < 1 || --p->count > 0);
5630 }
5631 static void analPaths(RCoreAnalPaths *p, PJ *pj);
5632
analPathFollow(RCoreAnalPaths * p,ut64 addr,PJ * pj)5633 static void analPathFollow(RCoreAnalPaths *p, ut64 addr, PJ *pj) {
5634 if (addr == UT64_MAX) {
5635 return;
5636 }
5637 if (!dict_get (&p->visited, addr)) {
5638 p->cur = r_anal_bb_from_offset (p->core->anal, addr);
5639 analPaths (p, pj);
5640 }
5641 }
5642
analPaths(RCoreAnalPaths * p,PJ * pj)5643 static void analPaths(RCoreAnalPaths *p, PJ *pj) {
5644 RAnalBlock *cur = p->cur;
5645 if (!cur) {
5646 // eprintf ("eof\n");
5647 return;
5648 }
5649 /* handle ^C */
5650 if (r_cons_is_breaked ()) {
5651 return;
5652 }
5653 dict_set (&p->visited, cur->addr, 1, NULL);
5654 r_list_append (p->path, cur);
5655 if (p->followDepth && --p->followDepth == 0) {
5656 return;
5657 }
5658 if (p->toBB && cur->addr == p->toBB->addr) {
5659 if (!printAnalPaths (p, pj)) {
5660 return;
5661 }
5662 } else {
5663 RAnalBlock *c = cur;
5664 ut64 j = cur->jump;
5665 ut64 f = cur->fail;
5666 analPathFollow (p, j, pj);
5667 cur = c;
5668 analPathFollow (p, f, pj);
5669 if (p->followCalls) {
5670 int i;
5671 for (i = 0; i < cur->op_pos_size; i++) {
5672 ut64 addr = cur->addr + cur->op_pos[i];
5673 RAnalOp *op = r_core_anal_op (p->core, addr, R_ANAL_OP_MASK_BASIC);
5674 if (op && op->type == R_ANAL_OP_TYPE_CALL) {
5675 analPathFollow (p, op->jump, pj);
5676 }
5677 cur = c;
5678 r_anal_op_free (op);
5679 }
5680 }
5681 }
5682 p->cur = r_list_pop (p->path);
5683 dict_del (&p->visited, cur->addr);
5684 if (p->followDepth) {
5685 p->followDepth++;
5686 }
5687 }
5688
r_core_anal_paths(RCore * core,ut64 from,ut64 to,bool followCalls,int followDepth,bool is_json)5689 R_API void r_core_anal_paths(RCore *core, ut64 from, ut64 to, bool followCalls, int followDepth, bool is_json) {
5690 RAnalBlock *b0 = r_anal_bb_from_offset (core->anal, from);
5691 RAnalBlock *b1 = r_anal_bb_from_offset (core->anal, to);
5692 PJ *pj = NULL;
5693 if (!b0) {
5694 eprintf ("Cannot find basic block for 0x%08"PFMT64x"\n", from);
5695 return;
5696 }
5697 if (!b1) {
5698 eprintf ("Cannot find basic block for 0x%08"PFMT64x"\n", to);
5699 return;
5700 }
5701 RCoreAnalPaths rcap = {{0}};
5702 dict_init (&rcap.visited, 32, free);
5703 rcap.path = r_list_new ();
5704 rcap.core = core;
5705 rcap.from = from;
5706 rcap.fromBB = b0;
5707 rcap.to = to;
5708 rcap.toBB = b1;
5709 rcap.cur = b0;
5710 rcap.count = r_config_get_i (core->config, "search.maxhits");;
5711 rcap.followCalls = followCalls;
5712 rcap.followDepth = followDepth;
5713
5714 // Initialize a PJ object for json mode
5715 if (is_json) {
5716 pj = r_core_pj_new (core);
5717 pj_a (pj);
5718 }
5719
5720 analPaths (&rcap, pj);
5721
5722 if (is_json) {
5723 pj_end (pj);
5724 r_cons_printf ("%s", pj_string (pj));
5725 }
5726
5727 if (pj) {
5728 pj_free (pj);
5729 }
5730
5731 dict_fini (&rcap.visited);
5732 r_list_free (rcap.path);
5733 }
5734
__cb(RFlagItem * fi,void * user)5735 static bool __cb(RFlagItem *fi, void *user) {
5736 r_list_append (user, r_str_newf ("0x%08"PFMT64x, fi->offset));
5737 return true;
5738 }
5739
__addrs_cmp(void * _a,void * _b)5740 static int __addrs_cmp(void *_a, void *_b) {
5741 ut64 a = r_num_get (NULL, _a);
5742 ut64 b = r_num_get (NULL, _b);
5743 if (a > b) {
5744 return 1;
5745 }
5746 if (a < b) {
5747 return -1;
5748 }
5749 return 0;
5750 }
5751
r_core_anal_inflags(RCore * core,const char * glob)5752 R_API void r_core_anal_inflags(RCore *core, const char *glob) {
5753 RList *addrs = r_list_newf (free);
5754 RListIter *iter;
5755 bool a2f = r_config_get_i (core->config, "anal.a2f");
5756 char *anal_in = strdup (r_config_get (core->config, "anal.in"));
5757 r_config_set (core->config, "anal.in", "block");
5758 // aaFa = use a2f instead of af+
5759 bool simple = (!glob || *glob != 'a');
5760 glob = r_str_trim_head_ro (glob);
5761 char *addr;
5762 r_flag_foreach_glob (core->flags, glob, __cb, addrs);
5763 // should be sorted already
5764 r_list_sort (addrs, (RListComparator)__addrs_cmp);
5765 r_list_foreach (addrs, iter, addr) {
5766 if (!iter->n || r_cons_is_breaked ()) {
5767 break;
5768 }
5769 char *addr2 = iter->n->data;
5770 if (!addr || !addr2) {
5771 break;
5772 }
5773 ut64 a0 = r_num_get (NULL, addr);
5774 ut64 a1 = r_num_get (NULL, addr2);
5775 if (a0 == a1) {
5776 // ignore
5777 continue;
5778 }
5779 if (a0 > a1) {
5780 eprintf ("Warning: unsorted flag list 0x%llx 0x%llx\n", a0, a1);
5781 continue;
5782 }
5783 st64 sz = a1 - a0;
5784 if (sz < 1 || sz > core->anal->opt.bb_max_size) {
5785 eprintf ("Warning: invalid flag range from 0x%08"PFMT64x" to 0x%08"PFMT64x"\n", a0, a1);
5786 continue;
5787 }
5788 if (simple) {
5789 RFlagItem *fi = r_flag_get_at (core->flags, a0, 0);
5790 r_core_cmdf (core, "af+ %s fcn.%s", addr, fi? fi->name: addr);
5791 r_core_cmdf (core, "afb+ %s %s %d", addr, addr, (int)sz);
5792 } else {
5793 r_core_cmdf (core, "aab@%s!%s-%s\n", addr, addr2, addr);
5794 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, r_num_math (core->num, addr), 0);
5795 if (fcn) {
5796 eprintf ("%s %s %"PFMT64d" # %s\n", addr, "af", sz, fcn->name);
5797 } else {
5798 if (a2f) {
5799 r_core_cmdf (core, "a2f@%s!%s-%s\n", addr, addr2, addr);
5800 } else {
5801 r_core_cmdf (core, "af@%s!%s-%s\n", addr, addr2, addr);
5802 }
5803 fcn = r_anal_get_fcn_in (core->anal, r_num_math (core->num, addr), 0);
5804 eprintf ("%s %s %.4"PFMT64d" # %s\n", addr, "aab", sz, fcn?fcn->name: "");
5805 }
5806 }
5807 }
5808 r_list_free (addrs);
5809 r_config_set (core->config, "anal.in", anal_in);
5810 free (anal_in);
5811 }
5812
analyze_noreturn_function(RCore * core,RAnalFunction * f)5813 static bool analyze_noreturn_function(RCore *core, RAnalFunction *f) {
5814 RListIter *iter;
5815 RAnalBlock *bb;
5816 r_list_foreach (f->bbs, iter, bb) {
5817 ut64 opaddr = r_anal_bb_opaddr_i (bb, bb->ninstr - 1);
5818 if (opaddr == UT64_MAX) {
5819 return false;
5820 }
5821
5822 // get last opcode
5823 RAnalOp *op = r_core_op_anal (core, opaddr, R_ANAL_OP_MASK_HINT);
5824 if (!op) {
5825 eprintf ("Cannot analyze opcode at 0x%08" PFMT64x "\n", opaddr);
5826 return false;
5827 }
5828
5829 switch (op->type & R_ANAL_OP_TYPE_MASK) {
5830 case R_ANAL_OP_TYPE_ILL:
5831 case R_ANAL_OP_TYPE_RET:
5832 r_anal_op_free (op);
5833 return false;
5834 case R_ANAL_OP_TYPE_JMP:
5835 if (!r_anal_function_contains (f, op->jump)) {
5836 r_anal_op_free (op);
5837 return false;
5838 }
5839 break;
5840 }
5841 r_anal_op_free (op);
5842 }
5843 return true;
5844 }
5845
r_core_anal_propagate_noreturn(RCore * core,ut64 addr)5846 R_API void r_core_anal_propagate_noreturn(RCore *core, ut64 addr) {
5847 RList *todo = r_list_newf (free);
5848 if (!todo) {
5849 return;
5850 }
5851
5852 HtUU *done = ht_uu_new0 ();
5853 if (!done) {
5854 r_list_free (todo);
5855 return;
5856 }
5857
5858 RAnalFunction *request_fcn = NULL;
5859 if (addr != UT64_MAX) {
5860 request_fcn = r_anal_get_function_at (core->anal, addr);
5861 if (!request_fcn) {
5862 r_list_free (todo);
5863 ht_uu_free (done);
5864 return;
5865 }
5866 }
5867
5868 // find known noreturn functions to propagate
5869 RListIter *iter;
5870 RAnalFunction *f;
5871 r_list_foreach (core->anal->fcns, iter, f) {
5872 if (f->is_noreturn) {
5873 ut64 *n = ut64_new (f->addr);
5874 r_list_append (todo, n);
5875 }
5876 }
5877
5878 while (!r_list_empty (todo)) {
5879 ut64 *paddr = (ut64*)r_list_pop (todo);
5880 ut64 noret_addr = *paddr;
5881 free (paddr);
5882 if (r_cons_is_breaked ()) {
5883 break;
5884 }
5885 RList *xrefs = r_anal_xrefs_get (core->anal, noret_addr);
5886 RAnalRef *xref;
5887 r_list_foreach (xrefs, iter, xref) {
5888 RAnalOp *xrefop = r_core_op_anal (core, xref->addr, R_ANAL_OP_MASK_ALL);
5889 if (!xrefop) {
5890 eprintf ("Cannot analyze opcode at 0x%08" PFMT64x "\n", xref->addr);
5891 continue;
5892 }
5893 ut64 call_addr = xref->addr;
5894 ut64 chop_addr = call_addr + xrefop->size;
5895 r_anal_op_free (xrefop);
5896 if (xref->type != R_ANAL_REF_TYPE_CALL) {
5897 continue;
5898 }
5899
5900 // Find the block that has an instruction at exactly the xref addr
5901 RList *blocks = r_anal_get_blocks_in (core->anal, call_addr);
5902 if (!blocks) {
5903 continue;
5904 }
5905 RAnalBlock *block = NULL;
5906 RListIter *bit;
5907 RAnalBlock *block_cur;
5908 r_list_foreach (blocks, bit, block_cur) {
5909 if (r_anal_block_op_starts_at (block_cur, call_addr)) {
5910 block = block_cur;
5911 break;
5912 }
5913 }
5914 if (block) {
5915 r_anal_block_ref (block);
5916 }
5917 r_list_free (blocks);
5918 if (!block) {
5919 continue;
5920 }
5921
5922 RList *block_fcns = r_list_clone (block->fcns);
5923 if (request_fcn) {
5924 // specific function requested, check if it contains the bb
5925 if (!r_list_contains (block->fcns, request_fcn)) {
5926 goto kontinue;
5927 }
5928 } else {
5929 // r_anal_block_chop_noreturn() might free the block!
5930 block = r_anal_block_chop_noreturn (block, chop_addr);
5931 }
5932
5933 RListIter *fit;
5934 r_list_foreach (block_fcns, fit, f) {
5935 bool found = ht_uu_find (done, f->addr, NULL) != 0;
5936 if (f->addr && !found && analyze_noreturn_function (core, f)) {
5937 f->is_noreturn = true;
5938 r_anal_noreturn_add (core->anal, NULL, f->addr);
5939 ut64 *n = malloc (sizeof (ut64));
5940 *n = f->addr;
5941 r_list_append (todo, n);
5942 ht_uu_insert (done, *n, 1);
5943 }
5944 }
5945 kontinue:
5946 if (block) {
5947 r_anal_block_unref (block);
5948 }
5949 r_list_free (block_fcns);
5950 }
5951 r_list_free (xrefs);
5952 }
5953 r_list_free (todo);
5954 ht_uu_free (done);
5955 }
5956