Commit message: Fix segfault in adf  (#16230)
CVE: CVE-2020-27795
CWE: CWE-703
Vulnerability description: A segmentation fault was discovered in radare2 with adf command. In libr/core/cmd_anal.c, when command "adf" has no or wrong argument, anal_fcn_data (core, input + 1) --> RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1); returns null pointer for fcn causing segmentation fault later in ensure_fcn_range (fcn).

Project: radare2
File: cmd_anal.c

static void __cmd_afvf(RCore *core, const char *input) {
	RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
	RListIter *iter;
	RAnalVar *p;
	RList *list = r_anal_var_all_list (core->anal, fcn);
	r_list_sort (list, delta_cmp2);
	r_list_foreach (list, iter, p) {
		if (p->isarg || p->delta > 0) {
			continue;
		}
		const char *pad = r_str_pad (' ', 10 - strlen (p->name));
		r_cons_printf ("0x%08"PFMT64x"  %s:%s%s\n", (ut64)-p->delta, p->name, pad, p->type);
	}
	r_list_sort (list, delta_cmp);
	r_list_foreach (list, iter, p) {
		if (!p->isarg && p->delta < 0) {
			continue;
		}
		// TODO: only stack vars if (p->kind == 's') { }
		const char *pad = r_str_pad (' ', 10 - strlen (p->name));
		// XXX this 0x6a is a hack
		r_cons_printf ("0x%08"PFMT64x"  %s:%s%s\n", ((ut64)p->delta) - 0x6a, p->name, pad, p->type);
	}
	r_list_free (list);

}

Project: radare2
File: cmd_anal.c

static int cmpaddr (const void *_a, const void *_b) {
	const RAnalFunction *a = _a, *b = _b;
	return (a->addr > b->addr)? 1: (a->addr <b->addr)? -1: 0;
}

Project: radare2
File: cmd_anal.c

static void agraph_print_edge_gml(RANode *from, RANode *to, void *user) {
	r_cons_printf ("  edge [\n"
		"    source  %d\n"
		"    target  %d\n"
		"  ]\n", from->gnode->idx, to->gnode->idx
		);
}

Project: radare2
File: cmd_anal.c

static void print_trampolines(RCore *core, ut64 a, ut64 b, size_t element_size) {
	int i;
	for (i = 0; i < core->blocksize; i += element_size) {
		ut32 n;
		memcpy (&n, core->block + i, sizeof (ut32));
		if (n >= a && n <= b) {
			if (element_size == 4) {
				r_cons_printf ("f trampoline.%x @ 0x%" PFMT64x "\n", n, core->offset + i);
			} else {
				r_cons_printf ("f trampoline.%" PFMT64x " @ 0x%" PFMT64x "\n", n, core->offset + i);
			}
			r_cons_printf ("Cd %u @ 0x%" PFMT64x ":%u\n", element_size, core->offset + i, element_size);
			// TODO: add data xrefs
		}
	}
}

Project: radare2
File: cmd_anal.c

static bool fcnNeedsPrefix(const char *name) {
	if (!strncmp (name, "entry", 5)) {
		return false;
	}
	if (!strncmp (name, "main", 4)) {
		return false;
	}
	return (!strchr (name, '.'));
}

Project: radare2
File: cmd_anal.c

R_API void r_core_agraph_print (RCore *core, int use_utf, const char *input) {
	if (use_utf != -1) {
		r_config_set_i (core->config, "scr.utf8", use_utf);
	}
	switch (*input) {
	case 0:
		core->graph->can->linemode = r_config_get_i (core->config, "graph.linemode");
		core->graph->can->color = r_config_get_i (core->config, "scr.color");
		r_agraph_set_title (core->graph,
			r_config_get (core->config, "graph.title"));
		r_agraph_print (core->graph);
		break;
	case 't':{ // "aggt" - tiny graph
		core->graph->is_tiny = true;
		int e = r_config_get_i (core->config, "graph.edges");
		r_config_set_i (core->config, "graph.edges", 0);
		r_core_visual_graph (core, core->graph, NULL, false);
		r_config_set_i (core->config, "graph.edges", e);
		core->graph->is_tiny = false;
		break;
		}
	case 'k': // "aggk"
	{
		Sdb *db = r_agraph_get_sdb (core->graph);
		char *o = sdb_querys (db, "null", 0, "*");
		r_cons_print (o);
		free (o);
		break;
	}
	case 'v': // "aggv"
	case 'i': // "aggi" - open current core->graph in interactive mode
	{
		RANode *ran = r_agraph_get_first_node (core->graph);
		if (ran) {
			ut64 oseek = core->offset;
			r_agraph_set_title (core->graph, r_config_get (core->config, "graph.title"));
			r_agraph_set_curnode (core->graph, ran);
			core->graph->force_update_seek = true;
			core->graph->need_set_layout = true;
			core->graph->layout = r_config_get_i (core->config, "graph.layout");
			int ov = r_cons_is_interactive ();
			core->graph->need_update_dim = true;
			int update_seek = r_core_visual_graph (core, core->graph, NULL, true);
			r_config_set_i (core->config, "scr.interactive", ov);
			r_cons_show_cursor (true);
			r_cons_enable_mouse (false);
			if (update_seek != -1) {
				r_core_seek (core, oseek, 0);
			}
		} else {
			eprintf ("This graph contains no nodes\n");
		}
		break;
	}
	case 'd': { // "aggd" - dot format
		const char *font = r_config_get (core->config, "graph.font");
		r_cons_printf ("digraph code {\nrankdir=LR;\noutputorder=edgesfirst\ngraph [bgcolor=azure];\n"
			"edge [arrowhead=normal, color=\"#3030c0\" style=bold weight=2];\n"
			"node [fillcolor=white, style=filled shape=box "
			"fontname=\"%s\" fontsize=\"8\"];\n", font);
		r_agraph_foreach (core->graph, agraph_print_node_dot, NULL);
		r_agraph_foreach_edge (core->graph, agraph_print_edge_dot, NULL);
		r_cons_printf ("}\n");
		break;
		}
	case '*': // "agg*" -
		r_agraph_foreach (core->graph, agraph_print_node, NULL);
		r_agraph_foreach_edge (core->graph, agraph_print_edge, NULL);
		break;
	case 'J':
	case 'j': {
		PJ *pj = pj_new ();
		if (!pj) {
			return;
		}
		pj_o (pj);
		pj_k (pj, "nodes");
		pj_a (pj);
		r_agraph_print_json (core->graph, pj);
		pj_end (pj);
		pj_end (pj);
		r_cons_println (pj_string (pj));
		pj_free (pj);
	} break;
	case 'g':
		r_cons_printf ("graph\n[\n" "hierarchic 1\n" "label \"\"\n" "directed 1\n");
		r_agraph_foreach (core->graph, agraph_print_node_gml, NULL);
		r_agraph_foreach_edge (core->graph, agraph_print_edge_gml, NULL);
		r_cons_print ("]\n");
		break;
	case 'w':{ // "aggw"
		if (r_config_get_i (core->config, "graph.web")) {
			r_core_cmd0 (core, "=H /graph/");
		} else {
			const char *filename = r_str_trim_head_ro (input + 1);
			char *cmd = graph_cmd (core, "aggd", filename);
			if (cmd && *cmd) {
				if (input[1] == ' ') {
					r_cons_printf ("Saving to file '%s'...\n", filename);
					r_cons_flush ();
				}
				r_core_cmd0 (core, cmd);
			}
			free (cmd);
		}
		break;
	}
	default:
		eprintf ("Usage: see ag?\n");
	}
}

