radare2/libr/core/cmd_anal.c
pancake 1c93e8a727 Better webui, fix segfault in ag, add agj for json graphs
More work on the webui
New 'agj' command to get function graphs in json
Fix segfault in 'ag' command
'agv' now launches the internal http server
Initial refactoring for RAnalHint integration into RCore
Add basic mime-type support in the http server
Enhace the graph view style
2013-01-24 03:48:24 +01:00

973 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* radare - LGPL - Copyright 2009-2013 - pancake */
#if 1
/* TODO: Move into cmd_anal() */
static void var_help() {
eprintf("Try afv?\n"
" afv 12 int buffer[3]\n"
" afv 12 byte buffer[1024]\n"
"Try af[aAv][gs] [delta] [[addr]]\n"
" afag 0 = arg0 get\n"
" afvs 12 = var12 set\n"
"a = arg, A = fastarg, v = var\n"
"TODO: [[addr]] is not yet implemented. use @\n");
}
static int var_cmd(RCore *core, const char *str) {
RAnalFunction *fcn = r_anal_fcn_find (core->anal, core->offset,
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
char *p, *p2, *p3, *ostr;
int scope, delta;
ostr = p = strdup (str);
str = (const char *)ostr;
switch (*str) {
case 'V': // show vars in human readable format
r_anal_var_list_show (core->anal, fcn, core->offset);
break;
case '?':
var_help ();
break;
case 'v': // frame variable
case 'a': // stack arg
case 'A': // fastcall arg
// XXX nested dup
switch (*str) {
case 'v': scope = R_ANAL_VAR_SCOPE_LOCAL|R_ANAL_VAR_DIR_NONE; break;
case 'a': scope = R_ANAL_VAR_SCOPE_ARG|R_ANAL_VAR_DIR_IN; break;
case 'A': scope = R_ANAL_VAR_SCOPE_ARGREG|R_ANAL_VAR_DIR_IN; break;
default:
eprintf ("Unknown type\n");
return 0;
}
/* Variable access CFvs = set fun var */
switch (str[1]) {
case '\0': r_anal_var_list (core->anal, fcn, 0, 0); return 0;
case '?': var_help(); return 0;
case '.': r_anal_var_list (core->anal, fcn, core->offset, 0); return 0;
case 's':
case 'g':
if (str[2]!='\0') {
if (fcn != NULL) {
RAnalVar *var = r_anal_var_get (core->anal, fcn, atoi (str+2), R_ANAL_VAR_SCOPE_LOCAL);
if (var != NULL)
return r_anal_var_access_add (core->anal, var, atoi (str+2), (str[1]=='g')?0:1);
eprintf ("Can not find variable in: '%s'\n", str);
} else eprintf ("Unknown variable in: '%s'\n", str);
return R_FALSE;
} else eprintf ("Missing argument\n");
break;
}
str++;
if (str[0]==' ') str++;
delta = atoi (str);
p = strchr (str, ' ');
if (p==NULL) {
var_help();
break;
}
// TODO: Improve parsing error handling
p[0]='\0'; p++;
p2 = strchr (p, ' ');
if (p2) {
p2[0]='\0'; p2 = p2+1;
p3 = strchr (p2,'[');
if (p3 != NULL) {
p3[0]='\0';
p3=p3+1;
}
// p2 - name of variable
r_anal_var_add (core->anal, fcn, core->offset, delta, scope,
r_anal_str_to_type (core->anal, p), p2, p3? atoi (p3): 0);
} else var_help ();
break;
default:
var_help ();
break;
}
free (ostr);
return 0;
}
#endif
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) {
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
}
}
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
}
}
break;
}
}
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
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;
}
if (i+1<item->args)
r_cons_printf (", ");
}
r_cons_printf (")\n");
}
static const char *optypestr(int type) {
switch (type) {
case R_ANAL_OP_TYPE_NULL : return "null";
case R_ANAL_OP_TYPE_JMP : return "jmp";
case R_ANAL_OP_TYPE_UJMP : return "ujmp";
case R_ANAL_OP_TYPE_CJMP : return "cjmp";
case R_ANAL_OP_TYPE_CALL : return "call";
case R_ANAL_OP_TYPE_UCALL : return "ucall";
case R_ANAL_OP_TYPE_REP : return "rep";
case R_ANAL_OP_TYPE_RET : return "ret";
case R_ANAL_OP_TYPE_ILL : return "ill";
case R_ANAL_OP_TYPE_UNK : return "unk";
case R_ANAL_OP_TYPE_NOP : return "nop";
case R_ANAL_OP_TYPE_MOV : return "mov";
case R_ANAL_OP_TYPE_TRAP : return "trap";
case R_ANAL_OP_TYPE_SWI : return "swi";
case R_ANAL_OP_TYPE_UPUSH : return "upush";
case R_ANAL_OP_TYPE_PUSH : return "push";
case R_ANAL_OP_TYPE_POP : return "pop";
case R_ANAL_OP_TYPE_CMP : return "cmp";
case R_ANAL_OP_TYPE_ADD : return "add";
case R_ANAL_OP_TYPE_SUB : return "sub";
case R_ANAL_OP_TYPE_MUL : return "mul";
case R_ANAL_OP_TYPE_DIV : return "div";
case R_ANAL_OP_TYPE_SHR : return "shr";
case R_ANAL_OP_TYPE_SHL : return "shl";
case R_ANAL_OP_TYPE_OR : return "or";
case R_ANAL_OP_TYPE_AND : return "andr";
case R_ANAL_OP_TYPE_XOR : return "xor";
case R_ANAL_OP_TYPE_NOT : return "not";
case R_ANAL_OP_TYPE_STORE : return "store";
case R_ANAL_OP_TYPE_LOAD : return "load";
case R_ANAL_OP_TYPE_LEA : return "lea";
case R_ANAL_OP_TYPE_LEAVE : return "leave";
}
return "err";
}
static void r_core_anal_bytes (RCore *core, const ut8 *buf, int len) {
int ret, idx;
RAnalOp op;
for (idx=ret=0; idx<len; idx+=ret) {
ret = r_anal_op (core->anal, &op,
core->offset+idx, buf + idx, (len-idx));
if (ret<1) {
eprintf ("Oops at 0x%08"PFMT64x" (%02x %02x %02x ...)\n",
core->offset+idx, buf[idx], buf[idx+1], buf[idx+2]);
break;
}
r_cons_printf ("addr: 0x%08"PFMT64x"\n", core->offset+idx);
r_cons_printf ("size: %d\n", op.length);
r_cons_printf ("type: %d (%s)\n", op.type, optypestr (op.type)); // TODO: string
r_cons_printf ("eob: %d\n", op.eob);
r_cons_printf ("jump: 0x%08"PFMT64x"\n", op.jump);
r_cons_printf ("fail: 0x%08"PFMT64x"\n", op.fail);
r_cons_printf ("stack: %d\n", op.stackop); // TODO: string
r_cons_printf ("cond: %d\n", op.cond); // TODO: string
r_cons_printf ("family: %d\n", op.family);
r_cons_printf ("\n");
//r_cons_printf ("false: 0x%08"PFMT64x"\n", core->offset+idx);
}
}
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;
#if 1
switch (input[0]) {
case 'o':
if (input[0] && input[1]) {
l = (int) r_num_get (core->num, input+2);
if (l>0) len = l;
if (l>tbs) {
r_core_block_size (core, l);
len = l;
}
} else len = l = core->blocksize;
}
#endif
r_cons_break (NULL, NULL);
switch (input[0]) {
case '8':
if (input[1]==' ') {
int len;
ut8 *buf = malloc (strlen (input));
len = r_hex_str2bin (input+2, buf);
if (len>0)
r_core_anal_bytes (core, buf, len);
free (buf);
} else eprintf ("Usage: ab [hexpair-bytes]\n");
break;
case 'x':
switch (input[1]) {
case '\0':
case ' ':
// list xrefs from current address
{
ut64 addr = input[1]? r_num_math (core->num, input+1): core->offset;
RAnalFunction *fcn = r_anal_fcn_find (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);
}
} else eprintf ("Cant find function\n");
}
break;
case 'c': // add meta xref
case 'd':
case 'C': {
char *p;
ut64 a, b;
RAnalFunction *fcn;
char *mi = strdup (input);
if (mi && mi[2]==' ' && (p=strchr (mi+3, ' '))) {
*p = 0;
a = r_num_math (core->num, mi+2);
b = r_num_math (core->num, p+1);
fcn = r_anal_fcn_find (core->anal, a, R_ANAL_FCN_TYPE_ROOT);
if (fcn) {
r_anal_fcn_xref_add (core->anal, fcn, a, b, input[1]);
} else eprintf ("Cannot add reference to non-function\n");
} else eprintf ("Usage: ax[cCd?] [src] [dst]\n");
free (mi);
}
break;
case '-': {
char *p;
ut64 a, b;
RAnalFunction *fcn;
char *mi = strdup (input);
if (mi && mi[2]==' ' && (p=strchr (mi+3, ' '))) {
*p = 0;
a = r_num_math (core->num, mi+2);
b = r_num_math (core->num, p+1);
fcn = r_anal_fcn_find (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: ax- [src] [dst]\n");
free (mi);
}
break;
default:
case '?':
r_cons_printf (
"Usage: ax[-cCd?] [src] [dst]\n"
" axc sym.main+0x38 sym.printf ; add code ref\n"
" axC sym.main sym.puts ; add call ref\n"
" axd sym.main str.helloworld ; add data ref\n"
" ax- sym.main str.helloworld ; remove reference\n");
break;
}
break;
case 'o':
if (input[1] == '?') {
r_cons_printf (
"Usage: ao[e?] [len]\n"
" aoe ; emulate opcode at current offset\n"
" aoe 4 ; emulate 4 opcodes starting at current offset\n"
" ao 5 ; display opcode analysis of 5 opcodes\n");
} else
if (input[1] == 'e') {
eprintf ("TODO: r_anal_op_execute\n");
} else {
r_core_anal_bytes (core, core->block, len);
}
break;
case 'F':
r_core_anal_fcn (core, core->offset, -1, R_ANAL_REF_TYPE_NULL, 1);
break;
case 'f':
switch (input[1]) {
case '-':
{
ut64 addr = r_num_math (core->num, input+2);
r_anal_fcn_del_locs (core->anal, addr);
r_anal_fcn_del (core->anal, addr);
}
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 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));
}
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;
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;
case 's': {
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_fcn_find (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;
case 'a':
case 'A':
case 'v':
var_cmd (core, input+1);
break;
case 'c':
{
RAnalFunction *fcn;
int cc;
if ((fcn = r_anal_get_fcn_at (core->anal, core->offset)) != NULL) {
cc = r_anal_fcn_cc (fcn);
r_cons_printf ("CyclomaticComplexity 0x%08"PFMT64x" = %i\n",
fcn->addr, cc);
} else eprintf ("Error: function not found\n");
}
break;
case 'b':
{
char *ptr = strdup(input+3);
const char *ptr2 = NULL;
ut64 fcnaddr = -1LL, addr = -1LL;
ut64 size = 0LL;
ut64 jump = -1LL;
ut64 fail = -1LL;
int type = R_ANAL_BB_TYPE_NULL;
RAnalFunction *fcn = NULL;
RAnalDiff *diff = NULL;
switch(r_str_word_set0 (ptr)) {
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));
}
if ((fcn = r_anal_get_fcn_at (core->anal, fcnaddr)) == NULL ||
!r_anal_fcn_add_bb (fcn, addr, size, jump, fail, type, diff))
eprintf ("Error: Cannot add bb\n");
r_anal_diff_free (diff);
free (ptr);
}
break;
case 'r':
{
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);
}
fcn = r_anal_fcn_find (core->anal, off,
R_ANAL_FCN_TYPE_FCN|R_ANAL_FCN_TYPE_SYM);
if (fcn) {
eprintf ("fr %s %s @ 0x%"PFMT64x,
fcn->name, name, off);
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);
}
break;
case 'e':
{
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_fcn_find (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%08llx\n", core->offset);
}
break;
case '?':
r_cons_printf (
"Usage: af[?+-l*]\n"
" af @ [addr] ; Analyze functions (start at addr)\n"
" af+ addr size name [type] [diff] ; Add function\n"
" af- [addr] ; Clean all function analysis data (or function at addr)\n"
" afb fcnaddr addr size name [type] [diff] ; Add bb to function @ fcnaddr\n"
" afl[*] [fcn name] ; List functions (addr, size, bbs, name)\n"
" afi [fcn name] ; Show function(s) information (verbose afl)\n"
" afr name [addr] ; Rename name for function at address (change flag too)\n"
" afs [addr] [fcnsign] ; Get/set function signature at current address\n"
" af[aAv][?] [arg] ; Manipulate args, fastargs and variables in function\n"
" afc @ [addr] ; Calculate the Cyclomatic Complexity (starting at addr)\n"
" af* ; Output radare commands\n");
break;
default:
r_core_anal_fcn (core, core->offset, -1, R_ANAL_REF_TYPE_NULL,
r_config_get_i (core->config, "anal.depth"));
}
break;
case 'g':
switch (input[1]) {
case 't':
{
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);
}
}
}
}
break;
case 'c':
r_core_anal_refs (core, r_num_math (core->num, input+2), input[2]=='j'? 2: 1);
break;
case 'j':
r_core_anal_graph (core, r_num_math (core->num, input+2), R_CORE_ANAL_JSON);
break;
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),
R_CORE_ANAL_GRAPHBODY|R_CORE_ANAL_GRAPHDIFF);
break;
case 'v':
r_core_cmd0 (core, "=H /graph/");
#if 0
{
int is_html = (r_config_get_i (core->config, "scr.html"));
const char *cmd = r_config_get (core->config, "cmd.graph");
//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);
r_core_cmdf (core, "%s", cmd);
free (tmp);
}
#endif
break;
case '?':
r_cons_printf (
"Usage: ag[?f]\n"
" ag [addr] ; Output graphviz code (bb at addr and children)\n"
" aga [addr] ; Idem, but only addresses\n"
" agc [addr] ; Output graphviz call graph of function\n"
" agd [fcn name] ; Output graphviz code of diffed function\n"
" agl [fcn name] ; Output graphviz code using meta-data\n"
" agt [addr] ; find paths from current offset to given address\n"
" agfl [fcn name] ; Output graphviz code of function using meta-data\n"
" agv[acdltfl] [a]; View function using graphviz\n");
break;
default:
r_core_anal_graph (core, r_num_math (core->num, input+1),
R_CORE_ANAL_GRAPHBODY);
}
break;
case 't':
switch (input[1]) {
case '?':
r_cons_strcat ("Usage: at[*] [addr]\n"
" at? ; show help message\n"
" at ; list all traced opcode ranges\n"
" at- ; reset the tracing information\n"
" at* ; list all traced opcode offsets\n"
" at+ [addr] [times] ; add trace for address N times\n"
" at [addr] ; show trace info at address\n"
" att [tag] ; select trace tag (no arg unsets)\n"
" at% ; TODO\n"
" ata 0x804020 ... ; only trace given addresses\n"
" atr ; show traces as range commands (ar+)\n"
" atd ; show disassembly trace\n"
" atD ; show dwarf trace (at*|rsc dwarf-traces $FILE)\n");
eprintf ("Current Tag: %d\n", core->dbg->trace->tag);
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) {
//eprintf("at(0x%08"PFMT64x")=%d (%s)\n", addr, atoi(ptr+1), ptr+1);
//trace_set_times(addr, atoi(ptr+1));
RDebugTracepoint *tp = r_debug_trace_add (core->dbg, addr, op->length);
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 ' ': {
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;
case '*':
r_debug_trace_list (core->dbg, 1);
break;
case 'r':
eprintf ("TODO\n");
//trace_show(-1, trace_tag_get());
break;
default:
r_debug_trace_list (core->dbg, 0);
}
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': {
int a0 = (int)r_debug_reg_get (core->dbg, "oeax"); //XXX
cmd_syscall_do (core, a0);
} break;
case ' ':
cmd_syscall_do (core, (int)r_num_get (core->num, input+2));
break;
default:
case '?':
r_cons_printf (
"Usage: as[l?]\n"
" as Display syscall and arguments\n"
" as 4 Show syscall 4 based on asm.os and current regs/mem\n"
" asl List of syscalls by asm.os and asm.arch\n"
" asl close Returns the syscall number for close\n"
" asl 4 Returns the name of the syscall number 4\n");
break;
}
break;
case 'r':
switch(input[1]) {
case '?':
r_cons_printf (
"Usage: ar[?d-l*]\n"
" ar addr [at] ; Add code ref\n"
" ard addr [at] ; Add data ref\n"
" ar- [at] ; Clean all refs (or refs from addr)\n"
" arl ; List refs\n"
" ar* ; Output radare commands\n");
break;
case '-':
r_anal_ref_del (core->anal, r_num_math (core->num, input+2));
break;
case 'l':
r_core_anal_ref_list (core, R_FALSE);
break;
case '*':
r_core_anal_ref_list (core, R_TRUE);
break;
default:
{
char *ptr = strdup (r_str_trim_head ((char*)input+2));
int n = r_str_word_set0 (ptr);
ut64 at = core->offset;
ut64 addr = -1LL;
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:
return R_FALSE;
}
r_anal_ref_add (core->anal, addr, at,
input[1]=='d'?R_ANAL_REF_TYPE_DATA:R_ANAL_REF_TYPE_CODE);
free (ptr);
}
}
break;
case 'a':
r_cons_break (NULL, NULL);
r_core_anal_all (core);
if (core->cons->breaked)
eprintf ("Interrupted\n");
r_cons_break_end();
break;
case 'p':
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);
break;
case 'd':
switch (input[1]) {
case 't':
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;
case 'k':
{
const char *r = r_anal_data_kind (core->anal,
core->offset, core->block, core->blocksize);
r_cons_printf ("%s\n", r);
}
break;
case '\0':
{
int word = core->assembler->bits / 8;
r_core_anal_data (core, core->offset,
core->blocksize/word, 1);
}
break;
default:
eprintf ("Usage: ad[kt] [...]\n"
" ad [N] [D] analyze N data words at D depth\n"
" adt analyze data trampolines (wip)\n"
" adk analyze data kind (code, text, data, invalid, ...)\n");
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");
} else
r_cons_printf (
"Usage: ah[lba-]\n"
" ah? # show this help\n"
" ah? offset # show hint of given offset\n"
" ah # list hints in human-readable format\n"
" ah- # remove all hints\n"
" ah- offset # remove hints at given offset\n"
" ah* offset # list hints in radare commands format\n"
" aha ppc 51 # set arch for a range of N bytes\n"
" ahb 16 @ $$ # force 16bit for current instruction\n"
" ahl 4 32 # set opcode size=4 for range of 32 bytes\n"
" aho foo a0,33 # replace opcode string\n"
" ahA eax+=3 # set vm analysis string\n"
);
break;
#if 0
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);
#endif
case 'a': // set arch
r_anal_hint_set_arch (core->anal, core->offset,
1, input+2);
break;
case 'b': // set bits
r_anal_hint_set_bits (core->anal, core->offset,
1, atoi (input+2));
//r_anal_hint_bits (op, 1);
break;
case 'l': // set size (opcode length)
r_anal_hint_set_length (core->anal, core->offset,
1, atoi (input+2));
break;
case 'o': // set opcode string
r_anal_hint_set_opcode (core->anal, core->offset,
1, input+2);
break;
case 'A': // set analysis string
r_anal_hint_set_analstr (core->anal, core->offset,
1, input+2);
break;
#if TODO
case 'e': // set endian
r_anal_hint_set_opcode (core->anal, core->offset,
1, atoi (input+2));
break;
#endif
case '*':
case 'j':
case '\0':
r_core_anal_hint_list (core->anal, input[1]);
break;
case '-':
if (input[2]) {
r_anal_hint_del (core->anal,
r_num_math (core->num, input+2));
} else r_anal_hint_clear (core->anal);
break;
}
break;
default:
r_cons_printf (
"Usage: a[?adfFghoprsx]\n"
" a8 [hexpairs] ; analyze bytes\n"
" aa ; analyze all (fcns + bbs)\n"
" ad ; analyze data trampoline (wip)\n"
" ad [from] [to] ; analyze data pointers to (from-to)\n"
" af[bcsl?+-*] ; analyze Functions\n"
" aF ; same as above, but using graph.depth=1\n"
" ag[?acgdlf] ; output Graphviz code\n"
" ah[?lba-] ; analysis hints (force opcode size, ...)\n"
" ao[e?] [len] ; analyze Opcodes (or emulate it)\n"
" ap ; find and analyze function preludes\n"
" ar[?ld-*] ; manage refs/xrefs\n"
" as [num] ; analyze syscall using dbg.reg\n"
" at[trd+-*?] [.] ; analyze execution Traces\n"
" ax[-cCd] [f] [t] ; manage code/call/data xrefs\n"
"Examples:\n"
" 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");
break;
}
if (tbs != core->blocksize)
r_core_block_size (core, tbs);
if (core->cons->breaked)
eprintf ("Interrupted\n");
r_cons_break_end();
return 0;
}