2014-01-31 01:02:51 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2014 - pancake */
|
2012-02-27 01:40:27 +00:00
|
|
|
|
2014-04-21 11:50:38 +00:00
|
|
|
static void find_refs(RCore *core, const char *glob) {
|
|
|
|
char cmd[128];
|
|
|
|
ut64 curseek = core->offset;
|
|
|
|
while (*glob==' ') glob++;
|
|
|
|
if (!glob || !*glob)
|
|
|
|
glob = "str.";
|
|
|
|
if (*glob == '?') {
|
|
|
|
eprintf ("Usage: arf [flag-str-filter]\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eprintf ("Finding references of flags matching '%s'...\n", glob);
|
|
|
|
snprintf (cmd, sizeof (cmd)-1, ".(findstref) @@= `f~%s[0]`", glob);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
#if 1
|
|
|
|
/* TODO: Move into cmd_anal() */
|
2014-09-02 00:48:41 +00:00
|
|
|
static void var_help(RCore *core, char ch) {
|
2014-06-26 23:43:04 +00:00
|
|
|
// TODO: colorize using r_core_help()
|
2014-09-04 22:40:46 +00:00
|
|
|
//const char *kind = (ch=='v')?"locals":"args";
|
2014-05-13 15:32:01 +00:00
|
|
|
if (ch=='a' || ch=='A' || ch=='v') {
|
2014-09-02 00:48:41 +00:00
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "af[aAv]", " [idx] [type] [name]",
|
2014-09-22 02:22:47 +00:00
|
|
|
"afa", "", "list function arguments",
|
|
|
|
"afa", " [idx] [name] ([type])", "define argument N with name and type",
|
2014-09-22 11:45:36 +00:00
|
|
|
"afa-", " [idx]", "delete argument at the given index",
|
2014-09-22 02:22:47 +00:00
|
|
|
"afag", " [idx] [addr]", "define var get reference",
|
|
|
|
"afas", " [idx] [addr]", "define var set reference",
|
|
|
|
"afv", "", "list function local variables",
|
|
|
|
"afv", " [idx] [name] ([type])", "define variable N with name and type",
|
2014-09-22 11:45:36 +00:00
|
|
|
"afv-", " [idx]", "delete variable at the given index",
|
2014-09-22 02:22:47 +00:00
|
|
|
"afvg", " [idx] [addr]", "define var get reference",
|
|
|
|
"afvs", " [idx] [addr]", "define var set reference",
|
2014-09-02 00:48:41 +00:00
|
|
|
NULL};
|
|
|
|
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
|
|
|
}
|
2014-03-31 02:42:55 +00:00
|
|
|
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: fastrg == 'A'
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int var_cmd(RCore *core, const char *str) {
|
2014-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
2014-09-22 15:23:17 +00:00
|
|
|
char *p, *ostr;
|
2014-09-26 12:24:33 +00:00
|
|
|
int delta, type = *str;
|
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
|
2014-09-22 11:45:36 +00:00
|
|
|
r_anal_var_list (core->anal, fcn, 'v', 0, 0);
|
|
|
|
r_anal_var_list (core->anal, fcn, 'a', 0, 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
|
|
|
|
/* Variable access CFvs = set fun var */
|
|
|
|
switch (str[1]) {
|
2014-04-28 23:31:46 +00:00
|
|
|
case '\0':
|
2014-09-22 02:22:47 +00:00
|
|
|
r_anal_var_list (core->anal, fcn, type, 0, 0);
|
2014-04-28 23:31:46 +00:00
|
|
|
goto end;
|
|
|
|
case '?':
|
2014-09-02 00:48:41 +00:00
|
|
|
var_help (core, *str);
|
2014-04-28 23:31:46 +00:00
|
|
|
goto end;
|
|
|
|
case '.':
|
2014-09-22 02:22:47 +00:00
|
|
|
r_anal_var_list (core->anal, fcn, core->offset, 0, 0);
|
2014-04-28 23:31:46 +00:00
|
|
|
goto end;
|
2014-09-22 11:45:36 +00:00
|
|
|
case '-':
|
|
|
|
r_anal_var_delete (core->anal, fcn->addr, type, 1, (int)
|
|
|
|
r_num_math (core->num, str+1));
|
|
|
|
goto end;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 's':
|
|
|
|
case 'g':
|
|
|
|
if (str[2]!='\0') {
|
|
|
|
if (fcn != NULL) {
|
2014-04-04 01:42:22 +00:00
|
|
|
int rw = 0; // 0 = read, 1 = write
|
2014-09-22 02:22:47 +00:00
|
|
|
char kind = type;
|
2014-04-04 01:42:22 +00:00
|
|
|
RAnalVar *var = r_anal_var_get (core->anal, fcn->addr,
|
2014-09-22 15:23:17 +00:00
|
|
|
kind, atoi (str+2), R_ANAL_VAR_SCOPE_LOCAL);
|
2014-04-04 01:42:22 +00:00
|
|
|
if (var != NULL) {
|
|
|
|
int scope = (str[1]=='g')?0: 1;
|
|
|
|
r_anal_var_access (core->anal, fcn->addr, kind,
|
|
|
|
scope, atoi (str+2), rw, core->offset);
|
|
|
|
//return r_anal_var_access_add (core->anal, var, atoi (str+2), (str[1]=='g')?0:1);
|
|
|
|
r_anal_var_free (var);
|
2014-04-28 23:31:46 +00:00
|
|
|
goto end;
|
2014-04-04 01:42:22 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
eprintf ("Can not find variable in: '%s'\n", str);
|
|
|
|
} else eprintf ("Unknown variable in: '%s'\n", str);
|
2014-04-28 23:31:46 +00:00
|
|
|
free (ostr);
|
2012-02-27 01:40:27 +00:00
|
|
|
return R_FALSE;
|
|
|
|
} else eprintf ("Missing argument\n");
|
|
|
|
break;
|
2014-09-22 02:22:47 +00:00
|
|
|
case ' ':
|
|
|
|
for (str++;*str==' ';) str++;
|
|
|
|
p = strchr (str, ' ');
|
|
|
|
if (!p) {
|
|
|
|
var_help (core, type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*p++ = 0;
|
|
|
|
delta = r_num_math (core->num, str);
|
|
|
|
{
|
|
|
|
int size = 4;
|
|
|
|
int scope = 1; // 0 = global, 1 = LOCAL;
|
|
|
|
const char *name = p;
|
|
|
|
char *vartype = strchr (name, ' ');
|
|
|
|
if (vartype) {
|
|
|
|
*vartype++ = 0;
|
|
|
|
}
|
|
|
|
if (fcn) {
|
|
|
|
r_anal_var_add (core->anal, fcn->addr,
|
|
|
|
scope, delta, type,
|
2014-09-26 13:40:17 +00:00
|
|
|
vartype, size, name);
|
2014-09-22 02:22:47 +00:00
|
|
|
} else eprintf ("Cannot find function\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-09-02 00:48:41 +00:00
|
|
|
var_help (core, *str);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
end:
|
2012-02-27 01:40:27 +00:00
|
|
|
free (ostr);
|
2014-04-28 23:31:46 +00:00
|
|
|
return R_TRUE;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-20 02:59:00 +00:00
|
|
|
static void cmd_anal_trampoline (RCore *core, const char *input) {
|
|
|
|
int i, bits = r_config_get_i (core->config, "asm.bits");
|
|
|
|
char *p, *inp = strdup (input);
|
|
|
|
p = strchr (inp, ' ');
|
|
|
|
if (p) *p=0;
|
|
|
|
ut64 a = r_num_math (core->num, inp);
|
|
|
|
ut64 b = p?r_num_math (core->num, p+1):0;
|
|
|
|
free (inp);
|
|
|
|
switch (bits) {
|
2013-02-21 10:31:04 +00:00
|
|
|
case 32:
|
|
|
|
for (i=0; i<core->blocksize; i+=4) {
|
|
|
|
ut32 n;
|
|
|
|
memcpy (&n, core->block+i, sizeof(ut32));
|
|
|
|
if (n>=a && n<=b) {
|
|
|
|
r_cons_printf ("f trampoline.%x @ 0x%"PFMT64x"\n", n, core->offset+i);
|
|
|
|
r_cons_printf ("Cd 4 @ 0x%"PFMT64x":4\n", core->offset+i);
|
|
|
|
// TODO: add data xrefs
|
2012-11-20 02:59:00 +00:00
|
|
|
}
|
2013-02-21 10:31:04 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
for (i=0; i<core->blocksize; i+=8) {
|
|
|
|
ut32 n;
|
|
|
|
memcpy (&n, core->block+i, sizeof(ut32));
|
|
|
|
if (n>=a && n<=b) {
|
|
|
|
r_cons_printf ("f trampoline.%"PFMT64x" @ 0x%"PFMT64x"\n", n, core->offset+i);
|
|
|
|
r_cons_printf ("Cd 8 @ 0x%"PFMT64x":8\n", core->offset+i);
|
|
|
|
// TODO: add data xrefs
|
2012-11-20 02:59:00 +00:00
|
|
|
}
|
2013-02-21 10:31:04 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-20 02:59:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-27 01:40:27 +00:00
|
|
|
static void cmd_syscall_do(RCore *core, int num) {
|
|
|
|
int i;
|
|
|
|
char str[64];
|
|
|
|
RSyscallItem *item = r_syscall_get (core->anal->syscall, num, -1);
|
|
|
|
if (item == NULL) {
|
|
|
|
r_cons_printf ("%d = unknown ()", num);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
r_cons_printf ("%d = %s (", item->num, item->name);
|
|
|
|
// TODO: move this to r_syscall
|
|
|
|
for (i=0; i<item->args; i++) {
|
|
|
|
ut64 arg = r_debug_arg_get (core->dbg, R_TRUE, i+1);
|
|
|
|
if (item->sargs==NULL)
|
|
|
|
r_cons_printf ("0x%08"PFMT64x"", arg);
|
|
|
|
else
|
2014-06-16 03:58:00 +00:00
|
|
|
switch (item->sargs[i]) {
|
|
|
|
case 'p': // pointer
|
|
|
|
r_cons_printf ("0x%08"PFMT64x"", arg);
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
r_cons_printf ("%"PFMT64d"", arg);
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
r_io_read_at (core->io, arg, (ut8*)str, sizeof (str));
|
|
|
|
// TODO: filter zero terminated string
|
|
|
|
str[63] = '\0';
|
|
|
|
r_str_filter (str, strlen (str));
|
|
|
|
r_cons_printf ("\"%s\"", str);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_cons_printf ("0x%08"PFMT64x"", arg);
|
|
|
|
break;
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
if (i+1<item->args)
|
|
|
|
r_cons_printf (", ");
|
|
|
|
}
|
|
|
|
r_cons_printf (")\n");
|
|
|
|
}
|
|
|
|
|
2013-12-14 03:15:01 +00:00
|
|
|
static void r_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;
|
2013-12-14 03:15:01 +00:00
|
|
|
if (fmt=='j') {
|
|
|
|
r_cons_printf ("[");
|
|
|
|
}
|
2013-02-25 01:35:16 +00:00
|
|
|
for (i=idx=ret=0; idx<len && (!nops|| (nops&&i<nops)); i++, idx+=ret) {
|
2013-06-17 01:26:48 +00:00
|
|
|
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);
|
2013-05-04 00:35:52 +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);
|
2012-02-27 01:40:27 +00:00
|
|
|
if (ret<1) {
|
|
|
|
eprintf ("Oops at 0x%08"PFMT64x" (%02x %02x %02x ...)\n",
|
2014-06-16 03:58:00 +00:00
|
|
|
core->offset+idx, buf[idx],
|
|
|
|
buf[idx+1], buf[idx+2]);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-12-06 04:31:54 +00:00
|
|
|
size = (hint&&hint->size)? hint->size: op.size;
|
2013-12-14 03:15:01 +00:00
|
|
|
if (fmt =='j') {
|
|
|
|
r_cons_printf ("{\"opcode\": \"%s\",", asmop.buf_asm);
|
|
|
|
if (hint && hint->opcode)
|
|
|
|
r_cons_printf ("\"ophint\": \"%s\",", hint->opcode);
|
|
|
|
r_cons_printf ("\"addr\": %"PFMT64d",", core->offset+idx);
|
|
|
|
r_cons_printf ("\"bytes\": \"");
|
|
|
|
for (j=0; j<size; j++)
|
|
|
|
r_cons_printf ("%02x", buf[j]);
|
|
|
|
r_cons_printf("\",");
|
|
|
|
if (op.val != UT64_MAX)
|
|
|
|
r_cons_printf ("\"val\": %"PFMT64d",", op.val);
|
|
|
|
if (op.ptr != UT64_MAX)
|
|
|
|
r_cons_printf ("\"ptr\": %"PFMT64d",", op.ptr);
|
|
|
|
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)
|
|
|
|
r_cons_printf ("\"jump\":%"PFMT64d",", op.jump);
|
|
|
|
if (hint && hint->fail != UT64_MAX)
|
|
|
|
op.fail = hint->fail;
|
|
|
|
if (op.fail != UT64_MAX)
|
|
|
|
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)
|
|
|
|
r_cons_printf ("failcycles: %d\n", op.failcycles);
|
2014-09-22 11:45:36 +00:00
|
|
|
r_cons_printf ("\"stack\":%d,", r_anal_stackop_tostring (op.stackop));
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("\"cond\":%d,",
|
|
|
|
(op.type &R_ANAL_OP_TYPE_COND)?1: op.cond);
|
|
|
|
r_cons_printf ("\"family\":%d}", op.family);
|
|
|
|
} else {
|
|
|
|
r_cons_printf ("opcode: %s\n", asmop.buf_asm);
|
|
|
|
if (hint && hint->opcode)
|
|
|
|
r_cons_printf ("ophint: %s\n", hint->opcode);
|
|
|
|
r_cons_printf ("addr: 0x%08"PFMT64x"\n", core->offset+idx);
|
|
|
|
r_cons_printf ("bytes: ");
|
|
|
|
for (j=0; j<size; j++)
|
|
|
|
r_cons_printf ("%02x", buf[j]);
|
|
|
|
r_cons_newline ();
|
|
|
|
if (op.val != UT64_MAX)
|
|
|
|
r_cons_printf ("val: 0x%08"PFMT64x"\n", op.val);
|
|
|
|
if (op.ptr != UT64_MAX)
|
|
|
|
r_cons_printf ("ptr: 0x%08"PFMT64x"\n", op.ptr);
|
|
|
|
r_cons_printf ("size: %d\n", size);
|
|
|
|
r_cons_printf ("type: %d (%s)\n", (int)(op.type & 0xffff),
|
|
|
|
r_anal_optype_to_string (op.type)); // TODO: string
|
|
|
|
if (*R_STRBUF_SAFEGET (&op.esil))
|
|
|
|
r_cons_printf ("esil: %s\n", R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
if (hint && hint->jump != UT64_MAX)
|
|
|
|
op.jump = hint->jump;
|
|
|
|
if (op.jump != UT64_MAX)
|
|
|
|
r_cons_printf ("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)
|
|
|
|
r_cons_printf ("fail: 0x%08"PFMT64x"\n", op.fail);
|
2013-10-25 00:06:00 +00:00
|
|
|
|
2014-09-22 11:45:36 +00:00
|
|
|
r_cons_printf ("stack: %s\n", r_anal_stackop_tostring (op.stackop));
|
2013-12-14 03:15:01 +00:00
|
|
|
r_cons_printf ("cond: %d\n",
|
|
|
|
(op.type &R_ANAL_OP_TYPE_COND)?1: op.cond);
|
|
|
|
r_cons_printf ("family: %d\n", op.family);
|
|
|
|
}
|
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);
|
2013-12-14 03:15:01 +00:00
|
|
|
if (((idx+ret)<len) && (!nops||(i+1)<nops))
|
|
|
|
r_cons_printf (",");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fmt=='j') {
|
|
|
|
r_cons_printf ("]");
|
|
|
|
r_cons_newline ();
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-24 00:53:15 +00:00
|
|
|
static int anal_fcn_add_bb (RCore *core, const char *input) {
|
|
|
|
char *ptr = strdup(input);
|
|
|
|
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;
|
|
|
|
|
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);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
if (ptr2[0] == 'm')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
|
|
else if (ptr2[0] == 'u')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
|
|
case 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-09-26 16:10:33 +00:00
|
|
|
if ((fcn = r_anal_get_fcn_in (core->anal, fcnaddr, 0)) == NULL ||
|
2014-06-16 03:58:00 +00:00
|
|
|
!r_anal_fcn_add_bb (fcn, addr, size, jump, fail, type, diff)) {
|
2013-05-24 00:53:15 +00:00
|
|
|
//eprintf ("Error: Cannot add bb\n");
|
|
|
|
}
|
|
|
|
r_anal_diff_free (diff);
|
|
|
|
free (ptr);
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
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;
|
2014-01-23 01:31:51 +00:00
|
|
|
case '-':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
ut64 addr = input[2]?
|
2014-01-23 01:31:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
break;
|
|
|
|
case '+':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
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;
|
2012-02-27 01:40:27 +00:00
|
|
|
|
2014-06-16 03:58:00 +00:00
|
|
|
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 R_FALSE;
|
|
|
|
}
|
|
|
|
if (ptr2[0] == 'm')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_MATCH;
|
|
|
|
else if (ptr2[0] == 'u')
|
|
|
|
diff->type = R_ANAL_DIFF_TYPE_UNMATCH;
|
|
|
|
case 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
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
if (!r_anal_fcn_add (core->anal, addr, size, name, type, diff))
|
|
|
|
eprintf ("Cannot add function (duplicated)\n");
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
r_anal_diff_free (diff);
|
|
|
|
free (ptr);
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'o':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
ut64 addr = core->offset;
|
|
|
|
if (input[2]==' ')
|
|
|
|
addr = r_num_math (core->num, input+2);
|
2014-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal,
|
2014-06-16 03:58:00 +00:00
|
|
|
addr, R_ANAL_FCN_TYPE_NULL);
|
|
|
|
if (fcn) r_cons_printf ("0x%08"PFMT64x"\n", fcn->addr);
|
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
r_core_anal_fcn_list (core, input+2, 0);
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
r_core_anal_fcn_list (core, input, 2);
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
r_core_anal_fcn_list (core, input+2, 1);
|
|
|
|
break;
|
2014-08-08 12:40:50 +00:00
|
|
|
case 'j':
|
|
|
|
r_core_anal_fcn_list (core, input+2, 'j');
|
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 's': {
|
2014-06-16 03:58:00 +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;
|
2014-09-26 13:40:17 +00:00
|
|
|
if ((f = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL))) {
|
2014-06-16 03:58:00 +00:00
|
|
|
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-01-23 01:31:51 +00:00
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
case 'v':
|
2014-06-16 03:58:00 +00:00
|
|
|
var_cmd (core, input+1);
|
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'c':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
RAnalFunction *fcn;
|
2014-09-26 16:10:33 +00:00
|
|
|
if ((fcn = r_anal_get_fcn_in (core->anal, core->offset, 0)) != NULL) {
|
2014-06-18 23:11:53 +00:00
|
|
|
r_cons_printf ("%i\n", r_anal_fcn_cc (fcn));
|
2014-06-19 08:27:02 +00:00
|
|
|
} else eprintf ("Error: Cannot find function at 0x08%"PFMT64x"\n", core->offset);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'b':
|
2014-06-16 03:58:00 +00:00
|
|
|
if (input[2] == 'b') {
|
|
|
|
anal_fcn_add_bb (core, input+3);
|
|
|
|
} else {
|
2014-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset,
|
2014-06-16 03:58:00 +00:00
|
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
|
|
|
|
if (fcn) fcn->bits = atoi (input+3);
|
|
|
|
else eprintf ("Cannot find function to set bits\n");
|
|
|
|
}
|
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'n':
|
2014-09-12 01:17:02 +00:00
|
|
|
if (input[2]=='a') { // afna autoname
|
|
|
|
char *name = r_core_anal_fcn_autoname (core, core->offset);
|
|
|
|
if (name) {
|
2014-09-18 09:37:28 +00:00
|
|
|
r_cons_printf ("afn %s 0x%08"PFMT64x"\n",
|
|
|
|
name, core->offset);
|
2014-09-12 01:17:02 +00:00
|
|
|
free (name);
|
|
|
|
}
|
|
|
|
} else {
|
2014-06-16 03:58:00 +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);
|
|
|
|
}
|
|
|
|
if (*name) {
|
2014-09-26 13:40:17 +00:00
|
|
|
fcn = r_anal_get_fcn_in (core->anal, off,
|
2014-06-16 03:58:00 +00:00
|
|
|
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM|R_ANAL_FCN_TYPE_LOC);
|
|
|
|
if (fcn) {
|
2014-09-22 11:45:36 +00:00
|
|
|
//r_cons_printf ("fr %s %s@ 0x%"PFMT64x"\n",
|
|
|
|
// fcn->name, name, off);
|
2014-06-16 03:58:00 +00:00
|
|
|
r_core_cmdf (core, "fr %s %s@ 0x%"PFMT64x,
|
|
|
|
fcn->name, name, off);
|
|
|
|
free (fcn->name);
|
|
|
|
fcn->name = strdup (name);
|
|
|
|
} else eprintf ("Cannot find function '%s' at 0x%08llx\n", name, off);
|
|
|
|
free (name);
|
|
|
|
} else {
|
|
|
|
eprintf ("Usage: afn newname [off] # set new name to given function\n");
|
|
|
|
free (name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
|
|
|
/* this is undocumented and probably have no uses. plz discuss */
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'e':
|
2014-06-16 03:58:00 +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);
|
|
|
|
}
|
2014-09-26 13:40:17 +00:00
|
|
|
fcn = r_anal_get_fcn_in (core->anal, off,
|
2014-06-16 03:58:00 +00:00
|
|
|
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%08llx\n", core->offset);
|
|
|
|
if (name) {
|
|
|
|
free (name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-09-22 22:40:35 +00:00
|
|
|
#endif
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'x':
|
2014-06-16 03:58:00 +00:00
|
|
|
switch (input[2]) {
|
|
|
|
case '\0':
|
|
|
|
case ' ':
|
2014-09-22 22:40:35 +00:00
|
|
|
#if FCN_OLD
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: sdbize!
|
|
|
|
// list xrefs from current address
|
|
|
|
{
|
|
|
|
ut64 addr = input[2]? r_num_math (core->num, input+2): core->offset;
|
2014-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
|
2014-06-16 03:58:00 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
} else eprintf ("Cant find function\n");
|
|
|
|
}
|
2014-09-22 22:40:35 +00:00
|
|
|
#else
|
|
|
|
#warning TODO_ FCNOLD sdbize xrefs here
|
|
|
|
eprintf ("TODO\n");
|
|
|
|
#endif
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
case 'c': // add meta xref
|
|
|
|
case 'd':
|
|
|
|
case 's':
|
|
|
|
case 'C': {
|
|
|
|
char *p;
|
|
|
|
ut64 a, b;
|
|
|
|
RAnalFunction *fcn;
|
|
|
|
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);
|
2014-09-26 13:40:17 +00:00
|
|
|
fcn = r_anal_get_fcn_in (core->anal, a, R_ANAL_FCN_TYPE_ROOT);
|
2014-06-16 03:58:00 +00:00
|
|
|
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);
|
2014-09-26 13:40:17 +00:00
|
|
|
fcn = r_anal_get_fcn_in (core->anal, a, R_ANAL_FCN_TYPE_ROOT);
|
2014-06-16 03:58:00 +00:00
|
|
|
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: afr- [src] [dst]\n");
|
|
|
|
free (mi);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-06-19 14:55:51 +00:00
|
|
|
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;
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-06-19 14:55:51 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "af", "",
|
|
|
|
"af", " @[addr]", "analyze functions (start at addr)",
|
|
|
|
"af+", " addr size name [type] [diff]", "add function",
|
|
|
|
"af-", " [addr]", "clean all function analysis data (or function at addr)",
|
|
|
|
"afb", " 16", "set current function as thumb",
|
|
|
|
"afbb", " fcnaddr addr size name [type] [diff]", "add bb to function @ fcnaddr",
|
2014-09-02 00:48:41 +00:00
|
|
|
"aff", "", "re-adjust function boundaries to fit",
|
2014-06-19 14:55:51 +00:00
|
|
|
"afl", "[*] [fcn name]", "list functions (addr, size, bbs, name)",
|
2014-08-08 12:40:50 +00:00
|
|
|
"afi", " [addr|fcn.name]", "show function(s) information (verbose afl)",
|
|
|
|
"afj", " [addr|fcn.name]", "show function(s) information in JSON",
|
2014-06-19 14:55:51 +00:00
|
|
|
"afn", " name [addr]", "rename name for function at address (change flag too)",
|
2014-09-12 01:17:02 +00:00
|
|
|
"afna", "", "suggest automatic name for current offset",
|
2014-06-19 14:55:51 +00:00
|
|
|
"afx", "[cCd-] src dst", "add/remove code/Call/data/string reference",
|
|
|
|
"afs", " [addr] [fcnsign]", "get/set function signature at current address",
|
|
|
|
"afv", "[?] [idx] [type] [name]", "add local var on current function",
|
|
|
|
"afa", "[?] [idx] [type] [name]", "add function argument",
|
|
|
|
"af[aAv?]", "[arg]", "manipulate args, fastargs and variables in function",
|
|
|
|
"afc", "@[addr]", "calculate the Cyclomatic Complexity (starting at addr)",
|
|
|
|
"af*", "", "output radare commands",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
default:
|
2014-09-22 13:00:41 +00:00
|
|
|
{
|
|
|
|
// first undefine
|
|
|
|
//r_core_anal_undefine (core, core->offset);
|
|
|
|
/* resize function if overlaps */
|
|
|
|
{
|
2014-09-26 16:10:33 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
|
2014-09-26 13:40:17 +00:00
|
|
|
if (fcn)
|
2014-09-22 13:00:41 +00:00
|
|
|
r_anal_fcn_resize (fcn, core->offset - fcn->addr);
|
|
|
|
}
|
|
|
|
r_core_anal_fcn (core, core->offset, UT64_MAX,
|
2014-07-01 15:01:52 +00:00
|
|
|
R_ANAL_REF_TYPE_NULL,
|
2014-09-22 13:00:41 +00:00
|
|
|
r_config_get_i (core->config, "anal.depth"));
|
|
|
|
}
|
2014-01-23 01:31:51 +00:00
|
|
|
}
|
|
|
|
return R_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-05-25 01:00:24 +00:00
|
|
|
static void __anal_reg_list (RCore *core, int type, int size, char mode) {
|
|
|
|
RReg *hack = core->dbg->reg;
|
2014-06-23 13:10:20 +00:00
|
|
|
int bits;
|
|
|
|
if (size > 0) //TODO: ar all
|
|
|
|
bits = size;
|
|
|
|
else bits = core->anal->bits;
|
2014-06-04 20:58:22 +00:00
|
|
|
const char *use_color;
|
2014-05-29 12:33:15 +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
|
|
|
|
use_color = ConsP(creg): Color_BWHITE;
|
|
|
|
} else {
|
|
|
|
use_color = NULL;
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
core->dbg->reg = core->anal->reg;
|
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) {
|
|
|
|
const char * help_message[] = {
|
|
|
|
"Usage: ar", "", "# Analysis Registers",
|
|
|
|
"ar", "", "Show 'gpr' registers",
|
|
|
|
"ar0", "", "Reset register arenas to 0",
|
|
|
|
"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",
|
|
|
|
"ar=", "", "Show register values in columns",
|
|
|
|
"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",
|
|
|
|
"aro", "", "Show old (previous) register values",
|
|
|
|
"arp"," <file>", "Load register profile from file",
|
|
|
|
"ars", "", "Stack register state",
|
|
|
|
"art","","List all register types",
|
|
|
|
".ar*","", "Import register values as flags",
|
|
|
|
".ar-","", "Unflag all registers",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
r_core_cmd_help (core, help_message);
|
|
|
|
}
|
|
|
|
|
2014-06-17 08:23:11 +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;
|
2014-05-29 12:33:15 +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
|
|
|
|
use_color = ConsP(creg): Color_BWHITE;
|
|
|
|
} else {
|
|
|
|
use_color = NULL;
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
switch (str[0]) {
|
2014-06-19 02:52:28 +00:00
|
|
|
case '0':
|
|
|
|
r_reg_arena_zero (core->anal->reg);
|
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case '?':
|
|
|
|
if (str[1]) {
|
|
|
|
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;
|
2014-07-03 09:54:58 +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);
|
2014-07-08 11:04:07 +00:00
|
|
|
free (buf);
|
2014-07-03 09:54:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'b':
|
2014-06-16 03:58:00 +00:00
|
|
|
{ // 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);
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2014-06-16 03:58:00 +00:00
|
|
|
// TODO: set flag values with drc zf=1
|
|
|
|
{
|
|
|
|
RRegItem *r;
|
|
|
|
const char *name = str+1;
|
|
|
|
while (*name==' ') name++;
|
|
|
|
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);
|
|
|
|
RRegFlags* rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
|
|
|
|
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);
|
|
|
|
if (*name=='=') {
|
|
|
|
for (i=0; i<R_REG_COND_LAST; i++) {
|
|
|
|
r_cons_printf ("%s:%d ",
|
|
|
|
r_reg_cond_to_string (i),
|
|
|
|
r_reg_cond_bits (core->dbg->reg, i, rf));
|
|
|
|
}
|
|
|
|
r_cons_newline ();
|
|
|
|
} else {
|
|
|
|
for (i=0; i<R_REG_COND_LAST; i++) {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
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;
|
2014-08-17 00:42:17 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "drs", " # Register states commands",
|
|
|
|
"drs", "", "List register stack",
|
|
|
|
"drs+", "", "Push register state",
|
|
|
|
"drs-", "", "Pop register state",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r_cons_printf ("%d\n", r_list_length (
|
2014-06-16 03:58:00 +00:00
|
|
|
core->dbg->reg->regset[0].pool));
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
if (!str[1]) {
|
|
|
|
if (core->dbg->reg->reg_profile_str) {
|
|
|
|
//core->anal->reg = core->dbg->reg;
|
|
|
|
r_cons_printf ("%s\n", core->dbg->reg->reg_profile_str);
|
|
|
|
//r_cons_printf ("%s\n", core->anal->reg->reg_profile);
|
|
|
|
} else eprintf ("No register profile defined. Try 'dr.'\n");
|
|
|
|
} else r_reg_set_profile (core->dbg->reg, str+2);
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
for (i=0; (name=r_reg_get_type (i)); i++)
|
|
|
|
r_cons_printf ("%s\n", name);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
name = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (str+2));
|
|
|
|
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;
|
|
|
|
case 'd':
|
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;
|
|
|
|
case 'o':
|
|
|
|
r_reg_arena_swap (core->dbg->reg, R_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
|
2014-05-25 01:00:24 +00:00
|
|
|
r_reg_arena_swap (core->dbg->reg, R_FALSE);
|
|
|
|
break;
|
|
|
|
case '=':
|
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 ' ':
|
|
|
|
arg = strchr (str+1, '=');
|
|
|
|
if (arg) {
|
2014-06-17 08:23:11 +00:00
|
|
|
char *ostr, *regname;
|
2014-05-25 01:00:24 +00:00
|
|
|
*arg = 0;
|
2014-08-08 00:11:23 +00:00
|
|
|
ostr = r_str_chop (strdup (str+1));
|
2014-06-17 08:23:11 +00:00
|
|
|
regname = r_str_clean (ostr);
|
2014-08-08 00:11:23 +00:00
|
|
|
r = r_reg_get (core->dbg->reg, regname, -1); //R_REG_TYPE_GPR);
|
2014-05-25 01:00:24 +00:00
|
|
|
if (r) {
|
|
|
|
r_cons_printf ("0x%08"PFMT64x" ->", str,
|
|
|
|
r_reg_get_value (core->dbg->reg, r));
|
|
|
|
r_reg_set_value (core->dbg->reg, r,
|
|
|
|
r_num_math (core->num, arg+1));
|
|
|
|
r_debug_reg_sync (core->dbg, -1, R_TRUE);
|
|
|
|
r_cons_printf ("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;
|
|
|
|
}
|
|
|
|
size = atoi (str+1);
|
|
|
|
if (size==0) {
|
2014-08-08 00:25:18 +00:00
|
|
|
r = r_reg_get (core->dbg->reg, str+1, -1);
|
|
|
|
if (r) {
|
|
|
|
r_cons_printf ("0x%08"PFMT64x"\n",
|
|
|
|
r_reg_get_value (core->dbg->reg, r));
|
|
|
|
return;
|
|
|
|
}
|
2014-05-25 01:00:24 +00:00
|
|
|
arg = strchr (str+1, ' ');
|
|
|
|
if (arg && size==0) {
|
|
|
|
*arg='\0';
|
|
|
|
size = atoi (arg);
|
|
|
|
} else size = bits;
|
|
|
|
type = r_reg_type_by_name (str+1);
|
|
|
|
}
|
|
|
|
if (type != R_REG_TYPE_LAST) {
|
|
|
|
__anal_reg_list (core, type, size, str[0]);
|
|
|
|
} else eprintf ("cmd_debug_reg: Unknown type\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-11 01:32:02 +00:00
|
|
|
static void esil_step(RCore *core, ut64 until_addr, const char *until_expr) {
|
|
|
|
// Stepping
|
|
|
|
int ret;
|
|
|
|
ut8 code[32];
|
|
|
|
RAnalOp op;
|
|
|
|
const char *name = r_reg_get_name (core->anal->reg, r_reg_get_name_idx ("pc"));
|
|
|
|
ut64 addr = r_reg_getv (core->anal->reg, name);
|
|
|
|
repeat:
|
|
|
|
if (r_cons_singleton()->breaked) {
|
|
|
|
eprintf ("[+] ESIL emulation interrupted at 0x%08"PFMT64x"\n", addr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!core->anal->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");
|
2014-08-11 01:32:02 +00:00
|
|
|
core->anal->esil = r_anal_esil_new ();
|
2014-09-11 02:18:23 +00:00
|
|
|
r_anal_esil_setup (core->anal->esil, core->anal, romem, stats); // setup io
|
2014-08-11 01:32:02 +00:00
|
|
|
RList *entries = r_bin_get_entries (core->bin);
|
|
|
|
RBinAddr *entry = NULL;
|
|
|
|
RBinInfo *info = NULL;
|
|
|
|
if (entries && r_list_length(entries)) {
|
|
|
|
entry = (RBinAddr *) r_list_pop (entries);
|
|
|
|
info = r_bin_get_info (core->bin);
|
|
|
|
if (info->has_va)
|
|
|
|
addr = entry->vaddr;
|
|
|
|
else addr = entry->paddr;
|
|
|
|
eprintf ("PC=entry0\n");
|
|
|
|
r_list_push (entries, entry);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
eprintf ("PC=OFF\n");
|
|
|
|
}
|
|
|
|
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 {
|
|
|
|
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
|
|
|
}
|
|
|
|
r_io_read_at (core->io, addr, code, 32);
|
|
|
|
r_asm_set_pc (core->assembler, addr);
|
|
|
|
ret = r_anal_op (core->anal, &op, addr, code, 32);
|
|
|
|
eprintf ("EMULATE %s\n", R_STRBUF_SAFEGET (&op.esil));
|
2014-09-20 13:53:29 +00:00
|
|
|
if (ret) {
|
2014-08-11 01:32:02 +00:00
|
|
|
//r_anal_esil_eval (core->anal, input+2);
|
|
|
|
RAnalEsil *esil = core->anal->esil;
|
2014-09-15 15:13:05 +00:00
|
|
|
r_anal_esil_set_offset (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)
|
|
|
|
core->anal->cur->esil_post_loop(esil, &op);
|
|
|
|
r_anal_esil_dumpstack (esil);
|
|
|
|
r_anal_esil_stack_free (esil);
|
|
|
|
}
|
|
|
|
ut64 newaddr = r_reg_getv (core->anal->reg, name);
|
|
|
|
if (addr == newaddr)
|
|
|
|
r_reg_setv (core->anal->reg, name, addr + op.size);
|
|
|
|
// check addr
|
|
|
|
if (until_addr != UT64_MAX) {
|
|
|
|
if (addr == until_addr) {
|
|
|
|
eprintf ("ADDR BREAK\n");
|
|
|
|
} else goto repeat;
|
|
|
|
}
|
2014-09-26 13:40:17 +00:00
|
|
|
// check esil
|
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");
|
|
|
|
} else goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-23 01:31:51 +00:00
|
|
|
static int cmd_anal(void *data, const char *input) {
|
|
|
|
const char *ptr;
|
|
|
|
RCore *core = (RCore *)data;
|
|
|
|
int l, len = core->blocksize;
|
|
|
|
ut64 addr = core->offset;
|
|
|
|
ut32 tbs = core->blocksize;
|
|
|
|
|
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
|
|
|
|
switch (input[0]) {
|
|
|
|
case '8': // TODO: rename to 'ab'?
|
|
|
|
if (input[1]==' ') {
|
|
|
|
int len;
|
|
|
|
ut8 *buf = malloc (strlen (input)+1);
|
|
|
|
len = r_hex_str2bin (input+2, buf);
|
|
|
|
if (len>0)
|
|
|
|
r_core_anal_bytes (core, buf, len, 0, 0);
|
|
|
|
free (buf);
|
|
|
|
} else eprintf ("Usage: ab [hexpair-bytes]\n");
|
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'r':
|
2014-06-16 03:58:00 +00:00
|
|
|
cmd_anal_reg (core, input+1);
|
2014-05-25 01:00:24 +00:00
|
|
|
break;
|
2013-05-04 00:35:52 +00:00
|
|
|
case 'e':
|
2014-06-16 03:58:00 +00:00
|
|
|
switch (input[1]) {
|
|
|
|
case 'r':
|
|
|
|
// 'aer' is an alias for 'ar'
|
|
|
|
return cmd_anal (core, input+1);
|
|
|
|
case ' ':
|
2014-08-07 22:22:01 +00:00
|
|
|
{
|
2014-09-11 02:18:23 +00:00
|
|
|
RAnalEsil *esil = core->anal->esil;
|
|
|
|
int romem = r_config_get_i (core->config, "esil.romem");
|
|
|
|
int stats = r_config_get_i (core->config, "esil.stats");
|
2014-06-16 03:58:00 +00:00
|
|
|
//r_anal_esil_eval (core->anal, input+2);
|
2014-09-11 02:18:23 +00:00
|
|
|
if (!esil) {
|
|
|
|
esil = r_anal_esil_new ();
|
|
|
|
r_anal_esil_setup (esil, core->anal, romem, stats); // setup io
|
|
|
|
core->anal->esil = esil;
|
2014-08-07 12:57:44 +00:00
|
|
|
}
|
2014-09-11 02:18:23 +00:00
|
|
|
r_anal_esil_setup (esil, core->anal, romem, stats); // setup io
|
|
|
|
esil = core->anal->esil;
|
2014-09-15 15:13:05 +00:00
|
|
|
r_anal_esil_set_offset (esil, core->offset);
|
2014-06-16 03:58:00 +00:00
|
|
|
r_anal_esil_parse (esil, input+2);
|
|
|
|
r_anal_esil_dumpstack (esil);
|
2014-08-07 12:57:44 +00:00
|
|
|
r_anal_esil_stack_free (esil);
|
2014-08-07 22:22:01 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
2014-09-26 13:40:17 +00:00
|
|
|
case 's':
|
2014-08-11 01:32:02 +00:00
|
|
|
// aes -> single step
|
|
|
|
// aesu -> until address
|
|
|
|
// aesue -> until esil expression
|
|
|
|
if (input[2]=='u') {
|
|
|
|
if (input[3]=='e') {
|
|
|
|
esil_step (core, UT64_MAX, input+4);
|
2014-08-08 16:21:21 +00:00
|
|
|
} else {
|
2014-08-11 01:32:02 +00:00
|
|
|
esil_step (core, r_num_math (core->num, input+3), NULL);
|
2014-08-07 12:57:44 +00:00
|
|
|
}
|
2014-08-11 01:32:02 +00:00
|
|
|
} else {
|
|
|
|
esil_step (core, UT64_MAX, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
// aec -> continue until ^C
|
|
|
|
// aecu -> until address
|
|
|
|
// aecue -> until esil expression
|
|
|
|
if (input[2]=='u') {
|
|
|
|
if (input[3]=='e') {
|
|
|
|
esil_step (core, UT64_MAX, input+4);
|
|
|
|
} else {
|
|
|
|
esil_step (core, r_num_math (core->num, input+3), NULL);
|
2014-08-07 12:57:44 +00:00
|
|
|
}
|
2014-08-11 01:32:02 +00:00
|
|
|
} else {
|
|
|
|
esil_step (core, UT64_MAX, "0");
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-08-08 16:18:40 +00:00
|
|
|
case 'd':
|
2014-08-07 12:57:44 +00:00
|
|
|
if (core->anal->esil)
|
|
|
|
r_anal_esil_free (core->anal->esil);
|
|
|
|
core->anal->esil = NULL;
|
|
|
|
break;
|
2014-08-08 16:18:40 +00:00
|
|
|
case 'i':
|
|
|
|
if (core->anal->esil)
|
|
|
|
r_anal_esil_free (core->anal->esil);
|
|
|
|
// reinitialize
|
|
|
|
core->anal->esil = r_anal_esil_new ();
|
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");
|
|
|
|
r_anal_esil_setup (core->anal->esil, core->anal, romem, stats); // setup io
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
switch (input[2]) {
|
|
|
|
case '\0':
|
|
|
|
input = "123*";
|
|
|
|
case ' ':
|
|
|
|
if (core && core->anal && core->anal->esil && core->anal->esil->stats) {
|
|
|
|
char *out = sdb_querys (core->anal->esil->stats, NULL, 0, input+3);
|
|
|
|
if (out) {
|
|
|
|
r_cons_printf ("%s\n", out);
|
|
|
|
free (out);
|
|
|
|
}
|
|
|
|
} else eprintf ("esil.stats is empty. Run 'aei'\n");
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
sdb_reset (core->anal->esil->stats);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalBlock *bb;
|
2014-09-26 13:40:17 +00:00
|
|
|
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal,
|
2014-09-11 02:18:23 +00:00
|
|
|
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
|
2014-09-20 13:53:29 +00:00
|
|
|
if (ret) {
|
2014-09-11 02:18:23 +00:00
|
|
|
r_reg_setv (core->anal->reg, "pc", pc);
|
|
|
|
r_anal_esil_parse (core->anal->esil, R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
r_anal_esil_dumpstack (core->anal->esil);
|
|
|
|
r_anal_esil_stack_free (core->anal->esil);
|
|
|
|
pc += op.size;
|
2014-09-20 13:53:29 +00:00
|
|
|
} else {
|
|
|
|
pc += 4; // XXX
|
|
|
|
}
|
2014-09-11 02:18:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else eprintf ("Cannot find function at 0x%08"PFMT64x"\n", core->offset);
|
|
|
|
}
|
2014-08-08 16:18:40 +00:00
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "ae[idesr?] [arg]", "ESIL code emulation",
|
|
|
|
"aei", "", "initialize ESIL VM state",
|
|
|
|
"aed", "", "deinitialize ESIL VM state",
|
|
|
|
"ae", " [expr]", "evaluate ESIL expression",
|
2014-09-11 02:18:23 +00:00
|
|
|
"aef", " [addr]", "emulate function",
|
|
|
|
"aek", " [query]", "perform sdb query on ESIL.info",
|
|
|
|
"aek-", "", "resets the ESIL.info sdb instance",
|
2014-08-11 01:32:02 +00:00
|
|
|
"aec", "", "continue until ^C",
|
|
|
|
"aecu", " [addr]", "continue until address",
|
|
|
|
"aecue", " [esil]", "continue until esil expression match",
|
2014-08-08 16:18:40 +00:00
|
|
|
"aes", "", "perform emulated debugger step",
|
2014-08-11 01:32:02 +00:00
|
|
|
"aesu", " [addr]", "step until given address",
|
|
|
|
"aesue", " [esil]", "step until esil expression match",
|
2014-08-08 16:18:40 +00:00
|
|
|
"aer", " [..]", "handle ESIL registers like 'ar' or 'dr' does",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
|
|
|
break;
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2013-05-04 00:35:52 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'o':
|
2014-06-16 03:58:00 +00:00
|
|
|
switch (input [1]) {
|
2014-06-19 14:55:51 +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",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
case 'j':
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
if (input[2] && input[3]) {
|
|
|
|
l = (int) r_num_get (core->num, input+2);
|
|
|
|
if (l>0) count = l;
|
|
|
|
if (l>tbs) {
|
|
|
|
r_core_block_size (core, l*4);
|
|
|
|
//len = l;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
len = l = core->blocksize;
|
|
|
|
count = 1;
|
2013-12-14 03:15:01 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
r_core_anal_bytes (core, core->block, len, count, 'j');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#if DEPRECATED
|
|
|
|
case 's':
|
2014-01-31 01:40:16 +00:00
|
|
|
if (input[2]==' ') {
|
|
|
|
char *esil = strdup (input+2);
|
2014-01-31 01:02:51 +00:00
|
|
|
char *o = r_anal_esil_to_sdb (esil);
|
|
|
|
// do stuff
|
2014-01-31 01:40:16 +00:00
|
|
|
if (o&&*o) r_cons_printf ("%s\n", o);
|
2014-01-31 01:02:51 +00:00
|
|
|
free (o);
|
2014-01-31 01:40:16 +00:00
|
|
|
free (esil);
|
|
|
|
} else {
|
|
|
|
RAnalOp *op = r_core_op_anal (core, addr);
|
|
|
|
if (op != NULL) {
|
|
|
|
char *esil = strdup (R_STRBUF_SAFEGET (&op->esil));
|
|
|
|
char *o = r_anal_esil_to_sdb (esil);
|
|
|
|
if (o&&*o) r_cons_printf ("%s\n", o);
|
|
|
|
// do stuff
|
|
|
|
free (esil);
|
|
|
|
free (o);
|
|
|
|
r_anal_op_free (op);
|
|
|
|
}
|
2014-01-31 01:02:51 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 'e':
|
|
|
|
eprintf ("TODO: See 'ae' command\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
if (input[0] && input[1]) {
|
|
|
|
l = (int) r_num_get (core->num, input+2);
|
|
|
|
if (l>0) count = l;
|
|
|
|
if (l>tbs) {
|
|
|
|
r_core_block_size (core, l*4);
|
|
|
|
//len = l;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
len = l = core->blocksize;
|
|
|
|
count = 1;
|
2013-02-11 09:51:45 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
r_core_anal_bytes (core, core->block, len, count, 0);
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
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;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'f':
|
2014-09-22 13:00:41 +00:00
|
|
|
if (!cmd_anal_fcn (core, input)) {
|
2014-01-23 01:31:51 +00:00
|
|
|
return R_FALSE;
|
2014-09-22 13:00:41 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
switch (input[1]) {
|
2012-06-14 00:18:15 +00:00
|
|
|
case 't':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
RList *list = r_core_anal_graph_to (core,
|
|
|
|
r_num_math (core->num, input+2), n);
|
|
|
|
if (list) {
|
|
|
|
RListIter *iter, *iter2;
|
|
|
|
RList *list2;
|
|
|
|
RAnalBlock *bb;
|
|
|
|
r_list_foreach (list, iter, list2) {
|
|
|
|
r_list_foreach (list2, iter2, bb) {
|
|
|
|
r_cons_printf ("-> 0x%08"PFMT64x"\n", bb->addr);
|
|
|
|
}
|
2012-06-14 00:18:15 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
r_list_purge (list);
|
|
|
|
free (list);
|
2012-06-14 00:18:15 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2012-06-14 00:18:15 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'c':
|
2012-12-10 00:52:11 +00:00
|
|
|
r_core_anal_refs (core, r_num_math (core->num, input+2), input[2]=='j'? 2: 1);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2013-01-24 02:48:24 +00:00
|
|
|
case 'j':
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input+2), R_CORE_ANAL_JSON);
|
|
|
|
break;
|
2014-04-27 00:48:42 +00:00
|
|
|
case 'k':
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input+2), R_CORE_ANAL_KEYVALUE);
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'l':
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input+2), R_CORE_ANAL_GRAPHLINES);
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input+2), 0);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, input+2),
|
2014-06-16 03:58:00 +00:00
|
|
|
R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2012-08-14 01:21:31 +00:00
|
|
|
case 'v':
|
2013-01-24 02:48:24 +00:00
|
|
|
r_core_cmd0 (core, "=H /graph/");
|
|
|
|
#if 0
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
2012-09-05 01:25:03 +00:00
|
|
|
int is_html = (r_config_get_i (core->config, "scr.html"));
|
2012-08-14 01:21:31 +00:00
|
|
|
const char *cmd = r_config_get (core->config, "cmd.graph");
|
2012-09-05 01:25:03 +00:00
|
|
|
//char *tmp = r_file_temp ("/tmp/a.dot");
|
|
|
|
char *tmp = strdup ("a.dot"); // XXX
|
|
|
|
|
|
|
|
if (!is_html && strstr (cmd, "htmlgraph")) {
|
|
|
|
is_html = 2;
|
|
|
|
r_config_set (core->config, "scr.html", "true");
|
|
|
|
}
|
|
|
|
r_cons_flush ();
|
|
|
|
int fd = r_cons_pipe_open (tmp, 0);
|
|
|
|
r_core_cmdf (core, "ag%s", input+2);
|
|
|
|
if (is_html==2)
|
|
|
|
r_config_set (core->config, "scr.html", "false");
|
|
|
|
r_cons_flush ();
|
|
|
|
r_cons_pipe_close (fd);
|
|
|
|
r_sys_setenv ("DOTFILE", tmp);
|
2012-08-14 01:21:31 +00:00
|
|
|
r_core_cmdf (core, "%s", cmd);
|
2012-09-05 01:25:03 +00:00
|
|
|
free (tmp);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2013-01-24 02:48:24 +00:00
|
|
|
#endif
|
2012-08-14 01:21:31 +00:00
|
|
|
break;
|
2014-06-19 14:55:51 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "ag[?f]", "Graphiz Code",
|
|
|
|
"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",
|
|
|
|
"agl", " [fcn name]", "output graphviz code using meta-data",
|
|
|
|
"agt", " [addr]", "find paths from current offset to given address",
|
|
|
|
"agfl", " [fcn name]", "output graphviz code of function using meta-data",
|
|
|
|
"agv", "[acdltfl] [a]", "view function using graphviz",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
default:
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
const char *arg = strchr (input, ' ');
|
|
|
|
if (arg) arg++;
|
|
|
|
r_core_anal_graph (core, r_num_math (core->num, arg),
|
|
|
|
R_CORE_ANAL_GRAPHBODY);
|
|
|
|
}
|
2013-09-26 23:38:49 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
switch (input[1]) {
|
2014-06-19 14:55:51 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"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",
|
|
|
|
"att", " [tag]", "select trace tag (no arg unsets)",
|
|
|
|
"at%", "", "TODO",
|
|
|
|
"ata", " 0x804020 ...", "only trace given addresses",
|
|
|
|
"atr", "", "show traces as range commands (ar+)",
|
|
|
|
"atd", "", "show disassembly trace",
|
|
|
|
"atD", "", "show dwarf trace (at*|rsc dwarf-traces $FILE)",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
2012-02-27 01:40:27 +00:00
|
|
|
eprintf ("Current Tag: %d\n", core->dbg->trace->tag);
|
2014-06-19 14:55:51 +00:00
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
eprintf ("NOTE: Ensure given addresses are in 0x%%08"PFMT64x" format\n");
|
|
|
|
r_debug_trace_at (core->dbg, input+2);
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
r_debug_trace_tag (core->dbg, atoi (input+2));
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
//trace_show (2, trace_tag_get());
|
|
|
|
eprintf ("TODO\n");
|
|
|
|
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 '+':
|
|
|
|
ptr = input+3;
|
|
|
|
addr = r_num_math (core->num, ptr);
|
|
|
|
ptr = strchr (ptr, ' ');
|
|
|
|
if (ptr != NULL) {
|
|
|
|
RAnalOp *op = r_core_op_anal (core, addr);
|
|
|
|
if (op != NULL) {
|
2013-12-06 04:04:17 +00:00
|
|
|
RDebugTracepoint *tp = r_debug_trace_add (core->dbg, addr, op->size);
|
2012-02-27 01:40:27 +00:00
|
|
|
tp->count = atoi (ptr+1);
|
|
|
|
r_anal_trace_bb (core->anal, addr);
|
|
|
|
r_anal_op_free (op);
|
|
|
|
} else eprintf ("Cannot analyze opcode at 0x%"PFMT64x"\n", addr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
r_debug_trace_free (core->dbg);
|
|
|
|
core->dbg->trace = r_debug_trace_new (core->dbg);
|
|
|
|
break;
|
|
|
|
case ' ': {
|
2014-06-16 03:58:00 +00:00
|
|
|
RDebugTracepoint *t = r_debug_trace_get (core->dbg,
|
|
|
|
r_num_math (core->num, input+1));
|
|
|
|
if (t != NULL) {
|
|
|
|
r_cons_printf ("offset = 0x%"PFMT64x"\n", t->addr);
|
|
|
|
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);
|
|
|
|
} }
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case '*':
|
2014-06-16 03:58:00 +00:00
|
|
|
r_debug_trace_list (core->dbg, 1);
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'r':
|
2014-06-16 03:58:00 +00:00
|
|
|
eprintf ("TODO\n");
|
|
|
|
//trace_show(-1, trace_tag_get());
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
default:
|
2014-06-16 03:58:00 +00:00
|
|
|
r_debug_trace_list (core->dbg, 0);
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
switch (input[1]) {
|
|
|
|
case 'l':
|
|
|
|
if (input[2] == ' ') {
|
|
|
|
int n = atoi (input+3);
|
|
|
|
if (n>0) {
|
|
|
|
RSyscallItem *si = r_syscall_get (core->anal->syscall, n, -1);
|
|
|
|
if (si) r_cons_printf ("%s\n", si->name);
|
|
|
|
else eprintf ("Unknown syscall number\n");
|
|
|
|
} else {
|
|
|
|
int n = r_syscall_get_num (core->anal->syscall, input+3);
|
|
|
|
if (n != -1) r_cons_printf ("%d\n", n);
|
|
|
|
else eprintf ("Unknown syscall name\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RSyscallItem *si;
|
|
|
|
RListIter *iter;
|
|
|
|
RList *list = r_syscall_list (core->anal->syscall);
|
|
|
|
r_list_foreach (list, iter, si) {
|
|
|
|
r_cons_printf ("%s = 0x%02x.%d\n", si->name, si->swi, si->num);
|
|
|
|
}
|
|
|
|
r_list_free (list);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '\0': {
|
2014-06-16 03:58:00 +00:00
|
|
|
int a0 = (int)r_debug_reg_get (core->dbg, "oeax"); //XXX
|
|
|
|
cmd_syscall_do (core, a0);
|
|
|
|
} break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case ' ':
|
2014-06-16 03:58:00 +00:00
|
|
|
cmd_syscall_do (core, (int)r_num_get (core->num, input+2));
|
|
|
|
break;
|
2014-09-26 12:24:33 +00:00
|
|
|
case 'k':
|
|
|
|
{
|
|
|
|
char *out = sdb_querys (core->anal->syscall->db, NULL, 0, input+3);
|
|
|
|
if (out) {
|
|
|
|
r_cons_printf ("%s\n", out);
|
|
|
|
free (out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
default:
|
2014-06-19 14:55:51 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage: as[l?]\n"
|
|
|
|
"as", "", "display syscall and arguments",
|
|
|
|
"as", " 4", "show syscall 4 based on asm.os and current regs/mem",
|
|
|
|
"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",
|
2014-09-26 12:24:33 +00:00
|
|
|
"ask", " [query]", "perform syscall/ queries",
|
2014-06-19 14:55:51 +00:00
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-05-25 01:00:24 +00:00
|
|
|
case 'x':
|
2013-07-19 01:35:45 +00:00
|
|
|
switch (input[1]) {
|
2012-02-27 01:40:27 +00:00
|
|
|
case '-':
|
2013-07-19 01:35:45 +00:00
|
|
|
r_anal_ref_del (core->anal, r_num_math (core->num, input+2), core->offset);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-01-23 01:31:51 +00:00
|
|
|
case 'k':
|
|
|
|
if (input[2]==' ') {
|
|
|
|
sdb_query (core->anal->sdb_xrefs, input+3);
|
2014-05-25 01:00:24 +00:00
|
|
|
} else eprintf ("|ERROR| Usage: axk [query]\n");
|
2014-01-23 01:31:51 +00:00
|
|
|
break;
|
2013-07-19 01:35:45 +00:00
|
|
|
case '\0':
|
2013-10-24 11:59:19 +00:00
|
|
|
case 'j':
|
2012-02-27 01:40:27 +00:00
|
|
|
case '*':
|
2013-10-24 11:59:19 +00:00
|
|
|
r_core_anal_ref_list (core, input[1]);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-09-03 21:40:57 +00:00
|
|
|
case 't':
|
|
|
|
{
|
|
|
|
RList *list;
|
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
2014-09-04 13:49:12 +00:00
|
|
|
ut8 buf[12];
|
|
|
|
RAsmOp asmop;
|
|
|
|
char* buf_asm = NULL;
|
2014-09-04 22:40:46 +00:00
|
|
|
char *space = strchr (input, ' ');
|
2014-09-04 13:49:12 +00:00
|
|
|
|
2014-09-04 22:40:46 +00:00
|
|
|
if (space) {
|
|
|
|
addr = r_num_math (core->num, space+1);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
2014-09-03 21:40:57 +00:00
|
|
|
list = r_anal_xrefs_get (core->anal, addr);
|
|
|
|
if (list) {
|
2014-09-04 13:49:12 +00:00
|
|
|
if (input[2] == 'q') { // axtq
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("0x%"PFMT64x"\n", ref->addr);
|
|
|
|
} else if (input[2] == 'j') { // axtj
|
|
|
|
r_cons_printf("[");
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->addr, buf, 12);
|
2014-09-04 22:40:46 +00:00
|
|
|
r_asm_set_pc (core->assembler, ref->addr);
|
2014-09-04 13:49:12 +00:00
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
|
|
|
r_cons_printf ("{\"from\":0x%"PFMT64x",\"type\":\"%c\",\"opcode\":\"%s\"}%s",
|
|
|
|
ref->addr, ref->type, asmop.buf_asm, iter->n?",":"");
|
|
|
|
}
|
|
|
|
r_cons_printf("]");
|
|
|
|
r_cons_newline();
|
|
|
|
} else if (input[2] == '*') { // axt*
|
|
|
|
// TODO: implement multi-line comments
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("CCa 0x%"PFMT64x" \"XREF from 0x%"PFMT64x"\n",
|
|
|
|
ref->addr, ref->type, asmop.buf_asm, iter->n?",":"");
|
|
|
|
} else { // axt
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->addr, buf, 12);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
|
|
|
buf_asm = r_print_colorize_opcode (asmop.buf_asm, core->cons->pal.reg,
|
|
|
|
core->cons->pal.num);
|
2014-09-04 22:40:46 +00:00
|
|
|
r_cons_printf ("%c 0x%"PFMT64x" %s\n",
|
|
|
|
ref->type, ref->addr, buf_asm);
|
2014-09-04 13:49:12 +00:00
|
|
|
}
|
2014-09-03 21:40:57 +00:00
|
|
|
}
|
|
|
|
r_list_free (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-04-21 11:50:38 +00:00
|
|
|
case 'f':
|
2014-09-03 21:40:57 +00:00
|
|
|
{
|
2014-09-04 22:40:46 +00:00
|
|
|
ut8 buf[12];
|
|
|
|
RAsmOp asmop;
|
|
|
|
char* buf_asm = NULL;
|
2014-09-03 21:40:57 +00:00
|
|
|
RList *list;
|
|
|
|
RAnalRef *ref;
|
|
|
|
RListIter *iter;
|
2014-09-04 22:40:46 +00:00
|
|
|
char *space = strchr (input, ' ');
|
|
|
|
|
|
|
|
if (space) {
|
|
|
|
addr = r_num_math (core->num, space+1);
|
|
|
|
} else {
|
|
|
|
addr = core->offset;
|
|
|
|
}
|
2014-09-03 21:40:57 +00:00
|
|
|
list = r_anal_xrefs_get_from (core->anal, addr);
|
|
|
|
if (list) {
|
2014-09-04 22:40:46 +00:00
|
|
|
if (input[2] == 'q') { // axtq
|
|
|
|
r_list_foreach (list, iter, ref)
|
|
|
|
r_cons_printf ("0x%"PFMT64x"\n", ref->at);
|
|
|
|
} else if (input[2] == 'j') { // axtj
|
|
|
|
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[2] == '*') { // axt*
|
|
|
|
// 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 { // axt
|
|
|
|
r_list_foreach (list, iter, ref) {
|
|
|
|
r_core_read_at (core, ref->at, buf, 12);
|
|
|
|
r_asm_disassemble (core->assembler, &asmop, buf, 12);
|
|
|
|
buf_asm = r_print_colorize_opcode (asmop.buf_asm, core->cons->pal.reg,
|
|
|
|
core->cons->pal.num);
|
|
|
|
r_cons_printf ("%c 0x%"PFMT64x" %s\n",
|
|
|
|
ref->type, ref->at, buf_asm);
|
|
|
|
}
|
2014-09-03 21:40:57 +00:00
|
|
|
}
|
|
|
|
r_list_free (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
// WTF
|
2014-04-21 11:50:38 +00:00
|
|
|
find_refs (core, input+2);
|
|
|
|
break;
|
2014-01-24 01:37:14 +00:00
|
|
|
case 'C':
|
|
|
|
case 'c':
|
2013-07-19 01:35:45 +00:00
|
|
|
case 'd':
|
|
|
|
case ' ':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
|
|
|
char *ptr = strdup (r_str_trim_head ((char*)input+2));
|
|
|
|
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));
|
|
|
|
case 1: // get addr
|
|
|
|
addr = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
free (ptr);
|
|
|
|
return R_FALSE;
|
|
|
|
}
|
|
|
|
r_anal_ref_add (core->anal, addr, at, input[1]);
|
2014-04-26 19:55:25 +00:00
|
|
|
free (ptr);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2013-07-19 01:35:45 +00:00
|
|
|
break;
|
|
|
|
default:
|
2014-06-19 14:55:51 +00:00
|
|
|
case '?':{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"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",
|
2014-09-03 21:40:57 +00:00
|
|
|
"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",
|
2014-06-19 14:55:51 +00:00
|
|
|
"ax-", " [at]", "clean all refs (or refs from addr)",
|
|
|
|
"ax", "", "list refs",
|
|
|
|
"axk", " [query]", "perform sdb query",
|
|
|
|
"ax*", "", "output radare commands",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2013-07-19 01:35:45 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
r_core_anal_all (core);
|
2014-09-24 20:45:38 +00:00
|
|
|
if (core->cons->breaked)
|
2012-02-27 01:40:27 +00:00
|
|
|
eprintf ("Interrupted\n");
|
2014-09-24 20:45:38 +00:00
|
|
|
r_cons_clear_line (1);
|
2012-02-27 01:40:27 +00:00
|
|
|
r_cons_break_end();
|
2014-09-17 21:54:36 +00:00
|
|
|
if (input[1] == '?') {
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "aa[0*?]", " # see also 'af' and 'afna'",
|
|
|
|
"aa", " ", "alias for 'af@@ sym.*;af@entry0;.afna @@ fcn.*'",
|
|
|
|
"aa0", "", "do not autoname functions after aa (see afna)",
|
|
|
|
"aa*", "", "print the commands that 'aa' will run",
|
|
|
|
NULL};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
} else if (input[1] == '*') {
|
|
|
|
r_cons_printf ("af @@ sym.* ; af @ entry0 ; .afna @@ fcn.*\n");
|
|
|
|
} else if (input[1] != '0') {
|
|
|
|
r_core_cmd0 (core, ".afna @@ fcn.*");
|
|
|
|
}
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
2014-03-24 23:48:42 +00:00
|
|
|
case 'c':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
2014-04-29 01:21:52 +00:00
|
|
|
char *instr_tmp = NULL;
|
2014-03-24 23:48:42 +00:00
|
|
|
int ccl = r_num_math (core->num, &input[2]); //get cycles to look for
|
|
|
|
int cr = r_config_get_i (core->config, "asm.cmtright"); //make stuff look nice
|
|
|
|
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");
|
|
|
|
r_config_set_i (core->config, "asm.cmtright", R_TRUE);
|
|
|
|
r_config_set_i (core->config, "asm.functions", R_FALSE);
|
|
|
|
r_config_set_i (core->config, "asm.lines", R_FALSE);
|
|
|
|
r_config_set_i (core->config, "asm.xrefs", R_FALSE);
|
|
|
|
RList *hooks ;
|
|
|
|
RListIter *iter;
|
|
|
|
RAnalCycleHook *hook;
|
|
|
|
r_cons_break (NULL, NULL);
|
|
|
|
hooks = r_core_anal_cycles (core, ccl); //analyse
|
|
|
|
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);
|
|
|
|
r_config_set_i (core->config, "asm.cmtright", cr); //reset settings
|
|
|
|
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-06-16 03:58:00 +00:00
|
|
|
}
|
2014-03-24 23:48:42 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
case 'p':
|
2012-06-14 00:18:15 +00:00
|
|
|
if (input[1]=='?') {
|
|
|
|
// TODO: accept parameters for ranges
|
|
|
|
r_cons_printf ("Usage: ap ; find in memory for function preludes");
|
|
|
|
} else r_core_search_preludes (core);
|
2012-02-27 01:40:27 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
2012-11-20 02:59:00 +00:00
|
|
|
switch (input[1]) {
|
|
|
|
case 't':
|
|
|
|
cmd_anal_trampoline (core, input+2);
|
|
|
|
break;
|
|
|
|
case ' ':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
2012-11-20 02:59:00 +00:00
|
|
|
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);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
break;
|
|
|
|
case 'k':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
2012-11-20 02:59:00 +00:00
|
|
|
const char *r = r_anal_data_kind (core->anal,
|
2013-03-05 00:28:32 +00:00
|
|
|
core->offset, core->block, core->blocksize);
|
2012-11-20 02:59:00 +00:00
|
|
|
r_cons_printf ("%s\n", r);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
break;
|
|
|
|
case '\0':
|
2014-06-16 03:58:00 +00:00
|
|
|
{
|
2013-02-22 20:05:08 +00:00
|
|
|
//int word = core->assembler->bits / 8;
|
2013-02-21 10:31:04 +00:00
|
|
|
r_core_anal_data (core, core->offset, core->blocksize, 1);
|
2014-06-16 03:58:00 +00:00
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
break;
|
2014-06-19 14:55:51 +00:00
|
|
|
default:{
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"Usage:", "ad", "[kt] [...]",
|
|
|
|
"ad", " [N] [D]","analyze N data words at D depth",
|
|
|
|
"adt", "", "analyze data trampolines (wip)",
|
|
|
|
"adk", "", "analyze data kind (code, text, data, invalid, ...)",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2013-01-22 04:06:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
switch (input[1]) {
|
|
|
|
case '?':
|
|
|
|
if (input[2]) {
|
|
|
|
//ut64 addr = r_num_math (core->num, input+2);
|
|
|
|
eprintf ("TODO: show hint\n");
|
2014-06-19 14:55:51 +00:00
|
|
|
} else {
|
|
|
|
const char* help_msg[] = {
|
|
|
|
"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",
|
|
|
|
"ahb", " 16 @ $$", "force 16bit for current instruction",
|
|
|
|
"ahc", " 0x804804", "override call/jump address",
|
|
|
|
"ahf", " 0x804840", "override fallback address for call",
|
|
|
|
"ahs", " 4", "set opcode size=4",
|
|
|
|
"aho", " foo a0,33", "replace opcode string",
|
|
|
|
"ahe", " eax+=3", "set vm analysis string",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
}
|
2013-01-22 04:06:12 +00:00
|
|
|
break;
|
|
|
|
#if 0
|
2014-06-16 03:58:00 +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);
|
2013-01-22 04:06:12 +00:00
|
|
|
#endif
|
2014-06-16 03:58:00 +00:00
|
|
|
case 'a': // set arch
|
|
|
|
if (input[2]) {
|
|
|
|
int i;
|
|
|
|
char *ptr = strdup (input+3);
|
|
|
|
i = r_str_word_set0 (ptr);
|
|
|
|
if (i==2)
|
2014-08-17 00:01:17 +00:00
|
|
|
r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
2014-06-16 03:58:00 +00:00
|
|
|
r_anal_hint_set_arch (core->anal, core->offset,
|
|
|
|
r_str_word_get0 (ptr, 0));
|
|
|
|
free (ptr);
|
|
|
|
} else eprintf("Missing argument\n");
|
|
|
|
break;
|
|
|
|
case 'b': // set bits
|
|
|
|
if (input[2]) {
|
|
|
|
char *ptr = strdup (input+3);
|
|
|
|
int bits;
|
|
|
|
int i = r_str_word_set0 (ptr);
|
|
|
|
if (i==2)
|
2014-08-17 00:01:17 +00:00
|
|
|
r_num_math (core->num, r_str_word_get0 (ptr, 1));
|
2014-06-16 03:58:00 +00:00
|
|
|
bits = r_num_math (core->num, r_str_word_get0 (ptr, 0));
|
|
|
|
r_anal_hint_set_bits (core->anal, core->offset, bits);
|
|
|
|
free (ptr);
|
|
|
|
} else eprintf("Missing argument\n");
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
r_anal_hint_set_jump (core->anal, core->offset,
|
|
|
|
r_num_math (core->num, input+2));
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
r_anal_hint_set_fail (core->anal, core->offset,
|
|
|
|
r_num_math (core->num, input+2));
|
|
|
|
break;
|
|
|
|
case 's': // set size (opcode length)
|
|
|
|
r_anal_hint_set_size (core->anal, core->offset, atoi (input+2));
|
|
|
|
break;
|
|
|
|
case 'o': // set opcode string
|
|
|
|
r_anal_hint_set_opcode (core->anal, core->offset, input+2);
|
|
|
|
break;
|
|
|
|
case 'e': // set ESIL string
|
|
|
|
r_anal_hint_set_esil (core->anal, core->offset, input+2);
|
|
|
|
break;
|
2013-01-22 04:06:12 +00:00
|
|
|
#if TODO
|
2014-06-16 03:58:00 +00:00
|
|
|
case 'e': // set endian
|
|
|
|
r_anal_hint_set_opcode (core->anal, core->offset, atoi (input+2));
|
|
|
|
break;
|
2013-01-22 04:06:12 +00:00
|
|
|
#endif
|
2014-06-16 03:58:00 +00:00
|
|
|
case 'p':
|
|
|
|
r_anal_hint_set_pointer (core->anal, core->offset, r_num_math (core->num, input+2));
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
case 'j':
|
|
|
|
case '\0':
|
|
|
|
r_core_anal_hint_list (core->anal, input[1]);
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
if (input[2]) {
|
|
|
|
int i;
|
|
|
|
char *ptr = strdup (input+2);
|
|
|
|
ut64 addr;
|
|
|
|
int size = 1;
|
|
|
|
i = r_str_word_set0 (ptr);
|
|
|
|
if (i==2)
|
|
|
|
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;
|
|
|
|
}
|
2013-06-17 01:26:48 +00:00
|
|
|
break;
|
2014-06-16 03:58:00 +00:00
|
|
|
case '!':
|
|
|
|
//eprintf("Trying analysis command extension.\n");
|
|
|
|
if (core->anal && core->anal->cur && core->anal->cur->cmd_ext)
|
|
|
|
return core->anal->cur->cmd_ext (core->anal, input+1);
|
|
|
|
else r_cons_printf ("No plugins for this analysis plugin\n");
|
2013-01-22 04:06:12 +00:00
|
|
|
break;
|
2014-06-19 14:55:51 +00:00
|
|
|
default:{
|
|
|
|
const char* help_msg[] = {
|
2014-09-21 23:39:24 +00:00
|
|
|
"Usage:", "a", "[8adefFghoprxstc] [...]",
|
2014-06-19 14:55:51 +00:00
|
|
|
"a8", " [hexpairs]", "analyze bytes",
|
2014-09-21 23:39:24 +00:00
|
|
|
"aa", "", "analyze all (fcns + bbs) (aa0 to avoid sub renaming)",
|
2014-06-19 14:55:51 +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 graph.depth=1",
|
|
|
|
"ag", "[?acgdlf]", "output Graphviz code",
|
|
|
|
"ah", "[?lba-]", "analysis hints (force opcode size, ...)",
|
|
|
|
"ao", "[e?] [len]", "analyze Opcodes (or emulate it)",
|
|
|
|
"ap", "", "find and analyze function preludes",
|
|
|
|
"ar", "", "like 'dr' but for the esil vm. (registers)",
|
|
|
|
"ax", "[?ld-*]", "manage refs/xrefs (see also afx?)",
|
|
|
|
"as", " [num]", "analyze syscall using dbg.reg",
|
|
|
|
"at", "[trd+-%*?] [.]", "analyze execution traces",
|
2014-09-21 23:39:24 +00:00
|
|
|
"ac", " [cycles]", "analyze which op could be executed in [cycles]",
|
2014-06-19 14:55:51 +00:00
|
|
|
//"ax", " [-cCd] [f] [t]", "manage code/call/data xrefs",
|
|
|
|
NULL
|
|
|
|
};
|
2014-06-26 23:43:04 +00:00
|
|
|
r_core_cmd_help (core, help_msg);
|
|
|
|
r_cons_printf ("Examples:\n"
|
2014-06-19 14:55:51 +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);
|
|
|
|
}
|
2012-11-20 02:59:00 +00:00
|
|
|
break;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
if (tbs != core->blocksize)
|
|
|
|
r_core_block_size (core, tbs);
|
2014-08-10 13:39:00 +00:00
|
|
|
if (core->cons->breaked) {
|
|
|
|
r_cons_clear_line (1);
|
2014-06-16 03:58:00 +00:00
|
|
|
eprintf ("Interrupted\n");
|
2014-08-10 13:39:00 +00:00
|
|
|
}
|
2014-06-16 03:58:00 +00:00
|
|
|
r_cons_break_end();
|
|
|
|
return 0;
|
2012-02-27 01:40:27 +00:00
|
|
|
}
|
|
|
|
|