Project: radare2
File: cmd_anal.c

static void cmd_anal_ucall_ref (RCore *core, ut64 addr) {
	RAnalFunction * fcn = r_anal_get_function_at (core->anal, addr);
	if (fcn) {
		r_cons_printf (" ; %s", fcn->name);
	} else {
		r_cons_printf (" ; 0x%" PFMT64x, addr);
	}
}

Project: radare2
File: cmd_anal.c

static int cmd_anal_all(RCore *core, const char *input) {
	switch (*input) {
	case '?':
		r_core_cmd_help (core, help_msg_aa);
		break;
	case 'b': // "aab"
		cmd_anal_blocks (core, input + 1);
		break;
	case 'f':
		if (input[1] == 'e') {  // "aafe"
			r_core_cmd0 (core, "aef@@f");
		} else if (input[1] == 'r') {
			ut64 cur = core->offset;
			bool hasnext = r_config_get_i (core->config, "anal.hasnext");
			RListIter *iter;
			RIOMap *map;
			RList *list = r_core_get_boundaries_prot (core, R_PERM_X, NULL, "anal");
			if (!list) {
				break;
			}
			r_list_foreach (list, iter, map) {
				r_core_seek (core, map->itv.addr, 1);
				r_config_set_i (core->config, "anal.hasnext", 1);
				r_core_cmd0 (core, "afr");
				r_config_set_i (core->config, "anal.hasnext", hasnext);
			}
			r_list_free (list);
			r_core_seek (core, cur, 1);
		} else if (input[1] == 't') { // "aaft"
			cmd_anal_aaft (core);
		} else if (input[1] == 0) { // "aaf"
			const bool analHasnext = r_config_get_i (core->config, "anal.hasnext");
			r_config_set_i (core->config, "anal.hasnext", true);
			r_core_cmd0 (core, "afr@@c:isq");
			r_config_set_i (core->config, "anal.hasnext", analHasnext);
		} else {
			r_cons_printf ("Usage: aaf[e|r|t] - analyze all functions again\n");
			r_cons_printf (" aafe = aef@@f\n");
			r_cons_printf ("aafr [len] = analyze all consecutive functions in section\n");
			r_cons_printf (" aaft = recursive type matching in all functions\n");
			r_cons_printf (" aaf  = afr@@c:isq\n");
		}
		break;
	case 'c': // "aac"
		switch (input[1]) {
		case '*': // "aac*"
			cmd_anal_calls (core, input + 1, true, false);
			break;
		case 'i': // "aaci"
			cmd_anal_calls (core, input + 1, input[2] == '*', true);
			break;
		case '?': // "aac?"
			eprintf ("Usage: aac, aac* or aaci (imports xrefs only)\n");
			break;
		default: // "aac"
			cmd_anal_calls (core, input + 1, false, false);
			break;
		}
	case 'j': // "aaj"
		cmd_anal_jumps (core, input + 1);
		break;
	case 'd': // "aad"
		cmd_anal_aad (core, input);
		break;
	case 'v': // "aav"
		cmd_anal_aav (core, input);
		break;
	case 'u': // "aau" - print areas not covered by functions
		r_core_anal_nofunclist (core, input + 1);
		break;
	case 'i': // "aai"
		r_core_anal_info (core, input + 1);
		break;
	case 's': // "aas"
		r_core_cmd0 (core, "af @@= `isq~[0]`");
		r_core_cmd0 (core, "af @@ entry*");
		break;
	case 'S': // "aaS"
		r_core_cmd0 (core, "af @@ sym.*");
		r_core_cmd0 (core, "af @@ entry*");
		break;
	case 'F': // "aaF" "aaFa"
		if (!input[1] || input[1] == ' ' || input[1] == 'a') {
			r_core_anal_inflags (core, input + 1);
		} else {
			eprintf ("Usage: aaF[a] - analyze functions in flag bounds (aaFa uses af/a2f instead of af+/afb+)\n");
		}
		break;
	case 'n': // "aan"
		switch (input[1]) {
		case 'r': // "aanr" // all noreturn propagation
			r_core_anal_propagate_noreturn (core);
			break;
		case 'g': // "aang"
			r_core_anal_autoname_all_golang_fcns (core);
			break;
		case '?':
			eprintf ("Usage: aan[rg]\n");
			eprintf ("aan  : autoname all functions\n");
			eprintf ("aang : autoname all golang functions\n");
			eprintf ("aanr : auto-noreturn propagation\n");
			break;
		default: // "aan"
			r_core_anal_autoname_all_fcns (core);
		}
		break;
	case 'p': // "aap"
		if (input[1] == '?') {
			// TODO: accept parameters for ranges
			eprintf ("Usage: /aap   ; find in memory for function preludes");
		} else {
			r_core_search_preludes (core, true);
		}
		break;
	case '\0': // "aa"
	case 'a':
		if (input[0] && (input[1] == '?' || (input[1] && input[2] == '?'))) {
			r_cons_println ("Usage: See aa? for more help");
		} else {
			bool didAap = false;
			char *dh_orig = NULL;
			if (!strncmp (input, "aaaaa", 5)) {
				eprintf ("An r2 developer is coming to your place to manually analyze this program. Please wait for it\n");
				if (r_cons_is_interactive ()) {
					r_cons_any_key (NULL);
				}
				goto jacuzzi;
			}
			ut64 curseek = core->offset;
			oldstr = r_print_rowlog (core->print, "Analyze all flags starting with sym. and entry0 (aa)");
			r_cons_break_push (NULL, NULL);
			r_cons_break_timeout (r_config_get_i (core->config, "anal.timeout"));
			r_core_anal_all (core);
			r_print_rowlog_done (core->print, oldstr);
			r_core_task_yield (&core->tasks);
			// Run pending analysis immediately after analysis
			// Usefull when running commands with ";" or via r2 -c,-i
			dh_orig = core->dbg->h
				? strdup (core->dbg->h->name)
				: strdup ("esil");
			if (core->io && core->io->desc && core->io->desc->plugin && !core->io->desc->plugin->isdbg) {
				//use dh_origin if we are debugging
				R_FREE (dh_orig);
			}
			if (r_cons_is_breaked ()) {
				goto jacuzzi;
			}
			r_cons_clear_line (1);
			bool cfg_debug = r_config_get_i (core->config, "cfg.debug");
			if (*input == 'a') { // "aaa"
				if (r_str_startswith (r_config_get (core->config, "bin.lang"), "go")) {
					oldstr = r_print_rowlog (core->print, "Find function and symbol names from golang binaries (aang)");
					r_print_rowlog_done (core->print, oldstr);
					r_core_anal_autoname_all_golang_fcns (core);
					oldstr = r_print_rowlog (core->print, "Analyze all flags starting with sym.go. (aF @@ sym.go.*)");
					r_core_cmd0 (core, "aF @@ sym.go.*");
					r_print_rowlog_done (core->print, oldstr);
				}
				r_core_task_yield (&core->tasks);
				if (!cfg_debug) {
					if (dh_orig && strcmp (dh_orig, "esil")) {
						r_core_cmd0 (core, "dL esil");
						r_core_task_yield (&core->tasks);
					}
				}
				int c = r_config_get_i (core->config, "anal.calls");
				r_config_set_i (core->config, "anal.calls", 1);
				r_core_cmd0 (core, "s $S");
				if (r_cons_is_breaked ()) {
					goto jacuzzi;
				}

				oldstr = r_print_rowlog (core->print, "Analyze function calls (aac)");
				(void)cmd_anal_calls (core, "", false, false); // "aac"
				r_core_seek (core, curseek, 1);
				// oldstr = r_print_rowlog (core->print, "Analyze data refs as code (LEA)");
				// (void) cmd_anal_aad (core, NULL); // "aad"
				r_print_rowlog_done (core->print, oldstr);
				r_core_task_yield (&core->tasks);
				if (r_cons_is_breaked ()) {
					goto jacuzzi;
				}

				if (is_unknown_file (core)) {
					oldstr = r_print_rowlog (core->print, "find and analyze function preludes (aap)");
					(void)r_core_search_preludes (core, false); // "aap"
					didAap = true;
					r_print_rowlog_done (core->print, oldstr);
					r_core_task_yield (&core->tasks);
					if (r_cons_is_breaked ()) {
						goto jacuzzi;
					}
				}

				oldstr = r_print_rowlog (core->print, "Analyze len bytes of instructions for references (aar)");
				(void)r_core_anal_refs (core, ""); // "aar"
				r_print_rowlog_done (core->print, oldstr);
				r_core_task_yield (&core->tasks);
				if (r_cons_is_breaked ()) {
					goto jacuzzi;
				}
				oldstr = r_print_rowlog (core->print, "Check for objc references");
				r_print_rowlog_done (core->print, oldstr);
				cmd_anal_objc (core, input + 1, true);
				r_core_task_yield (&core->tasks);
				oldstr = r_print_rowlog (core->print, "Check for vtables");
				r_core_cmd0 (core, "avrr");
				r_print_rowlog_done (core->print, oldstr);
				r_core_task_yield (&core->tasks);
				r_config_set_i (core->config, "anal.calls", c);
				r_core_task_yield (&core->tasks);
				if (r_cons_is_breaked ()) {
					goto jacuzzi;
				}
				if (!r_str_startswith (r_config_get (core->config, "asm.arch"), "x86")) {
					r_core_cmd0 (core, "aav");
					r_core_task_yield (&core->tasks);
					bool ioCache = r_config_get_i (core->config, "io.pcache");
					r_config_set_i (core->config, "io.pcache", 1);
					oldstr = r_print_rowlog (core->print, "Emulate code to find computed references (aae)");
					r_core_cmd0 (core, "aae");
					r_print_rowlog_done (core->print, oldstr);
					r_core_task_yield (&core->tasks);
					if (!ioCache) {
						r_core_cmd0 (core, "wc-*");
						r_core_task_yield (&core->tasks);
					}
					r_config_set_i (core->config, "io.pcache", ioCache);
					if (r_cons_is_breaked ()) {
						goto jacuzzi;
					}
				}
				if (r_config_get_i (core->config, "anal.autoname")) {
					oldstr = r_print_rowlog (core->print, "Speculatively constructing a function name "
					                         "for fcn.* and sym.func.* functions (aan)");
					r_core_anal_autoname_all_fcns (core);
					r_print_rowlog_done (core->print, oldstr);
					r_core_task_yield (&core->tasks);
				}
				if (core->anal->opt.vars) {
					RAnalFunction *fcni;
					RListIter *iter;
					r_list_foreach (core->anal->fcns, iter, fcni) {
						if (r_cons_is_breaked ()) {
							break;
						}
						RList *list = r_anal_var_list (core->anal, fcni, 'r');
						if (!r_list_empty (list)) {
							r_list_free (list);
							continue;
						}
						//extract only reg based var here
						r_core_recover_vars (core, fcni, true);
						r_list_free (list);
					}
					r_core_task_yield (&core->tasks);
				}
				if (!sdb_isempty (core->anal->sdb_zigns)) {
					oldstr = r_print_rowlog (core->print, "Check for zignature from zigns folder (z/)");
					r_core_cmd0 (core, "z/");
					r_print_rowlog_done (core->print, oldstr);
					r_core_task_yield (&core->tasks);
				}

				oldstr = r_print_rowlog (core->print, "Type matching analysis for all functions (aaft)");
				r_core_cmd0 (core, "aaft");
				r_print_rowlog_done (core->print, oldstr);
				r_core_task_yield (&core->tasks);

				oldstr = r_print_rowlog (core->print, "Propagate noreturn information");
				r_core_anal_propagate_noreturn (core);
				r_print_rowlog_done (core->print, oldstr);
				r_core_task_yield (&core->tasks);

				oldstr = r_print_rowlog (core->print, "Use -AA or aaaa to perform additional experimental analysis.");
				r_print_rowlog_done (core->print, oldstr);

				if (input[1] == 'a') { // "aaaa"
					if (!didAap) {
						oldstr = r_print_rowlog (core->print, "Finding function preludes");
						(void)r_core_search_preludes (core, false); // "aap"
						r_print_rowlog_done (core->print, oldstr);
						r_core_task_yield (&core->tasks);
					}

					oldstr = r_print_rowlog (core->print, "Enable constraint types analysis for variables");
					r_config_set (core->config, "anal.types.constraint", "true");
					r_print_rowlog_done (core->print, oldstr);
				}
				r_core_cmd0 (core, "s-");
				if (dh_orig) {
					r_core_cmdf (core, "dL %s", dh_orig);
					r_core_task_yield (&core->tasks);
				}
			}
			r_core_seek (core, curseek, 1);
		jacuzzi:
			// XXX this shouldnt be called. flags muts be created wheen the function is registered
			flag_every_function (core);
			r_cons_break_pop ();
			R_FREE (dh_orig);
		}
		break;
	case 't': { // "aat"
		char *off = input[1]? r_str_trim_dup (input + 2): NULL;
		RAnalFunction *fcn;
		RListIter *it;
		if (off && *off) {
			ut64 addr = r_num_math (NULL, off);
			fcn = r_anal_get_function_at (core->anal, core->offset);
			if (fcn) {
				r_core_link_stroff (core, fcn);
			} else {
				eprintf ("Cannot find function at %08" PFMT64x "\n", addr);
			}
		} else {
			if (r_list_empty (core->anal->fcns)) {
				eprintf ("Couldn't find any functions\n");
				break;
			}
			r_list_foreach (core->anal->fcns, it, fcn) {
				if (r_cons_is_breaked ()) {
					break;
				}
				r_core_link_stroff (core, fcn);
			}
		}
		free (off);
		break;
	}
	case 'T': // "aaT"
		cmd_anal_aftertraps (core, input + 1);
		break;
	case 'o': // "aao"
		cmd_anal_objc (core, input + 1, false);
		break;
	case 'e': // "aae"
		if (input[1]) {
			const char *len = (char *)input + 1;
			char *addr = strchr (input + 2, ' ');
			if (addr) {
				*addr++ = 0;
			}
			r_core_anal_esil (core, len, addr);
		} else {
			ut64 at = core->offset;
			RIOMap *map;
			RListIter *iter;
			RList *list = r_core_get_boundaries_prot (core, -1, NULL, "anal");
			if (!list) {
				break;
			}
			r_list_foreach (list, iter, map) {
				r_core_seek (core, map->itv.addr, 1);
				r_core_anal_esil (core, "$SS", NULL);
			}
			r_list_free (list);
			r_core_seek (core, at, 1);
		}
		break;
	case 'r':
		(void)r_core_anal_refs (core, input + 1);
		break;
	default:
		r_core_cmd_help (core, help_msg_aa);
		break;
	}

	return true;
}

