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