2016-02-03 16:05:03 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2016 - pancake, maijin */
|
2012-02-27 01:40:27 +00:00
|
|
|
|
2015-01-27 04:47:27 +00:00
|
|
|
#include "r_util.h"
|
|
|
|
|
2014-04-21 11:50:38 +00:00
|
|
|
static void find_refs(RCore *core, const char *glob) {
|
|
|
|
char cmd[128];
|
|
|
|
ut64 curseek = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
while (*glob == ' ') glob++;
|
2015-02-19 11:57:58 +00:00
|
|
|
if (!*glob)
|
2014-04-21 11:50:38 +00:00
|
|
|
glob = "str.";
|
|
|
|
if (*glob == '?') {
|
|
|
|
eprintf ("Usage: arf [flag-str-filter]\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eprintf ("Finding references of flags matching '%s'...\n", glob);
|
2015-12-16 13:35:56 +00:00
|
|
|
snprintf (cmd, sizeof (cmd) - 1, ".(findstref) @@= `f~%s[0]`", glob);
|
2014-04-21 11:50:38 +00:00
|
|
|
r_core_cmd0 (core, "(findstref,f here=$$,s entry0,/r here,f-here)");
|
|
|
|
r_core_cmd0 (core, cmd);
|
|
|
|
r_core_cmd0 (core, "(-findstref)");
|
|
|
|
r_core_seek (core, curseek, 1);
|
|
|
|
}
|
|
|
|
|
2015-07-27 21:56:11 +00:00
|
|
|
/* set flags for every function */
|
|
|
|
static void flag_every_function(RCore *core) {
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
r_flag_space_push (core->flags, "functions");
|
|
|
|
r_list_foreach (core->anal->fcns, iter, fcn) {
|
|
|
|
r_flag_set (core->flags, fcn->name,
|
|
|
|
fcn->addr, fcn->size, 0);
|
|
|
|
}
|
|
|
|
r_flag_space_pop (core->flags);
|
|
|
|
}
|
|
|
|
|
2014-09-02 00:48:41 +00:00
|
|
|
static void var_help(RCore *core, char ch) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "af[aAv]", " [idx] [type] [name]",
|
|
|
|
"afa", "", "list function arguments",
|
|
|
|
"afa*", "", "list function arguments in commands",
|
|
|
|
"afa", " [idx] [name] ([type])", "define argument N with name and type",
|
|
|
|
"afan", " [old_name] [new_name]", "rename function argument",
|
|
|
|
"afat", " [name] [new_type]", "change type for given argument",
|
|
|
|
"afaj", "", "return list of function arguments in JSON format",
|
|
|
|
"afa-", " [idx]", "delete argument at the given index",
|
|
|
|
"afag", " [idx] [addr]", "define var get reference",
|
|
|
|
"afas", " [idx] [addr]", "define var set reference",
|
|
|
|
"afv", "", "list function local variables",
|
2015-12-27 20:39:43 +00:00
|
|
|
"afv*", "", "list function local variables in commands",
|
2015-12-16 13:35:56 +00:00
|
|
|
"afv", " [idx] [name] ([type])", "define variable N with name and type",
|
|
|
|
"afvn", " [old_name] [new_name]", "rename local variable",
|
|
|
|
"afvt", " [name] [new_type]", "change type for given variable",
|
|
|
|
"afvj", "", "return list of function local variables in JSON format",
|
|
|
|
"afv-", " [idx]", "delete variable at the given index",
|
|
|
|
"afvg", " [idx] [addr]", "define var get reference",
|
|
|
|
"afvs", " [idx] [addr]", "define var set reference",
|
|
|
|
"afx", "[-] [from] [to]", "manipulate function xrefs",
|
|
|
|
NULL };
|
|
|
|
if (ch == 'a' || ch == 'A' || ch == 'v') {
|
2015-03-18 00:56:55 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
2014-05-13 15:32:01 +00:00
|
|
|
} else {
|
|
|
|
eprintf ("See afv? and afa?\n");
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int var_cmd(RCore *core, const char *str) {
|
2014-09-22 15:23:17 +00:00
|
|
|
char *p, *ostr;
|
2015-11-19 20:26:54 +00:00
|
|
|
int delta, type = *str, res = true;
|
2015-12-28 00:47:16 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
2012-02-27 01:40:27 +00:00
|
|
|
|
|
|
|
ostr = p = strdup (str);
|
|
|
|
str = (const char *)ostr;
|
|
|
|
|
2014-09-22 02:22:47 +00:00
|
|
|
switch (type) {
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'V': // show vars in human readable format
|
2015-05-31 21:46:32 +00:00
|
|
|
r_anal_var_list_show (core->anal, fcn, 'v', 0);
|
|
|
|
r_anal_var_list_show (core->anal, fcn, 'a', 0);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case '?':
|
2014-09-02 00:48:41 +00:00
|
|
|
var_help (core, 0);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'v': // frame variable
|
|
|
|
case 'a': // stack arg
|
|
|
|
case 'A': // fastcall arg
|
|
|
|
// XXX nested dup
|
2015-11-22 20:45:25 +00:00
|
|
|
if (str[1] == '?') {
|
|
|
|
var_help (core, *str);
|
|
|
|
break;
|
|
|
|
}
|
2015-11-19 20:26:54 +00:00
|
|
|
if (!fcn && str[1] != 'j' && str[1] != '*') {
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("Cannot find function here\n");
|
2015-11-19 20:26:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
/* Variable access CFvs = set fun var */
|
|
|
|
switch (str[1]) {
|
2014-04-28 23:31:46 +00:00
|
|
|
case '\0':
|
2015-05-31 21:46:32 +00:00
|
|
|
case '*':
|
|
|
|
case 'j':
|
|
|
|
r_anal_var_list_show (core->anal, fcn, type, str[1]);
|
2015-11-19 20:26:54 +00:00
|
|
|
break;
|
2014-04-28 23:31:46 +00:00
|
|
|
case '.':
|
2015-05-31 21:46:32 +00:00
|
|
|
r_anal_var_list_show (core->anal, fcn, core->offset, 0);
|
2015-11-19 20:26:54 +00:00
|
|
|
break;
|
2015-12-28 00:47:16 +00:00
|
|
|
case '-': // "afv-"
|
2015-12-15 01:08:53 +00:00
|
|
|
if (str[2] == '*') {
|
|
|
|
r_anal_var_delete_all (core->anal, fcn->addr, type);
|
|
|
|
} else {
|
2015-12-28 00:47:16 +00:00
|
|
|
if (IS_NUMBER (str[2])) {
|
|
|
|
r_anal_var_delete (core->anal, fcn->addr,
|
|
|
|
type, 1, (int)r_num_math (core->num, str + 1));
|
|
|
|
} else {
|
|
|
|
r_anal_var_delete_byname (core->anal, fcn, type, str + 2);
|
|
|
|
}
|
2015-12-15 01:08:53 +00:00
|
|
|
}
|
2015-11-19 20:26:54 +00:00
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'n': {
|
2014-12-13 17:06:01 +00:00
|
|
|
str++;
|
2015-12-16 13:35:56 +00:00
|
|
|
for (str++; *str == ' ';) str++;
|
2014-12-13 17:06:01 +00:00
|
|
|
char *new_name = strchr (str, ' ');
|
|
|
|
if (!new_name) {
|
|
|
|
var_help (core, type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*new_name++ = 0;
|
|
|
|
char *old_name = strdup (str);
|
2015-12-14 00:49:53 +00:00
|
|
|
r_str_split (old_name, ' ');
|
2015-03-23 23:16:00 +00:00
|
|
|
r_anal_var_rename (core->anal, fcn->addr,
|
2015-12-16 13:35:56 +00:00
|
|
|
R_ANAL_VAR_SCOPE_LOCAL, (char)type,
|
|
|
|
old_name, new_name);
|
2015-01-14 01:53:34 +00:00
|
|
|
free (old_name);
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
|
|
|
case 't': {
|
|
|
|
const char *name = str + 1;
|
|
|
|
for (name++; *name == ' ';) name++;
|
2015-12-14 00:49:53 +00:00
|
|
|
char *new_type = strchr (name, ' ');
|
|
|
|
if (!new_type) {
|
|
|
|
var_help (core, type);
|
|
|
|
break;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
*new_type++ = 0;
|
2015-12-14 00:49:53 +00:00
|
|
|
r_anal_var_retype (core->anal, fcn->addr,
|
2015-12-16 13:35:56 +00:00
|
|
|
R_ANAL_VAR_SCOPE_LOCAL, -1, (char)str[0],
|
|
|
|
new_type, -1, name);
|
|
|
|
} break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 's':
|
|
|
|
case 'g':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (str[2] != '\0') {
|
2015-11-19 20:26:54 +00:00
|
|
|
int rw = 0; // 0 = read, 1 = write
|
|
|
|
RAnalVar *var = r_anal_var_get (core->anal, fcn->addr,
|
2015-12-16 13:35:56 +00:00
|
|
|
(char)type, atoi (str + 2), R_ANAL_VAR_SCOPE_LOCAL);
|
2015-11-19 20:26:54 +00:00
|
|
|
if (!var) {
|
2016-01-04 01:19:02 +00:00
|
|
|
eprintf ("Cannot find variable in: '%s'\n", str);
|
2015-11-19 20:26:54 +00:00
|
|
|
res = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (var != NULL) {
|
2015-12-16 13:35:56 +00:00
|
|
|
int scope = (str[1] == 'g')? 0: 1;
|
2015-11-19 20:26:54 +00:00
|
|
|
r_anal_var_access (core->anal, fcn->addr, (char)type,
|
2015-12-16 13:35:56 +00:00
|
|
|
scope, atoi (str + 2), rw, core->offset);
|
2015-11-19 20:26:54 +00:00
|
|
|
r_anal_var_free (var);
|
|
|
|
break;
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
} else eprintf ("Missing argument\n");
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case ' ': {
|
2015-11-19 20:26:54 +00:00
|
|
|
const char *name;
|
|
|
|
char *vartype;
|
|
|
|
int size = 4;
|
|
|
|
int scope = 1;
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
for (str++; *str == ' ';) str++;
|
2014-09-22 02:22:47 +00:00
|
|
|
p = strchr (str, ' ');
|
|
|
|
if (!p) {
|
|
|
|
var_help (core, type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*p++ = 0;
|
|
|
|
delta = r_num_math (core->num, str);
|
2015-11-19 20:26:54 +00:00
|
|
|
name = p;
|
|
|
|
vartype = strchr (name, ' ');
|
|
|
|
if (vartype) {
|
|
|
|
*vartype++ = 0;
|
|
|
|
r_anal_var_add (core->anal, fcn->addr,
|
2015-12-16 13:35:56 +00:00
|
|
|
scope, delta, type,
|
|
|
|
vartype, size, name);
|
2015-11-19 20:26:54 +00:00
|
|
|
} else eprintf ("Missing name\n");
|
2014-09-22 02:22:47 +00:00
|
|
|
break;
|
2015-11-19 20:26:54 +00:00
|
|
|
}
|
2014-09-22 02:22:47 +00:00
|
|
|
default:
|
2014-09-02 00:48:41 +00:00
|
|
|
var_help (core, *str);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-11-19 20:26:54 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
2015-11-19 20:26:54 +00:00
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
free (ostr);
|
2015-11-19 20:26:54 +00:00
|
|
|
return res;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
|
2014-12-05 17:56:33 +00:00
|
|
|
static void print_trampolines(RCore *core, ut64 a, ut64 b, size_t element_size) {
|
|
|
|
int i;
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = 0; i < core->blocksize; i += element_size) {
|
2014-12-05 17:56:33 +00:00
|
|
|
ut32 n;
|
2015-12-16 13:35:56 +00:00
|
|
|
memcpy (&n, core->block + i, sizeof (ut32));
|
|
|
|
if (n >= a && n <= b) {
|
2014-12-05 17:56:33 +00:00
|
|
|
if (element_size == 4)
|
2015-12-16 13:35:56 +00:00
|
|
|
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);
|
2014-12-05 17:56:33 +00:00
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("Cd %u @ 0x%" PFMT64x ":%u\n", element_size, core->offset + i, element_size);
|
2014-12-05 17:56:33 +00:00
|
|
|
// TODO: add data xrefs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static void cmd_anal_trampoline(RCore *core, const char *input) {
|
2014-12-05 17:56:33 +00:00
|
|
|
int bits = r_config_get_i (core->config, "asm.bits");
|
2012-11-20 02:59:00 +00:00
|
|
|
char *p, *inp = strdup (input);
|
|
|
|
p = strchr (inp, ' ');
|
2015-12-16 13:35:56 +00:00
|
|
|
if (p) *p = 0;
|
2012-11-20 02:59:00 +00:00
|
|
|
ut64 a = r_num_math (core->num, inp);
|
2015-12-16 13:35:56 +00:00
|
|
|
ut64 b = p? r_num_math (core->num, p + 1): 0;
|
2012-11-20 02:59:00 +00:00
|
|
|
free (inp);
|
2014-12-05 17:56:33 +00:00
|
|
|
|
2012-11-20 02:59:00 +00:00
|
|
|
switch (bits) {
|
2013-02-21 10:31:04 +00:00
|
|
|
case 32:
|
2015-12-16 13:35:56 +00:00
|
|
|
print_trampolines (core, a, b, 4);
|
2013-02-21 10:31:04 +00:00
|
|
|
break;
|
|
|
|
case 64:
|
2015-12-16 13:35:56 +00:00
|
|
|
print_trampolines (core, a, b, 8);
|
2013-02-21 10:31:04 +00:00
|
|
|
break;
|
2012-11-20 02:59:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-29 10:54:00 +00:00
|
|
|
R_API char *cmd_syscall_dostr(RCore *core, int n) {
|
|
|
|
char *res = NULL;
|
2012-02-27 01:40:27 +00:00
|
|
|
int i;
|
|
|
|
char str[64];
|
2015-10-29 10:54:00 +00:00
|
|
|
if (n == -1) {
|
|
|
|
n = (int)r_debug_reg_get (core->dbg, "oeax");
|
|
|
|
if (n == 0 || n == -1) {
|
|
|
|
const char *a0 = r_reg_get_name (core->anal->reg, R_REG_NAME_A0);
|
|
|
|
n = (int)r_debug_reg_get (core->dbg, a0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RSyscallItem *item = r_syscall_get (core->anal->syscall, n, -1);
|
2012-02-27 01:40:27 +00:00
|
|
|
if (item == NULL) {
|
2015-10-29 10:54:00 +00:00
|
|
|
res = r_str_concatf (res, "%d = unknown ()", n);
|
|
|
|
return res;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
2015-10-29 10:54:00 +00:00
|
|
|
res = r_str_concatf (res, "%d = %s (", item->num, item->name);
|
2012-02-27 01:40:27 +00:00
|
|
|
// TODO: move this to r_syscall
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = 0; i < item->args; i++) {
|
|
|
|
ut64 arg = r_debug_arg_get (core->dbg, true, i + 1);
|
|
|
|
//r_cons_printf ("%d:0x%llx", i, r_debug_arg_get (core->dbg, true, i+1));
|
2015-10-29 10:22:49 +00:00
|
|
|
if (item->sargs) {
|
2014-06-16 03:58:00 +00:00
|
|
|
switch (item->sargs[i]) {
|
|
|
|
case 'p': // pointer
|
2015-12-16 13:35:56 +00:00
|
|
|
res = r_str_concatf (res, "0x%08" PFMT64x "", arg);
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
2015-12-16 13:35:56 +00:00
|
|
|
res = r_str_concatf (res, "%" PFMT64d "", arg);
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
case 'z':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_io_read_at (core->io, arg, (ut8 *)str, sizeof (str));
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: filter zero terminated string
|
|
|
|
str[63] = '\0';
|
|
|
|
r_str_filter (str, strlen (str));
|
2015-10-29 10:54:00 +00:00
|
|
|
res = r_str_concatf (res, "\"%s\"", str);
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'Z': {
|
|
|
|
ut64 len = r_debug_arg_get (core->dbg, true, i + 2);
|
|
|
|
len = R_MIN (len + 1, sizeof (str) - 1);
|
|
|
|
if (len == 0) len = 16; // override default
|
|
|
|
r_io_read_at (core->io, arg, (ut8 *)str, len);
|
|
|
|
str[len] = 0;
|
|
|
|
r_str_filter (str, -1);
|
|
|
|
res = r_str_concatf (res, "\"%s\"", str);
|
|
|
|
} break;
|
2014-06-16 03:58:00 +00:00
|
|
|
default:
|
2015-12-16 13:35:56 +00:00
|
|
|
res = r_str_concatf (res, "0x%08" PFMT64x "", arg);
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-10-29 10:22:49 +00:00
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
res = r_str_concatf (res, "0x%08" PFMT64x "", arg);
|
2015-10-29 10:22:49 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (i + 1 < item->args)
|
2015-10-29 10:54:00 +00:00
|
|
|
res = r_str_concatf (res, ", ");
|
|
|
|
}
|
|
|
|
res = r_str_concatf (res, ")");
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmd_syscall_do(RCore *core, int n) {
|
|
|
|
char *msg = cmd_syscall_dostr (core, n);
|
|
|
|
if (msg) {
|
|
|
|
r_cons_printf ("%s\n", msg);
|
|
|
|
free (msg);
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static void core_anal_bytes(RCore *core, const ut8 *buf, int len, int nops, int fmt) {
|
2013-11-26 02:25:31 +00:00
|
|
|
int ret, i, j, idx, size;
|
2013-05-04 00:35:52 +00:00
|
|
|
RAsmOp asmop;
|
2012-02-27 01:40:27 +00:00
|
|
|
RAnalOp op;
|
2013-06-17 01:26:48 +00:00
|
|
|
ut64 addr;
|
|
|
|
RAnalHint *hint;
|
2014-10-16 23:15:17 +00:00
|
|
|
int use_color = core->print->flags & R_PRINT_FLAGS_COLOR;
|
|
|
|
const char *color = "";
|
|
|
|
if (use_color)
|
|
|
|
color = core->cons->pal.label;
|
2015-12-16 13:35:56 +00:00
|
|
|
if (fmt == 'j')
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("[");
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = idx = ret = 0; idx < len && (!nops || (nops && i < nops)); i++, idx += ret) {
|
|
|
|
addr = core->offset + idx;
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: use more anal hints
|
|
|
|
hint = r_anal_hint_get (core->anal, addr);
|
2013-06-17 01:26:48 +00:00
|
|
|
r_asm_set_pc (core->assembler, addr);
|
2015-12-16 13:35:56 +00:00
|
|
|
ret = r_asm_disassemble (core->assembler, &asmop, buf + idx, len - idx);
|
|
|
|
ret = r_anal_op (core->anal, &op, core->offset + idx, buf + idx, len - idx);
|
|
|
|
if (ret < 1 && fmt != 'd') {
|
|
|
|
eprintf ("Oops at 0x%08" PFMT64x " (", core->offset + idx);
|
|
|
|
for (i = idx, j = 0; i < core->blocksize && j < 3; ++i, ++j) {
|
2015-07-14 20:58:54 +00:00
|
|
|
eprintf ("%02x ", buf[i]);
|
2015-07-13 20:57:51 +00:00
|
|
|
}
|
|
|
|
eprintf ("...)\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
size = (hint && hint->size)? hint->size: op.size;
|
|
|
|
if (fmt == 'd') {
|
2015-01-27 04:47:27 +00:00
|
|
|
char *opname = strdup (asmop.buf_asm);
|
|
|
|
r_str_split (opname, ' ');
|
|
|
|
char *d = r_asm_describe (core->assembler, opname);
|
|
|
|
if (d && *d) {
|
|
|
|
r_cons_printf ("%s: %s\n", opname, d);
|
|
|
|
free (d);
|
|
|
|
} else r_cons_printf ("Unknown opcode\n");
|
2015-12-16 13:35:56 +00:00
|
|
|
free (opname);
|
|
|
|
} else if (fmt == 'j') {
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("{\"opcode\": \"%s\",", asmop.buf_asm);
|
|
|
|
if (hint && hint->opcode)
|
|
|
|
r_cons_printf ("\"ophint\": \"%s\",", hint->opcode);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\"prefix\": %" PFMT64d ",", op.prefix);
|
|
|
|
r_cons_printf ("\"addr\": %" PFMT64d ",", core->offset + idx);
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("\"bytes\": \"");
|
2015-12-16 13:35:56 +00:00
|
|
|
for (j = 0; j < size; j++)
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("%02x", buf[j]);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\",");
|
2013-12-14 03:15:01 +00:00
|
|
|
if (op.val != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\"val\": %" PFMT64d ",", op.val);
|
2013-12-14 03:15:01 +00:00
|
|
|
if (op.ptr != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\"ptr\": %" PFMT64d ",", op.ptr);
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("\"size\": %d,", size);
|
|
|
|
r_cons_printf ("\"type\": \"%s\",",
|
|
|
|
r_anal_optype_to_string (op.type));
|
|
|
|
if (*R_STRBUF_SAFEGET (&op.esil))
|
|
|
|
r_cons_printf ("\"esil\": \"%s\",",
|
|
|
|
R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
if (hint && hint->jump != UT64_MAX)
|
|
|
|
op.jump = hint->jump;
|
|
|
|
if (op.jump != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\"jump\":%" PFMT64d ",", op.jump);
|
2013-12-14 03:15:01 +00:00
|
|
|
if (hint && hint->fail != UT64_MAX)
|
|
|
|
op.fail = hint->fail;
|
2014-11-07 02:48:27 +00:00
|
|
|
if (op.refptr != -1)
|
2015-03-25 02:03:34 +00:00
|
|
|
r_cons_printf ("\"refptr\":%d,", op.refptr);
|
2013-12-14 03:15:01 +00:00
|
|
|
if (op.fail != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("\"fail\":%" PFMT64d ",", op.fail);
|
2013-10-25 00:06:00 +00:00
|
|
|
|
2014-08-08 11:50:16 +00:00
|
|
|
r_cons_printf ("\"cycles\":%d,", op.cycles);
|
2014-02-25 23:03:42 +00:00
|
|
|
if (op.failcycles)
|
2015-06-20 19:40:14 +00:00
|
|
|
r_cons_printf ("\"failcycles\":%d,", op.failcycles);
|
2015-06-20 19:39:52 +00:00
|
|
|
r_cons_printf ("\"delay\":%d,", op.delay);
|
2015-06-01 14:02:40 +00:00
|
|
|
r_cons_printf ("\"stack\":\"%s\",", r_anal_stackop_tostring (op.stackop));
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("\"cond\":%d,",
|
2015-12-16 13:35:56 +00:00
|
|
|
(op.type & R_ANAL_OP_TYPE_COND)? 1: op.cond);
|
2014-12-01 23:36:42 +00:00
|
|
|
r_cons_printf ("\"family\":\"%s\"}", r_anal_op_family_to_string (op.family));
|
2013-12-14 03:15:01 +00:00
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
#define printline(k, fmt, arg)\
|
|
|
|
{ \
|
|
|
|
if (use_color)\
|
|
|
|
r_cons_printf ("%s%s: " Color_RESET, color, k);\
|
|
|
|
else\
|
|
|
|
r_cons_printf ("%s: ", k);\
|
|
|
|
if (fmt) r_cons_printf (fmt, arg);\
|
|
|
|
}
|
|
|
|
printline ("address", "0x%" PFMT64x "\n", core->offset + idx);
|
2014-10-16 23:15:17 +00:00
|
|
|
printline ("opcode", "%s\n", asmop.buf_asm);
|
|
|
|
if (hint) {
|
|
|
|
if (hint->opcode)
|
|
|
|
printline ("ophint", "%s\n", hint->opcode);
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("addr", "0x%08" PFMT64x "\n", (hint->addr + idx));
|
2014-10-16 23:15:17 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("prefix", "%" PFMT64d "\n", op.prefix);
|
2014-10-16 23:15:17 +00:00
|
|
|
printline ("bytes", NULL, 0);
|
2015-12-16 13:35:56 +00:00
|
|
|
for (j = 0; j < size; j++)
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("%02x", buf[j]);
|
|
|
|
r_cons_newline ();
|
|
|
|
if (op.val != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("val", "0x%08" PFMT64x "\n", op.val);
|
2013-12-14 03:15:01 +00:00
|
|
|
if (op.ptr != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("ptr", "0x%08" PFMT64x "\n", op.ptr);
|
2014-11-07 02:48:27 +00:00
|
|
|
if (op.refptr != -1)
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("refptr", "%d\n", op.refptr);
|
2014-10-16 23:15:17 +00:00
|
|
|
printline ("size", "%d\n", size);
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("type", "%s\n", r_anal_optype_to_string (op.type));
|
2015-10-14 22:03:11 +00:00
|
|
|
printline ("type2", "%s\n", r_anal_optype_to_string (op.type2));
|
2013-12-14 03:15:01 +00:00
|
|
|
if (*R_STRBUF_SAFEGET (&op.esil))
|
2014-10-16 23:15:17 +00:00
|
|
|
printline ("esil", "%s\n", R_STRBUF_SAFEGET (&op.esil));
|
2013-12-14 03:15:01 +00:00
|
|
|
if (hint && hint->jump != UT64_MAX)
|
|
|
|
op.jump = hint->jump;
|
|
|
|
if (op.jump != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("jump", "0x%08" PFMT64x "\n", op.jump);
|
2013-10-25 00:06:00 +00:00
|
|
|
|
2013-12-14 03:15:01 +00:00
|
|
|
if (hint && hint->fail != UT64_MAX)
|
|
|
|
op.fail = hint->fail;
|
|
|
|
if (op.fail != UT64_MAX)
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("fail", "0x%08" PFMT64x "\n", op.fail);
|
2013-10-25 00:06:00 +00:00
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
printline ("stack", "%s\n", r_anal_stackop_tostring (op.stackop));
|
|
|
|
printline ("cond", "%d\n", (op.type & R_ANAL_OP_TYPE_COND)? 1: op.cond);
|
|
|
|
printline ("family", "%s\n", r_anal_op_family_to_string (op.family));
|
2013-12-14 03:15:01 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
//r_cons_printf ("false: 0x%08"PFMT64x"\n", core->offset+idx);
|
2014-03-29 01:49:49 +00:00
|
|
|
//free (hint);
|
|
|
|
r_anal_hint_free (hint);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (((idx + ret) < len) && (!nops || (i + 1) < nops))
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf (",");
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
if (fmt == 'j') {
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("]");
|
|
|
|
r_cons_newline ();
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-15 22:16:29 +00:00
|
|
|
static int bb_cmp(const void *a, const void *b) {
|
|
|
|
const RAnalBlock *ba = a;
|
|
|
|
const RAnalBlock *bb = b;
|
2015-01-31 03:13:59 +00:00
|
|
|
return ba->addr - bb->addr;
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static int anal_fcn_list_bb(RCore *core, const char *input) {
|
2015-01-29 23:36:15 +00:00
|
|
|
RDebugTracepoint *tp = NULL;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *b;
|
2015-01-29 12:33:33 +00:00
|
|
|
int mode = 0;
|
|
|
|
ut64 addr;
|
2015-01-29 23:36:15 +00:00
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*input && (input[1] == ' ' || !input[1])) {
|
2015-01-29 12:41:38 +00:00
|
|
|
if (*input == 'r')
|
|
|
|
mode = '*';
|
2015-12-16 13:35:56 +00:00
|
|
|
else mode = *input;
|
2015-01-29 12:33:33 +00:00
|
|
|
input++;
|
|
|
|
}
|
|
|
|
if (input && *input) {
|
|
|
|
addr = r_num_math (core->num, input);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, addr, 0);
|
|
|
|
if (!fcn)
|
2015-09-14 10:35:38 +00:00
|
|
|
return false;
|
2015-01-29 12:33:33 +00:00
|
|
|
switch (mode) {
|
|
|
|
case 'j':
|
|
|
|
r_cons_printf ("[");
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
r_cons_printf ("fs blocks\n");
|
|
|
|
break;
|
|
|
|
}
|
2015-01-31 03:13:59 +00:00
|
|
|
r_list_sort (fcn->bbs, bb_cmp);
|
2015-01-29 12:33:33 +00:00
|
|
|
r_list_foreach (fcn->bbs, iter, b) {
|
|
|
|
switch (mode) {
|
|
|
|
case '*':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("f bb.%05" PFMT64x " = 0x%08" PFMT64x "\n",
|
2015-01-29 12:41:38 +00:00
|
|
|
b->addr & 0xFFFFF, b->addr);
|
2015-01-29 12:33:33 +00:00
|
|
|
break;
|
|
|
|
case 'q':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("0x%08" PFMT64x "\n", b->addr);
|
2015-01-29 12:33:33 +00:00
|
|
|
break;
|
|
|
|
case 'j':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("%" PFMT64d "%s", b->addr, iter->n? ",": "");
|
2015-01-29 12:33:33 +00:00
|
|
|
break;
|
|
|
|
default:
|
2015-01-29 23:36:15 +00:00
|
|
|
tp = r_debug_trace_get (core->dbg, b->addr);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("0x%08" PFMT64x " 0x%08" PFMT64x " %02X:%04X %d",
|
2015-01-29 23:36:15 +00:00
|
|
|
b->addr, b->addr + b->size,
|
2015-12-16 13:35:56 +00:00
|
|
|
tp? tp->times: 0, tp? tp->count: 0,
|
2015-01-29 23:36:15 +00:00
|
|
|
b->size);
|
2015-01-29 12:33:33 +00:00
|
|
|
if (b->jump != UT64_MAX) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf (" j 0x%08" PFMT64x, b->jump);
|
2015-01-29 12:33:33 +00:00
|
|
|
}
|
|
|
|
if (b->fail != UT64_MAX) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf (" f 0x%08" PFMT64x, b->fail);
|
2015-01-29 12:33:33 +00:00
|
|
|
}
|
|
|
|
r_cons_newline ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (mode == 'j') {
|
2015-01-29 12:33:33 +00:00
|
|
|
r_cons_printf ("]");
|
|
|
|
}
|
2015-09-14 10:35:38 +00:00
|
|
|
return true;
|
2015-01-29 12:33:33 +00:00
|
|
|
}
|
|
|
|
|
2016-01-25 16:28:56 +00:00
|
|
|
static bool anal_fcn_del_bb(RCore *core, const char *input) {
|
|
|
|
ut64 addr = r_num_math (core->num, input);
|
|
|
|
if (!addr) addr = core->offset;
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, -1);
|
|
|
|
if (fcn) {
|
2016-01-25 18:19:01 +00:00
|
|
|
if (!strcmp (input, "*")) {
|
|
|
|
r_list_free (fcn->bbs);
|
|
|
|
fcn->bbs = NULL;
|
|
|
|
} else {
|
|
|
|
RAnalBlock *b;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (fcn->bbs, iter, b) {
|
|
|
|
if (b->addr == addr) {
|
|
|
|
r_list_delete (fcn->bbs, iter);
|
|
|
|
return true;
|
|
|
|
}
|
2016-01-25 16:28:56 +00:00
|
|
|
}
|
2016-01-25 18:19:01 +00:00
|
|
|
eprintf ("Cannot find basic block\n");
|
2016-01-25 16:28:56 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
eprintf ("Cannot find function\n");
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static int anal_fcn_add_bb(RCore *core, const char *input) {
|
2014-11-13 10:17:43 +00:00
|
|
|
// fcn_addr bb_addr bb_size [jump] [fail]
|
|
|
|
char *ptr;
|
2013-05-24 00:53:15 +00:00
|
|
|
const char *ptr2 = NULL;
|
|
|
|
ut64 fcnaddr = -1LL, addr = -1LL;
|
|
|
|
ut64 size = 0LL;
|
2013-10-25 00:06:00 +00:00
|
|
|
ut64 jump = UT64_MAX;
|
|
|
|
ut64 fail = UT64_MAX;
|
2013-05-24 00:53:15 +00:00
|
|
|
int type = R_ANAL_BB_TYPE_NULL;
|
|
|
|
RAnalFunction *fcn = NULL;
|
|
|
|
RAnalDiff *diff = NULL;
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
while (*input == ' ') input++;
|
2014-11-13 10:17:43 +00:00
|
|
|
ptr = strdup (input);
|
|
|
|
|
2013-10-25 00:06:00 +00:00
|
|
|
switch (r_str_word_set0 (ptr)) {
|
2014-06-16 03:58:00 +00:00
|
|
|
case 7:
|
|
|
|
ptr2 = r_str_word_get0 (ptr, 6);
|
|
|
|
if (!(diff = r_anal_diff_new ())) {
|
|
|
|
eprintf ("error: Cannot init RAnalDiff\n");
|
|
|
|
free (ptr);
|
2015-09-14 10:35:38 +00:00
|
|
|
return false;
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
|
|
|
if (ptr2[0] == 'm')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
|
|
else if (ptr2[0] == 'u')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
|
|
case 6:
|
|
|
|
ptr2 = r_str_word_get0 (ptr, 5);
|
|
|
|
if (strchr (ptr2, 'h'))
|
|
|
|
type |= R_ANAL_BB_TYPE_HEAD;
|
|
|
|
if (strchr (ptr2, 'b'))
|
|
|
|
type |= R_ANAL_BB_TYPE_BODY;
|
|
|
|
if (strchr (ptr2, 'l'))
|
|
|
|
type |= R_ANAL_BB_TYPE_LAST;
|
|
|
|
if (strchr (ptr2, 'f'))
|
|
|
|
type |= R_ANAL_BB_TYPE_FOOT;
|
|
|
|
case 5: // get fail
|
|
|
|
fail = r_num_math (core->num, r_str_word_get0 (ptr, 4));
|
|
|
|
case 4: // get jump
|
|
|
|
jump = r_num_math (core->num, r_str_word_get0 (ptr, 3));
|
|
|
|
case 3: // get size
|
|
|
|
size = r_num_math (core->num, r_str_word_get0 (ptr, 2));
|
|
|
|
case 2: // get addr
|
|
|
|
addr = r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
|
|
|
case 1: // get fcnaddr
|
|
|
|
fcnaddr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
2013-05-24 00:53:15 +00:00
|
|
|
}
|
2014-12-14 00:49:04 +00:00
|
|
|
fcn = r_anal_get_fcn_in (core->anal, fcnaddr, 0);
|
|
|
|
if (fcn) {
|
2015-03-16 01:52:26 +00:00
|
|
|
int ret = r_anal_fcn_add_bb (core->anal, fcn, addr,
|
2015-12-16 13:35:56 +00:00
|
|
|
size, jump, fail, type, diff);
|
2014-12-14 00:49:04 +00:00
|
|
|
if (!ret) {
|
|
|
|
eprintf ("Cannot add basic block\n");
|
|
|
|
}
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("Cannot find function at 0x%" PFMT64x "\n", fcnaddr);
|
2013-05-24 00:53:15 +00:00
|
|
|
}
|
|
|
|
r_anal_diff_free (diff);
|
|
|
|
free (ptr);
|
2015-09-14 10:35:38 +00:00
|
|
|
return true;
|
2013-05-24 00:53:15 +00:00
|
|
|
}
|
2014-11-13 10:17:43 +00:00
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static bool fcnNeedsPrefix(const char *name) {
|
2015-10-18 16:47:04 +00:00
|
|
|
if (!strncmp (name, "entry", 5))
|
|
|
|
return false;
|
|
|
|
if (!strncmp (name, "main", 4))
|
|
|
|
return false;
|
|
|
|
return (!strchr (name, '.'));
|
|
|
|
}
|
|
|
|
|
2015-10-18 15:54:27 +00:00
|
|
|
static bool setFunctionName(RCore *core, ut64 off, const char *name) {
|
|
|
|
char *oname, *nname = NULL;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
if (!core || !name)
|
|
|
|
return false;
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, off,
|
2015-12-16 13:35:56 +00:00
|
|
|
R_ANAL_FCN_TYPE_FCN | R_ANAL_FCN_TYPE_SYM | R_ANAL_FCN_TYPE_LOC);
|
2015-10-18 15:54:27 +00:00
|
|
|
if (!fcn) return false;
|
2015-10-18 16:47:04 +00:00
|
|
|
if (fcnNeedsPrefix (name)) {
|
2015-10-18 15:54:27 +00:00
|
|
|
nname = r_str_newf ("fcn.%s", name);
|
|
|
|
} else {
|
|
|
|
nname = strdup (name);
|
|
|
|
}
|
2015-03-16 01:52:26 +00:00
|
|
|
oname = fcn->name;
|
2016-01-18 23:44:24 +00:00
|
|
|
r_flag_rename (core->flags, r_flag_get (core->flags, fcn->name), nname);
|
2015-10-18 15:54:27 +00:00
|
|
|
fcn->name = strdup (nname);
|
2015-03-16 01:52:26 +00:00
|
|
|
if (core->anal->cb.on_fcn_rename) {
|
2015-10-18 15:54:27 +00:00
|
|
|
core->anal->cb.on_fcn_rename (core->anal,
|
2015-12-16 13:35:56 +00:00
|
|
|
core->anal->user, fcn, nname);
|
2015-03-16 01:52:26 +00:00
|
|
|
}
|
|
|
|
free (oname);
|
2015-10-18 15:54:27 +00:00
|
|
|
free (nname);
|
|
|
|
return true;
|
2014-11-08 00:03:04 +00:00
|
|
|
}
|
2013-05-24 00:53:15 +00:00
|
|
|
|
2014-01-23 01:31:51 +00:00
|
|
|
static int cmd_anal_fcn(RCore *core, const char *input) {
|
|
|
|
switch (input[1]) {
|
2014-09-02 00:41:40 +00:00
|
|
|
case 'f':
|
|
|
|
r_anal_fcn_fit_overlaps (core->anal, NULL);
|
|
|
|
break;
|
2015-11-13 08:22:56 +00:00
|
|
|
case '-': // "af-"
|
2015-12-16 13:35:56 +00:00
|
|
|
if (!input[2] || !strcmp (input + 2, "*")) {
|
2015-11-13 08:22:56 +00:00
|
|
|
r_anal_fcn_del_locs (core->anal, UT64_MAX);
|
|
|
|
r_anal_fcn_del (core->anal, UT64_MAX);
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
ut64 addr = input[2] ?
|
|
|
|
r_num_math (core->num, input + 2) :
|
|
|
|
core->offset;
|
2014-06-16 03:58:00 +00:00
|
|
|
r_anal_fcn_del_locs (core->anal, addr);
|
|
|
|
r_anal_fcn_del (core->anal, addr);
|
2015-12-16 13:35:56 +00:00
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'u': {
|
2014-11-26 12:25:23 +00:00
|
|
|
ut64 addr = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
ut64 addr_end = r_num_math (core->num, input + 2);
|
2015-03-16 01:52:26 +00:00
|
|
|
if (addr_end < addr) {
|
2014-11-26 12:25:23 +00:00
|
|
|
eprintf ("Invalid address ranges\n");
|
|
|
|
} else {
|
|
|
|
int depth = 1;
|
|
|
|
ut64 a, b;
|
2014-11-26 12:34:23 +00:00
|
|
|
const char *c;
|
2014-11-26 12:25:23 +00:00
|
|
|
a = r_config_get_i (core->config, "anal.from");
|
|
|
|
b = r_config_get_i (core->config, "anal.to");
|
2014-11-26 12:34:23 +00:00
|
|
|
c = r_config_get (core->config, "anal.limits");
|
2014-11-26 12:25:23 +00:00
|
|
|
r_config_set_i (core->config, "anal.from", addr);
|
|
|
|
r_config_set_i (core->config, "anal.to", addr_end);
|
2014-11-26 12:34:23 +00:00
|
|
|
r_config_set (core->config, "anal.limits", "true");
|
2014-11-26 12:25:23 +00:00
|
|
|
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (fcn) r_anal_fcn_resize (fcn, addr_end - addr);
|
2014-11-26 12:25:23 +00:00
|
|
|
r_core_anal_fcn (core, addr, UT64_MAX,
|
|
|
|
R_ANAL_REF_TYPE_NULL, depth);
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, addr, 0);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (fcn) r_anal_fcn_resize (fcn, addr_end - addr);
|
2014-11-26 12:25:23 +00:00
|
|
|
|
|
|
|
r_config_set_i (core->config, "anal.from", a);
|
|
|
|
r_config_set_i (core->config, "anal.to", b);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_config_set (core->config, "anal.limits", c? c: "");
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case '+': {
|
|
|
|
char *ptr = strdup (input + 3);
|
|
|
|
const char *ptr2;
|
|
|
|
int n = r_str_word_set0 (ptr);
|
|
|
|
const char *name = NULL;
|
|
|
|
ut64 addr = -1LL;
|
|
|
|
ut64 size = 0LL;
|
|
|
|
RAnalDiff *diff = NULL;
|
|
|
|
int type = R_ANAL_FCN_TYPE_FCN;
|
|
|
|
if (n > 2) {
|
|
|
|
switch (n) {
|
|
|
|
case 5:
|
|
|
|
ptr2 = r_str_word_get0 (ptr, 4);
|
|
|
|
if (!(diff = r_anal_diff_new ())) {
|
|
|
|
eprintf ("error: Cannot init RAnalDiff\n");
|
|
|
|
free (ptr);
|
|
|
|
return false;
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (ptr2[0] == 'm')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
|
|
else if (ptr2[0] == 'u')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
|
|
case 4:
|
|
|
|
ptr2 = r_str_word_get0 (ptr, 3);
|
|
|
|
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 3:
|
|
|
|
name = r_str_word_get0 (ptr, 2);
|
|
|
|
case 2:
|
|
|
|
size = r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
|
|
|
case 1:
|
|
|
|
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (!r_anal_fcn_add (core->anal, addr, size, name, type, diff))
|
|
|
|
eprintf ("Cannot add function (duplicated)\n");
|
|
|
|
}
|
|
|
|
r_anal_diff_free (diff);
|
|
|
|
free (ptr);
|
|
|
|
} break;
|
2014-10-29 09:41:43 +00:00
|
|
|
case 'o': // "afo"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
ut64 addr = core->offset;
|
|
|
|
if (input[2] == ' ')
|
|
|
|
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;
|
2014-10-20 23:07:25 +00:00
|
|
|
case 'i': // "afi"
|
|
|
|
switch (input[2]) {
|
2015-02-04 00:25:53 +00:00
|
|
|
case '?': eprintf ("Usage: afi[j*] <addr>\n"); break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'j': r_core_anal_fcn_list (core, input + 3, 'j'); break; // "afij"
|
|
|
|
case '*': r_core_anal_fcn_list (core, input + 3, 1); break; // "afi*"
|
|
|
|
default: r_core_anal_fcn_list (core, input + 2, 0); break;
|
2014-10-20 23:07:25 +00:00
|
|
|
}
|
2014-08-08 12:40:50 +00:00
|
|
|
break;
|
2015-01-31 18:24:18 +00:00
|
|
|
case 'l': // "afl"
|
|
|
|
switch (input[2]) {
|
2015-05-31 21:46:32 +00:00
|
|
|
case '?':
|
|
|
|
eprintf ("Usage: afl[ajq*] <addr>\n");
|
|
|
|
eprintf ("List all functions in quiet, commands or json format\n");
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
case '*':
|
|
|
|
case 'j':
|
|
|
|
case 'q':
|
|
|
|
r_core_anal_fcn_list (core, NULL, input[2]);
|
|
|
|
break;
|
|
|
|
default:
|
2015-08-31 22:32:23 +00:00
|
|
|
r_core_anal_fcn_list (core, NULL, 'o');
|
2015-05-31 21:46:32 +00:00
|
|
|
break;
|
2015-01-31 18:24:18 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-10-15 14:05:47 +00:00
|
|
|
case 's': { // "afs"
|
2015-12-16 13:35:56 +00:00
|
|
|
ut64 addr;
|
|
|
|
RAnalFunction *f;
|
|
|
|
const char *arg = input + 3;
|
|
|
|
if (input[2] && (addr = r_num_math (core->num, arg))) {
|
|
|
|
arg = strchr (arg, ' ');
|
|
|
|
if (arg) arg++;
|
|
|
|
} else addr = core->offset;
|
|
|
|
if ((f = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL))) {
|
|
|
|
if (arg && *arg) {
|
|
|
|
r_anal_str_to_fcn (core->anal, f, arg);
|
|
|
|
} else {
|
|
|
|
char *str = r_anal_fcn_to_string (core->anal, f);
|
|
|
|
r_cons_printf ("%s\n", str);
|
|
|
|
free (str);
|
|
|
|
}
|
|
|
|
} else eprintf ("No function defined at 0x%08" PFMT64x "\n", addr);
|
|
|
|
} break;
|
2014-11-15 01:07:08 +00:00
|
|
|
case 'm': // "afm" - merge two functions
|
|
|
|
r_core_anal_fcn_merge (core,
|
2015-12-16 13:35:56 +00:00
|
|
|
core->offset, r_num_math (core->num, input + 2));
|
2014-11-15 01:07:08 +00:00
|
|
|
break;
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'a': // "afa"
|
|
|
|
case 'A': // "afA"
|
|
|
|
case 'v': // "afv"
|
2015-12-16 13:35:56 +00:00
|
|
|
var_cmd (core, input + 1);
|
|
|
|
break;
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'c': // "afc"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
if ((fcn = r_anal_get_fcn_in (core->anal, core->offset, 0)) != NULL) {
|
|
|
|
r_cons_printf ("%i\n", r_anal_fcn_cc (fcn));
|
|
|
|
} else eprintf ("Error: Cannot find function at 0x08%" PFMT64x "\n", core->offset);
|
|
|
|
} break;
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'C': // "afC"
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[2] == '?') {
|
2014-10-14 15:09:42 +00:00
|
|
|
int i;
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = 0;; i++) {
|
2014-10-14 15:09:42 +00:00
|
|
|
const char *s = r_anal_cc_type2str (i);
|
|
|
|
if (!s) break;
|
|
|
|
r_cons_printf ("%s\n", s);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
|
|
|
|
if (fcn) {
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[2] == 'a') {
|
2014-10-14 15:09:42 +00:00
|
|
|
eprintf ("TODO: analyze function to guess its calling convention\n");
|
2015-12-16 13:35:56 +00:00
|
|
|
} else if (input[2] == ' ') {
|
|
|
|
int type = r_anal_cc_str2type (input + 3);
|
|
|
|
if (type == -1) {
|
|
|
|
eprintf ("Unknown calling convention '%s'\n", input + 3);
|
2014-10-14 15:09:42 +00:00
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
// set calling convention for current function
|
|
|
|
fcn->call = type;
|
2014-10-14 15:09:42 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} else {
|
|
|
|
const char *type = r_anal_cc_type2str (fcn->call);
|
|
|
|
if (type) {
|
|
|
|
r_cons_printf ("%s\n", type);
|
|
|
|
} else {
|
|
|
|
eprintf ("Unknown calling convention\n");
|
|
|
|
}
|
|
|
|
}
|
2014-10-14 15:09:42 +00:00
|
|
|
} else {
|
|
|
|
eprintf ("Cannot find function\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-01-29 12:41:38 +00:00
|
|
|
case 'B': // "afB" // set function bits
|
|
|
|
if (input[2] == ' ') {
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset,
|
2015-12-16 13:35:56 +00:00
|
|
|
R_ANAL_FCN_TYPE_FCN | R_ANAL_FCN_TYPE_SYM);
|
|
|
|
if (fcn)
|
|
|
|
fcn->bits = atoi (input + 3);
|
2015-01-29 12:41:38 +00:00
|
|
|
else eprintf ("Cannot find function to set bits\n");
|
|
|
|
} else {
|
|
|
|
eprintf ("Usage: afB [bits]\n");
|
|
|
|
}
|
|
|
|
break;
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'b': // "afb"
|
2014-11-13 10:17:43 +00:00
|
|
|
switch (input[2]) {
|
2016-01-25 16:28:56 +00:00
|
|
|
case '-':
|
|
|
|
anal_fcn_del_bb (core, input +3);
|
|
|
|
break;
|
2016-01-25 18:19:01 +00:00
|
|
|
case 0:
|
2015-01-29 12:41:38 +00:00
|
|
|
case ' ':
|
|
|
|
case 'q':
|
|
|
|
case 'r':
|
|
|
|
case '*':
|
|
|
|
case 'j':
|
2015-12-16 13:35:56 +00:00
|
|
|
anal_fcn_list_bb (core, input + 2);
|
2015-01-29 12:33:33 +00:00
|
|
|
break;
|
2014-11-13 10:17:43 +00:00
|
|
|
case '+': // "afb+"
|
2015-12-16 13:35:56 +00:00
|
|
|
anal_fcn_add_bb (core, input + 3);
|
2014-11-13 10:17:43 +00:00
|
|
|
break;
|
2015-01-29 12:33:33 +00:00
|
|
|
default:
|
|
|
|
case '?':
|
|
|
|
eprintf ("Usage: afb+ or afbb or afb\n"
|
2015-12-16 13:35:56 +00:00
|
|
|
" afB [bits] - define asm.bits for given function\n"
|
|
|
|
" afb [addr] - list basic blocks of function (see afbq, afbj, afb*)\n"
|
|
|
|
" afb+ fcn_at bbat bbsz [jump] [fail] ([type] ([diff])) add bb to function @ fcnaddr\n");
|
2015-01-29 12:33:33 +00:00
|
|
|
break;
|
2014-11-13 10:17:43 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'n': // "afn"
|
2015-07-06 09:30:35 +00:00
|
|
|
switch (input[2]) {
|
|
|
|
case '?':
|
|
|
|
eprintf ("Usage: afn[sa] - analyze function names\n");
|
|
|
|
eprintf (" afna - construct a function name for the current offset\n");
|
|
|
|
eprintf (" afns - list all strings associated with the current function\n");
|
|
|
|
eprintf (" afn [name] - rename function\n");
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
free (r_core_anal_fcn_autoname (core, core->offset, 1));
|
|
|
|
break;
|
|
|
|
case 'a': {
|
|
|
|
char *name = r_core_anal_fcn_autoname (core, core->offset, 0);
|
2014-09-12 01:17:02 +00:00
|
|
|
if (name) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("afn %s 0x%08" PFMT64x "\n",
|
2014-09-18 09:37:28 +00:00
|
|
|
name, core->offset);
|
2014-09-12 01:17:02 +00:00
|
|
|
free (name);
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2015-07-06 09:30:35 +00:00
|
|
|
default: {
|
|
|
|
ut64 off = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
char *p, *name = strdup (input + 3);
|
|
|
|
if ((p = strchr (name, ' '))) {
|
2015-07-06 09:30:35 +00:00
|
|
|
*p++ = 0;
|
|
|
|
off = r_num_math (core->num, p);
|
|
|
|
}
|
|
|
|
if (*name) {
|
|
|
|
if (!setFunctionName (core, off, name))
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("Cannot find function '%s' at 0x%08" PFMT64x "\n", name, off);
|
2015-07-06 09:30:35 +00:00
|
|
|
free (name);
|
|
|
|
} else {
|
|
|
|
eprintf ("Usage: afn newname [off] # set new name to given function\n");
|
|
|
|
free (name);
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
break;
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2015-12-16 13:35:56 +00:00
|
|
|
/* this is undocumented and probably have no uses. plz discuss */
|
2014-10-28 16:24:01 +00:00
|
|
|
case 'e': // "afe"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
ut64 off = core->offset;
|
|
|
|
char *p, *name = strdup (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;
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'x':
|
2015-12-16 13:35:56 +00:00
|
|
|
switch (input[2]) {
|
|
|
|
case '\0':
|
|
|
|
case ' ':
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2015-12-16 13:35:56 +00:00
|
|
|
// TODO: sdbize!
|
|
|
|
// 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;
|
|
|
|
r_list_foreach (fcn->refs, iter, ref) {
|
|
|
|
r_cons_printf ("%c 0x%08" PFMT64x " -> 0x%08" PFMT64x "\n",
|
|
|
|
ref->type, ref->at, ref->addr);
|
|
|
|
}
|
2016-01-04 01:19:02 +00:00
|
|
|
} else eprintf ("Cannot find function\n");
|
2015-12-16 13:35:56 +00:00
|
|
|
}
|
2014-09-22 22:40:35 +00:00
|
|
|
#else
|
|
|
|
#warning TODO_ FCNOLD sdbize xrefs here
|
|
|
|
eprintf ("TODO\n");
|
|
|
|
#endif
|
2015-12-16 13:35:56 +00:00
|
|
|
break;
|
|
|
|
case 'c': // add meta xref
|
|
|
|
case 'd':
|
|
|
|
case 's':
|
|
|
|
case 'C': {
|
|
|
|
char *p;
|
|
|
|
ut64 a, b;
|
2015-12-14 09:19:07 +00:00
|
|
|
RAnalFunction *fcn;
|
2015-12-16 13:35:56 +00:00
|
|
|
char *mi = strdup (input);
|
|
|
|
if (mi && mi[3] == ' ' && (p = strchr (mi + 4, ' '))) {
|
|
|
|
*p = 0;
|
|
|
|
a = r_num_math (core->num, mi + 3);
|
|
|
|
b = r_num_math (core->num, p + 1);
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, a, R_ANAL_FCN_TYPE_ROOT);
|
|
|
|
if (fcn) {
|
|
|
|
r_anal_fcn_xref_add (core->anal, fcn, a, b, input[2]);
|
|
|
|
} else eprintf ("Cannot add reference to non-function\n");
|
|
|
|
} else eprintf ("Usage: afx[cCd?] [src] [dst]\n");
|
|
|
|
free (mi);
|
|
|
|
} break;
|
|
|
|
case '-': {
|
|
|
|
char *p;
|
|
|
|
ut64 a, b;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
char *mi = strdup (input + 2);
|
|
|
|
if (mi && *mi == ' ' && (p = strchr (mi + 1, ' '))) {
|
|
|
|
*p = 0;
|
|
|
|
a = r_num_math (core->num, mi);
|
|
|
|
b = r_num_math (core->num, p + 1);
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, a, R_ANAL_FCN_TYPE_ROOT);
|
|
|
|
if (fcn) {
|
|
|
|
r_anal_fcn_xref_del (core->anal, fcn, a, b, -1);
|
|
|
|
} else eprintf ("Cannot del reference to non-function\n");
|
|
|
|
} else eprintf ("Usage: afx- [src] [dst]\n");
|
|
|
|
free (mi);
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
case '?': {
|
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "afx[-cCd?] [src] [dst]", "# manage function references (see also ar?)",
|
|
|
|
"afxc", " sym.main+0x38 sym.printf", "add code ref",
|
|
|
|
"afxC", " sym.main sym.puts", "add call ref",
|
|
|
|
"afxd", " sym.main str.helloworld", "add data ref",
|
|
|
|
"afx-", " sym.main str.helloworld", "remove reference",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} break;
|
2015-12-14 09:19:07 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'g': // "afg" - non-interactive VV
|
2016-01-04 22:00:01 +00:00
|
|
|
r_core_visual_graph (core, NULL, NULL, false);
|
2015-12-16 13:35:56 +00:00
|
|
|
break;
|
|
|
|
case 'F': // "afF"
|
|
|
|
{
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
int val = input[2] && r_num_math (core->num, input + 2);
|
|
|
|
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?"
|
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "af", "",
|
|
|
|
"af", " ([name]) ([addr])", "analyze functions (start at addr or $$)",
|
|
|
|
"afr", " ([name]) ([addr])", "analyze functions recursively",
|
|
|
|
"af+", " addr size name [type] [diff]", "hand craft a function (requires afb+)",
|
|
|
|
"af-", " [addr]", "clean all function analysis data (or function at addr)",
|
2016-01-11 20:24:04 +00:00
|
|
|
"afa", "[?] [idx] [name] ([type])", "add function argument",
|
2015-12-16 13:35:56 +00:00
|
|
|
"af[aAv?]", "[arg]", "manipulate args, fastargs and variables in function",
|
|
|
|
"afb+", " fa a sz [j] [f] ([t]( [d]))", "add bb to function @ fcnaddr",
|
|
|
|
"afb", " [addr]", "List basic blocks of given function",
|
|
|
|
"afB", " 16", "set current function as thumb (change asm.bits)",
|
|
|
|
"afc", "@[addr]", "calculate the Cyclomatic Complexity (starting at addr)",
|
|
|
|
"afC[a]", " type @[addr]", "set calling convention for function (afC?=list cc types)",
|
|
|
|
"aff", "", "re-adjust function boundaries to fit",
|
|
|
|
"afF", "[1|0|]", "fold/unfold/toggle",
|
|
|
|
"afg", "", "non-interactive ascii-art basic-block graph (See VV)",
|
|
|
|
"afi", " [addr|fcn.name]", "show function(s) information (verbose afl)",
|
|
|
|
"afl", "[*] [fcn name]", "list functions (addr, size, bbs, name)",
|
|
|
|
"afo", " [fcn.name]", "show address for the function named like this",
|
|
|
|
"afn", " name [addr]", "rename name for function at address (change flag too)",
|
|
|
|
"afna", "", "suggest automatic name for current offset",
|
|
|
|
"afs", " [addr] [fcnsign]", "get/set function signature at current address",
|
|
|
|
"afx", "[cCd-] src dst", "add/remove code/Call/data/string reference",
|
|
|
|
"afv", "[?] [idx] [type] [name]", "add local var on current function",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} break;
|
2015-07-27 21:56:11 +00:00
|
|
|
case 'r': // "afr" // analyze function recursively
|
2015-12-16 13:35:56 +00:00
|
|
|
default: {
|
|
|
|
char *uaddr = NULL, *name = NULL;
|
|
|
|
int depth = r_config_get_i (core->config, "anal.depth");
|
|
|
|
int analyze_recursively = r_config_get_i (core->config, "anal.calls");
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
ut64 addr = core->offset;
|
|
|
|
if (input[1] == 'r') {
|
|
|
|
input++;
|
|
|
|
analyze_recursively = true;
|
|
|
|
}
|
2014-11-08 00:03:04 +00:00
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
// first undefine
|
|
|
|
if (input[0] && input[1] == ' ') {
|
|
|
|
name = strdup (input + 2);
|
|
|
|
uaddr = strchr (name, ' ');
|
|
|
|
if (uaddr) {
|
|
|
|
*uaddr++ = 0;
|
|
|
|
addr = r_num_math (core->num, uaddr);
|
2014-11-08 00:03:04 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
// depth = 1; // or 1?
|
|
|
|
// disable hasnext
|
|
|
|
}
|
|
|
|
//r_core_anal_undefine (core, core->offset);
|
|
|
|
r_core_anal_fcn (core, addr, UT64_MAX,
|
2014-11-08 00:03:04 +00:00
|
|
|
R_ANAL_REF_TYPE_NULL, depth);
|
2015-12-16 13:35:56 +00:00
|
|
|
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;
|
|
|
|
RIOSection *sect = r_io_section_vget (core->io, fcn->addr);
|
|
|
|
ut64 text_addr = 0x1000; // XXX use file baddr
|
|
|
|
if (sect) {
|
|
|
|
text_addr = sect->vaddr;
|
|
|
|
}
|
|
|
|
r_list_foreach (fcn->refs, iter, ref) {
|
|
|
|
if (ref->addr == UT64_MAX || ref->addr < text_addr)
|
|
|
|
continue;
|
|
|
|
r_core_anal_fcn (core, ref->addr, fcn->addr, R_ANAL_REF_TYPE_CALL, depth);
|
|
|
|
RAnalFunction *f = r_anal_get_fcn_at (core->anal, fcn->addr, 0);
|
|
|
|
if (!f) {
|
|
|
|
f = r_anal_get_fcn_in (core->anal, fcn->addr, 0);
|
|
|
|
if (f) {
|
|
|
|
/* cut function */
|
|
|
|
r_anal_fcn_resize (f, addr - fcn->addr);
|
|
|
|
r_core_anal_fcn (core, ref->addr, fcn->addr,
|
2015-09-06 22:30:48 +00:00
|
|
|
R_ANAL_REF_TYPE_CALL, depth);
|
2015-12-16 13:35:56 +00:00
|
|
|
f = r_anal_get_fcn_at (core->anal, fcn->addr, 0);
|
|
|
|
}
|
|
|
|
if (!f) {
|
|
|
|
eprintf ("Cannot find function at 0x%08" PFMT64x "\n", fcn->addr);
|
2015-07-27 21:56:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-22 13:00:41 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (name) {
|
|
|
|
if (*name && !setFunctionName (core, addr, name))
|
|
|
|
eprintf ("Cannot find function '%s' at 0x%08" PFMT64x "\n", name, addr);
|
|
|
|
free (name);
|
|
|
|
}
|
|
|
|
flag_every_function (core);
|
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
2015-09-14 10:35:38 +00:00
|
|
|
return true;
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static void __anal_reg_list(RCore *core, int type, int size, char mode) {
|
2014-05-25 01:00:24 +00:00
|
|
|
RReg *hack = core->dbg->reg;
|
2015-12-16 13:35:56 +00:00
|
|
|
int bits = (size > 0)? size: core->anal->bits;
|
|
|
|
;
|
2014-06-04 20:58:22 +00:00
|
|
|
const char *use_color;
|
2015-12-16 13:35:56 +00:00
|
|
|
int use_colors = r_config_get_i (core->config, "scr.color");
|
2014-06-04 20:58:22 +00:00
|
|
|
if (use_colors) {
|
|
|
|
#undef ConsP
|
|
|
|
#define ConsP(x) (core->cons && core->cons->pal.x)? core->cons->pal.x
|
2015-12-16 13:35:56 +00:00
|
|
|
use_color = ConsP (creg)
|
|
|
|
: Color_BWHITE;
|
2014-06-04 20:58:22 +00:00
|
|
|
} else {
|
|
|
|
use_color = NULL;
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
core->dbg->reg = core->anal->reg;
|
2015-05-05 22:38:23 +00:00
|
|
|
/* workaround for thumb */
|
2015-12-16 13:35:56 +00:00
|
|
|
if (core->anal->cur->arch && !strcmp (core->anal->cur->arch, "arm") && bits == 16) {
|
2015-05-05 22:38:23 +00:00
|
|
|
bits = 32;
|
|
|
|
}
|
2015-10-14 20:12:58 +00:00
|
|
|
if (mode == '=') {
|
2015-10-14 00:50:08 +00:00
|
|
|
int pcbits = 0;
|
|
|
|
const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
|
|
|
|
if (bits != reg->size)
|
|
|
|
pcbits = reg->size;
|
|
|
|
if (pcbits)
|
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, 2, use_color); // XXX detect which one is current usage
|
|
|
|
}
|
2014-06-04 20:58:22 +00:00
|
|
|
r_debug_reg_list (core->dbg, type, bits, mode, use_color);
|
2014-05-25 01:00:24 +00:00
|
|
|
core->dbg->reg = hack;
|
|
|
|
}
|
|
|
|
|
2014-06-19 02:52:28 +00:00
|
|
|
static void ar_show_help(RCore *core) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_message[] = {
|
2014-06-19 02:52:28 +00:00
|
|
|
"Usage: ar", "", "# Analysis Registers",
|
|
|
|
"ar", "", "Show 'gpr' registers",
|
|
|
|
"ar0", "", "Reset register arenas to 0",
|
2015-11-23 23:58:03 +00:00
|
|
|
"ara", "", "Manage register arenas",
|
2014-06-19 02:52:28 +00:00
|
|
|
"ar", " 16", "Show 16 bit registers",
|
|
|
|
"ar", " 32", "Show 32 bit registers",
|
|
|
|
"ar", " all", "Show all bit registers",
|
|
|
|
"ar", " <type>", "Show all registers of given type",
|
2016-01-09 02:14:18 +00:00
|
|
|
"arC", "", "Display register profile comments",
|
2015-09-28 00:04:08 +00:00
|
|
|
"arr", "", "Show register references (telescoping)",
|
2014-06-19 02:52:28 +00:00
|
|
|
"ar=", "", "Show register values in columns",
|
2015-12-16 13:35:56 +00:00
|
|
|
"ar?", " <reg>", "Show register value",
|
|
|
|
"arb", " <type>", "Display hexdump of the given arena",
|
|
|
|
"arc", " <name>", "Conditional flag registers",
|
|
|
|
"ard", " <name>", "Show only different registers",
|
|
|
|
"arn", " <regalias>", "Get regname for pc,sp,bp,a0-3,zf,cf,of,sg",
|
2014-06-19 02:52:28 +00:00
|
|
|
"aro", "", "Show old (previous) register values",
|
2015-12-16 13:35:56 +00:00
|
|
|
"arp", " <file>", "Load register profile from file",
|
2014-06-19 02:52:28 +00:00
|
|
|
"ars", "", "Stack register state",
|
2015-12-16 13:35:56 +00:00
|
|
|
"art", "", "List all register types",
|
|
|
|
".ar*", "", "Import register values as flags",
|
|
|
|
".ar-", "", "Unflag all registers",
|
|
|
|
NULL };
|
2014-06-19 02:52:28 +00:00
|
|
|
r_core_cmd_help (core, help_message);
|
|
|
|
}
|
|
|
|
|
2015-11-25 14:20:25 +00:00
|
|
|
static void cmd_ara_help(RCore *core) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-11-25 14:20:25 +00:00
|
|
|
"Usage:", "ara[+-s]", "Register Arena Push/Pop/Swap",
|
|
|
|
"ara", "", "show all register arenas allocated",
|
|
|
|
"ara", "+", "push a new register arena for each type",
|
|
|
|
"ara", "-", "pop last register arena",
|
|
|
|
"aras", "", "swap last two register arenas",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
|
|
|
|
2015-11-18 10:29:48 +00:00
|
|
|
// XXX dup from drp :OOO
|
2015-12-16 13:35:56 +00:00
|
|
|
void cmd_anal_reg (RCore *core, const char *str) {
|
2014-05-26 01:06:29 +00:00
|
|
|
int size = 0, i, type = R_REG_TYPE_GPR;
|
2014-05-25 01:00:24 +00:00
|
|
|
int bits = (core->anal->bits & R_SYS_BITS_64)? 64: 32;
|
2015-12-16 13:35:56 +00:00
|
|
|
int use_colors = r_config_get_i (core->config, "scr.color");
|
2014-06-16 03:58:00 +00:00
|
|
|
struct r_reg_item_t *r;
|
2014-06-04 20:58:22 +00:00
|
|
|
const char *use_color;
|
2014-06-16 03:58:00 +00:00
|
|
|
const char *name;
|
|
|
|
char *arg;
|
|
|
|
|
2014-06-04 20:58:22 +00:00
|
|
|
if (use_colors) {
|
|
|
|
#define ConsP(x) (core->cons && core->cons->pal.x)? core->cons->pal.x
|
2015-12-16 13:35:56 +00:00
|
|
|
use_color = ConsP (creg)
|
|
|
|
: Color_BWHITE;
|
2014-06-04 20:58:22 +00:00
|
|
|
} else {
|
|
|
|
use_color = NULL;
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
switch (str[0]) {
|
2015-11-23 23:58:03 +00:00
|
|
|
case 'l': // "arl"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
RRegSet *rs = r_reg_regset_get (core->anal->reg, R_REG_TYPE_GPR);
|
|
|
|
if (rs) {
|
|
|
|
RRegItem *r;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (rs->regs, iter, r) {
|
|
|
|
r_cons_printf ("%s\n", r->name);
|
2014-10-15 00:24:22 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2015-11-23 23:58:03 +00:00
|
|
|
case '0': // "ar"
|
2014-06-19 02:52:28 +00:00
|
|
|
r_reg_arena_zero (core->anal->reg);
|
|
|
|
break;
|
2016-01-09 02:14:18 +00:00
|
|
|
case 'C': // "ara"
|
|
|
|
if (core->anal->reg->reg_profile_cmt) {
|
|
|
|
r_cons_printf ("%s\n", core->anal->reg->reg_profile_cmt);
|
|
|
|
}
|
|
|
|
break;
|
2015-11-23 23:58:03 +00:00
|
|
|
case 'a': // "ara"
|
|
|
|
switch (str[1]) {
|
2015-11-25 14:20:25 +00:00
|
|
|
case '?':
|
|
|
|
cmd_ara_help (core);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
r_reg_arena_swap (core->anal->reg, false);
|
|
|
|
break;
|
2015-11-23 23:58:03 +00:00
|
|
|
case '+':
|
|
|
|
r_reg_arena_push (core->anal->reg);
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
r_reg_arena_pop (core->anal->reg);
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
default: {
|
|
|
|
int i, j;
|
|
|
|
RRegArena *a;
|
|
|
|
RListIter *iter;
|
|
|
|
for (i = 0; i < R_REG_TYPE_LAST; i++) {
|
|
|
|
RRegSet *rs = &core->anal->reg->regset[i];
|
|
|
|
j = 0;
|
|
|
|
r_list_foreach (rs->pool, iter, a) {
|
|
|
|
r_cons_printf ("%s %p %d %d %s %d\n",
|
|
|
|
(a == rs->arena)? "*": ".", a,
|
|
|
|
i, j, r_reg_get_type (i), a->size);
|
|
|
|
j++;
|
2015-11-23 23:58:03 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2015-11-23 23:58:03 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case '?':
|
|
|
|
if (str[1]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
ut64 off = r_reg_getv (core->anal->reg, str + 1);
|
|
|
|
r_cons_printf ("0x%08" PFMT64x "\n", off);
|
2014-06-19 02:52:28 +00:00
|
|
|
} else ar_show_help (core);
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2015-09-28 00:04:08 +00:00
|
|
|
case 'r':
|
|
|
|
r_core_debug_rr (core, core->anal->reg);
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'S': {
|
|
|
|
int sz;
|
|
|
|
ut8 *buf = r_reg_get_bytes (
|
|
|
|
core->anal->reg, R_REG_TYPE_GPR, &sz);
|
|
|
|
r_cons_printf ("%d\n", sz);
|
|
|
|
free (buf);
|
|
|
|
} break;
|
|
|
|
case 'b': { // WORK IN PROGRESS // DEBUG COMMAND
|
|
|
|
int len;
|
|
|
|
const ut8 *buf = r_reg_get_bytes (core->dbg->reg, R_REG_TYPE_GPR, &len);
|
|
|
|
//r_print_hexdump (core->print, 0LL, buf, len, 16, 16);
|
|
|
|
r_print_hexdump (core->print, 0LL, buf, len, 32, 4);
|
|
|
|
} break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'c':
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: set flag values with drc zf=1
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
2014-06-16 03:58:00 +00:00
|
|
|
RRegItem *r;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *name = str + 1;
|
|
|
|
while (*name == ' ') name++;
|
2014-06-16 03:58:00 +00:00
|
|
|
if (*name && name[1]) {
|
|
|
|
r = r_reg_cond_get (core->dbg->reg, name);
|
|
|
|
if (r) {
|
|
|
|
r_cons_printf ("%s\n", r->name);
|
|
|
|
} else {
|
|
|
|
int id = r_reg_cond_from_string (name);
|
2015-12-16 13:35:56 +00:00
|
|
|
RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
|
2014-06-16 03:58:00 +00:00
|
|
|
if (rf) {
|
|
|
|
int o = r_reg_cond_bits (core->dbg->reg, id, rf);
|
|
|
|
core->num->value = o;
|
|
|
|
// ORLY?
|
|
|
|
r_cons_printf ("%d\n", o);
|
|
|
|
free (rf);
|
|
|
|
} else eprintf ("unknown conditional or flag register\n");
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
} else {
|
2014-06-16 03:58:00 +00:00
|
|
|
RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
|
2014-05-25 01:00:24 +00:00
|
|
|
if (rf) {
|
2014-06-16 03:58:00 +00:00
|
|
|
r_cons_printf ("| s:%d z:%d c:%d o:%d p:%d\n",
|
|
|
|
rf->s, rf->z, rf->c, rf->o, rf->p);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*name == '=') {
|
|
|
|
for (i = 0; i < R_REG_COND_LAST; i++) {
|
2014-06-16 03:58:00 +00:00
|
|
|
r_cons_printf ("%s:%d ",
|
|
|
|
r_reg_cond_to_string (i),
|
|
|
|
r_reg_cond_bits (core->dbg->reg, i, rf));
|
|
|
|
}
|
|
|
|
r_cons_newline ();
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = 0; i < R_REG_COND_LAST; i++) {
|
2014-06-16 03:58:00 +00:00
|
|
|
r_cons_printf ("%d %s\n",
|
|
|
|
r_reg_cond_bits (core->dbg->reg, i, rf),
|
|
|
|
r_reg_cond_to_string (i));
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
free (rf);
|
2014-05-25 01:00:24 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-10-19 20:43:33 +00:00
|
|
|
case 's': // "drs"
|
2014-05-25 01:00:24 +00:00
|
|
|
switch (str[1]) {
|
|
|
|
case '-':
|
|
|
|
r_reg_arena_pop (core->dbg->reg);
|
|
|
|
// restore debug registers if in debugger mode
|
|
|
|
r_debug_reg_sync (core->dbg, 0, 1);
|
|
|
|
break;
|
|
|
|
case '+':
|
|
|
|
r_reg_arena_push (core->dbg->reg);
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case '?': {
|
|
|
|
const char *help_msg[] = {
|
2014-08-17 00:42:17 +00:00
|
|
|
"Usage:", "drs", " # Register states commands",
|
|
|
|
"drs", "", "List register stack",
|
|
|
|
"drs+", "", "Push register state",
|
|
|
|
"drs-", "", "Pop register state",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-08-17 00:42:17 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2014-05-25 01:00:24 +00:00
|
|
|
default:
|
|
|
|
r_cons_printf ("%d\n", r_list_length (
|
2015-12-16 13:35:56 +00:00
|
|
|
core->dbg->reg->regset[0].pool));
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'p': // drp
|
2015-11-18 10:29:48 +00:00
|
|
|
cmd_reg_profile (core, str);
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-10-27 16:23:13 +00:00
|
|
|
case 't': // "drt"
|
2015-12-16 13:35:56 +00:00
|
|
|
for (i = 0; (name = r_reg_get_type (i)); i++)
|
2014-05-25 01:00:24 +00:00
|
|
|
r_cons_printf ("%s\n", name);
|
|
|
|
break;
|
2015-10-31 01:20:25 +00:00
|
|
|
case 'n': // "drn" // "arn"
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*(str + 1) == '\0') {
|
2015-10-31 01:20:25 +00:00
|
|
|
eprintf ("Oops. try drn [PC|SP|BP|A0|A1|A2|A3|A4|R0|R1|ZF|SF|NF|OF\n");
|
2015-06-15 19:20:44 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
name = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (str + 2));
|
2014-05-25 01:00:24 +00:00
|
|
|
if (name && *name)
|
|
|
|
r_cons_printf ("%s\n", name);
|
|
|
|
else eprintf ("Oops. try drn [pc|sp|bp|a0|a1|a2|a3|zf|sf|nf|of]\n");
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'd': // "drd"
|
2014-06-04 20:58:22 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 3, use_color); // XXX detect which one is current usage
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-10-27 16:23:13 +00:00
|
|
|
case 'o': // "dro"
|
2015-09-14 10:35:38 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
2014-06-04 20:58:22 +00:00
|
|
|
r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, 0, use_color); // XXX detect which one is current usage
|
2015-09-14 10:35:38 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, false);
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-10-27 16:23:13 +00:00
|
|
|
case '=': // "dr="
|
2014-06-17 08:23:11 +00:00
|
|
|
__anal_reg_list (core, type, size, 2);
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-07-31 18:53:18 +00:00
|
|
|
case '-':
|
2014-05-25 01:00:24 +00:00
|
|
|
case '*':
|
|
|
|
case 'j':
|
|
|
|
case '\0':
|
|
|
|
__anal_reg_list (core, type, size, str[0]);
|
|
|
|
break;
|
|
|
|
case ' ':
|
2015-12-16 13:35:56 +00:00
|
|
|
arg = strchr (str + 1, '=');
|
2014-05-25 01:00:24 +00:00
|
|
|
if (arg) {
|
2014-06-17 08:23:11 +00:00
|
|
|
char *ostr, *regname;
|
2014-05-25 01:00:24 +00:00
|
|
|
*arg = 0;
|
2015-12-16 13:35:56 +00:00
|
|
|
ostr = r_str_chop (strdup (str + 1));
|
2014-06-17 08:23:11 +00:00
|
|
|
regname = r_str_clean (ostr);
|
2015-10-14 20:12:58 +00:00
|
|
|
r = r_reg_get (core->dbg->reg, regname, -1);
|
2015-07-15 16:18:04 +00:00
|
|
|
if (!r) {
|
|
|
|
int type = r_reg_get_name_idx (regname);
|
|
|
|
if (type != -1) {
|
|
|
|
const char *alias = r_reg_get_name (core->dbg->reg, type);
|
|
|
|
r = r_reg_get (core->dbg->reg, alias, -1);
|
|
|
|
}
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
if (r) {
|
2015-08-20 00:24:46 +00:00
|
|
|
//eprintf ("%s 0x%08"PFMT64x" -> ", str,
|
|
|
|
// r_reg_get_value (core->dbg->reg, r));
|
2014-05-25 01:00:24 +00:00
|
|
|
r_reg_set_value (core->dbg->reg, r,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, arg + 1));
|
2015-09-14 10:35:38 +00:00
|
|
|
r_debug_reg_sync (core->dbg, -1, true);
|
2015-08-20 00:24:46 +00:00
|
|
|
//eprintf ("0x%08"PFMT64x"\n",
|
|
|
|
// r_reg_get_value (core->dbg->reg, r));
|
2014-06-17 08:23:11 +00:00
|
|
|
} else {
|
|
|
|
eprintf ("ar: Unknown register '%s'\n", regname);
|
|
|
|
}
|
|
|
|
free (ostr);
|
2014-05-25 01:00:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
size = atoi (str + 1);
|
|
|
|
if (size == 0) {
|
|
|
|
r = r_reg_get (core->dbg->reg, str + 1, -1);
|
2014-08-08 00:25:18 +00:00
|
|
|
if (r) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("0x%08" PFMT64x "\n",
|
2014-08-08 00:25:18 +00:00
|
|
|
r_reg_get_value (core->dbg->reg, r));
|
|
|
|
return;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
arg = strchr (str + 1, ' ');
|
|
|
|
if (arg && size == 0) {
|
|
|
|
*arg = '\0';
|
2014-05-25 01:00:24 +00:00
|
|
|
size = atoi (arg);
|
|
|
|
} else size = bits;
|
2015-12-16 13:35:56 +00:00
|
|
|
type = r_reg_type_by_name (str + 1);
|
2014-05-25 01:00:24 +00:00
|
|
|
}
|
|
|
|
if (type != R_REG_TYPE_LAST) {
|
|
|
|
__anal_reg_list (core, type, size, str[0]);
|
|
|
|
} else eprintf ("cmd_debug_reg: Unknown type\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 23:17:55 +00:00
|
|
|
static int esil_step(RCore *core, ut64 until_addr, const char *until_expr) {
|
2014-08-11 01:32:02 +00:00
|
|
|
// Stepping
|
|
|
|
int ret;
|
2014-10-03 18:05:33 +00:00
|
|
|
ut8 code[256];
|
2014-08-11 01:32:02 +00:00
|
|
|
RAnalOp op;
|
2015-12-06 18:38:50 +00:00
|
|
|
RAnalEsil *esil = core->anal->esil;
|
2015-09-09 22:34:21 +00:00
|
|
|
const char *name = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
2014-08-11 01:32:02 +00:00
|
|
|
ut64 addr = r_reg_getv (core->anal->reg, name);
|
2015-12-16 13:35:56 +00:00
|
|
|
repeat:
|
|
|
|
if (r_cons_singleton ()->breaked) {
|
|
|
|
eprintf ("[+] ESIL emulation interrupted at 0x%08" PFMT64x "\n", addr);
|
2015-09-08 23:17:55 +00:00
|
|
|
return 0;
|
2014-08-11 01:32:02 +00:00
|
|
|
}
|
2015-12-06 18:38:50 +00:00
|
|
|
if (!esil) {
|
2014-09-11 02:18:23 +00:00
|
|
|
int romem = r_config_get_i (core->config, "esil.romem");
|
|
|
|
int stats = r_config_get_i (core->config, "esil.stats");
|
2015-09-08 23:17:55 +00:00
|
|
|
int iotrap = r_config_get_i (core->config, "esil.iotrap");
|
2015-09-23 10:46:22 +00:00
|
|
|
int exectrap = r_config_get_i (core->config, "esil.exectrap");
|
2016-01-19 23:36:21 +00:00
|
|
|
int stacksize = r_config_get_i (core->config, "esil.stacksize");
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!(core->anal->esil = r_anal_esil_new (stacksize, iotrap)))
|
|
|
|
return 0;
|
2015-12-06 18:38:50 +00:00
|
|
|
esil = core->anal->esil;
|
|
|
|
r_anal_esil_setup (esil, core->anal, romem, stats); // setup io
|
|
|
|
esil->exectrap = exectrap;
|
2014-08-11 01:32:02 +00:00
|
|
|
RList *entries = r_bin_get_entries (core->bin);
|
|
|
|
RBinAddr *entry = NULL;
|
|
|
|
RBinInfo *info = NULL;
|
2015-09-08 00:53:33 +00:00
|
|
|
if (entries && !r_list_empty (entries)) {
|
2015-12-16 13:35:56 +00:00
|
|
|
entry = (RBinAddr *)r_list_pop (entries);
|
2014-08-11 01:32:02 +00:00
|
|
|
info = r_bin_get_info (core->bin);
|
2015-12-16 13:35:56 +00:00
|
|
|
addr = info->has_va? entry->vaddr: entry->paddr;
|
2014-08-11 01:32:02 +00:00
|
|
|
r_list_push (entries, entry);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
|
|
|
r_reg_setv (core->anal->reg, name, addr);
|
2014-09-11 02:18:23 +00:00
|
|
|
// set memory read only
|
2014-08-11 01:32:02 +00:00
|
|
|
} else {
|
2015-12-06 18:38:50 +00:00
|
|
|
esil->trap = 0;
|
2014-08-11 01:32:02 +00:00
|
|
|
addr = r_reg_getv (core->anal->reg, name);
|
2014-09-14 00:52:30 +00:00
|
|
|
//eprintf ("PC=0x%llx\n", (ut64)addr);
|
2014-08-11 01:32:02 +00:00
|
|
|
}
|
2015-06-30 08:50:46 +00:00
|
|
|
if (r_anal_pin_call (core->anal, addr)) {
|
|
|
|
eprintf ("esil pin called\n");
|
2015-09-08 23:17:55 +00:00
|
|
|
return 1;
|
2015-06-30 08:50:46 +00:00
|
|
|
}
|
2015-12-06 18:38:50 +00:00
|
|
|
if (esil->exectrap) {
|
2015-09-23 10:46:22 +00:00
|
|
|
if (!(r_io_section_get_rwx (core->io, addr) & R_IO_EXEC)) {
|
|
|
|
esil->trap = R_ANAL_TRAP_EXEC_ERR;
|
|
|
|
esil->trap_code = addr;
|
|
|
|
eprintf ("[ESIL] Trap, trying to execute on non-executable memory\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2014-10-03 18:05:33 +00:00
|
|
|
r_io_read_at (core->io, addr, code, sizeof (code));
|
2014-08-11 01:32:02 +00:00
|
|
|
r_asm_set_pc (core->assembler, addr);
|
2014-10-03 18:05:33 +00:00
|
|
|
ret = r_anal_op (core->anal, &op, addr, code, sizeof (code));
|
2015-12-16 13:35:56 +00:00
|
|
|
if (op.size < 1) op.size = 1; // avoid inverted stepping
|
2015-12-02 07:11:34 +00:00
|
|
|
r_reg_setv (core->anal->reg, name, addr + op.size);
|
2014-09-20 13:53:29 +00:00
|
|
|
if (ret) {
|
2015-12-06 18:38:50 +00:00
|
|
|
ut64 delay_slot = 0;
|
|
|
|
r_anal_esil_reg_read (esil, "$ds", &delay_slot, NULL);
|
|
|
|
if (delay_slot > 0) {
|
2015-12-16 13:35:56 +00:00
|
|
|
if (op.type >= R_ANAL_OP_TYPE_JMP &&
|
|
|
|
op.type <= R_ANAL_OP_TYPE_CRET) {
|
2015-12-06 18:38:50 +00:00
|
|
|
// branches are illegal in a delay slot
|
|
|
|
esil->trap = R_ANAL_TRAP_EXEC_ERR;
|
|
|
|
esil->trap_code = addr;
|
|
|
|
eprintf ("[ESIL] Trap, trying to execute a branch in a delay slot\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 09:31:54 +00:00
|
|
|
r_anal_esil_set_pc (esil, addr);
|
2014-08-11 01:32:02 +00:00
|
|
|
r_anal_esil_parse (esil, R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
if (core->anal->cur && core->anal->cur->esil_post_loop)
|
2014-10-03 18:05:33 +00:00
|
|
|
core->anal->cur->esil_post_loop (esil, &op);
|
2014-08-11 01:32:02 +00:00
|
|
|
r_anal_esil_dumpstack (esil);
|
|
|
|
r_anal_esil_stack_free (esil);
|
2015-12-06 18:38:50 +00:00
|
|
|
|
|
|
|
delay_slot--;
|
|
|
|
|
|
|
|
if (((st64)delay_slot) <= 0) {
|
|
|
|
// no delay slot, or just consumed
|
|
|
|
ut64 jump_target_set = 0;
|
|
|
|
r_anal_esil_reg_read (esil, "$js", &jump_target_set, NULL);
|
|
|
|
if (jump_target_set) {
|
|
|
|
// perform the branch
|
|
|
|
ut64 jump_target = 0;
|
|
|
|
r_anal_esil_reg_read (esil, "$jt", &jump_target, NULL);
|
|
|
|
r_anal_esil_reg_write (esil, "$js", 0);
|
|
|
|
r_reg_setv (core->anal->reg, name, jump_target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
if (((st64)delay_slot) >= 0) {
|
2015-12-07 20:30:06 +00:00
|
|
|
// save decreased delay slot counter
|
|
|
|
r_anal_esil_reg_write (esil, "$ds", delay_slot);
|
|
|
|
if (!esil->trap) {
|
|
|
|
// emulate the instruction and its delay slots in the same 'aes' step
|
|
|
|
goto repeat;
|
|
|
|
}
|
2015-12-06 18:38:50 +00:00
|
|
|
}
|
2014-10-03 18:05:33 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 16:09:46 +00:00
|
|
|
st64 follow = (st64)r_config_get_i (core->config, "dbg.follow");
|
2015-12-16 13:35:56 +00:00
|
|
|
if (follow > 0) {
|
2015-10-31 00:57:52 +00:00
|
|
|
ut64 pc = r_debug_reg_get (core->dbg, "PC");
|
2015-12-16 13:35:56 +00:00
|
|
|
if ((pc < core->offset) || (pc > (core->offset + follow)))
|
2015-10-31 00:57:52 +00:00
|
|
|
r_core_cmd0 (core, "sr PC");
|
2014-10-03 18:05:33 +00:00
|
|
|
}
|
2015-09-16 01:51:35 +00:00
|
|
|
|
2015-01-30 01:07:47 +00:00
|
|
|
if (core->dbg->trace->enabled) {
|
|
|
|
RReg *reg = core->dbg->reg;
|
|
|
|
core->dbg->reg = core->anal->reg;
|
|
|
|
r_debug_trace_pc (core->dbg);
|
|
|
|
core->dbg->reg = reg;
|
|
|
|
}
|
2014-08-11 01:32:02 +00:00
|
|
|
// check addr
|
|
|
|
if (until_addr != UT64_MAX) {
|
2015-02-28 22:25:11 +00:00
|
|
|
if (r_reg_getv (core->anal->reg, name) == until_addr) {
|
2014-08-11 01:32:02 +00:00
|
|
|
eprintf ("ADDR BREAK\n");
|
2015-09-08 23:17:55 +00:00
|
|
|
return 0;
|
2014-08-11 01:32:02 +00:00
|
|
|
} else goto repeat;
|
|
|
|
}
|
2014-09-26 13:40:17 +00:00
|
|
|
// check esil
|
2015-12-06 18:38:50 +00:00
|
|
|
if (esil->trap) {
|
2015-09-08 23:17:55 +00:00
|
|
|
eprintf ("TRAP\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2014-08-11 01:32:02 +00:00
|
|
|
if (until_expr) {
|
|
|
|
if (r_anal_esil_condition (core->anal->esil, until_expr)) {
|
|
|
|
eprintf ("ESIL BREAK!\n");
|
2015-09-08 23:17:55 +00:00
|
|
|
return 0;
|
2014-08-11 01:32:02 +00:00
|
|
|
} else goto repeat;
|
|
|
|
}
|
2015-09-08 23:17:55 +00:00
|
|
|
return 1;
|
2014-08-11 01:32:02 +00:00
|
|
|
}
|
|
|
|
|
2014-10-15 00:24:22 +00:00
|
|
|
static void cmd_address_info(RCore *core, const char *addrstr, int fmt) {
|
|
|
|
ut64 addr, type;
|
|
|
|
if (!addrstr || !*addrstr) {
|
|
|
|
addr = core->offset;
|
|
|
|
} else {
|
|
|
|
addr = r_num_math (core->num, addrstr);
|
|
|
|
}
|
|
|
|
type = r_core_anal_address (core, addr);
|
|
|
|
int isp = 0;
|
2015-12-16 13:35:56 +00:00
|
|
|
switch (fmt) {
|
2014-10-15 00:24:22 +00:00
|
|
|
case 'j':
|
2015-12-16 13:35:56 +00:00
|
|
|
#define COMMA isp++? ",": ""
|
2014-10-15 00:24:22 +00:00
|
|
|
r_cons_printf ("{");
|
2014-10-15 14:05:47 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_PROGRAM)
|
|
|
|
r_cons_printf ("%s\"program\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_LIBRARY)
|
|
|
|
r_cons_printf ("%s\"library\":true", COMMA);
|
2014-10-15 00:24:22 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_EXEC)
|
|
|
|
r_cons_printf ("%s\"exec\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_READ)
|
|
|
|
r_cons_printf ("%s\"read\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_WRITE)
|
|
|
|
r_cons_printf ("%s\"write\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_FLAG)
|
|
|
|
r_cons_printf ("%s\"flag\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_FUNC)
|
|
|
|
r_cons_printf ("%s\"func\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_STACK)
|
|
|
|
r_cons_printf ("%s\"stack\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_HEAP)
|
|
|
|
r_cons_printf ("%s\"heap\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_REG)
|
|
|
|
r_cons_printf ("%s\"reg\":true", COMMA);
|
2014-10-24 19:31:46 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_ASCII)
|
|
|
|
r_cons_printf ("%s\"ascii\":true", COMMA);
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_SEQUENCE)
|
|
|
|
r_cons_printf ("%s\"sequence\":true", COMMA);
|
2014-10-15 00:24:22 +00:00
|
|
|
r_cons_printf ("}");
|
|
|
|
break;
|
|
|
|
default:
|
2014-10-15 14:05:47 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_PROGRAM)
|
|
|
|
r_cons_printf ("program\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_LIBRARY)
|
|
|
|
r_cons_printf ("library\n");
|
2014-10-15 00:24:22 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_EXEC)
|
|
|
|
r_cons_printf ("exec\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_READ)
|
|
|
|
r_cons_printf ("read\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_WRITE)
|
|
|
|
r_cons_printf ("write\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_FLAG)
|
|
|
|
r_cons_printf ("flag\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_FUNC)
|
|
|
|
r_cons_printf ("func\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_STACK)
|
|
|
|
r_cons_printf ("stack\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_HEAP)
|
|
|
|
r_cons_printf ("heap\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_REG)
|
|
|
|
r_cons_printf ("reg\n");
|
2014-10-24 19:31:46 +00:00
|
|
|
if (type & R_ANAL_ADDR_TYPE_ASCII)
|
|
|
|
r_cons_printf ("ascii\n");
|
|
|
|
if (type & R_ANAL_ADDR_TYPE_SEQUENCE)
|
|
|
|
r_cons_printf ("sequence\n");
|
2014-10-15 00:24:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-05 06:34:54 +00:00
|
|
|
static void cmd_anal_info(RCore *core, const char *input) {
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2014-12-05 06:34:54 +00:00
|
|
|
case '?':
|
|
|
|
eprintf ("Usage: ai @ rsp\n");
|
2014-01-23 01:31:51 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case ' ':
|
2014-12-05 06:51:21 +00:00
|
|
|
cmd_address_info (core, input, 0);
|
2014-10-15 00:24:22 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'j': // "aij"
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_address_info (core, input + 1, 'j');
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
default:
|
|
|
|
cmd_address_info (core, NULL, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static void cmd_esil_mem(RCore *core, const char *input) {
|
2015-01-27 11:46:15 +00:00
|
|
|
ut64 curoff = core->offset;
|
2015-03-13 23:14:30 +00:00
|
|
|
ut64 addr = 0x100000;
|
|
|
|
ut32 size = 0xf0000;
|
|
|
|
char name[128];
|
2015-01-27 11:46:15 +00:00
|
|
|
RCoreFile *cf;
|
|
|
|
RFlagItem *fi;
|
2015-10-01 10:04:58 +00:00
|
|
|
const char *sp;
|
2015-01-27 11:46:15 +00:00
|
|
|
char uri[32];
|
2015-03-16 00:37:53 +00:00
|
|
|
char nomalloc[256];
|
2015-03-13 23:14:30 +00:00
|
|
|
char *p;
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*input == '?') {
|
2015-03-13 23:14:30 +00:00
|
|
|
eprintf ("Usage: [addr] [size] [name]\n");
|
|
|
|
eprintf ("Default: 0x100000 0xf0000\n");
|
2015-01-27 11:46:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-16 00:37:53 +00:00
|
|
|
p = strncpy (nomalloc, input, 255);
|
|
|
|
if ((p = strchr (p, ' '))) {
|
2015-03-13 23:14:30 +00:00
|
|
|
while (*p == ' ') p++;
|
|
|
|
addr = r_num_math (core->num, p);
|
2015-03-16 00:37:53 +00:00
|
|
|
if ((p = strchr (p, ' '))) {
|
2015-03-13 23:14:30 +00:00
|
|
|
while (*p == ' ') p++;
|
2015-03-14 15:42:14 +00:00
|
|
|
size = (ut32)r_num_math (core->num, p);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (size < 1)
|
2015-03-14 15:42:14 +00:00
|
|
|
size = 0xf0000;
|
2015-03-16 00:37:53 +00:00
|
|
|
if ((p = strchr (p, ' '))) {
|
2015-03-14 15:42:14 +00:00
|
|
|
while (*p == ' ') p++;
|
|
|
|
snprintf (name, 128, "mem.%s", p);
|
2015-12-16 13:35:56 +00:00
|
|
|
} else snprintf (name, 128, "mem.0x%" PFMT64x "_0x%x", addr, size);
|
|
|
|
} else snprintf (name, 128, "mem.0x%" PFMT64x "_0x%x", addr, size);
|
|
|
|
} else snprintf (name, 128, "mem.0x%" PFMT64x "_0x%x", addr, size);
|
2015-03-13 23:14:30 +00:00
|
|
|
|
|
|
|
fi = r_flag_get (core->flags, name);
|
2015-01-27 11:46:15 +00:00
|
|
|
if (fi) {
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*input == '-') {
|
2015-03-13 23:14:30 +00:00
|
|
|
cf = r_core_file_get_by_fd (core, fi->offset);
|
|
|
|
r_core_file_close (core, cf);
|
2016-02-20 14:25:27 +00:00
|
|
|
r_flag_unset_name (core->flags, name);
|
2015-03-13 23:14:30 +00:00
|
|
|
eprintf ("Deinitialized %s\n", name);
|
2015-01-27 11:46:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-03-13 23:14:30 +00:00
|
|
|
eprintf ("Cannot create mem here, mem allready lives here");
|
|
|
|
return;
|
2015-01-27 11:46:15 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*input == '-') {
|
2015-03-13 23:14:30 +00:00
|
|
|
eprintf ("Cannot deinitialize %s\n", name);
|
2015-01-27 11:46:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-04-08 11:07:46 +00:00
|
|
|
snprintf (uri, sizeof (uri), "malloc://%d", (int)size);
|
2015-03-13 23:14:30 +00:00
|
|
|
cf = r_core_file_open (core, uri, R_IO_RW, addr);
|
2015-07-27 21:56:11 +00:00
|
|
|
if (cf) r_flag_set (core->flags, name, addr, size, 0);
|
2015-01-27 11:46:15 +00:00
|
|
|
//r_core_cmdf (core, "f stack_fd=`on malloc://%d 0x%08"
|
|
|
|
// PFMT64x"`", stack_size, stack_addr);
|
|
|
|
//r_core_cmdf (core, "f stack=0x%08"PFMT64x, stack_addr);
|
|
|
|
//r_core_cmdf (core, "dr %s=0x%08"PFMT64x, sp, stack_ptr);
|
2015-10-01 10:04:58 +00:00
|
|
|
sp = r_reg_get_name (core->dbg->reg, R_REG_NAME_SP);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_debug_reg_set (core->dbg, sp, addr + (size / 2));
|
2015-01-27 11:46:15 +00:00
|
|
|
//r_core_cmdf (core, "ar %s=0x%08"PFMT64x, sp, stack_ptr);
|
|
|
|
//r_core_cmdf (core, "f %s=%s", sp, sp);
|
|
|
|
r_core_seek (core, curoff, 0);
|
|
|
|
}
|
|
|
|
|
2016-01-15 00:50:08 +00:00
|
|
|
static ut64 opc = UT64_MAX;
|
|
|
|
static ut8 *regstate = NULL;
|
|
|
|
|
|
|
|
static void esil_init (RCore *core) {
|
|
|
|
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
opc = r_reg_getv (core->anal->reg, pc);
|
|
|
|
if (!opc || opc==UT64_MAX) opc = core->offset;
|
|
|
|
if (!core->anal->esil) {
|
|
|
|
int iotrap = r_config_get_i (core->config, "esil.iotrap");
|
2016-01-19 23:36:21 +00:00
|
|
|
int stacksize = r_config_get_i (core->config, "esil.stacksize");
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!(core->anal->esil = r_anal_esil_new (stacksize, iotrap))) {
|
|
|
|
R_FREE (regstate);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-15 00:50:08 +00:00
|
|
|
r_anal_esil_setup (core->anal->esil, core->anal, 0, 0);
|
|
|
|
}
|
|
|
|
free (regstate);
|
|
|
|
regstate = r_reg_arena_peek (core->anal->reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void esil_fini(RCore *core) {
|
|
|
|
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
r_reg_arena_poke (core->anal->reg, regstate);
|
|
|
|
r_reg_setv (core->anal->reg, pc, opc);
|
|
|
|
R_FREE (regstate);
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:49 +00:00
|
|
|
typedef struct {
|
|
|
|
RList *regs;
|
|
|
|
RList *regread;
|
|
|
|
RList *regwrite;
|
|
|
|
} AeaStats;
|
|
|
|
|
|
|
|
static void aea_stats_init (AeaStats *stats) {
|
|
|
|
stats->regs = r_list_newf (free);
|
|
|
|
stats->regread = r_list_newf (free);
|
|
|
|
stats->regwrite = r_list_newf (free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void aea_stats_fini (AeaStats *stats) {
|
|
|
|
R_FREE (stats->regs);
|
|
|
|
R_FREE (stats->regread);
|
|
|
|
R_FREE (stats->regwrite);
|
|
|
|
}
|
|
|
|
|
2016-01-15 00:50:08 +00:00
|
|
|
static bool contains(RList *list, const char *name) {
|
|
|
|
RListIter *iter;
|
|
|
|
const char *n;
|
|
|
|
r_list_foreach (list, iter, n) {
|
|
|
|
if (!strcmp (name, n))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:49 +00:00
|
|
|
static char *oldregread = NULL;
|
|
|
|
|
2016-01-15 00:50:08 +00:00
|
|
|
static int myregwrite(RAnalEsil *esil, const char *name, ut64 val) {
|
2016-01-15 01:51:49 +00:00
|
|
|
AeaStats *stats = esil->user;
|
|
|
|
if (oldregread && !strcmp (name, oldregread)) {
|
|
|
|
r_list_pop (stats->regread);
|
|
|
|
R_FREE (oldregread)
|
|
|
|
}
|
|
|
|
if (!IS_NUMBER (*name)) {
|
|
|
|
if (!contains (stats->regs, name)) {
|
|
|
|
r_list_push (stats->regs, strdup (name));
|
|
|
|
}
|
|
|
|
if (!contains (stats->regwrite, name)) {
|
|
|
|
r_list_push (stats->regwrite, strdup (name));
|
|
|
|
}
|
2016-01-15 00:50:08 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int myregread(RAnalEsil *esil, const char *name, ut64 *val, int *len) {
|
2016-01-15 01:51:49 +00:00
|
|
|
AeaStats *stats = esil->user;
|
|
|
|
if (!IS_NUMBER (*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));
|
2016-01-15 00:50:08 +00:00
|
|
|
}
|
2016-01-15 01:51:49 +00:00
|
|
|
}
|
2016-01-15 00:50:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:49 +00:00
|
|
|
static void showregs (RList *list) {
|
|
|
|
if (!r_list_empty (list)) {
|
|
|
|
char *reg;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (list, iter, reg) {
|
|
|
|
r_cons_printf ("%s", reg);
|
|
|
|
if (iter->n) r_cons_printf (" ");
|
|
|
|
}
|
|
|
|
r_cons_newline();
|
|
|
|
}
|
|
|
|
}
|
2016-01-18 10:15:02 +00:00
|
|
|
|
2016-01-15 00:50:08 +00:00
|
|
|
static bool cmd_aea(RCore* core, int mode, ut64 addr, int length) {
|
2016-01-15 01:51:49 +00:00
|
|
|
RAnalEsil *esil;
|
2016-01-18 10:15:02 +00:00
|
|
|
int ptr, ops, ops_end = 0, len, buf_sz, maxopsize;
|
2016-01-15 00:50:08 +00:00
|
|
|
ut64 addr_end;
|
2016-01-15 01:51:49 +00:00
|
|
|
AeaStats stats;
|
2016-01-15 00:50:08 +00:00
|
|
|
const char *esilstr;
|
|
|
|
RAnalOp aop = {0};
|
|
|
|
ut8 *buf;
|
|
|
|
if (!core)
|
|
|
|
return false;
|
|
|
|
maxopsize = r_anal_archinfo (core->anal, R_ANAL_ARCHINFO_MAX_OP_SIZE);
|
|
|
|
if (maxopsize < 1) maxopsize = 16;
|
2016-01-15 01:51:49 +00:00
|
|
|
if (mode & 1) {
|
|
|
|
// number of bytes / length
|
|
|
|
buf_sz = length;
|
|
|
|
} else {
|
|
|
|
// number of instructions / opcodes
|
2016-01-15 00:50:08 +00:00
|
|
|
ops_end = length;
|
|
|
|
if (ops_end < 1) ops_end = 1;
|
|
|
|
buf_sz = ops_end * maxopsize;
|
|
|
|
}
|
|
|
|
if (buf_sz < 1) {
|
|
|
|
buf_sz = maxopsize;
|
|
|
|
}
|
|
|
|
addr_end = addr + buf_sz;
|
|
|
|
buf = malloc (buf_sz);
|
|
|
|
if (!buf) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
(void)r_io_read_at (core->io, addr, (ut8 *)buf, buf_sz);
|
2016-01-15 01:51:49 +00:00
|
|
|
aea_stats_init (&stats);
|
|
|
|
|
2016-01-15 00:50:08 +00:00
|
|
|
esil_init (core);
|
2016-01-15 01:51:49 +00:00
|
|
|
esil = core->anal->esil;
|
|
|
|
# define hasNext(x) (x&1) ? (addr<addr_end) : (ops<ops_end)
|
|
|
|
esil->user = &stats;
|
|
|
|
esil->cb.hook_reg_write = myregwrite;
|
|
|
|
esil->cb.hook_reg_read = myregread;
|
|
|
|
esil->nowrite = true;
|
|
|
|
for (ops = ptr = 0; ptr < buf_sz && hasNext (mode); ops++, ptr += len) {
|
2016-01-15 00:50:08 +00:00
|
|
|
len = r_anal_op (core->anal, &aop, addr + ptr, buf + ptr, buf_sz - ptr);
|
|
|
|
esilstr = R_STRBUF_SAFEGET (&aop.esil);
|
|
|
|
if (len < 1) {
|
|
|
|
eprintf ("Invalid 0x%08"PFMT64x" instruction %02x %02x\n",
|
|
|
|
addr + ptr, buf[ptr], buf[ptr + 1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r_anal_esil_parse (esil, esilstr);
|
|
|
|
r_anal_esil_stack_free (esil);
|
|
|
|
}
|
2016-01-15 01:51:49 +00:00
|
|
|
esil->nowrite = false;
|
|
|
|
esil->cb.hook_reg_write = NULL;
|
|
|
|
esil->cb.hook_reg_read = NULL;
|
2016-01-15 00:50:08 +00:00
|
|
|
esil_fini (core);
|
2016-01-15 01:51:49 +00:00
|
|
|
|
|
|
|
/* show registers used */
|
|
|
|
if ((mode >> 1) & 1) {
|
|
|
|
showregs (stats.regread);
|
|
|
|
} else if ((mode >> 2) & 1) {
|
|
|
|
showregs (stats.regwrite);
|
|
|
|
} else if ((mode >> 3) & 1) {
|
2016-01-15 00:50:08 +00:00
|
|
|
RListIter *iter;
|
2016-01-15 01:51:49 +00:00
|
|
|
char *reg;
|
|
|
|
r_list_foreach (stats.regs, iter, reg) {
|
|
|
|
if (!contains (stats.regwrite, reg)) {
|
|
|
|
r_cons_printf ("%s", reg);
|
|
|
|
if (iter->n) r_cons_printf (" ");
|
|
|
|
}
|
2016-01-15 00:50:08 +00:00
|
|
|
}
|
|
|
|
r_cons_newline();
|
2016-01-15 01:51:49 +00:00
|
|
|
} else {
|
|
|
|
r_cons_printf ("A: ");
|
|
|
|
showregs (stats.regs);
|
|
|
|
r_cons_printf ("R: ");
|
|
|
|
showregs (stats.regread);
|
|
|
|
r_cons_printf ("W: ");
|
|
|
|
showregs (stats.regwrite);
|
|
|
|
r_cons_printf ("N: ");
|
|
|
|
{
|
|
|
|
RListIter *iter;
|
|
|
|
char *reg;
|
|
|
|
r_list_foreach (stats.regs, iter, reg) {
|
|
|
|
if (!contains (stats.regwrite, reg)) {
|
|
|
|
r_cons_printf ("%s", reg);
|
|
|
|
if (iter->n) r_cons_printf (" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_cons_newline();
|
|
|
|
}
|
2016-01-15 00:50:08 +00:00
|
|
|
}
|
2016-01-15 01:51:49 +00:00
|
|
|
aea_stats_fini (&stats);
|
2016-01-15 00:50:08 +00:00
|
|
|
free (buf);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:51:49 +00:00
|
|
|
static void aea_help(RCore *core) {
|
|
|
|
const char *help_msg[] = {
|
|
|
|
"Examples:", "aea", " show regs used in a range",
|
|
|
|
"aea", " [ops]", "Show regs used in N instructions",
|
|
|
|
"aeaf", "", "Show regs used in current function",
|
|
|
|
"aear", " [ops]", "Show regs read in N instructions",
|
|
|
|
"aeaw", " [ops]", "Show regs written in N instructions",
|
|
|
|
"aean", " [ops]", "Show regs not written in N instructions",
|
|
|
|
"aeA", " [len]", "Show regs used in N bytes (subcommands are the same)",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
|
|
|
|
2014-12-05 06:34:54 +00:00
|
|
|
static void cmd_anal_esil(RCore *core, const char *input) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-07-12 13:55:55 +00:00
|
|
|
"Usage:", "aep[-c] ", " [...]",
|
|
|
|
"aepc", " [addr]", "change program counter for esil",
|
|
|
|
"aep", "-[addr]", "remove pin",
|
|
|
|
"aep", " [name] @ [addr]", "set pin",
|
|
|
|
"aep", "", "list pins",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-12-05 17:56:33 +00:00
|
|
|
RAnalEsil *esil = core->anal->esil;
|
2014-12-05 06:34:54 +00:00
|
|
|
ut64 addr = core->offset;
|
2016-01-19 23:36:21 +00:00
|
|
|
int stacksize = r_config_get_i (core->config, "esil.stacksize");
|
2015-09-08 23:17:55 +00:00
|
|
|
int iotrap = r_config_get_i (core->config, "esil.iotrap");
|
2014-12-05 17:56:33 +00:00
|
|
|
int romem = r_config_get_i (core->config, "esil.romem");
|
|
|
|
int stats = r_config_get_i (core->config, "esil.stats");
|
|
|
|
ut64 until_addr = UT64_MAX;
|
|
|
|
const char *until_expr = NULL;
|
2015-01-30 00:55:21 +00:00
|
|
|
RAnalOp *op;
|
2014-12-05 06:34:54 +00:00
|
|
|
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-06-30 08:50:46 +00:00
|
|
|
case 'p': // "aep"
|
|
|
|
switch (input[1]) {
|
|
|
|
case 'c':
|
|
|
|
if (input[2] == ' ') {
|
|
|
|
// seek to this address
|
|
|
|
r_core_cmd0 (core, "aei"); // init vm
|
|
|
|
r_core_cmd0 (core, "aeim"); // init stack
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_cmdf (core, "ar PC=%s", input + 3);
|
2015-06-30 08:50:46 +00:00
|
|
|
r_core_cmd0 (core, ".ar*");
|
|
|
|
} else {
|
|
|
|
eprintf ("Missing argument\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
r_anal_pin_list (core->anal);
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
if (input[2])
|
2015-12-16 13:35:56 +00:00
|
|
|
addr = r_num_math (core->num, input + 2);
|
2015-06-30 08:50:46 +00:00
|
|
|
r_anal_pin_unset (core->anal, addr);
|
|
|
|
break;
|
|
|
|
case ' ':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_pin (core->anal, addr, input + 2);
|
2015-06-30 08:50:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
2015-06-16 08:45:54 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'r':
|
|
|
|
// 'aer' is an alias for 'ar'
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_reg (core, input + 1);
|
2015-02-22 10:18:40 +00:00
|
|
|
break;
|
2015-09-08 00:53:33 +00:00
|
|
|
case '*':
|
|
|
|
// XXX: this is wip, not working atm
|
2015-09-09 09:16:49 +00:00
|
|
|
if (core->anal->esil) {
|
2015-09-08 00:53:33 +00:00
|
|
|
r_cons_printf ("trap: %d\n", core->anal->esil->trap);
|
|
|
|
r_cons_printf ("trap-code: %d\n", core->anal->esil->trap_code);
|
|
|
|
} else {
|
|
|
|
eprintf ("esil vm not initialized. run `aei`\n");
|
|
|
|
}
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case ' ':
|
2014-12-05 17:56:33 +00:00
|
|
|
//r_anal_esil_eval (core->anal, input+1);
|
|
|
|
if (!esil) {
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!(core->anal->esil = esil = r_anal_esil_new (stacksize, iotrap)))
|
|
|
|
return;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2014-12-05 17:56:33 +00:00
|
|
|
r_anal_esil_setup (esil, core->anal, romem, stats); // setup io
|
2015-09-14 09:31:54 +00:00
|
|
|
r_anal_esil_set_pc (esil, core->offset);
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_esil_parse (esil, input + 1);
|
2014-12-05 17:56:33 +00:00
|
|
|
r_anal_esil_dumpstack (esil);
|
|
|
|
r_anal_esil_stack_free (esil);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2014-12-05 17:56:33 +00:00
|
|
|
case 's':
|
2015-01-30 00:55:21 +00:00
|
|
|
// "aes" "aeso" "aesu" "aesue"
|
2014-12-05 06:34:54 +00:00
|
|
|
// aes -> single step
|
2015-01-30 00:55:21 +00:00
|
|
|
// aeso -> single step over
|
2014-12-05 06:34:54 +00:00
|
|
|
// aesu -> until address
|
|
|
|
// aesue -> until esil expression
|
2015-01-30 00:55:21 +00:00
|
|
|
switch (input[1]) {
|
2015-08-31 09:53:03 +00:00
|
|
|
case '?':
|
|
|
|
eprintf ("See: ae?~aes\n");
|
|
|
|
break;
|
2015-10-03 12:48:20 +00:00
|
|
|
case 'l': // "aesl"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
ut64 pc = r_debug_reg_get (core->dbg, "PC");
|
|
|
|
RAnalOp *op = r_core_anal_op (core, pc);
|
|
|
|
if (!op) break;
|
|
|
|
esil_step (core, UT64_MAX, NULL);
|
|
|
|
r_debug_reg_set (core->dbg, "PC", pc + op->size);
|
|
|
|
r_anal_esil_set_pc (esil, pc + op->size);
|
|
|
|
r_core_cmd0 (core, ".ar*");
|
|
|
|
} break;
|
2015-09-08 23:17:55 +00:00
|
|
|
case 'u': // "aesu"
|
2015-01-30 00:55:21 +00:00
|
|
|
if (input[2] == 'e') {
|
|
|
|
until_expr = input + 3;
|
|
|
|
} else {
|
|
|
|
until_addr = r_num_math (core->num, input + 2);
|
|
|
|
}
|
|
|
|
esil_step (core, until_addr, until_expr);
|
2015-06-27 23:42:21 +00:00
|
|
|
r_core_cmd0 (core, ".ar*");
|
2015-01-30 00:55:21 +00:00
|
|
|
break;
|
2015-09-08 23:17:55 +00:00
|
|
|
case 'o': // "aeso"
|
2015-01-30 00:55:21 +00:00
|
|
|
// step over
|
|
|
|
op = r_core_anal_op (core, addr);
|
|
|
|
if (op && op->type == R_ANAL_OP_TYPE_CALL) {
|
|
|
|
until_addr = addr + op->size;
|
|
|
|
}
|
|
|
|
esil_step (core, until_addr, until_expr);
|
|
|
|
r_anal_op_free (op);
|
2015-06-27 23:42:21 +00:00
|
|
|
r_core_cmd0 (core, ".ar*");
|
2015-01-30 00:55:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
esil_step (core, until_addr, until_expr);
|
2015-06-27 23:42:21 +00:00
|
|
|
r_core_cmd0 (core, ".ar*");
|
2015-01-30 00:55:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2015-09-08 23:17:55 +00:00
|
|
|
if (input[1] == '?') { // "aec?"
|
|
|
|
eprintf ("aecs - continue until syscall\n");
|
|
|
|
eprintf ("aec - continue until exception\n");
|
|
|
|
eprintf ("aecu [addr] - continue until address\n");
|
|
|
|
eprintf ("aecue [expr] - continue until esil expression\n");
|
2015-12-16 13:35:56 +00:00
|
|
|
} else if (input[1] == 's') { // "aecs"
|
2015-09-08 23:17:55 +00:00
|
|
|
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
ut64 newaddr;
|
|
|
|
int ret;
|
|
|
|
for (;;) {
|
|
|
|
op = r_core_anal_op (core, addr);
|
|
|
|
if (!op) break;
|
|
|
|
if (op->type == R_ANAL_OP_TYPE_SWI) {
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("syscall at 0x%08" PFMT64x "\n", addr);
|
2015-09-08 23:17:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (op->type == R_ANAL_OP_TYPE_TRAP) {
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("trap at 0x%08" PFMT64x "\n", addr);
|
2015-09-08 23:17:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = esil_step (core, UT64_MAX, NULL);
|
|
|
|
r_anal_op_free (op);
|
|
|
|
if (core->anal->esil->trap || core->anal->esil->trap_code) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!ret)
|
|
|
|
break;
|
|
|
|
r_core_cmd0 (core, ".ar*");
|
|
|
|
newaddr = r_num_get (core->num, pc);
|
|
|
|
if (addr == newaddr) {
|
|
|
|
addr++;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
addr = newaddr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// "aec" -> continue until ^C
|
|
|
|
// "aecu" -> until address
|
|
|
|
// "aecue" -> until esil expression
|
|
|
|
if (input[1] == 'u' && input[2] == 'e')
|
|
|
|
until_expr = input + 3;
|
|
|
|
else if (input[1] == 'u')
|
|
|
|
until_addr = r_num_math (core->num, input + 2);
|
|
|
|
else until_expr = "0";
|
|
|
|
esil_step (core, until_addr, until_expr);
|
|
|
|
}
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2015-02-22 10:18:40 +00:00
|
|
|
case 'i': // "aei"
|
2015-12-16 13:35:56 +00:00
|
|
|
switch (input[1]) {
|
2015-06-22 22:01:41 +00:00
|
|
|
case 's':
|
2015-03-13 23:14:30 +00:00
|
|
|
case 'm':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_esil_mem (core, input + 2);
|
2015-01-27 11:46:15 +00:00
|
|
|
break;
|
2015-07-15 16:18:04 +00:00
|
|
|
case 'p': // initialize pc = $$
|
2015-11-20 13:46:23 +00:00
|
|
|
r_core_cmd0 (core, "ar PC=$$");
|
2015-07-15 16:18:04 +00:00
|
|
|
break;
|
2015-01-27 11:46:15 +00:00
|
|
|
case '?':
|
2015-03-13 23:14:30 +00:00
|
|
|
cmd_esil_mem (core, "?");
|
2015-01-29 11:16:37 +00:00
|
|
|
break;
|
2015-09-19 17:54:49 +00:00
|
|
|
case '-':
|
|
|
|
if (esil) {
|
|
|
|
sdb_reset (esil->stats);
|
|
|
|
}
|
|
|
|
r_anal_esil_free (esil);
|
|
|
|
core->anal->esil = NULL;
|
|
|
|
break;
|
2015-01-27 11:46:15 +00:00
|
|
|
case 0:
|
|
|
|
r_anal_esil_free (esil);
|
|
|
|
// reinitialize
|
2015-07-15 16:18:04 +00:00
|
|
|
{
|
|
|
|
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
|
|
|
|
if (r_reg_getv (core->anal->reg, pc) == 0LL) {
|
2015-11-05 15:45:45 +00:00
|
|
|
r_core_cmd0 (core, "ar PC=$$");
|
2015-07-15 16:18:04 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!(esil = core->anal->esil = r_anal_esil_new (stacksize, iotrap)))
|
|
|
|
return;
|
2015-01-27 11:46:15 +00:00
|
|
|
r_anal_esil_setup (esil, core->anal, romem, stats); // setup io
|
2015-03-12 15:45:23 +00:00
|
|
|
esil->debug = (int)r_config_get_i (core->config, "esil.debug");
|
2015-09-08 00:53:33 +00:00
|
|
|
/* restore user settings for interrupt handling */
|
2015-11-05 15:45:45 +00:00
|
|
|
{
|
|
|
|
const char *s = r_config_get (core->config, "cmd.esil.intr");
|
|
|
|
if (s) {
|
|
|
|
char *my = strdup (s);
|
2016-01-20 16:13:30 +00:00
|
|
|
if (my)
|
|
|
|
r_config_set (core->config, "cmd.esil.intr", my);
|
2015-11-05 15:45:45 +00:00
|
|
|
free (my);
|
|
|
|
}
|
|
|
|
}
|
2015-01-27 11:46:15 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'k':
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[1]) {
|
2014-12-09 16:45:44 +00:00
|
|
|
case '\0':
|
|
|
|
input = "123*";
|
|
|
|
case ' ':
|
2015-04-01 14:06:53 +00:00
|
|
|
if (esil && esil->stats) {
|
2015-12-16 13:35:56 +00:00
|
|
|
char *out = sdb_querys (esil->stats, NULL, 0, input + 2);
|
2014-12-09 16:45:44 +00:00
|
|
|
if (out) {
|
|
|
|
r_cons_printf ("%s\n", out);
|
|
|
|
free (out);
|
|
|
|
}
|
|
|
|
} else eprintf ("esil.stats is empty. Run 'aei'\n");
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-10-18 19:38:06 +00:00
|
|
|
case 'f': // "aef"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal,
|
|
|
|
core->offset, R_ANAL_FCN_TYPE_FCN | R_ANAL_FCN_TYPE_SYM);
|
|
|
|
if (fcn) {
|
|
|
|
// emulate every instruction in the function recursively across all the basic blocks
|
|
|
|
r_list_foreach (fcn->bbs, iter, bb) {
|
|
|
|
ut64 pc = bb->addr;
|
|
|
|
ut64 end = bb->addr + bb->size;
|
|
|
|
RAnalOp op;
|
|
|
|
ut8 *buf;
|
|
|
|
int ret, bbs = end - pc;
|
|
|
|
if (bbs < 1 || bbs > 0xfffff) {
|
|
|
|
eprintf ("Invalid block size\n");
|
|
|
|
}
|
|
|
|
eprintf ("Emulate basic block 0x%08" PFMT64x " - 0x%08" PFMT64x "\n", pc, end);
|
|
|
|
buf = malloc (bbs + 1);
|
|
|
|
r_io_read_at (core->io, pc, buf, bbs);
|
|
|
|
while (pc < end) {
|
|
|
|
r_asm_set_pc (core->assembler, pc);
|
|
|
|
ret = r_anal_op (core->anal, &op, addr, buf, 32); // read overflow
|
|
|
|
if (ret) {
|
|
|
|
r_reg_setv (core->anal->reg, "PC", pc);
|
|
|
|
r_anal_esil_parse (esil, R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
r_anal_esil_dumpstack (esil);
|
|
|
|
r_anal_esil_stack_free (esil);
|
|
|
|
pc += op.size;
|
|
|
|
} else {
|
|
|
|
pc += 4; // XXX
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
}
|
|
|
|
} else eprintf ("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
|
|
} break;
|
2015-04-26 12:35:37 +00:00
|
|
|
case 't': // "aet"
|
2015-03-30 13:15:25 +00:00
|
|
|
switch (input[1]) {
|
2015-09-08 00:53:33 +00:00
|
|
|
case 'r': // "aetr"
|
2015-12-16 13:35:56 +00:00
|
|
|
{
|
|
|
|
// anal ESIL to REIL.
|
2016-01-19 23:36:21 +00:00
|
|
|
RAnalEsil *esil = r_anal_esil_new (stacksize, iotrap);
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!esil)
|
|
|
|
return;
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_esil_to_reil_setup (esil, core->anal, romem, stats);
|
|
|
|
r_anal_esil_set_pc (esil, core->offset);
|
|
|
|
r_anal_esil_parse (esil, input + 2);
|
|
|
|
r_anal_esil_dumpstack (esil);
|
2016-01-19 23:36:21 +00:00
|
|
|
r_anal_esil_free (esil);
|
2015-12-16 13:35:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-08 00:53:33 +00:00
|
|
|
default:
|
|
|
|
eprintf ("Unknown command. Use `aetr`.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2016-01-15 01:51:49 +00:00
|
|
|
case 'A': // "aeA"
|
|
|
|
if (input[1] == '?') {
|
|
|
|
aea_help (core);
|
|
|
|
} else if (input[1] == 'r') {
|
|
|
|
cmd_aea (core, 1 + (1<<1), core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'w') {
|
|
|
|
cmd_aea (core, 1 + (1<<2), core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'n') {
|
|
|
|
cmd_aea (core, 1 + (1<<3), core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'f') {
|
2016-01-15 00:50:08 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
|
|
|
if (fcn) cmd_aea (core, 1, fcn->addr, fcn->size);
|
|
|
|
} else {
|
|
|
|
cmd_aea (core, 1, core->offset, (int)r_num_math (core->num, input+2));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a': // "aea"
|
2016-01-15 01:51:49 +00:00
|
|
|
if (input[1] == '?') {
|
|
|
|
aea_help (core);
|
|
|
|
} else if (input[1] == 'r') {
|
|
|
|
cmd_aea (core, 1<<1, core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'w') {
|
|
|
|
cmd_aea (core, 1<<2, core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'n') {
|
|
|
|
cmd_aea (core, 1<<3, core->offset, r_num_math (core->num, input+2));
|
|
|
|
} else if (input[1] == 'f') {
|
2016-01-15 00:50:08 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
|
|
|
if (fcn) cmd_aea (core, 1, fcn->addr, fcn->size);
|
|
|
|
} else {
|
|
|
|
cmd_aea (core, 0, core->offset, r_num_math (core->num, input+2));
|
|
|
|
}
|
|
|
|
break;
|
2015-04-01 01:01:44 +00:00
|
|
|
case '?':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == '?') {
|
|
|
|
const char *help_msg[] = {
|
2015-04-01 01:01:44 +00:00
|
|
|
"Examples:", "ESIL", " examples and documentation",
|
|
|
|
"+", "=", "A+=B => B,A,+=",
|
|
|
|
"+", "", "A=A+B => B,A,+,A,=",
|
|
|
|
"*", "=", "A*=B => B,A,*=",
|
|
|
|
"/", "=", "A/=B => B,A,/=",
|
|
|
|
"&", "=", "and ax, bx => bx,ax,&=",
|
|
|
|
"|", "", "or r0, r1, r2 => r2,r1,|,r0,=",
|
|
|
|
"^", "=", "xor ax, bx => bx,ax,^=",
|
|
|
|
">>", "=", "shr ax, bx => bx,ax,>>= # shift right",
|
|
|
|
"<<", "=", "shr ax, bx => bx,ax,<<= # shift left",
|
|
|
|
"", "[]", "mov eax,[eax] => eax,[],eax,=",
|
|
|
|
"=", "[]", "mov [eax+3], 1 => 1,3,eax,+,=[]",
|
|
|
|
"=", "[1]", "mov byte[eax],1 => 1,eax,=[1]",
|
|
|
|
"=", "[8]", "mov [rax],1 => 1,rax,=[8]",
|
|
|
|
"$", "", "int 0x80 => 0x80,$",
|
|
|
|
"$$", "", "simulate a hardware trap",
|
|
|
|
"==", "", "pops twice, compare and update esil flags",
|
|
|
|
"<", "", "compare for smaller",
|
|
|
|
"<", "=", "compare for smaller or equal",
|
|
|
|
">", "", "compare for bigger",
|
|
|
|
">", "=", "compare bigger for or equal",
|
2016-01-21 22:21:11 +00:00
|
|
|
"?{", "", "if popped value != 0 run the block until }",
|
2015-04-01 01:01:44 +00:00
|
|
|
"POP", "", "drops last element in the esil stack",
|
|
|
|
"TODO", "", "the instruction is not yet esilized",
|
|
|
|
"STACK", "", "show contents of stack",
|
|
|
|
"CLEAR", "", "clears the esil stack",
|
|
|
|
"BREAK", "", "terminates the string parsing",
|
2016-01-21 22:21:11 +00:00
|
|
|
"GOTO", "", "jump to the Nth word popped from the stack",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2015-04-01 01:01:44 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
/* fall through */
|
|
|
|
default: {
|
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "ae[idesr?] [arg]", "ESIL code emulation",
|
|
|
|
"ae?", "", "show this help",
|
|
|
|
"ae??", "", "show ESIL help",
|
|
|
|
"aei", "", "initialize ESIL VM state (aei- to deinitialize)",
|
|
|
|
"aeim", "", "initialize ESIL VM stack (aeim- remove)",
|
|
|
|
"aeip", "", "initialize ESIL program counter to curseek",
|
|
|
|
"ae", " [expr]", "evaluate ESIL expression",
|
2016-01-15 01:51:49 +00:00
|
|
|
"ae[aA]", "[f] [count]", "analyse esil accesses (regs, mem..)",
|
2015-12-16 13:35:56 +00:00
|
|
|
"aep", " [addr]", "change esil PC to this address",
|
|
|
|
"aef", " [addr]", "emulate function",
|
|
|
|
"aek", " [query]", "perform sdb query on ESIL.info",
|
|
|
|
"aek-", "", "resets the ESIL.info sdb instance",
|
|
|
|
"aec", "", "continue until ^C",
|
|
|
|
"aecs", " [sn]", "continue until syscall number",
|
|
|
|
"aecu", " [addr]", "continue until address",
|
|
|
|
"aecue", " [esil]", "continue until esil expression match",
|
|
|
|
"aetr", "[esil]", "Convert an ESIL Expression to REIL",
|
|
|
|
"aes", "", "perform emulated debugger step",
|
|
|
|
"aeso", " ", "step over",
|
|
|
|
"aesu", " [addr]", "step until given address",
|
|
|
|
"aesue", " [esil]", "step until esil expression match",
|
|
|
|
"aer", " [..]", "handle ESIL registers like 'ar' or 'dr' does",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} break;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-12 12:47:44 +00:00
|
|
|
static void cmd_anal_noreturn(RCore *core, const char *input) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-11-12 12:47:44 +00:00
|
|
|
"Usage:", "an [-][0xaddr|symname]", " manage no-return marks",
|
|
|
|
"an[a]", " 0x3000", "stop function analysis if call/jmp to this address",
|
|
|
|
"an[n]", " sym.imp.exit", "same as above but for flag/fcn names",
|
|
|
|
"an", "-*", "remove all no-return references",
|
|
|
|
"an", "", "list them all",
|
2015-11-20 13:46:23 +00:00
|
|
|
NULL };
|
2015-11-12 12:47:44 +00:00
|
|
|
switch (input[0]) {
|
|
|
|
case '-':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_noreturn_drop (core->anal, input + 1);
|
2015-11-12 12:47:44 +00:00
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
if (input[1] == '0' && input[2] == 'x') {
|
|
|
|
r_anal_noreturn_add (core->anal, NULL,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, input + 1));
|
2015-11-12 12:47:44 +00:00
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_noreturn_add (core->anal, input + 1,
|
|
|
|
r_num_math (core->num, input + 1));
|
2015-11-12 12:47:44 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
if (input[1] == ' ') {
|
|
|
|
r_anal_noreturn_add (core->anal, NULL,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, input + 1));
|
2015-11-12 12:47:44 +00:00
|
|
|
} else r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
if (input[1] == ' ') {
|
|
|
|
} else r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
case 'r':
|
|
|
|
r_anal_noreturn_list (core->anal, 1);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
r_anal_noreturn_list (core->anal, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case '?':
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-05 06:34:54 +00:00
|
|
|
static void cmd_anal_opcode(RCore *core, const char *input) {
|
|
|
|
int l, len = core->blocksize;
|
|
|
|
ut32 tbs = core->blocksize;
|
|
|
|
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
case '?': {
|
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "ao[e?] [len]", "Analyze Opcodes",
|
|
|
|
"aoj", "", "display opcode analysis information in JSON",
|
|
|
|
"aoe", "", "emulate opcode at current offset",
|
|
|
|
"aos", " [esil]", "show sdb representation of esil expression (TODO)",
|
|
|
|
"aoe", " 4", "emulate 4 opcodes starting at current offset",
|
|
|
|
"ao", " 5", "display opcode analysis of 5 opcodes",
|
|
|
|
"ao*", "", "display opcode in r commands",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} break;
|
|
|
|
case 'j': {
|
|
|
|
int count = 1;
|
|
|
|
if (input[1] && input[2]) {
|
|
|
|
l = (int)r_num_get (core->num, input + 1);
|
|
|
|
if (l > 0) count = l;
|
|
|
|
if (l > tbs) {
|
|
|
|
r_core_block_size (core, l * 4);
|
|
|
|
//len = l;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} else {
|
|
|
|
len = l = core->blocksize;
|
|
|
|
count = 1;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
core_anal_bytes (core, core->block, len, count, 'j');
|
|
|
|
} break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'e':
|
|
|
|
eprintf ("TODO: See 'ae' command\n");
|
|
|
|
break;
|
2015-05-21 19:05:22 +00:00
|
|
|
case '*':
|
|
|
|
r_core_anal_hint_list (core->anal, input[0]);
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
default: {
|
|
|
|
int count = 0;
|
|
|
|
if (input[0]) {
|
|
|
|
l = (int)r_num_get (core->num, input + 1);
|
|
|
|
if (l > 0) count = l;
|
|
|
|
if (l > tbs) {
|
|
|
|
r_core_block_size (core, l * 4);
|
|
|
|
//len = l;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} else {
|
|
|
|
len = l = core->blocksize;
|
|
|
|
count = 1;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
core_anal_bytes (core, core->block, len, count, 0);
|
|
|
|
}
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-06 22:30:48 +00:00
|
|
|
static void cmd_anal_jumps(RCore *core, const char *input) {
|
|
|
|
r_core_cmdf (core, "af @@= `ax~ref.code.jmp[1]`");
|
|
|
|
}
|
|
|
|
|
2014-12-13 10:28:17 +00:00
|
|
|
static void cmd_anal_calls(RCore *core, const char *input) {
|
2015-11-17 01:38:01 +00:00
|
|
|
int bufi, minop = 1; // 4
|
|
|
|
ut8 *buf;
|
2015-05-23 11:35:31 +00:00
|
|
|
RBinFile *binfile;
|
2014-12-13 10:28:17 +00:00
|
|
|
RAnalOp op;
|
|
|
|
ut64 addr, addr_end;
|
2015-12-01 17:30:11 +00:00
|
|
|
int depth = r_config_get_i (core->config, "anal.depth");
|
2015-01-18 01:49:19 +00:00
|
|
|
ut64 len = r_num_math (core->num, input);
|
2014-12-13 10:28:17 +00:00
|
|
|
if (len > 0xffffff) {
|
|
|
|
eprintf ("Too big\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-05-23 11:35:31 +00:00
|
|
|
binfile = r_core_bin_cur (core);
|
2015-11-16 23:59:24 +00:00
|
|
|
if (!binfile) {
|
2015-05-23 11:35:31 +00:00
|
|
|
eprintf ("cur binfile null\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-11-19 22:49:45 +00:00
|
|
|
addr = core->offset;
|
2015-11-17 11:22:09 +00:00
|
|
|
if (!len) {
|
2015-11-19 22:49:45 +00:00
|
|
|
// ignore search.in to avoid problems. analysis != search
|
|
|
|
RIOSection *s = r_io_section_vget (core->io, addr);
|
|
|
|
if (s && s->rwx & 1) {
|
|
|
|
// search in current section
|
2015-11-19 23:29:16 +00:00
|
|
|
if (s->size > binfile->size) {
|
|
|
|
addr = s->vaddr;
|
|
|
|
len = binfile->size - s->offset;
|
|
|
|
} else {
|
|
|
|
addr = s->vaddr;
|
|
|
|
len = s->size;
|
|
|
|
}
|
2015-11-19 22:49:45 +00:00
|
|
|
} else {
|
|
|
|
// search in full file
|
|
|
|
ut64 o = r_io_section_vaddr_to_maddr (core->io, core->offset);
|
2015-11-19 23:14:24 +00:00
|
|
|
if (o != UT64_MAX && binfile->size > o) {
|
2015-11-19 22:49:45 +00:00
|
|
|
len = binfile->size - o;
|
|
|
|
} else {
|
2015-11-19 23:14:24 +00:00
|
|
|
if (binfile->size > core->offset) {
|
|
|
|
len = binfile->size - core->offset;
|
|
|
|
} else {
|
|
|
|
eprintf ("Oops invalid range\n");
|
|
|
|
len = 0;
|
|
|
|
}
|
2015-11-19 22:49:45 +00:00
|
|
|
}
|
2015-11-16 23:59:24 +00:00
|
|
|
}
|
2015-05-23 11:35:31 +00:00
|
|
|
}
|
2015-11-19 22:49:45 +00:00
|
|
|
/*
|
2015-12-16 13:35:56 +00:00
|
|
|
if (core->offset + len > binfile->size) {
|
|
|
|
len = binfile->size - core->offset;
|
|
|
|
}
|
|
|
|
*/
|
2014-12-13 10:28:17 +00:00
|
|
|
addr_end = addr + len;
|
2015-10-14 10:34:18 +00:00
|
|
|
r_cons_break (NULL, NULL);
|
2015-11-17 01:38:01 +00:00
|
|
|
buf = malloc (4096);
|
|
|
|
if (!buf) return;
|
|
|
|
bufi = 0;
|
2014-12-13 10:28:17 +00:00
|
|
|
while (addr < addr_end) {
|
2015-09-07 16:12:08 +00:00
|
|
|
if (core->cons->breaked)
|
|
|
|
break;
|
2015-11-17 00:14:18 +00:00
|
|
|
// TODO: too many ioreads here
|
2015-12-16 13:35:56 +00:00
|
|
|
if (bufi > 4000) bufi = 0;
|
2015-11-17 01:38:01 +00:00
|
|
|
if (!bufi) {
|
|
|
|
r_io_read_at (core->io, addr, buf, 4096);
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
if (r_anal_op (core->anal, &op, addr, buf + bufi, 4096 - bufi)) {
|
2015-11-17 00:14:18 +00:00
|
|
|
if (op.size < 1) op.size = minop; // XXX must be +4 on arm/mips/.. like we do in disasm.c
|
2014-12-13 10:28:17 +00:00
|
|
|
if (op.type == R_ANAL_OP_TYPE_CALL) {
|
2015-12-14 16:03:20 +00:00
|
|
|
r_core_anal_fcn (core, op.jump, addr,
|
2015-12-01 17:30:11 +00:00
|
|
|
R_ANAL_REF_TYPE_NULL, depth);
|
2014-12-13 10:28:17 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
op.size = minop;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
addr += (op.size > 0)? op.size: 1;
|
|
|
|
bufi += (op.size > 0)? op.size: 1;
|
2014-12-13 10:28:17 +00:00
|
|
|
}
|
2015-11-17 01:38:01 +00:00
|
|
|
free (buf);
|
2014-12-13 10:28:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 02:07:22 +00:00
|
|
|
static void cmd_asf(RCore *core, const char *input) {
|
|
|
|
char *ret;
|
|
|
|
if (input[0] == ' ') {
|
2015-12-16 13:35:56 +00:00
|
|
|
ret = sdb_querys (core->anal->sdb_fcnsign, NULL, 0, input + 1);
|
2015-10-30 02:07:22 +00:00
|
|
|
} else {
|
|
|
|
ret = sdb_querys (core->anal->sdb_fcnsign, NULL, 0, "*");
|
|
|
|
}
|
2015-10-30 02:34:40 +00:00
|
|
|
if (ret && *ret)
|
|
|
|
r_cons_printf ("%s\n", ret);
|
|
|
|
free (ret);
|
2015-10-30 02:07:22 +00:00
|
|
|
}
|
|
|
|
|
2014-12-05 06:34:54 +00:00
|
|
|
static void cmd_anal_syscall(RCore *core, const char *input) {
|
2014-12-05 17:56:33 +00:00
|
|
|
RSyscallItem *si;
|
|
|
|
RListIter *iter;
|
|
|
|
RList *list;
|
2015-01-30 00:55:21 +00:00
|
|
|
char *out;
|
|
|
|
int n;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-01-30 00:55:21 +00:00
|
|
|
"Usage: as[ljk?]", "", "syscall name <-> number utility",
|
|
|
|
"as", "", "show current syscall and arguments",
|
|
|
|
"as", " 4", "show syscall 4 based on asm.os and current regs/mem",
|
2015-10-30 02:07:22 +00:00
|
|
|
"asf", " [k[=[v]]]", "list/set/unset pf function signatures (see fcnsign)",
|
2015-01-30 00:55:21 +00:00
|
|
|
"asj", "", "list of syscalls in JSON",
|
|
|
|
"asl", "", "list of syscalls by asm.os and asm.arch",
|
|
|
|
"asl", " close", "returns the syscall number for close",
|
|
|
|
"asl", " 4", "returns the name of the syscall number 4",
|
|
|
|
"ask", " [query]", "perform syscall/ queries",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-12-05 17:56:33 +00:00
|
|
|
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-10-30 02:07:22 +00:00
|
|
|
case 'f': // "asf"
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_asf (core, input + 1);
|
2015-10-30 02:07:22 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'l': // "asl"
|
2014-12-05 06:51:21 +00:00
|
|
|
if (input[1] == ' ') {
|
2015-12-16 13:35:56 +00:00
|
|
|
if ((n = atoi (input + 2)) > 0) {
|
2014-12-05 17:56:33 +00:00
|
|
|
si = r_syscall_get (core->anal->syscall, n, -1);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (si)
|
|
|
|
r_cons_printf ("%s\n", si->name);
|
2014-12-05 06:34:54 +00:00
|
|
|
else eprintf ("Unknown syscall number\n");
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
n = r_syscall_get_num (core->anal->syscall, input + 2);
|
|
|
|
if (n != -1)
|
|
|
|
r_cons_printf ("%d\n", n);
|
2014-12-05 06:34:54 +00:00
|
|
|
else eprintf ("Unknown syscall name\n");
|
|
|
|
}
|
|
|
|
} else {
|
2014-12-05 17:56:33 +00:00
|
|
|
list = r_syscall_list (core->anal->syscall);
|
2014-12-05 06:34:54 +00:00
|
|
|
r_list_foreach (list, iter, si) {
|
|
|
|
r_cons_printf ("%s = 0x%02x.%d\n",
|
2015-12-16 13:35:56 +00:00
|
|
|
si->name, si->swi, si->num);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
r_list_free (list);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'j': // "asj"
|
2014-12-05 17:56:33 +00:00
|
|
|
list = r_syscall_list (core->anal->syscall);
|
|
|
|
r_cons_printf ("[");
|
|
|
|
r_list_foreach (list, iter, si) {
|
|
|
|
r_cons_printf ("{\"name\":\"%s\","
|
2015-12-16 13:35:56 +00:00
|
|
|
"\"swi\":\"%d\",\"num\":\"%d\"}",
|
|
|
|
si->name, si->swi, si->num);
|
2014-12-05 17:56:33 +00:00
|
|
|
if (iter->n) r_cons_printf (",");
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2014-12-05 17:56:33 +00:00
|
|
|
r_cons_printf ("]\n");
|
|
|
|
r_list_free (list);
|
2014-12-05 06:34:54 +00:00
|
|
|
// JSON support
|
|
|
|
break;
|
|
|
|
case '\0':
|
2015-10-29 10:54:00 +00:00
|
|
|
cmd_syscall_do (core, -1); //n);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case ' ':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_syscall_do (core, (int)r_num_get (core->num, input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'k': // "ask"
|
2015-12-16 13:35:56 +00:00
|
|
|
out = sdb_querys (core->anal->syscall->db, NULL, 0, input + 2);
|
2015-01-30 00:55:21 +00:00
|
|
|
if (out) {
|
|
|
|
r_cons_printf ("%s\n", out);
|
|
|
|
free (out);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case '?':
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-03 01:05:13 +00:00
|
|
|
static bool cmd_anal_refs(RCore *core, const char *input) {
|
2014-12-05 06:34:54 +00:00
|
|
|
ut64 addr = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-01-30 00:55:21 +00:00
|
|
|
"Usage:", "ax[?d-l*]", " # see also 'afx?'",
|
|
|
|
"ax", " addr [at]", "add code ref pointing to addr (from curseek)",
|
|
|
|
"axc", " addr [at]", "add code jmp ref // unused?",
|
|
|
|
"axC", " addr [at]", "add code call ref",
|
|
|
|
"axd", " addr [at]", "add data ref",
|
|
|
|
"axj", "", "list refs in json format",
|
|
|
|
"axF", " [flg-glob]", "find data/code references of flags",
|
|
|
|
"axt", " [addr]", "find data/code references to this address",
|
|
|
|
"axf", " [addr]", "find data/code references from this address",
|
|
|
|
"ax-", " [at]", "clean all refs (or refs from addr)",
|
|
|
|
"ax", "", "list refs",
|
|
|
|
"axk", " [query]", "perform sdb query",
|
|
|
|
"ax*", "", "output radare commands",
|
|
|
|
NULL };
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
case '-': { // "ax-"
|
|
|
|
const char *inp;
|
|
|
|
ut64 a, b;
|
|
|
|
for (inp = input + 1; *inp && IS_WHITESPACE (*inp); inp++)
|
|
|
|
;
|
|
|
|
if (!strcmp (inp, "*")) {
|
|
|
|
r_anal_xrefs_init (core->anal);
|
|
|
|
} else {
|
|
|
|
char *p = strdup (inp);
|
|
|
|
char *q = strchr (p, ' ');
|
|
|
|
a = r_num_math (core->num, p);
|
|
|
|
if (q) {
|
|
|
|
*q++ = 0;
|
|
|
|
b = r_num_math (core->num, q);
|
2015-07-08 18:43:02 +00:00
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
//b = UT64_MAX;
|
|
|
|
b = core->offset;
|
2015-07-08 18:43:02 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_ref_del (core->anal, b, a);
|
|
|
|
free (p);
|
2015-07-08 18:43:02 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2016-01-27 01:49:40 +00:00
|
|
|
case 'k': // "axk"
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == ' ') {
|
|
|
|
sdb_query (core->anal->sdb_xrefs, input + 2);
|
2014-12-05 06:34:54 +00:00
|
|
|
} else eprintf ("|ERROR| Usage: axk [query]\n");
|
|
|
|
break;
|
|
|
|
case '\0':
|
2016-01-27 01:49:40 +00:00
|
|
|
case 'j': // "axj"
|
|
|
|
case '*': // "ax*"
|
2014-12-05 06:51:21 +00:00
|
|
|
r_core_anal_ref_list (core, input[0]);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2016-01-27 01:49:40 +00:00
|
|
|
case 't': { // "axt"
|
2015-12-16 13:35:56 +00:00
|
|
|
const int size = 12;
|
|
|
|
RList *list;
|
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
|
|
|
ut8 buf[12];
|
|
|
|
RAsmOp asmop;
|
|
|
|
char *buf_asm = NULL;
|
|
|
|
char *space = strchr (input, ' ');
|
|
|
|
|
|
|
|
if (space) {
|
|
|
|
addr = r_num_math (core->num, space + 1);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
|
|
|
list = r_anal_xrefs_get (core->anal, addr);
|
|
|
|
if (list) {
|
|
|
|
if (input[1] == 'q') { // "axtq"
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("0x%" PFMT64x "\n", ref->addr);
|
|
|
|
} else if (input[1] == 'j') { // "axtj"
|
|
|
|
r_cons_printf ("[");
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->addr, buf, size);
|
|
|
|
r_asm_set_pc (core->assembler, ref->addr);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, size);
|
2014-12-05 06:34:54 +00:00
|
|
|
char str[512];
|
2015-12-16 13:35:56 +00:00
|
|
|
r_parse_filter (core->parser, core->flags,
|
|
|
|
asmop.buf_asm, str, sizeof (str));
|
|
|
|
r_cons_printf ("{\"from\":%" PFMT64u ",\"type\":\"%c\",\"opcode\":\"%s\"}%s",
|
|
|
|
ref->addr, ref->type, str, iter->n? ",": "");
|
|
|
|
}
|
|
|
|
r_cons_printf ("]");
|
|
|
|
r_cons_newline ();
|
|
|
|
} else if (input[1] == '*') { // axt*
|
|
|
|
// TODO: implement multi-line comments
|
|
|
|
r_list_foreach (list, iter, ref)
|
2016-01-27 01:49:40 +00:00
|
|
|
r_cons_printf ("CCa 0x%" PFMT64x " \"XREF type %d at 0x%" PFMT64x"%s\n",
|
|
|
|
ref->addr, ref->type, addr, iter->n? ",": "");
|
2015-12-16 13:35:56 +00:00
|
|
|
} else { // axt
|
|
|
|
int has_color = core->print->flags & R_PRINT_FLAGS_COLOR;
|
|
|
|
char str[512];
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
char *buf_fcn;
|
|
|
|
char *comment;
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->addr, buf, size);
|
|
|
|
r_asm_set_pc (core->assembler, ref->addr);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, size);
|
|
|
|
r_parse_filter (core->parser, core->flags,
|
|
|
|
asmop.buf_asm, str, sizeof (str));
|
|
|
|
fcn = r_anal_get_fcn_in (core->anal, ref->addr, 0);
|
|
|
|
if (has_color) {
|
|
|
|
buf_asm = r_print_colorize_opcode (str, core->cons->pal.reg,
|
|
|
|
core->cons->pal.num);
|
|
|
|
} else {
|
|
|
|
buf_asm = r_str_new (str);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, ref->addr);
|
|
|
|
if (comment) {
|
2016-01-17 19:18:17 +00:00
|
|
|
buf_fcn = r_str_newf ("%s; %s", fcn ?
|
|
|
|
fcn->name : "unknown function",
|
|
|
|
strtok (comment, "\n"));
|
2015-12-16 13:35:56 +00:00
|
|
|
} else {
|
2016-01-17 19:18:17 +00:00
|
|
|
buf_fcn = r_str_newf ("%s", fcn ? fcn->name : "unknown function");
|
2015-12-16 13:35:56 +00:00
|
|
|
}
|
2016-02-09 17:38:55 +00:00
|
|
|
r_cons_printf ("%s 0x%" PFMT64x " %s in %s\n",
|
|
|
|
r_anal_ref_to_string (core->anal, ref->type),
|
|
|
|
ref->addr, buf_asm, buf_fcn);
|
2015-12-16 13:35:56 +00:00
|
|
|
free (buf_asm);
|
|
|
|
free (buf_fcn);
|
2014-01-31 01:40:16 +00:00
|
|
|
}
|
2014-01-31 01:02:51 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
r_list_free (list);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
|
|
|
case 'f': {
|
|
|
|
ut8 buf[12];
|
|
|
|
RAsmOp asmop;
|
|
|
|
char *buf_asm = NULL;
|
|
|
|
RList *list;
|
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
|
|
|
char *space = strchr (input, ' ');
|
|
|
|
|
|
|
|
if (space) {
|
|
|
|
addr = r_num_math (core->num, space + 1);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
|
|
|
list = r_anal_xrefs_get_from (core->anal, addr);
|
|
|
|
if (list) {
|
|
|
|
if (input[1] == 'q') { // axfq
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("0x%" PFMT64x "\n", ref->at);
|
|
|
|
} else if (input[1] == 'j') { // axfj
|
|
|
|
r_cons_printf ("[");
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->at, buf, 12);
|
|
|
|
r_asm_set_pc (core->assembler, ref->at);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
|
|
|
r_cons_printf ("{\"from\":0x%" PFMT64x ",\"type\":\"%c\",\"opcode\":\"%s\"}%s",
|
|
|
|
ref->at, ref->type, asmop.buf_asm, iter->n? ",": "");
|
|
|
|
}
|
|
|
|
r_cons_printf ("]\n");
|
|
|
|
} else if (input[1] == '*') { // axf*
|
|
|
|
// TODO: implement multi-line comments
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("CCa 0x%" PFMT64x " \"XREF from 0x%" PFMT64x "\n",
|
|
|
|
ref->at, ref->type, asmop.buf_asm, iter->n? ",": "");
|
|
|
|
} else { // axf
|
|
|
|
char str[512];
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->at, buf, 12);
|
|
|
|
r_asm_set_pc (core->assembler, ref->at);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
|
|
|
r_parse_filter (core->parser, core->flags,
|
|
|
|
asmop.buf_asm, str, sizeof (str));
|
|
|
|
buf_asm = r_print_colorize_opcode (str, core->cons->pal.reg,
|
|
|
|
core->cons->pal.num);
|
|
|
|
r_cons_printf ("%c 0x%" PFMT64x " %s\n",
|
|
|
|
ref->type, ref->at, buf_asm);
|
|
|
|
free (buf_asm);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
r_list_free (list);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
} break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'F':
|
2015-12-16 13:35:56 +00:00
|
|
|
find_refs (core, input + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2016-02-09 17:52:26 +00:00
|
|
|
case 'C': // "axC"
|
|
|
|
case 'c': // "axc"
|
|
|
|
case 'd': // "axd"
|
2015-12-16 13:35:56 +00:00
|
|
|
case ' ': {
|
|
|
|
char *ptr = strdup (r_str_trim_head ((char *)input + 1));
|
|
|
|
int n = r_str_word_set0 (ptr);
|
|
|
|
ut64 at = core->offset;
|
|
|
|
ut64 addr = UT64_MAX;
|
|
|
|
switch (n) {
|
|
|
|
case 2: // get at
|
|
|
|
at = r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
2016-02-09 17:52:26 +00:00
|
|
|
/* fall through */
|
2015-12-16 13:35:56 +00:00
|
|
|
case 1: // get addr
|
|
|
|
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
break;
|
|
|
|
default:
|
2014-12-05 06:34:54 +00:00
|
|
|
free (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
return false;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_ref_add (core->anal, addr, at, input[0]);
|
|
|
|
free (ptr);
|
|
|
|
} break;
|
2014-12-05 06:34:54 +00:00
|
|
|
default:
|
|
|
|
case '?':
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-09-14 10:35:38 +00:00
|
|
|
return true;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2015-01-30 00:55:21 +00:00
|
|
|
/*
|
2015-12-16 13:35:56 +00:00
|
|
|
in core/disasm we call
|
|
|
|
R_API int r_core_hint(RCore *core, ut64 addr) {
|
|
|
|
static int hint_bits = 0;
|
|
|
|
RAnalHint *hint = r_anal_hint_get (core->anal, addr);
|
|
|
|
if (hint->bits) {
|
|
|
|
if (!hint_bits)
|
|
|
|
hint_bits = core->assembler->bits;
|
|
|
|
r_config_set_i (core->config, "asm.bits", hint->bits);
|
|
|
|
} else if (hint_bits) {
|
|
|
|
r_config_set_i (core->config, "asm.bits", hint_bits);
|
|
|
|
hint_bits = 0;
|
|
|
|
}
|
|
|
|
if (hint->arch)
|
|
|
|
r_config_set (core->config, "asm.arch", hint->arch);
|
|
|
|
if (hint->length)
|
|
|
|
force_instruction_length = hint->length;
|
|
|
|
r_anal_hint_free (hint);
|
|
|
|
}
|
|
|
|
*/
|
2015-01-30 00:55:21 +00:00
|
|
|
|
|
|
|
static void cmd_anal_hint(RCore *core, const char *input) {
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-01-30 00:55:21 +00:00
|
|
|
"Usage:", "ah[lba-]", "Analysis Hints",
|
|
|
|
"ah?", "", "show this help",
|
|
|
|
"ah?", " offset", "show hint of given offset",
|
|
|
|
"ah", "", "list hints in human-readable format",
|
|
|
|
"ah-", "", "remove all hints",
|
|
|
|
"ah-", " offset [size]", "remove hints at given offset",
|
|
|
|
"ah*", " offset", "list hints in radare commands format",
|
|
|
|
"aha", " ppc 51", "set arch for a range of N bytes",
|
2015-12-16 13:35:56 +00:00
|
|
|
"ahb", " 16 @ $$", "force 16bit for current instruction",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ahc", " 0x804804", "override call/jump address",
|
|
|
|
"ahf", " 0x804840", "override fallback address for call",
|
2016-01-16 23:46:57 +00:00
|
|
|
"ahi", " 10", "define numeric base for immediates (1, 8, 10, 16, s)",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ahs", " 4", "set opcode size=4",
|
2015-05-09 22:12:33 +00:00
|
|
|
"ahS", " jz", "set asm.syntax=jz for this opcode",
|
2015-01-30 00:55:21 +00:00
|
|
|
"aho", " foo a0,33", "replace opcode string",
|
|
|
|
"ahe", " eax+=3", "set vm analysis string",
|
|
|
|
NULL };
|
|
|
|
switch (input[0]) {
|
|
|
|
case '?':
|
|
|
|
if (input[1]) {
|
|
|
|
//ut64 addr = r_num_math (core->num, input+1);
|
|
|
|
eprintf ("TODO: show hint\n");
|
|
|
|
} else r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'a': // set arch
|
2014-12-05 06:51:21 +00:00
|
|
|
if (input[1]) {
|
2014-12-05 06:34:54 +00:00
|
|
|
int i;
|
2015-12-16 13:35:56 +00:00
|
|
|
char *ptr = strdup (input + 2);
|
2014-12-05 06:34:54 +00:00
|
|
|
i = r_str_word_set0 (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (i == 2)
|
2014-12-05 06:34:54 +00:00
|
|
|
r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
|
|
|
r_anal_hint_set_arch (core->anal, core->offset,
|
|
|
|
r_str_word_get0 (ptr, 0));
|
|
|
|
free (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
} else eprintf ("Missing argument\n");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'b': // set bits
|
2014-12-05 06:51:21 +00:00
|
|
|
if (input[1]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
char *ptr = strdup (input + 2);
|
2014-12-05 06:34:54 +00:00
|
|
|
int bits;
|
|
|
|
int i = r_str_word_set0 (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (i == 2)
|
2014-12-05 06:34:54 +00:00
|
|
|
r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
|
|
|
bits = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
r_anal_hint_set_bits (core->anal, core->offset, bits);
|
|
|
|
free (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
} else eprintf ("Missing argument\n");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2016-01-16 23:46:57 +00:00
|
|
|
case 'i': // "ahi"
|
|
|
|
if (input[1] == '?') {
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage", "ahi [sbodh] [@ offset]", " Define numeric base",
|
|
|
|
"ahi", " [base]", "set numeric base (1, 2, 8, 10, 16)",
|
|
|
|
"ahi", " b", "set base to binary (1)",
|
|
|
|
"ahi", " d", "set base to decimal (10)",
|
|
|
|
"ahi", " h", "set base to hexadecimal (16)",
|
|
|
|
"ahi", " o", "set base to octal (8)",
|
2016-02-03 11:29:32 +00:00
|
|
|
"ahi", " i", "set base to IP address (32)",
|
2016-02-03 16:05:03 +00:00
|
|
|
"ahi", " S", "set base to syscall (80)",
|
2016-01-16 23:46:57 +00:00
|
|
|
"ahi", " s", "set base to string (2)",
|
|
|
|
NULL };
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} else {
|
|
|
|
// You can either specify immbase with letters, or numbers
|
|
|
|
const int base =
|
|
|
|
(input[2] == 'b') ? 1 :
|
|
|
|
(input[2] == 's') ? 2 :
|
|
|
|
(input[2] == 'o') ? 8 :
|
|
|
|
(input[2] == 'd') ? 10 :
|
|
|
|
(input[2] == 'h') ? 16 :
|
2016-02-03 11:29:32 +00:00
|
|
|
(input[2] == 'i') ? 32 : // ip address
|
2016-02-03 16:05:03 +00:00
|
|
|
(input[2] == 'S') ? 80 : // syscall
|
2016-01-16 23:46:57 +00:00
|
|
|
(int) r_num_math (core->num, input + 1);
|
|
|
|
r_anal_hint_set_immbase (core->anal, core->offset, base);
|
|
|
|
}
|
2015-09-27 23:00:06 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'c':
|
|
|
|
r_anal_hint_set_jump (core->anal, core->offset,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
r_anal_hint_set_fail (core->anal, core->offset,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 's': // set size (opcode length)
|
2015-05-09 22:12:33 +00:00
|
|
|
if (input[1]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_hint_set_size (core->anal, core->offset, atoi (input + 1));
|
2015-05-09 22:12:33 +00:00
|
|
|
} else eprintf ("Usage: ahs 16\n");
|
|
|
|
break;
|
|
|
|
case 'S': // set size (opcode length)
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == ' ') {
|
|
|
|
r_anal_hint_set_syntax (core->anal, core->offset, input + 2);
|
2015-05-09 22:12:33 +00:00
|
|
|
} else eprintf ("Usage: ahS att\n");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'o': // set opcode string
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == ' ') {
|
|
|
|
r_anal_hint_set_opcode (core->anal, core->offset, input + 2);
|
2015-05-09 22:12:33 +00:00
|
|
|
} else eprintf ("Usage: aho popall\n");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'e': // set ESIL string
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == ' ') {
|
|
|
|
r_anal_hint_set_esil (core->anal, core->offset, input + 2);
|
2015-05-09 22:12:33 +00:00
|
|
|
} else eprintf ("Usage: ahe r0,pc,=\n");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
#if TODO
|
|
|
|
case 'e': // set endian
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_hint_set_opcode (core->anal, core->offset, atoi (input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2014-06-16 03:58:00 +00:00
|
|
|
#endif
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'p':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_anal_hint_set_pointer (core->anal, core->offset, r_num_math (core->num, input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
case 'j':
|
|
|
|
case '\0':
|
2014-12-05 06:51:21 +00:00
|
|
|
r_core_anal_hint_list (core->anal, input[0]);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case '-':
|
2014-12-05 06:51:21 +00:00
|
|
|
if (input[1]) {
|
2014-12-05 06:34:54 +00:00
|
|
|
int i;
|
2015-12-16 13:35:56 +00:00
|
|
|
char *ptr = strdup (input + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
ut64 addr;
|
|
|
|
int size = 1;
|
|
|
|
i = r_str_word_set0 (ptr);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (i == 2)
|
2014-12-05 06:34:54 +00:00
|
|
|
size = r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
|
|
|
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
r_anal_hint_del (core->anal, addr, size);
|
|
|
|
free (ptr);
|
|
|
|
} else r_anal_hint_clear (core->anal);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-14 22:23:08 +00:00
|
|
|
static void agraph_print_node_dot(RANode *n, void *user) {
|
|
|
|
char *label = strdup (n->body);
|
|
|
|
label = r_str_replace (label, "\n", "\\l", 1);
|
|
|
|
if (!label || !*label) {
|
|
|
|
free (label);
|
|
|
|
label = strdup (n->title);
|
|
|
|
}
|
|
|
|
r_cons_printf ("\"%s\" [URL=\"%s\", color=\"lightgray\", label=\"%s\"]\n",
|
|
|
|
n->title, n->title, label);
|
|
|
|
free (label);
|
|
|
|
}
|
|
|
|
|
2015-10-15 07:00:53 +00:00
|
|
|
static void agraph_print_node(RANode *n, void *user) {
|
2015-07-19 12:32:00 +00:00
|
|
|
char *encbody, *cmd;
|
|
|
|
int len = strlen (n->body);
|
|
|
|
|
|
|
|
if (n->body[len - 1] == '\n') len--;
|
|
|
|
encbody = r_base64_encode_dyn (n->body, len);
|
|
|
|
cmd = r_str_newf ("agn \"%s\" base64:%s\n", n->title, encbody);
|
|
|
|
r_cons_printf (cmd);
|
|
|
|
free (cmd);
|
|
|
|
free (encbody);
|
|
|
|
}
|
|
|
|
|
2015-12-14 22:23:08 +00:00
|
|
|
static void agraph_print_edge_dot(RANode *from, RANode *to, void *user) {
|
|
|
|
r_cons_printf ("\"%s\" -> \"%s\"\n", from->title, to->title);
|
|
|
|
}
|
2015-07-19 12:32:00 +00:00
|
|
|
|
2015-12-14 22:23:08 +00:00
|
|
|
static void agraph_print_edge(RANode *from, RANode *to, void *user) {
|
|
|
|
r_cons_printf ("age \"%s\" \"%s\"\n", from->title, to->title);
|
2015-07-19 12:32:00 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 17:28:49 +00:00
|
|
|
static void cmd_agraph_node(RCore *core, const char *input) {
|
2015-07-19 12:32:00 +00:00
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "agn [title] [body]", "",
|
|
|
|
"Examples:", "", "",
|
|
|
|
"agn", " title1 body1", "Add a node with title \"title1\" and body \"body1\"",
|
|
|
|
"agn", " \"title with space\" \"body with space\"", "Add a node with spaces in the title and in the body",
|
|
|
|
"agn", " title1 base64:Ym9keTE=", "Add a node with the body specified as base64",
|
2015-10-02 17:28:49 +00:00
|
|
|
"agn-", " title1", "Remove a node with title \"title1\"",
|
2015-07-19 12:32:00 +00:00
|
|
|
"agn?", "", "Show this help",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2015-07-19 12:32:00 +00:00
|
|
|
|
|
|
|
switch (*input) {
|
2015-12-16 13:35:56 +00:00
|
|
|
case ' ': {
|
2015-07-19 12:32:00 +00:00
|
|
|
char *newbody = NULL;
|
|
|
|
char **args, *body;
|
|
|
|
int n_args, B_LEN = strlen ("base64:");
|
|
|
|
|
|
|
|
input++;
|
|
|
|
args = r_str_argv (input, &n_args);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (n_args < 1 || n_args > 2) {
|
2015-07-19 12:32:00 +00:00
|
|
|
r_cons_printf ("Wrong arguments\n");
|
|
|
|
r_str_argv_free (args);
|
|
|
|
break;
|
|
|
|
}
|
2015-07-24 23:09:13 +00:00
|
|
|
//strdup cause there is double free in r_str_argv_free due to a realloc call
|
2015-12-16 13:35:56 +00:00
|
|
|
if (n_args > 1) {
|
2015-12-10 21:45:00 +00:00
|
|
|
body = strdup (args[1]);
|
|
|
|
if (strncmp (body, "base64:", B_LEN) == 0) {
|
|
|
|
body = r_str_replace (body, "\\n", "", true);
|
|
|
|
newbody = (char *)r_base64_decode_dyn (body + B_LEN, -1);
|
|
|
|
free (body);
|
2015-12-16 13:35:56 +00:00
|
|
|
if (!newbody) {
|
|
|
|
eprintf ("Not enough space to allocate %s at %d\n", __FILE__, __LINE__);
|
2015-12-10 21:45:00 +00:00
|
|
|
r_str_argv_free (args);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
body = newbody;
|
2015-07-24 23:09:13 +00:00
|
|
|
}
|
2015-12-10 21:45:00 +00:00
|
|
|
body = r_str_concat (body, "\n");
|
|
|
|
} else {
|
|
|
|
body = strdup ("");
|
2015-07-19 12:32:00 +00:00
|
|
|
}
|
|
|
|
r_agraph_add_node (core->graph, args[0], body);
|
|
|
|
r_str_argv_free (args);
|
2015-07-24 23:09:13 +00:00
|
|
|
free (body);
|
|
|
|
//free newbody it's not necessary since r_str_concat reallocate the space
|
2015-07-19 12:32:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
case '-': {
|
2015-10-02 17:28:49 +00:00
|
|
|
char **args;
|
|
|
|
int n_args;
|
|
|
|
|
|
|
|
input++;
|
|
|
|
args = r_str_argv (input, &n_args);
|
|
|
|
if (n_args != 1) {
|
|
|
|
r_cons_printf ("Wrong arguments\n");
|
|
|
|
r_str_argv_free (args);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r_agraph_del_node (core->graph, args[0]);
|
|
|
|
r_str_argv_free (args);
|
|
|
|
break;
|
|
|
|
}
|
2015-07-19 12:32:00 +00:00
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 17:28:49 +00:00
|
|
|
static void cmd_agraph_edge(RCore *core, const char *input) {
|
2015-07-19 12:32:00 +00:00
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "age [title1] [title2]", "",
|
|
|
|
"Examples:", "", "",
|
|
|
|
"age", " title1 title2", "Add an edge from the node with \"title1\" as title to the one with title \"title2\"",
|
|
|
|
"age", " \"title1 with spaces\" title2", "Add an edge from node \"title1 with spaces\" to node \"title2\"",
|
2015-10-02 17:28:49 +00:00
|
|
|
"age-", " title1 title2", "Remove an edge from the node with \"title1\" as title to the one with title \"title2\"",
|
2015-07-19 12:32:00 +00:00
|
|
|
"age?", "", "Show this help",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2015-07-19 12:32:00 +00:00
|
|
|
|
|
|
|
switch (*input) {
|
|
|
|
case ' ':
|
2015-12-16 13:35:56 +00:00
|
|
|
case '-': {
|
2015-07-19 12:32:00 +00:00
|
|
|
RANode *u, *v;
|
|
|
|
char **args;
|
|
|
|
int n_args;
|
|
|
|
|
2015-10-02 17:28:49 +00:00
|
|
|
args = r_str_argv (input + 1, &n_args);
|
2015-07-19 12:32:00 +00:00
|
|
|
if (n_args != 2) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("Wrong arguments\n");
|
2015-07-24 21:59:38 +00:00
|
|
|
r_str_argv_free (args);
|
2015-07-19 12:32:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
u = r_agraph_get_node (core->graph, args[0]);
|
|
|
|
v = r_agraph_get_node (core->graph, args[1]);
|
|
|
|
if (!u || !v) {
|
|
|
|
r_cons_printf ("Nodes not found!\n");
|
2015-07-24 21:59:38 +00:00
|
|
|
r_str_argv_free (args);
|
2015-07-19 12:32:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-10-02 17:28:49 +00:00
|
|
|
if (*input == ' ') {
|
|
|
|
r_agraph_add_edge (core->graph, u, v);
|
|
|
|
} else {
|
|
|
|
r_agraph_del_edge (core->graph, u, v);
|
|
|
|
}
|
2015-07-19 12:32:00 +00:00
|
|
|
r_str_argv_free (args);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 17:28:49 +00:00
|
|
|
static void cmd_agraph_print(RCore *core, const char *input) {
|
2016-01-04 23:47:41 +00:00
|
|
|
const char *help_msg[] = {
|
|
|
|
"Usage:", "agg[kid?*]", "print graph",
|
|
|
|
"agg", "", "show current graph in ascii art",
|
|
|
|
"aggk", "", "show graph in key=value form",
|
|
|
|
"aggd", "", "print the current graph in GRAPHVIZ dot format",
|
|
|
|
"aggi", "", "enter interactive mode for the current graph",
|
|
|
|
"agg*", "", "in r2 commands, to save in projects, etc",
|
|
|
|
NULL };
|
2015-07-19 12:32:00 +00:00
|
|
|
switch (*input) {
|
2015-12-14 22:23:08 +00:00
|
|
|
case 'k': // "aggk"
|
2015-07-19 12:32:00 +00:00
|
|
|
{
|
|
|
|
Sdb *db = r_agraph_get_sdb (core->graph);
|
|
|
|
char *o = sdb_querys (db, "NULL", 0, "*");
|
|
|
|
r_cons_printf ("%s", o);
|
|
|
|
free (o);
|
|
|
|
break;
|
|
|
|
}
|
2016-01-04 22:00:01 +00:00
|
|
|
case 'i': // "aggi" - open current core->graph in interactive mode
|
|
|
|
{
|
|
|
|
RANode *ran = r_agraph_get_first_node (core->graph);
|
|
|
|
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->need_update_dim = true;
|
2016-01-04 23:47:41 +00:00
|
|
|
r_core_visual_graph (core, core->graph, NULL, true);
|
|
|
|
r_cons_show_cursor (true);
|
2016-01-04 22:00:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-14 22:23:08 +00:00
|
|
|
case 'd': // "aggd" - dot format
|
|
|
|
r_cons_printf ("digraph code {\ngraph [bgcolor=white];\n"
|
|
|
|
"node [color=lightgray, style=filled shape=box "
|
|
|
|
"fontname=\"Courier\" fontsize=\"8\"];\n");
|
|
|
|
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*" -
|
2015-10-15 07:00:53 +00:00
|
|
|
r_agraph_foreach (core->graph, agraph_print_node, NULL);
|
|
|
|
r_agraph_foreach_edge (core->graph, agraph_print_edge, NULL);
|
2015-07-19 12:32:00 +00:00
|
|
|
break;
|
2016-01-04 23:47:41 +00:00
|
|
|
case '?':
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
break;
|
2015-07-19 12:32:00 +00:00
|
|
|
default:
|
|
|
|
core->graph->can->linemode = 1;
|
|
|
|
core->graph->can->color = r_config_get_i (core->config, "scr.color");
|
|
|
|
r_agraph_set_title (core->graph,
|
2016-01-04 22:00:01 +00:00
|
|
|
r_config_get (core->config, "graph.title"));
|
2015-07-19 12:32:00 +00:00
|
|
|
r_agraph_print (core->graph);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-05 06:34:54 +00:00
|
|
|
static void cmd_anal_graph(RCore *core, const char *input) {
|
2014-12-05 17:56:33 +00:00
|
|
|
RList *list;
|
2015-01-30 00:55:21 +00:00
|
|
|
const char *arg;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-10-02 17:28:49 +00:00
|
|
|
"Usage:", "ag[?f]", "Graphviz/graph code",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ag", " [addr]", "output graphviz code (bb at addr and children)",
|
|
|
|
"agj", " [addr]", "idem, but in JSON format",
|
|
|
|
"agk", " [addr]", "idem, but in SDB key-value format",
|
|
|
|
"aga", " [addr]", "idem, but only addresses",
|
|
|
|
"agc", " [addr]", "output graphviz call graph of function",
|
|
|
|
"agd", " [fcn name]", "output graphviz code of diffed function",
|
2015-12-16 13:35:56 +00:00
|
|
|
"agl", " [fcn name]", "output graphviz code using meta-data",
|
2015-01-30 00:55:21 +00:00
|
|
|
"agt", " [addr]", "find paths from current offset to given address",
|
2015-06-25 14:57:15 +00:00
|
|
|
"agf", " [addr]", "Show ASCII art graph of given function",
|
2015-07-09 21:56:55 +00:00
|
|
|
"ag-", "", "Reset the current ASCII art graph",
|
2016-01-04 23:47:41 +00:00
|
|
|
"agn", "[?] title body", "Add a node to the current graph",
|
|
|
|
"age", "[?] title1 title2", "Add an edge to the current graph",
|
|
|
|
"agg", "[kdi*]", "Print graph in ASCII-Art, graphviz, k=v, r2 or visual",
|
2015-01-30 00:55:21 +00:00
|
|
|
"agv", "[acdltfl] [a]", "view function using graphviz",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-12-05 17:56:33 +00:00
|
|
|
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'f': // "agf"
|
2015-06-25 14:57:15 +00:00
|
|
|
r_core_cmd0 (core, "afg"); // afg should be deprecated imho
|
|
|
|
break;
|
2015-07-09 21:56:55 +00:00
|
|
|
case '-':
|
|
|
|
r_agraph_reset (core->graph);
|
|
|
|
break;
|
2015-12-10 21:45:00 +00:00
|
|
|
case 'n': // "agn"
|
2015-07-19 12:32:00 +00:00
|
|
|
cmd_agraph_node (core, input + 1);
|
2015-07-09 21:56:55 +00:00
|
|
|
break;
|
2015-12-10 21:45:00 +00:00
|
|
|
case 'e': // "age"
|
2015-07-19 12:32:00 +00:00
|
|
|
cmd_agraph_edge (core, input + 1);
|
2015-07-09 21:56:55 +00:00
|
|
|
break;
|
2015-12-10 21:45:00 +00:00
|
|
|
case 'g': // "agg"
|
2015-07-19 12:32:00 +00:00
|
|
|
cmd_agraph_print (core, input + 1);
|
2015-07-09 21:56:55 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 't':
|
2015-12-16 13:35:56 +00:00
|
|
|
list = r_core_anal_graph_to (core, r_num_math (core->num, input + 1), 0);
|
2014-12-05 17:56:33 +00:00
|
|
|
if (list) {
|
|
|
|
RListIter *iter, *iter2;
|
|
|
|
RList *list2;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
r_list_foreach (list, iter, list2) {
|
|
|
|
r_list_foreach (list2, iter2, bb) {
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_printf ("-> 0x%08" PFMT64x "\n", bb->addr);
|
2013-02-11 09:51:45 +00:00
|
|
|
}
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2014-12-05 17:56:33 +00:00
|
|
|
r_list_purge (list);
|
|
|
|
free (list);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_coderefs (core, r_num_math (core->num, input + 1), input[1] == 'j'? 2: 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'j':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input + 1), R_CORE_ANAL_JSON);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'k':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input + 1), R_CORE_ANAL_KEYVALUE);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'l':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input + 1), R_CORE_ANAL_GRAPHLINES);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input + 1), 0);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input + 1),
|
|
|
|
R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
r_core_cmd0 (core, "=H /graph/");
|
|
|
|
break;
|
|
|
|
case '?':
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
2015-01-30 00:55:21 +00:00
|
|
|
arg = strchr (input, ' ');
|
|
|
|
if (arg) arg++;
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, arg),
|
|
|
|
R_CORE_ANAL_GRAPHBODY);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static void cmd_anal_trace(RCore *core, const char *input) {
|
2015-01-30 00:55:21 +00:00
|
|
|
RDebugTracepoint *t;
|
2014-12-05 06:34:54 +00:00
|
|
|
const char *ptr;
|
|
|
|
ut64 addr = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg[] = {
|
2015-01-30 00:55:21 +00:00
|
|
|
"Usage:", "at", "[*] [addr]",
|
|
|
|
"at", "", "list all traced opcode ranges",
|
|
|
|
"at-", "", "reset the tracing information",
|
|
|
|
"at*", "", "list all traced opcode offsets",
|
|
|
|
"at+", " [addr] [times]", "add trace for address N times",
|
|
|
|
"at", " [addr]", "show trace info at address",
|
2015-02-22 10:18:40 +00:00
|
|
|
"ate", "", "show esil trace logs (anal.trace)",
|
|
|
|
"ate", " [idx]", "show commands to restore to this trace index",
|
|
|
|
"ate", "-", "clear esil trace logs",
|
2015-01-30 00:55:21 +00:00
|
|
|
"att", " [tag]", "select trace tag (no arg unsets)",
|
|
|
|
"at%", "", "TODO",
|
|
|
|
"ata", " 0x804020 ...", "only trace given addresses",
|
|
|
|
"atr", "", "show traces as range commands (ar+)",
|
2015-08-12 08:40:24 +00:00
|
|
|
"atd", "", "show disassembly trace (use .atd)",
|
|
|
|
"atl", "", "list all traced addresses (useful for @@= `atl`)",
|
2015-01-30 00:55:21 +00:00
|
|
|
"atD", "", "show dwarf trace (at*|rsc dwarf-traces $FILE)",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-12-05 06:34:54 +00:00
|
|
|
|
2014-12-05 06:51:21 +00:00
|
|
|
switch (input[0]) {
|
2015-08-12 08:40:24 +00:00
|
|
|
case 'r':
|
|
|
|
eprintf ("TODO\n");
|
|
|
|
//trace_show(-1, trace_tag_get());
|
|
|
|
break;
|
2015-02-22 10:18:40 +00:00
|
|
|
case 'e': // "ate"
|
|
|
|
if (!core->anal->esil) {
|
2016-01-19 23:36:21 +00:00
|
|
|
int stacksize = r_config_get_i (core->config, "esil.stacksize");
|
2015-02-22 10:18:40 +00:00
|
|
|
int romem = r_config_get_i (core->config, "esil.romem");
|
|
|
|
int stats = r_config_get_i (core->config, "esil.stats");
|
2015-09-08 23:17:55 +00:00
|
|
|
int iotrap = r_config_get_i (core->config, "esil.iotrap");
|
2016-01-20 16:13:30 +00:00
|
|
|
if (!(core->anal->esil = r_anal_esil_new (stacksize, iotrap)))
|
|
|
|
return;
|
2015-10-14 10:34:18 +00:00
|
|
|
r_anal_esil_setup (core->anal->esil,
|
2015-12-16 13:35:56 +00:00
|
|
|
core->anal, romem, stats);
|
2015-02-22 10:18:40 +00:00
|
|
|
}
|
|
|
|
switch (input[1]) {
|
|
|
|
case 0:
|
|
|
|
r_anal_esil_trace_list (core->anal->esil);
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'i': {
|
|
|
|
RAnalOp *op;
|
|
|
|
ut64 addr = r_num_math (core->num, input + 2);
|
|
|
|
if (!addr)
|
|
|
|
addr = core->offset;
|
|
|
|
op = r_core_anal_op (core, addr);
|
|
|
|
if (op)
|
|
|
|
r_anal_esil_trace (core->anal->esil, op);
|
|
|
|
r_anal_op_free (op);
|
|
|
|
} break;
|
2015-02-22 10:18:40 +00:00
|
|
|
case '-':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (!strcmp (input + 2, "*")) {
|
2015-02-22 10:18:40 +00:00
|
|
|
if (core->anal->esil) {
|
|
|
|
sdb_free (core->anal->esil->db_trace);
|
|
|
|
core->anal->esil->db_trace = sdb_new0 ();
|
|
|
|
}
|
|
|
|
} else {
|
2016-01-04 01:19:02 +00:00
|
|
|
eprintf ("TODO: ate- cannot delete specific logs. Use ate-*\n");
|
2015-02-22 10:18:40 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case ' ': {
|
|
|
|
int idx = atoi (input + 2);
|
|
|
|
r_anal_esil_trace_show (
|
|
|
|
core->anal->esil, idx);
|
|
|
|
} break;
|
2015-02-22 10:18:40 +00:00
|
|
|
case 'k':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[2] == ' ') {
|
2015-02-22 10:18:40 +00:00
|
|
|
char *s = sdb_querys (core->anal->esil->db_trace,
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL, 0, input + 3);
|
2015-02-22 10:18:40 +00:00
|
|
|
r_cons_printf ("%s\n", s);
|
|
|
|
free (s);
|
|
|
|
} else {
|
|
|
|
eprintf ("Usage: atek [query]\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
eprintf ("|Usage: ate[ilk] [-arg]\n"
|
2015-12-16 13:35:56 +00:00
|
|
|
"| ate esil trace log single instruction\n"
|
|
|
|
"| ate idx show commands for that index log\n"
|
|
|
|
"| ate-* delete all esil traces\n"
|
|
|
|
"| atei esil trace log single instruction\n"
|
|
|
|
"| atek [sdbq] esil trace log single instruction\n");
|
2015-02-22 10:18:40 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case '?':
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
eprintf ("Current Tag: %d\n", core->dbg->trace->tag);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
2015-12-16 13:35:56 +00:00
|
|
|
eprintf ("NOTE: Ensure given addresses are in 0x%%08" PFMT64x " format\n");
|
|
|
|
r_debug_trace_at (core->dbg, input + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 't':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_debug_trace_tag (core->dbg, atoi (input + 1));
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2015-08-12 08:40:24 +00:00
|
|
|
case 'l':
|
|
|
|
r_debug_trace_list (core->dbg, 'l');
|
|
|
|
r_cons_newline ();
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case 'd':
|
2015-08-12 08:40:24 +00:00
|
|
|
r_debug_trace_list (core->dbg, 'd');
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
// XXX: not yet tested..and rsc dwarf-traces comes from r1
|
|
|
|
r_core_cmd (core, "at*|rsc dwarf-traces $FILE", 0);
|
|
|
|
break;
|
|
|
|
case '+':
|
2015-12-16 13:35:56 +00:00
|
|
|
ptr = input + 2;
|
2014-12-05 06:34:54 +00:00
|
|
|
addr = r_num_math (core->num, ptr);
|
|
|
|
ptr = strchr (ptr, ' ');
|
|
|
|
if (ptr != NULL) {
|
|
|
|
RAnalOp *op = r_core_op_anal (core, addr);
|
|
|
|
if (op != NULL) {
|
|
|
|
RDebugTracepoint *tp = r_debug_trace_add (core->dbg, addr, op->size);
|
2015-12-16 13:35:56 +00:00
|
|
|
tp->count = atoi (ptr + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
r_anal_trace_bb (core->anal, addr);
|
|
|
|
r_anal_op_free (op);
|
2015-12-16 13:35:56 +00:00
|
|
|
} else eprintf ("Cannot analyze opcode at 0x%" PFMT64x "\n", addr);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
r_debug_trace_free (core->dbg);
|
2015-01-13 01:01:44 +00:00
|
|
|
core->dbg->trace = r_debug_trace_new ();
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case ' ':
|
2015-01-30 00:55:21 +00:00
|
|
|
if ((t = r_debug_trace_get (core->dbg,
|
2015-12-16 13:35:56 +00:00
|
|
|
r_num_math (core->num, input)))) {
|
|
|
|
r_cons_printf ("offset = 0x%" PFMT64x "\n", t->addr);
|
2015-01-30 00:55:21 +00:00
|
|
|
r_cons_printf ("opsize = %d\n", t->size);
|
|
|
|
r_cons_printf ("times = %d\n", t->times);
|
|
|
|
r_cons_printf ("count = %d\n", t->count);
|
|
|
|
//TODO cons_printf("time = %d\n", t->tm);
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
case '*':
|
|
|
|
r_debug_trace_list (core->dbg, 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_debug_trace_list (core->dbg, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-07 16:20:29 +00:00
|
|
|
R_API int r_core_anal_refs(RCore *core, const char *input) {
|
|
|
|
int cfg_debug = r_config_get_i (core->config, "cfg.debug");
|
|
|
|
ut64 from, to;
|
|
|
|
char *ptr;
|
|
|
|
int rad, n;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg_aar[] = {
|
2015-09-07 16:20:29 +00:00
|
|
|
"Usage:", "aar", "[j*] [sz] # search and analyze xrefs",
|
|
|
|
"aar", " [sz]", "analyze xrefs in current section or sz bytes of code",
|
|
|
|
"aarj", " [sz]", "list found xrefs in JSON format",
|
|
|
|
"aar*", " [sz]", "list found xrefs in radare commands format",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2015-09-07 16:20:29 +00:00
|
|
|
if (*input == '?') {
|
|
|
|
r_core_cmd_help (core, help_msg_aar);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*input == 'j' || *input == '*') {
|
|
|
|
rad = *input;
|
|
|
|
input++;
|
|
|
|
} else {
|
|
|
|
rad = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
from = to = 0;
|
|
|
|
ptr = r_str_trim_head (strdup (input));
|
|
|
|
n = r_str_word_set0 (ptr);
|
|
|
|
if (n == 0) {
|
|
|
|
int rwx = R_IO_EXEC;
|
|
|
|
// get boundaries of current memory map, section or io map
|
|
|
|
if (cfg_debug) {
|
|
|
|
RDebugMap *map = r_debug_map_get (core->dbg, core->offset);
|
|
|
|
if (map) {
|
|
|
|
from = map->addr;
|
|
|
|
to = map->addr_end;
|
|
|
|
rwx = map->perm;
|
|
|
|
}
|
|
|
|
} else if (core->io->va) {
|
|
|
|
RIOSection *section = r_io_section_vget (core->io, core->offset);
|
|
|
|
if (section) {
|
|
|
|
from = section->vaddr;
|
|
|
|
to = section->vaddr + section->vsize;
|
|
|
|
rwx = section->rwx;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RIOMap *map = r_io_map_get (core->io, core->offset);
|
|
|
|
from = core->offset;
|
2015-12-16 13:35:56 +00:00
|
|
|
to = r_io_size (core->io) + (map? map->to: 0);
|
2015-09-07 16:20:29 +00:00
|
|
|
}
|
|
|
|
if (from == 0 && to == 0) {
|
|
|
|
eprintf ("Cannot determine xref search boundaries\n");
|
|
|
|
} else if (!(rwx & R_IO_EXEC)) {
|
|
|
|
eprintf ("Warning: Searching xrefs in non-executable region\n");
|
|
|
|
}
|
|
|
|
} else if (n == 1) {
|
|
|
|
from = core->offset;
|
|
|
|
to = core->offset + r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
} else {
|
|
|
|
eprintf ("Invalid number of arguments\n");
|
|
|
|
}
|
|
|
|
free (ptr);
|
|
|
|
|
2015-09-14 10:35:38 +00:00
|
|
|
if (from == UT64_MAX && to == UT64_MAX) return false;
|
|
|
|
if (from == 0 && to == 0) return false;
|
2015-12-16 13:35:56 +00:00
|
|
|
if (to - from > r_io_size (core->io)) return false;
|
2015-09-07 16:20:29 +00:00
|
|
|
|
|
|
|
return r_core_anal_search_xrefs (core, from, to, rad);
|
|
|
|
}
|
|
|
|
|
2015-12-16 13:35:56 +00:00
|
|
|
static int cmd_anal_all(RCore *core, const char *input) {
|
|
|
|
const char *help_msg_aa[] = {
|
2015-03-23 18:02:56 +00:00
|
|
|
"Usage:", "aa[0*?]", " # see also 'af' and 'afna'",
|
2015-01-30 00:55:21 +00:00
|
|
|
"aa", " ", "alias for 'af@@ sym.*;af@entry0'", //;.afna @@ fcn.*'",
|
2015-03-24 03:30:02 +00:00
|
|
|
"aa*", "", "analyze all flags starting with sym. (af @@ sym.*)",
|
2015-01-30 00:55:21 +00:00
|
|
|
"aaa", "", "autoname functions after aa (see afna)",
|
2015-03-23 18:02:56 +00:00
|
|
|
"aac", " [len]", "analyze function calls (af @@ `pi len~call[1]`)",
|
2015-07-24 13:20:32 +00:00
|
|
|
"aae", " [len]", "analyze references with ESIL",
|
2015-07-11 04:53:58 +00:00
|
|
|
"aar", " [len]", "analyze len bytes of instructions for references",
|
2015-09-06 22:36:18 +00:00
|
|
|
"aan", "", "afna @@ fcn*",
|
2015-03-24 03:30:02 +00:00
|
|
|
"aas", " [len]", "analyze symbols (af @@= `isq~[0]`)",
|
2015-07-28 16:57:01 +00:00
|
|
|
"aat", " [len]", "analyze all consecutive functions in section",
|
2015-04-21 21:21:03 +00:00
|
|
|
"aap", "", "find and analyze function preludes",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2015-07-31 10:40:04 +00:00
|
|
|
|
|
|
|
switch (*input) {
|
|
|
|
case '?': r_core_cmd_help (core, help_msg_aa); break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'c': cmd_anal_calls (core, input + 1); break; // "aac"
|
|
|
|
case 'j': cmd_anal_jumps (core, input + 1); break; // "aaj"
|
2015-07-31 10:40:04 +00:00
|
|
|
case '*':
|
|
|
|
r_core_cmd0 (core, "af @@ sym.*");
|
|
|
|
r_core_cmd0 (core, "af @ entry0");
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
r_core_cmd0 (core, "af @@= `isq~[0]`");
|
|
|
|
r_core_cmd0 (core, "af @ entry0");
|
|
|
|
break;
|
2015-09-06 22:36:18 +00:00
|
|
|
case 'n': r_core_cmd0 (core, ".afna @@ fcn.*"); break;
|
2016-02-10 17:45:25 +00:00
|
|
|
case 'p': // "aap"
|
2015-12-16 13:35:56 +00:00
|
|
|
if (*input == '?') {
|
2015-07-31 10:40:04 +00:00
|
|
|
// TODO: accept parameters for ranges
|
2016-01-24 10:33:36 +00:00
|
|
|
eprintf ("Usage: /aap ; find in memory for function preludes");
|
2015-07-31 10:40:04 +00:00
|
|
|
} else {
|
|
|
|
r_core_search_preludes (core);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '\0': // "aa"
|
|
|
|
case 'a':
|
2016-01-25 16:19:30 +00:00
|
|
|
if (input[0] && (input[1] == '?' || (input[1] && input[2] == '?'))) {
|
2016-01-24 10:33:36 +00:00
|
|
|
eprintf ("Usage: See aa? for more help\n");
|
|
|
|
} else {
|
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
ut64 curseek = core->offset;
|
|
|
|
r_core_anal_all (core);
|
2015-09-06 22:30:48 +00:00
|
|
|
if (core->cons->breaked)
|
|
|
|
goto jacuzzi;
|
2016-01-24 10:33:36 +00:00
|
|
|
r_cons_clear_line (1);
|
|
|
|
r_cons_break_end ();
|
|
|
|
if (*input == 'a') { // "aaa"
|
|
|
|
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");
|
|
|
|
(void)r_core_anal_refs (core, input + 1); // "aar"
|
|
|
|
if (core->cons->breaked)
|
|
|
|
goto jacuzzi;
|
|
|
|
r_core_seek (core, curseek, 1);
|
|
|
|
(void)cmd_anal_calls (core, ""); // "aac"
|
|
|
|
if (core->cons->breaked)
|
|
|
|
goto jacuzzi;
|
|
|
|
r_config_set_i (core->config, "anal.calls", c);
|
|
|
|
r_core_cmd0 (core, ".afna @@ fcn.*");
|
|
|
|
if (core->cons->breaked)
|
|
|
|
goto jacuzzi;
|
|
|
|
r_core_cmd0 (core, "s-");
|
|
|
|
}
|
|
|
|
jacuzzi:
|
|
|
|
flag_every_function (core);
|
2015-07-31 10:40:04 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 't': {
|
2015-07-31 10:40:04 +00:00
|
|
|
ut64 cur = core->offset;
|
|
|
|
RIOSection *s = r_io_section_vget (core->io, cur);
|
|
|
|
if (s) {
|
|
|
|
int hasnext = r_config_get_i (core->config, "anal.hasnext");
|
|
|
|
r_core_seek (core, s->vaddr, 1);
|
|
|
|
r_config_set_i (core->config, "anal.hasnext", 1);
|
2016-02-03 11:53:35 +00:00
|
|
|
(void)cmd_anal_fcn (core, "");
|
2015-07-31 10:40:04 +00:00
|
|
|
r_config_set_i (core->config, "anal.hasnext", hasnext);
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
// TODO: honor search.in? support dbg.maps?
|
2015-07-31 10:40:04 +00:00
|
|
|
eprintf ("Cannot find section boundaries in here\n");
|
|
|
|
}
|
|
|
|
r_core_seek (core, cur, 1);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-21 23:22:52 +00:00
|
|
|
case 'e': // "aae"
|
2015-07-31 10:40:04 +00:00
|
|
|
r_core_anal_esil (core, input + 1);
|
|
|
|
break;
|
|
|
|
case 'r':
|
2015-09-07 16:20:29 +00:00
|
|
|
(void)r_core_anal_refs (core, input + 1);
|
2015-07-31 10:40:04 +00:00
|
|
|
break;
|
|
|
|
default: r_core_cmd_help (core, help_msg_aa); break;
|
|
|
|
}
|
|
|
|
|
2015-09-14 10:35:38 +00:00
|
|
|
return true;
|
2015-07-31 10:40:04 +00:00
|
|
|
}
|
|
|
|
|
2016-01-25 16:19:30 +00:00
|
|
|
static bool anal_fcn_data (RCore *core, const char *input) {
|
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
|
|
|
if (fcn) {
|
|
|
|
int i;
|
2016-01-25 18:19:01 +00:00
|
|
|
bool gap = false;
|
|
|
|
ut64 gap_addr = UT64_MAX;
|
2016-01-25 16:19:30 +00:00
|
|
|
char *bitmap = calloc (1, fcn->size);
|
|
|
|
if (bitmap) {
|
|
|
|
RAnalBlock *b;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (fcn->bbs, iter, b) {
|
|
|
|
int f = b->addr - fcn->addr;
|
2016-01-25 18:19:01 +00:00
|
|
|
int t = R_MIN (f + b->size, fcn->size);
|
|
|
|
if (f>=0) {
|
2016-01-25 16:19:30 +00:00
|
|
|
while (f < t) {
|
|
|
|
bitmap[f++] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i=0; i<fcn->size; i++) {
|
|
|
|
ut64 here = fcn->addr + i;
|
2016-02-16 01:08:09 +00:00
|
|
|
if (bitmap && bitmap[i]) {
|
2016-01-25 18:19:01 +00:00
|
|
|
if (gap) {
|
|
|
|
r_cons_printf ("Cd %d @ 0x%08"PFMT64x"\n", here - gap_addr, gap_addr);
|
|
|
|
gap = false;
|
2016-01-25 16:19:30 +00:00
|
|
|
}
|
2016-01-25 18:19:01 +00:00
|
|
|
gap_addr = UT64_MAX;
|
2016-01-25 16:19:30 +00:00
|
|
|
} else {
|
2016-01-25 18:19:01 +00:00
|
|
|
if (!gap) {
|
|
|
|
gap = true;
|
|
|
|
gap_addr = here;
|
|
|
|
}
|
2016-01-25 16:19:30 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-25 18:19:01 +00:00
|
|
|
if (gap) {
|
|
|
|
r_cons_printf ("Cd %d @ 0x%08"PFMT64x"\n", fcn->addr + fcn->size - gap_addr, gap_addr);
|
|
|
|
gap = false;
|
|
|
|
}
|
2016-01-25 16:19:30 +00:00
|
|
|
free (bitmap);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmpaddr (const void *_a, const void *_b) {
|
|
|
|
const RAnalFunction *a = _a, *b = _b;
|
|
|
|
return (a->addr > b->addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool anal_fcn_data_gaps (RCore *core, const char *input) {
|
|
|
|
ut64 end = UT64_MAX;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
RListIter *iter;
|
|
|
|
int i, wordsize = (core->assembler->bits == 64)? 8: 4;
|
|
|
|
r_list_sort (core->anal->fcns, cmpaddr);
|
|
|
|
r_list_foreach (core->anal->fcns, iter, fcn) {
|
|
|
|
if (end != UT64_MAX) {
|
|
|
|
int range = fcn->addr - end;
|
|
|
|
if (range > 0) {
|
|
|
|
for (i = 0; i + wordsize < range; i+= wordsize) {
|
|
|
|
r_cons_printf ("Cd %d @ 0x%08"PFMT64x"\n", wordsize, end + i);
|
|
|
|
}
|
|
|
|
r_cons_printf ("Cd %d @ 0x%08"PFMT64x"\n", range - i, end + i);
|
|
|
|
//r_cons_printf ("Cd %d @ 0x%08"PFMT64x"\n", range, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end = fcn->addr + fcn->size;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-31 10:40:04 +00:00
|
|
|
static int cmd_anal(void *data, const char *input) {
|
|
|
|
const char *r;
|
|
|
|
RCore *core = (RCore *)data;
|
|
|
|
ut32 tbs = core->blocksize;
|
2015-12-16 13:35:56 +00:00
|
|
|
const char *help_msg_ad[] = {
|
|
|
|
"Usage:", "ad", "[kt] [...]",
|
|
|
|
"ad", " [N] [D]", "analyze N data words at D depth",
|
2016-01-25 16:19:30 +00:00
|
|
|
"adf", "", "analyze data in function (use like .adf @@=`afl~[0]`",
|
|
|
|
"adfg", "", "analyze data in function gaps",
|
2015-07-31 10:40:04 +00:00
|
|
|
"adt", "", "analyze data trampolines (wip)",
|
|
|
|
"adk", "", "analyze data kind (code, text, data, invalid, ...)",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
|
|
|
const char *help_msg[] = {
|
2015-10-06 22:09:37 +00:00
|
|
|
"Usage:", "a", "[abdefFghoprxstc] [...]",
|
|
|
|
"ab", " [hexpairs]", "analyze bytes",
|
2015-01-30 00:55:21 +00:00
|
|
|
"aa", "", "analyze all (fcns + bbs) (aa0 to avoid sub renaming)",
|
2015-03-23 18:02:56 +00:00
|
|
|
"ac", " [cycles]", "analyze which op could be executed in [cycles]",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ad", "", "analyze data trampoline (wip)",
|
|
|
|
"ad", " [from] [to]", "analyze data pointers to (from-to)",
|
|
|
|
"ae", " [expr]", "analyze opcode eval expression (see ao)",
|
|
|
|
"af", "[rnbcsl?+-*]", "analyze Functions",
|
|
|
|
"aF", "", "same as above, but using anal.depth=1",
|
|
|
|
"ag", "[?acgdlf]", "output Graphviz code",
|
|
|
|
"ah", "[?lba-]", "analysis hints (force opcode size, ...)",
|
|
|
|
"ai", " [addr]", "address information (show perms, stack, heap, ...)",
|
|
|
|
"ao", "[e?] [len]", "analyze Opcodes (or emulate it)",
|
2015-11-12 12:47:44 +00:00
|
|
|
"an", "[an-] [...]", "manage no-return addresses/symbols/functions",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ar", "", "like 'dr' but for the esil vm. (registers)",
|
2016-01-24 02:05:27 +00:00
|
|
|
"ap", "", "find prelude for current offset",
|
2015-01-30 00:55:21 +00:00
|
|
|
"ax", "[?ld-*]", "manage refs/xrefs (see also afx?)",
|
|
|
|
"as", " [num]", "analyze syscall using dbg.reg",
|
|
|
|
"at", "[trd+-%*?] [.]", "analyze execution traces",
|
|
|
|
//"ax", " [-cCd] [f] [t]", "manage code/call/data xrefs",
|
2015-12-16 13:35:56 +00:00
|
|
|
NULL };
|
2014-12-05 06:34:54 +00:00
|
|
|
|
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
|
|
|
|
switch (input[0]) {
|
2016-01-24 02:05:27 +00:00
|
|
|
case 'p': // "ap"
|
|
|
|
{
|
|
|
|
const ut8 *prelude = (const ut8*)"\xe9\x2d"; //:fffff000";
|
|
|
|
const int prelude_sz = 2;
|
|
|
|
const int bufsz = 4096;
|
|
|
|
ut8 *buf = calloc (1, bufsz);
|
|
|
|
ut64 off = core->offset;
|
|
|
|
if (input[1] == ' ') {
|
|
|
|
off = r_num_math (core->num, input+1);
|
|
|
|
r_io_read_at (core->io, off - bufsz + prelude_sz, buf, bufsz);
|
|
|
|
} else {
|
|
|
|
r_io_read_at (core->io, off - bufsz + prelude_sz, buf, bufsz);
|
|
|
|
}
|
|
|
|
//const char *prelude = "\x2d\xe9\xf0\x47"; //:fffff000";
|
|
|
|
r_mem_reverse (buf, bufsz);
|
|
|
|
//r_print_hexdump (NULL, off, buf, bufsz, 16, -16);
|
|
|
|
const ut8 *pos = r_mem_mem (buf, bufsz, prelude, prelude_sz);
|
|
|
|
if (pos) {
|
|
|
|
int delta = (size_t)(pos - buf);
|
|
|
|
eprintf ("POS = %d\n", delta);
|
|
|
|
eprintf ("HIT = 0x%"PFMT64x"\n", off - delta);
|
|
|
|
r_cons_printf ("0x%08"PFMT64x"\n", off - delta);
|
|
|
|
} else {
|
|
|
|
eprintf ("Cannot find prelude\n");
|
|
|
|
}
|
|
|
|
free (buf);
|
|
|
|
}
|
|
|
|
break;
|
2015-10-06 22:09:37 +00:00
|
|
|
case 'b':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == ' ' || input[1] == 'j') {
|
|
|
|
ut8 *buf = malloc (strlen (input) + 1);
|
|
|
|
int len = r_hex_str2bin (input + 2, buf);
|
|
|
|
if (len > 0)
|
2015-10-06 22:09:37 +00:00
|
|
|
core_anal_bytes (core, buf, len, 0, input[1]);
|
2014-12-05 06:34:54 +00:00
|
|
|
free (buf);
|
2015-10-22 13:18:23 +00:00
|
|
|
} else eprintf ("Usage: ab [hexpair-bytes]\n abj [hexpair-bytes] (json)");
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
2015-12-16 13:35:56 +00:00
|
|
|
case 'i': cmd_anal_info (core, input + 1); break; // "ai"
|
|
|
|
case 'r': cmd_anal_reg (core, input + 1); break; // "ar"
|
|
|
|
case 'e': cmd_anal_esil (core, input + 1); break; // "ae"
|
|
|
|
case 'o': cmd_anal_opcode (core, input + 1); break;
|
|
|
|
case 'n': cmd_anal_noreturn (core, input + 1); break; // "an"
|
2012-11-08 08:49:27 +00:00
|
|
|
case 'F':
|
2014-07-01 15:01:52 +00:00
|
|
|
r_core_anal_fcn (core, core->offset, UT64_MAX, R_ANAL_REF_TYPE_NULL, 1);
|
2012-11-08 08:49:27 +00:00
|
|
|
break;
|
2016-01-18 23:44:24 +00:00
|
|
|
case 'f': // "af"
|
2014-09-22 13:00:41 +00:00
|
|
|
if (!cmd_anal_fcn (core, input)) {
|
2015-01-30 00:55:21 +00:00
|
|
|
r_cons_break_end ();
|
2015-09-14 10:35:38 +00:00
|
|
|
return false;
|
2014-09-22 13:00:41 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'g':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_graph (core, input + 1);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 't':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_trace (core, input + 1);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-10-19 20:43:33 +00:00
|
|
|
case 's': // "as"
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_syscall (core, input + 1);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'x':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (!cmd_anal_refs (core, input + 1)) {
|
2015-01-30 00:55:21 +00:00
|
|
|
r_cons_break_end ();
|
2015-09-14 10:35:38 +00:00
|
|
|
return false;
|
2015-01-30 00:55:21 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
2015-07-31 10:40:04 +00:00
|
|
|
if (!cmd_anal_all (core, input + 1))
|
2015-09-14 10:35:38 +00:00
|
|
|
return false;
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2015-03-23 18:02:56 +00:00
|
|
|
case 'c':
|
2015-12-16 13:35:56 +00:00
|
|
|
if (input[1] == '?') {
|
2015-03-23 23:16:00 +00:00
|
|
|
eprintf ("Usage: ac [cycles] # analyze instructions that fit in N cycles\n");
|
|
|
|
} else {
|
2015-12-16 13:35:56 +00:00
|
|
|
RList *hooks;
|
2015-03-23 23:16:00 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RAnalCycleHook *hook;
|
2014-04-29 01:21:52 +00:00
|
|
|
char *instr_tmp = NULL;
|
2015-12-16 13:35:56 +00:00
|
|
|
int ccl = input[1]? r_num_math (core->num, &input[2]): 0; //get cycles to look for
|
2015-01-30 00:55:21 +00:00
|
|
|
int cr = r_config_get_i (core->config, "asm.cmtright");
|
2014-03-24 23:48:42 +00:00
|
|
|
int fun = r_config_get_i (core->config, "asm.functions");
|
|
|
|
int li = r_config_get_i (core->config, "asm.lines");
|
|
|
|
int xr = r_config_get_i (core->config, "asm.xrefs");
|
2015-03-23 23:16:00 +00:00
|
|
|
|
2015-09-14 10:35:38 +00:00
|
|
|
r_config_set_i (core->config, "asm.cmtright", true);
|
|
|
|
r_config_set_i (core->config, "asm.functions", false);
|
|
|
|
r_config_set_i (core->config, "asm.lines", false);
|
|
|
|
r_config_set_i (core->config, "asm.xrefs", false);
|
2015-03-23 23:16:00 +00:00
|
|
|
|
2014-03-24 23:48:42 +00:00
|
|
|
r_cons_break (NULL, NULL);
|
2015-01-30 00:55:21 +00:00
|
|
|
hooks = r_core_anal_cycles (core, ccl); //analyse
|
2014-03-24 23:48:42 +00:00
|
|
|
r_cons_break_end ();
|
|
|
|
r_cons_clear_line (1);
|
|
|
|
r_list_foreach (hooks, iter, hook) {
|
2014-04-29 01:21:52 +00:00
|
|
|
instr_tmp = r_core_disassemble_instr (core, hook->addr, 1);
|
|
|
|
r_cons_printf ("After %4i cycles:\t%s", (ccl - hook->cycles), instr_tmp);
|
2014-03-24 23:48:42 +00:00
|
|
|
r_cons_flush ();
|
2014-04-29 01:21:52 +00:00
|
|
|
free (instr_tmp);
|
2014-03-24 23:48:42 +00:00
|
|
|
}
|
|
|
|
r_list_free (hooks);
|
2015-03-23 23:16:00 +00:00
|
|
|
|
2015-01-30 00:55:21 +00:00
|
|
|
r_config_set_i (core->config, "asm.cmtright", cr); //reset settings
|
2014-03-24 23:48:42 +00:00
|
|
|
r_config_set_i (core->config, "asm.functions", fun);
|
|
|
|
r_config_set_i (core->config, "asm.lines", li);
|
|
|
|
r_config_set_i (core->config, "asm.xrefs", xr);
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
2014-03-24 23:48:42 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'd':
|
2012-11-20 02:59:00 +00:00
|
|
|
switch (input[1]) {
|
2016-01-25 16:19:30 +00:00
|
|
|
case 'f':
|
|
|
|
if (input[2] == 'g') {
|
|
|
|
anal_fcn_data_gaps (core, input + 1);
|
|
|
|
} else {
|
|
|
|
anal_fcn_data (core, input + 1);
|
|
|
|
}
|
|
|
|
break;
|
2012-11-20 02:59:00 +00:00
|
|
|
case 't':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_trampoline (core, input + 2);
|
|
|
|
break;
|
|
|
|
case ' ': {
|
|
|
|
const int default_depth = 1;
|
|
|
|
const char *p;
|
|
|
|
int a, b;
|
|
|
|
a = r_num_math (core->num, input + 2);
|
|
|
|
p = strchr (input + 2, ' ');
|
|
|
|
b = p? r_num_math (core->num, p + 1): default_depth;
|
|
|
|
if (a < 1) a = 1;
|
|
|
|
if (b < 1) b = 1;
|
|
|
|
r_core_anal_data (core, core->offset, a, b);
|
|
|
|
} break;
|
2012-11-20 02:59:00 +00:00
|
|
|
case 'k':
|
2015-01-30 00:55:21 +00:00
|
|
|
r = r_anal_data_kind (core->anal,
|
|
|
|
core->offset, core->block, core->blocksize);
|
|
|
|
r_cons_printf ("%s\n", r);
|
2012-11-20 02:59:00 +00:00
|
|
|
break;
|
|
|
|
case '\0':
|
2015-12-16 13:35:56 +00:00
|
|
|
r_core_anal_data (core, core->offset, 2 + (core->blocksize / 4), 1);
|
2013-01-22 04:06:12 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
default:
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg_ad);
|
2013-01-22 04:06:12 +00:00
|
|
|
break;
|
2014-12-05 06:34:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
2015-12-16 13:35:56 +00:00
|
|
|
cmd_anal_hint (core, input + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
case '!':
|
|
|
|
if (core->anal && core->anal->cur && core->anal->cur->cmd_ext)
|
2015-12-16 13:35:56 +00:00
|
|
|
return core->anal->cur->cmd_ext (core->anal, input + 1);
|
2014-12-05 06:34:54 +00:00
|
|
|
else r_cons_printf ("No plugins for this analysis plugin\n");
|
|
|
|
break;
|
|
|
|
default:
|
2015-01-30 00:55:21 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
r_cons_printf ("Examples:\n"
|
2015-12-16 13:35:56 +00:00
|
|
|
" f ts @ `S*~text:0[3]`; f t @ section..text\n"
|
|
|
|
" f ds @ `S*~data:0[3]`; f d @ section..data\n"
|
|
|
|
" .ad t t+ts @ d:ds\n",
|
|
|
|
NULL);
|
2014-12-05 06:34:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (tbs != core->blocksize)
|
|
|
|
r_core_block_size (core, tbs);
|
|
|
|
if (core->cons->breaked) {
|
|
|
|
r_cons_clear_line (1);
|
|
|
|
eprintf ("Interrupted\n");
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
2015-12-16 13:35:56 +00:00
|
|
|
r_cons_break_end ();
|
2014-12-05 06:34:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|