Project: radare2
File: cmd_anal.c

static int cmpsize (const void *a, const void *b) {
	ut64 sa = (int) r_anal_function_linear_size ((RAnalFunction *) a);
	ut64 sb = (int) r_anal_function_linear_size ((RAnalFunction *) b);
	return (sa > sb)? -1: (sa < sb)? 1 : 0;
}

Project: radare2
File: cmd_anal.c

static void var_accesses_list(RAnal *a, RAnalFunction *fcn, int delta, const char *typestr) {
	const char *var_local = sdb_fmt ("var.0x%"PFMT64x".%d.%d.%s",
			fcn->addr, 1, delta, typestr);
	const char *xss = sdb_const_get (a->sdb_fcns, var_local, 0);
	if (xss && *xss) {
		r_cons_printf ("%s\n", xss);
	} else {
		r_cons_newline ();
	}
}

Project: radare2
File: cmd_anal.c

static int myregread(RAnalEsil *esil, const char *name, ut64 *val, int *len) {
	AeaStats *stats = esil->user;
	if (!IS_DIGIT (*name)) {
		if (!contains (stats->inputregs, name)) {
			if (!contains (stats->regwrite, name)) {
				r_list_push (stats->inputregs, strdup (name));
			}
		}
		if (!contains (stats->regs, name)) {
			r_list_push (stats->regs, strdup (name));
		}
		if (!contains (stats->regread, name)) {
			r_list_push (stats->regread, strdup (name));
		}
	}
	return 0;
}

Project: radare2
File: cmd_anal.c

static int cmd_anal_fcn(RCore *core, const char *input) {
	char i;

	r_cons_break_timeout (r_config_get_i (core->config, "anal.timeout"));
	switch (input[1]) {
	case '-': // "af-"
		if (!input[2]) {
			cmd_anal_fcn (core, "f-$$");
			r_core_anal_undefine (core, core->offset);
		} else if (!strcmp (input + 2, "*")) {
			RAnalFunction *f;
			RListIter *iter;
			r_list_foreach (core->anal->fcns, iter, f) {
				r_anal_del_jmprefs (core->anal, f);
			}
			r_list_purge (core->anal->fcns);
		} else {
			ut64 addr = input[2]
				? r_num_math (core->num, input + 2)
				: core->offset;
			r_core_anal_undefine (core, addr);
			r_anal_fcn_del_locs (core->anal, addr);
			r_anal_fcn_del (core->anal, addr);
		}
		break;
	case 'j': // "afj"
		{
			RList *blocks = r_anal_get_blocks_in (core->anal, core->offset);
			RAnalBlock *block = r_list_first (blocks);
			if (block && !r_list_empty (block->fcns)) {
				char *args = strdup (input + 2);
				RList *argv = r_str_split_list (args, " ", 0);
				ut64 table = r_num_math (core->num, r_list_get_n (argv, 0));
				ut64 elements = r_num_math (core->num, r_list_get_n (argv, 1));
				r_anal_jmptbl (core->anal, r_list_first (block->fcns), block, core->offset, table, elements, UT64_MAX);
			} else {
				eprintf ("No function defined here\n");
			}
			r_list_free (blocks);
		}
		break;
	case 'a': // "afa"
		if (input[2] == 'l') { // "afal" : list function call arguments
			int show_args = r_config_get_i (core->config, "dbg.funcarg");
			if (show_args) {
				r_core_print_func_args (core);
			}
		} else {
			r_core_print_func_args (core);
		}
		break;
	case 'd': // "afd"
		{
		ut64 addr = 0;
		if (input[2] == '?') {
			eprintf ("afd [offset]\n");
		} else if (input[2] == ' ') {
			addr = r_num_math (core->num, input + 2);
		} else {
			addr = core->offset;
		}
		RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
		if (input[2] == 'j') { // afdj
			PJ *pj = pj_new ();
			if (!pj) {
				return false;
			}
			pj_o (pj);
			if (fcn) {
				pj_ks (pj, "name", fcn->name);
				pj_ki (pj, "offset", (int)(addr - fcn->addr));
			}
			pj_end (pj);
			r_cons_println (pj_string (pj));
			pj_free (pj);
		} else {
			if (fcn) {
				if (fcn->addr != addr) {
					r_cons_printf ("%s + %d\n", fcn->name,
							(int)(addr - fcn->addr));
				} else {
					r_cons_println (fcn->name);
				}
			} else {
				eprintf ("afd: Cannot find function\n");
			}
		}
		}
		break;
	case 'u': // "afu"
		{
		if (input[2] != ' ') {
			eprintf ("Missing argument\n");
			return false;
		}

		ut64 addr = core->offset;
		ut64 addr_end = r_num_math (core->num, input + 2);
		if (addr_end < addr) {
			eprintf ("Invalid address ranges\n");
		} else {
			int depth = 1;
			ut64 a, b;
			const char *c;
			a = r_config_get_i (core->config, "anal.from");
			b = r_config_get_i (core->config, "anal.to");
			c = r_config_get (core->config, "anal.limits");
			r_config_set_i (core->config, "anal.from", addr);
			r_config_set_i (core->config, "anal.to", addr_end);
			r_config_set (core->config, "anal.limits", "true");

			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
			if (fcn) {
				r_anal_fcn_resize (core->anal, fcn, addr_end - addr);
			}
			r_core_anal_fcn (core, addr, UT64_MAX,
					R_ANAL_REF_TYPE_NULL, depth);
			fcn = r_anal_get_fcn_in (core->anal, addr, 0);
			if (fcn) {
				r_anal_fcn_resize (core->anal, fcn, addr_end - addr);
			}
			r_config_set_i (core->config, "anal.from", a);
			r_config_set_i (core->config, "anal.to", b);
			r_config_set (core->config, "anal.limits", c? c: "");
		}
		}
		break;
	case '+': { // "af+"
		if (input[2] != ' ') {
			eprintf ("Missing arguments\n");
			return false;
		}
		char *ptr = strdup (input + 3);
		const char *ptr2;
		int n = r_str_word_set0 (ptr);
		const char *name = NULL;
		ut64 addr = UT64_MAX;
		RAnalDiff *diff = NULL;
		int type = R_ANAL_FCN_TYPE_FCN;
		if (n > 1) {
			switch (n) {
			case 4:
				ptr2 = r_str_word_get0 (ptr, 3);
				if (!(diff = r_anal_diff_new ())) {
					eprintf ("error: Cannot init RAnalDiff\n");
					free (ptr);
					return false;
				}
				if (ptr2[0] == 'm') {
					diff->type = R_ANAL_DIFF_TYPE_MATCH;
				} else if (ptr2[0] == 'u') {
					diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
				}
			case 3:
				ptr2 = r_str_word_get0 (ptr, 2);
				if (strchr (ptr2, 'l')) {
					type = R_ANAL_FCN_TYPE_LOC;
				} else if (strchr (ptr2, 'i')) {
					type = R_ANAL_FCN_TYPE_IMP;
				} else if (strchr (ptr2, 's')) {
					type = R_ANAL_FCN_TYPE_SYM;
				} else {
					type = R_ANAL_FCN_TYPE_FCN;
				}
			case 2:
				name = r_str_word_get0 (ptr, 1);
			case 1:
				addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
			}
			RAnalFunction *fcn = r_anal_create_function (core->anal, name, addr, type, diff);
			if (!fcn) {
				eprintf ("Cannot add function (duplicated)\n");
			}
		}
		r_anal_diff_free (diff);
		free (ptr);
		}
		break;
	case 'o': // "afo"
		switch (input[2]) {
		case '?':
			eprintf ("Usage: afo[?sj] ([name|offset])\n");
			break;
		case 'j':
			{
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				PJ *pj = pj_new ();
				if (!pj) {
					return false;
				}
				pj_o (pj);
				if (fcn) {
					pj_ki (pj, "address", fcn->addr);
				}
				pj_end (pj);
				r_cons_println (pj_string (pj));
				pj_free (pj);
			}
			break;
		case '\0':
			{
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					r_cons_printf ("0x%08" PFMT64x "\n", fcn->addr);
				}
			}
			break;
		case 's': // "afos"
			{
				ut64 addr = core->offset;
				RListIter *iter;
				RList *list = r_anal_get_functions_in (core->anal, addr);
				RAnalFunction *fcn;
				r_list_foreach (list, iter, fcn) {
					r_cons_printf ("= 0x%08" PFMT64x "\n", fcn->addr);
				}
				r_list_free (list);
			}
			break;
		case ' ':
			{
				RAnalFunction *fcn;
				ut64 addr = r_num_math (core->num, input + 3);
				if (addr == 0LL) {
					fcn = r_anal_fcn_find_name (core->anal, input + 3);
				} else {
					fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
				}
				if (fcn) {
					r_cons_printf ("0x%08" PFMT64x "\n", fcn->addr);
				}
			}
			break;
		}
		break;
	case 'i': // "afi"
		switch (input[2]) {
		case '?':
			r_core_cmd_help (core, help_msg_afi);
			break;
		case '.': // "afi."
			{
				ut64 addr = core->offset;
				if (input[3] == ' ') {
					addr = r_num_math (core->num, input + 3);
				}
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					r_cons_printf ("%s\n", fcn->name);
				}
			}
			break;
		case 'l': // "afil"
			if (input[3] == '?') {
				// TODO #7967 help refactor
				help_msg_afll[1] = "afil";
				r_core_cmd_help (core, help_msg_afll);
				break;
			}
			/* fallthrough */
		case 'i': // "afii"
			if (input[3] == '-') {
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					r_list_free (fcn->imports);
					fcn->imports = NULL;
				}
			} else if (input[3] == ' ') {
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					if (!fcn->imports) {
						fcn->imports = r_list_newf ((RListFree)free);
					}
					r_list_append (fcn->imports, r_str_trim_dup (input + 4));
				} else {
					eprintf ("No function found\n");
				}
			} else {
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				if (fcn && fcn->imports) {
					char *imp;
					RListIter *iter;
					r_list_foreach (fcn->imports, iter, imp) {
						r_cons_printf ("%s\n", imp);
					}
				}
			}
			break;
		case 's': // "afis"
			if (input[3] == 'a') { // "afisa"
				__core_cmd_anal_fcn_allstats (core, input + 4);
			} else {
				sdb_free (__core_cmd_anal_fcn_stats (core, input + 3));
			}
			break;
		case 'j': // "afij"
		case '*': // "afi*"
			r_core_anal_fcn_list (core, input + 3, input + 2);
			break;
		case 'p': // "afip"
			{
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					r_cons_printf ("is-pure: %s\n", r_anal_fcn_get_purity (core->anal, fcn) ? "true" : "false");
				}
			}
			break;
		default:
			i = 1;
			r_core_anal_fcn_list (core, input + 2, &i);
			break;
		}
		break;
	case 'l': // "afl"
		switch (input[2]) {
		case '?':
			r_core_cmd_help (core, help_msg_afl);
			break;
		case 's': // "afls"
			switch (input[3]) {
			case '?':
				r_core_cmd_help (core, help_msg_afls);
				break;
			case 'a': // "aflsa"
				core->anal->fcns->sorted = false;
				r_list_sort (core->anal->fcns, cmpaddr);
				break;
			case 'b': // "aflsb"
				core->anal->fcns->sorted = false;
				r_list_sort (core->anal->fcns, cmpbbs);
				break;
			case 's': // "aflss"
				core->anal->fcns->sorted = false;
				r_list_sort (core->anal->fcns, cmpsize);
				break;
			case 'n': // "aflsn"
				core->anal->fcns->sorted = false;
				r_list_sort (core->anal->fcns, cmpname);
				break;
			default:
				core->anal->fcns->sorted = false;
				r_list_sort (core->anal->fcns, cmpaddr);
				break;
			}
			break;
		case 'l': // "afll"
			if (input[3] == '?') {
				// TODO #7967 help refactor
				help_msg_afll[1] = "afll";
				r_core_cmd_help (core, help_msg_afll);
				break;
			}
			/* fallthrough */
		case 't': // "aflt"
		case 'j': // "aflj"
		case 'q': // "aflq"
		case 'm': // "aflm"
		case '+': // "afl+"
		case '=': // "afl="
		case '*': // "afl*"
		case '.': // "afl*"
			r_core_anal_fcn_list (core, NULL, input + 2);
			break;
		case 'c': // "aflc"
			r_cons_printf ("%d\n", r_list_length (core->anal->fcns));
			break;
		default: // "afl "
			r_core_anal_fcn_list (core, NULL, "o");
			break;
		}
		break;
	case 's': // "afs"
		switch (input[2]) {
		case '!': { // "afs!"
			char *sig = r_core_cmd_str (core, "afs");
			char *data = r_core_editor (core, NULL, sig);
			if (sig && data) {
				r_core_cmdf (core, "\"afs %s\"", data);
			}
			free (sig);
			free (data);
			break;
		}
		case 'r': { // "afsr"
			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
			if (fcn) {
				char *type = r_str_newf ("type.%s", input + 4);
				if (sdb_exists (core->anal->sdb_types, type)) {
					char *query = r_str_newf ("anal/types/func.%s.ret=%s", fcn->name, input + 4);
					sdb_querys (core->sdb, NULL, 0, query);
					free (query);
				}
				free (type);
			} else {
				eprintf ("There's no function defined in here.\n");
			}
			break;
		}
		case '*': // "afs*"
			eprintf ("TODO\n");
			break;
		case 'j': // "afsj"
			cmd_afsj (core, input + 2);
			break;
		case 0:
		case ' ': { // "afs"
			ut64 addr = core->offset;
			RAnalFunction *f;
			const char *arg = r_str_trim_head_ro (input + 2);
			if ((f = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL))) {
				if (arg && *arg) {
					// parse function signature here
					char *fcnstr = r_str_newf ("%s;", arg), *fcnstr_copy = strdup (fcnstr);
					char *fcnname_aux = strtok (fcnstr_copy, "(");
					r_str_trim_tail (fcnname_aux);
					char *fcnname = NULL;
					const char *ls = r_str_lchr (fcnname_aux, ' ');
					fcnname = strdup (ls? ls: fcnname_aux);
					if (fcnname) {
						// TODO: move this into r_anal_str_to_fcn()
						if (strcmp (f->name, fcnname)) {
							(void)__setFunctionName (core, addr, fcnname, false);
							f = r_anal_get_fcn_in (core->anal, addr, -1);
						}
						r_anal_str_to_fcn (core->anal, f, fcnstr);
					}
					free (fcnname);
					free (fcnstr_copy);
					free (fcnstr);
				} else {
					char *str = r_anal_function_get_signature (f);
					if (str) {
						r_cons_println (str);
						free (str);
					}
				}
			} else {
				eprintf ("No function defined at 0x%08" PFMT64x "\n", addr);
			}
			break;
		}
		default:
		// case '?': // "afs?"
			r_core_cmd_help (core, help_msg_afs);
			break;
		}
		break;
	case 'm': // "afm" - merge two functions
		r_core_anal_fcn_merge (core, core->offset, r_num_math (core->num, input + 2));
		break;
	case 'M': // "afM" - print functions map
		r_core_anal_fmap (core, input + 1);
		break;
	case 'v': // "afv"
		var_cmd (core, input + 2);
		break;
	case 't': // "aft"
		type_cmd (core, input + 2);
		break;
	case 'C': // "afC"
		if (input[2] == 'c') {
			RAnalFunction *fcn;
			if ((fcn = r_anal_get_fcn_in (core->anal, core->offset, 0)) != NULL) {
				r_cons_printf ("%i\n", r_anal_fcn_cc (core->anal, fcn));
			} else {
				eprintf ("Error: Cannot find function at 0x08%" PFMT64x "\n", core->offset);
			}
		} else if (input[2] == 'l') {
			RAnalFunction *fcn;
			if ((fcn = r_anal_get_fcn_in (core->anal, core->offset, 0)) != NULL) {
				r_cons_printf ("%d\n", r_anal_fcn_loops (fcn));
			} else {
				eprintf ("Error: Cannot find function at 0x08%" PFMT64x "\n", core->offset);
			}
		} else if (input[2] == '?') {
			r_core_cmd_help (core, help_msg_afC);
		} else {
			afCc (core, r_str_trim_head_ro (input + 2));
		}
		break;
	case 'c':{ // "afc"
		RAnalFunction *fcn = NULL;
		if (!input[2] || input[2] == ' ' || input[2] == 'r' || input[2] == 'a') {
			fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
			if (!fcn) {
				eprintf ("afc: Cannot find function here\n");
				break;
			}
		}
		switch (input[2]) {
		case '\0': // "afc"
			r_cons_println (fcn->cc);
			break;
		case ' ': { // "afc "
			char *argument = strdup (input + 3);
			char *cc = argument;
			r_str_trim (cc);
			if (!r_anal_cc_exist (core->anal, cc)) {
				const char *asmOs = r_config_get (core->config, "asm.os");
				eprintf ("afc: Unknown calling convention '%s' for '%s'\n"
						"See afcl for available types\n", cc, asmOs);
			} else {
				fcn->cc = r_str_constpool_get (&core->anal->constpool, cc);
			}
			free (argument);
			break;
		}
		case '=': // "afc="
			if (input[3]) {
				char *argument = strdup (input + 3);
				char *cc = argument;
				r_str_trim (cc);
				r_core_cmdf (core, "k anal/cc/default.cc=%s", cc);
				r_anal_set_reg_profile (core->anal);
				free (argument);
			} else {
				r_core_cmd0 (core, "k anal/cc/default.cc");
			}
			break;
		case 'a': // "afca"
			eprintf ("Todo\n");
			break;
		case 'f': // "afcf" "afcfj"
			cmd_anal_fcn_sig (core, input + 3);
			break;
		case 'k': // "afck"
			r_core_cmd0 (core, "k anal/cc/*");
			break;
		case 'l': // "afcl" list all function Calling conventions.
			sdb_foreach (core->anal->sdb_cc, cc_print, NULL);
			break;
		case 'o': { // "afco"
			char *dbpath = r_str_trim_dup (input + 3);
			if (r_file_exists (dbpath)) {
				Sdb *db = sdb_new (0, dbpath, 0);
				sdb_merge (core->anal->sdb_cc, db);
				sdb_close (db);
				sdb_free (db);
			}
			free (dbpath);
			break;
		}
		case 'r': {	// "afcr"
			int i;
			RStrBuf *json_buf = r_strbuf_new ("{");
			bool json = input[3] == 'j';

			char *cmd = r_str_newf ("cc.%s.ret", fcn->cc);
			const char *regname = sdb_const_get (core->anal->sdb_cc, cmd, 0);
			if (regname) {
				if (json) {
					r_strbuf_appendf (json_buf, "\"ret\":\"%s\"", regname);
				} else {
					r_cons_printf ("%s: %s\n", cmd, regname);
				}
			}
			free (cmd);

			bool isFirst = true;
			for (i = 0; i < R_ANAL_CC_MAXARG; i++) {
				cmd = r_str_newf ("cc.%s.arg%d", fcn->cc, i);
				regname = sdb_const_get (core->anal->sdb_cc, cmd, 0);
				if (regname) {
					if (json) {
						if (isFirst) {
							r_strbuf_appendf (json_buf, ",\"args\":[\"%s\"", regname);
							isFirst = false;
						} else {
							r_strbuf_appendf (json_buf, ",\"%s\"", regname);
						}
					} else {
						r_cons_printf ("%s: %s\n", cmd, regname);
					}
				}
				free (cmd);
			}
			if (!isFirst) {
				r_strbuf_append (json_buf, "]");
			}

			cmd = r_str_newf ("cc.%s.self", fcn->cc);
			regname = sdb_const_get (core->anal->sdb_cc, cmd, 0);
			if (regname) {
				if (json) {
					r_strbuf_appendf (json_buf, ",\"self\":\"%s\"", regname);
				} else {
					r_cons_printf ("%s: %s\n", cmd, regname);
				}
			}
			free (cmd);
			cmd = r_str_newf ("cc.%s.error", fcn->cc);
			regname = sdb_const_get (core->anal->sdb_cc, cmd, 0);
			if (regname) {
				if (json) {
					r_strbuf_appendf (json_buf, ",\"error\":\"%s\"", regname);
				} else {
					r_cons_printf ("%s: %s\n", cmd, regname);
				}
			}
			free (cmd);

			r_strbuf_append (json_buf, "}");
			if (json) {
				r_cons_printf ("%s\n", r_strbuf_drain (json_buf));
			}
		} break;
		case 'R': { // "afcR"
			/* very slow, but im tired of waiting for having this, so this is the quickest implementation */
			int i;
			char *cc = r_core_cmd_str (core, "k anal/cc/default.cc");
			r_str_trim (cc);
			for (i = 0; i < 6; i++) {
				char *res = r_core_cmd_strf (core, "k anal/cc/cc.%s.arg%d", cc, i);
				r_str_trim_nc (res);
				if (*res) {
					char *row = r_core_cmd_strf (core, "drr~%s 0x", res);
					r_str_trim (row);
					r_cons_printf ("arg[%d] %s\n", i, row);
					free (row);
				}
				free (res);
			}
			free (cc);
			}
			break;
		case '?': // "afc?"
		default:
			r_core_cmd_help (core, help_msg_afc);
		}
		}
		break;
	case 'B': // "afB" // set function bits
		if (input[2] == ' ') {
			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
			if (fcn) {
				int bits = atoi (input + 3);
				r_anal_hint_set_bits (core->anal, r_anal_function_min_addr (fcn), bits);
				r_anal_hint_set_bits (core->anal, r_anal_function_max_addr (fcn), core->anal->bits);
				fcn->bits = bits;
			} else {
				eprintf ("afB: Cannot find function to set bits at 0x%08"PFMT64x"\n", core->offset);
			}
		} else {
			eprintf ("Usage: afB [bits]\n");
		}
		break;
	case 'b': // "afb"
		switch (input[2]) {
		case '-': // "afb-"
			anal_fcn_del_bb (core, input + 3);
			break;
		case 'e': // "afbe"
			anal_bb_edge (core, input + 3);
			break;
		case 'F': // "afbF"
			{
			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
			if (fcn) {
				RAnalBlock *bb = r_anal_fcn_bbget_in (core->anal, fcn, core->offset);
				if (bb) {
					if (input[3]) {
						int n = atoi (input + 3);
						bb->folded = n;
					} else {
						bb->folded = !bb->folded;
					}
				} else {
					r_warn_if_reached ();
				}
			}
			}
			break;
		case 0:
		case ' ': // "afb "
		case 'q': // "afbq"
		case 'r': // "afbr"
		case '=': // "afb="
		case '*': // "afb*"
		case 'j': // "afbj"
		case 't': // "afbt"
			anal_fcn_list_bb (core, input + 2, false);
			break;
		case 'i': // "afbi"
			anal_fcn_list_bb (core, input + 2, true);
			break;
		case '.': // "afb."
			anal_fcn_list_bb (core, input[2]? " $$": input + 2, true);
			break;
		case '+': // "afb+"
			anal_fcn_add_bb (core, input + 3);
			break;
		case 'c': // "afbc"
			{
			const char *ptr = input + 3;
			ut64 addr = r_num_math (core->num, ptr);
			ut32 color;
			ptr = strchr (ptr, ' ');
			if (ptr) {
				ptr = strchr (ptr + 1, ' ');
				if (ptr) {
					color = r_num_math (core->num, ptr + 1);
					RAnalOp *op = r_core_op_anal (core, addr);
					if (op) {
						r_anal_colorize_bb (core->anal, addr, color);
						r_anal_op_free (op);
					} else {
						eprintf ("Cannot analyze opcode at 0x%08" PFMT64x "\n", addr);
					}
				}
			}
			}
			break;
		default:
		case '?':
			r_core_cmd_help (core, help_msg_afb);
			break;
		}
		break;
	case 'n': // "afn"
		switch (input[2]) {
		case 's': // "afns"
			if (input[3] == 'j') { // "afnsj"
				free (r_core_anal_fcn_autoname (core, core->offset, 1, input[3]));
			} else {
				free (r_core_anal_fcn_autoname (core, core->offset, 1, 0));
			}
			break;
		case 'a': // "afna"
			{
			char *name = r_core_anal_fcn_autoname (core, core->offset, 0, 0);
			if (name) {
				r_cons_printf ("afn %s 0x%08" PFMT64x "\n", name, core->offset);
				free (name);
			}
			}
			break;
		case '.': // "afn."
		case 0: // "afn"
			{
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
				if (fcn) {
					r_cons_printf ("%s\n", fcn->name);
				}
			}
			break;
		case ' ': // "afn "
			{
			ut64 off = core->offset;
			char *p, *name = strdup (r_str_trim_head_ro (input + 3));
			if ((p = strchr (name, ' '))) {
				*p++ = 0;
				off = r_num_math (core->num, p);
			}
			if (*name == '?') {
				eprintf ("Usage: afn newname [off]   # set new name to given function\n");
			} else {
				if (r_str_startswith (name, "base64:")) {
					char *res = (char *)r_base64_decode_dyn (name + 7, -1);
					if (res) {
						free (name);
						name = res;
					}
				}
				if (!*name || !__setFunctionName (core, off, name, false)) {
					eprintf ("Cannot find function at 0x%08" PFMT64x "\n", off);
				}
			}
			free (name);
			}
			break;
		default:
			r_core_cmd_help (core, help_msg_afn);
			break;
		}
		break;
	case 'S': // afS"
		{
		RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
		if (fcn) {
			fcn->maxstack = r_num_math (core->num, input + 3);
			//fcn->stack = fcn->maxstack;
		}
		}
		break;
#if 0
	/* this is undocumented and probably have no uses. plz discuss */
	case 'e': // "afe"
		{
		RAnalFunction *fcn;
		ut64 off = core->offset;
		char *p, *name = strdup ((input[2]&&input[3])? input + 3: "");
		if ((p = strchr (name, ' '))) {
			*p = 0;
			off = r_num_math (core->num, p + 1);
		}
		fcn = r_anal_get_fcn_in (core->anal, off, R_ANAL_FCN_TYPE_FCN | R_ANAL_FCN_TYPE_SYM);
		if (fcn) {
			RAnalBlock *b;
			RListIter *iter;
			RAnalRef *r;
			r_list_foreach (fcn->refs, iter, r) {
				r_cons_printf ("0x%08" PFMT64x " -%c 0x%08" PFMT64x "\n", r->at, r->type, r->addr);
			}
			r_list_foreach (fcn->bbs, iter, b) {
				int ok = 0;
				if (b->type == R_ANAL_BB_TYPE_LAST) ok = 1;
				if (b->type == R_ANAL_BB_TYPE_FOOT) ok = 1;
				if (b->jump == UT64_MAX && b->fail == UT64_MAX) ok = 1;
				if (ok) {
					r_cons_printf ("0x%08" PFMT64x " -r\n", b->addr);
					// TODO: check if destination is outside the function boundaries
				}
			}
		} else eprintf ("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
		free (name);
		}
		break;
#endif
	case 'x': // "afx"
		switch (input[2]) {
		case '\0': // "afx"
		case 'j': // "afxj"
		case ' ': // "afx "
		{
			PJ *pj = pj_new ();
			if (input[2] == 'j') {
				pj_a (pj);
			}
			if (!pj) {
				return false;
			}
			// list xrefs from current address
			{
				ut64 addr = input[2]==' '? r_num_math (core->num, input + 2): core->offset;
				RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
				if (fcn) {
					RAnalRef *ref;
					RListIter *iter;
					RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
					r_list_foreach (refs, iter, ref) {
						if (input[2] == 'j') {
							pj_o (pj);
							pj_ks (pj, "type", r_anal_ref_type_tostring (ref->type));
							pj_kn (pj, "from", ref->at);
							pj_kn (pj, "to", ref->addr);
							pj_end (pj);
						} else {
							r_cons_printf ("%c 0x%08" PFMT64x " -> 0x%08" PFMT64x "\n",
									ref->type, ref->at, ref->addr);
						}
					}
					r_list_free (refs);
				} else {
					eprintf ("afx: Cannot find function at 0x%08"PFMT64x"\n", addr);
				}
			}
			if (input[2] == 'j') {
				pj_end (pj);
				r_cons_println (pj_string (pj));
			}
			pj_free (pj);
			break;
		}
		default:
			eprintf ("Wrong command. Look at af?\n");
			break;
		}
		break;
	case 'F': // "afF"
		{
			int val = input[2] && r_num_math (core->num, input + 2);
			RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, R_ANAL_FCN_TYPE_NULL);
			if (fcn) {
				fcn->folded = input[2]? val: !fcn->folded;
			}
		}
		break;
	case '?': // "af?"
		r_core_cmd_help (core, help_msg_af);
		break;
	case 'r': // "afr" // analyze function recursively
	case ' ': // "af "
	case '\0': // "af"
		{
		char *uaddr = NULL, *name = NULL;
		int depth = r_config_get_i (core->config, "anal.depth");
		bool analyze_recursively = r_config_get_i (core->config, "anal.calls");
		RAnalFunction *fcn = NULL;
		ut64 addr = core->offset;
		if (input[1] == 'r') {
			input++;
			analyze_recursively = true;
		}

		// first undefine
		if (input[0] && input[1] == ' ') {
			name = strdup (r_str_trim_head_ro (input + 2));
			uaddr = strchr (name, ' ');
			if (uaddr) {
				*uaddr++ = 0;
				addr = r_num_math (core->num, uaddr);
			}
			// depth = 1; // or 1?
			// disable hasnext
		}
		//r_core_anal_undefine (core, core->offset);
		r_core_anal_fcn (core, addr, UT64_MAX, R_ANAL_REF_TYPE_NULL, depth);
		fcn = r_anal_get_fcn_in (core->anal, addr, 0);
		if (fcn) {
			/* ensure we use a proper name */
			__setFunctionName (core, addr, fcn->name, false);
			if (core->anal->opt.vars) {
				r_core_recover_vars (core, fcn, true);
			}
			__add_vars_sdb (core, fcn);
		} else {
			if (core->anal->verbose) {
				eprintf ("Warning: Unable to analyze function at 0x%08"PFMT64x"\n", addr);
			}
		}
		if (analyze_recursively) {
			fcn = r_anal_get_fcn_in (core->anal, addr, 0); /// XXX wrong in case of nopskip
			if (fcn) {
				RAnalRef *ref;
				RListIter *iter;
				RList *refs = r_anal_fcn_get_refs (core->anal, fcn);
				r_list_foreach (refs, iter, ref) {
					if (ref->addr == UT64_MAX) {
						//eprintf ("Warning: ignore 0x%08"PFMT64x" call 0x%08"PFMT64x"\n", ref->at, ref->addr);
						continue;
					}
					if (ref->type != R_ANAL_REF_TYPE_CODE && ref->type != R_ANAL_REF_TYPE_CALL) {
						/* only follow code/call references */
						continue;
					}
					if (!r_io_is_valid_offset (core->io, ref->addr, !core->anal->opt.noncode)) {
						continue;
					}
					r_core_anal_fcn (core, ref->addr, fcn->addr, R_ANAL_REF_TYPE_CALL, depth);
					/* use recursivity here */
#if 1
					RAnalFunction *f = r_anal_get_function_at (core->anal, ref->addr);
					if (f) {
						RListIter *iter;
						RAnalRef *ref;
						RList *refs1 = r_anal_fcn_get_refs (core->anal, f);
						r_list_foreach (refs1, iter, ref) {
							if (!r_io_is_valid_offset (core->io, ref->addr, !core->anal->opt.noncode)) {
								continue;
							}
							if (ref->type != 'c' && ref->type != 'C') {
								continue;
							}
							r_core_anal_fcn (core, ref->addr, f->addr, R_ANAL_REF_TYPE_CALL, depth);
							// recursively follow fcn->refs again and again
						}
						r_list_free (refs1);
					} else {
						f = r_anal_get_fcn_in (core->anal, fcn->addr, 0);
						if (f) {
							/* cut function */
							r_anal_fcn_resize (core->anal, f, addr - fcn->addr);
							r_core_anal_fcn (core, ref->addr, fcn->addr,
									R_ANAL_REF_TYPE_CALL, depth);
							f = r_anal_get_function_at (core->anal, fcn->addr);
						}
						if (!f) {
							eprintf ("af: Cannot find function at 0x%08" PFMT64x "\n", fcn->addr);
						}
					}
#endif
				}
				r_list_free (refs);
				if (core->anal->opt.vars) {
					r_core_recover_vars (core, fcn, true);
				}
			}
		}
		if (name) {
			if (*name && !__setFunctionName (core, addr, name, true)) {
				eprintf ("af: Cannot find function at 0x%08" PFMT64x "\n", addr);
			}
			free (name);
		}
		r_core_anal_propagate_noreturn (core);
#if 0
		// XXX THIS IS VERY SLOW
		if (core->anal->opt.vars) {
			RListIter *iter;
			RAnalFunction *fcni = NULL;
			r_list_foreach (core->anal->fcns, iter, fcni) {
				if (r_cons_is_breaked ()) {
					break;
				}
				r_core_recover_vars (core, fcni, true);
			}
		}
#endif
		flag_every_function (core);
	}
		break;
	default:
		return false;
		break;
	}
	return true;
}

Project: radare2
File: cmd_anal.c

R_API char *cmd_syscall_dostr(RCore *core, st64 n, ut64 addr) {
	int i;
	char str[64];
	st64 N = n;
	int defVector = r_syscall_get_swi (core->anal->syscall);
	if (defVector > 0) {
		n = -1;
	}
	if (n == -1 || defVector > 0) {
		n = (int)r_debug_reg_get (core->dbg, "oeax");
		if (!n || n == -1) {
			const char *a0 = r_reg_get_name (core->anal->reg, R_REG_NAME_SN);
			n = (a0 == NULL)? -1: (int)r_debug_reg_get (core->dbg, a0);
		}
	}
	RSyscallItem *item = r_syscall_get (core->anal->syscall, n, defVector);
	if (!item) {
		item =  r_syscall_get (core->anal->syscall, N, -1);
	}
	if (!item) {
		return r_str_newf ("%s = unknown ()", syscallNumber (n));
	}
	char *res = r_str_newf ("%s = %s (", syscallNumber (item->num), item->name);
	// TODO: move this to r_syscall
	//TODO replace the hardcoded CC with the sdb ones
	for (i = 0; i < item->args; i++) {
		// XXX this is a hack to make syscall args work on x86-32 and x86-64
		// we need to shift sn first.. which is bad, but needs to be redesigned
		int regidx = i;
		if (core->assembler->bits == 32) {
			regidx++;
		}
		ut64 arg = r_debug_arg_get (core->dbg, R_ANAL_CC_TYPE_FASTCALL, regidx);
		//r_cons_printf ("(%d:0x%"PFMT64x")\n", i, arg);
		if (item->sargs) {
			switch (item->sargs[i]) {
			case 'p': // pointer
				res = r_str_appendf (res, "0x%08" PFMT64x "", arg);
				break;
			case 'i':
				res = r_str_appendf (res, "%" PFMT64u "", arg);
				break;
			case 'z':
				memset (str, 0, sizeof (str));
				r_io_read_at (core->io, arg, (ut8 *)str, sizeof (str) - 1);
				r_str_filter (str, strlen (str));
				res = r_str_appendf (res, "\"%s\"", str);
				break;
			case 'Z': {
				//TODO replace the hardcoded CC with the sdb ones
				ut64 len = r_debug_arg_get (core->dbg, R_ANAL_CC_TYPE_FASTCALL, i + 2);
				len = R_MIN (len + 1, sizeof (str) - 1);
				if (len == 0) {
					len = 16; // override default
				}
				(void)r_io_read_at (core->io, arg, (ut8 *)str, len);
				str[len] = 0;
				r_str_filter (str, -1);
				res = r_str_appendf (res, "\"%s\"", str);
			} break;
			default:
				res = r_str_appendf (res, "0x%08" PFMT64x "", arg);
				break;
			}
		} else {
			res = r_str_appendf (res, "0x%08" PFMT64x "", arg);
		}
		if (i + 1 < item->args) {
			res = r_str_appendf (res, ", ");
		}
	}
	r_syscall_item_free (item);
	return r_str_appendf (res, ")");
}