diff --git a/libr/core/cmd_anal.c b/libr/core/cmd_anal.c index 1b9b92b096..f427bfcd94 100644 --- a/libr/core/cmd_anal.c +++ b/libr/core/cmd_anal.c @@ -91,14 +91,25 @@ static const char *help_msg_aar[] = { static const char *help_msg_ab[] = { "Usage:", "ab", "", "ab", " [addr]", "show basic block information at given address", + "ab.", "", "same as: ab $$", "aba", " [addr]", "analyze esil accesses in basic block (see aea?)", "abb", " [length]", "analyze N bytes and extract basic blocks", "abj", " [addr]", "display basic block information in JSON (alias to afbj)", + "abl", "[,qj]", "list all basic blocks", "abx", " [hexpair-bytes]", "analyze N bytes", "abt[?]", " [addr] [num]", "find num paths from current offset to addr", NULL }; +static const char *help_msg_abl[] = { + "Usage:", "abl", "analyzed basicblocks listing", + "abl", "", "list all program-wide basic blocks analyzed", + "abl,", " [table-query]", "render the list using a table", + "ablj", "", "in json format", + "ablq", "", "in quiet format", + NULL +}; + static const char *help_msg_abt[] = { "Usage:", "abt", "[addr] [num] # find num paths from current offset to addr", "abt", " [addr] [num]", "find num paths from current offset to addr", @@ -2191,6 +2202,230 @@ static ut64 __opaddr(RAnalBlock *b, ut64 addr) { return UT64_MAX; } +static RList *get_xrefs(RAnalBlock *block) { + RListIter *iter; + RAnalRef *ref; + RList *list = NULL; + size_t i; + for (i = 0; i < block->ninstr; i++) { + ut64 ia = block->addr + block->op_pos[i]; + RList *xrefs = r_anal_xrefs_get (block->anal, ia); + r_list_foreach (xrefs, iter, ref) { + if (!list) { + list = r_list_newf (free); + } + r_list_push (list, ut64_new (ref->addr)); + } + } + return list; +} + +static char *fcnjoin(RList *list) { + RAnalFunction *n; + RListIter *iter; + RStrBuf buf; + r_strbuf_init (&buf); + r_list_foreach (list, iter, n) { + r_strbuf_appendf (&buf, " 0x%08" PFMT64x, n->addr); + } + char *s = strdup (r_strbuf_get (&buf)); + r_strbuf_fini (&buf); + return s; +} + +static char *ut64join(RList *list) { + ut64 *n; + RListIter *iter; + RStrBuf buf; + r_strbuf_init (&buf); + r_list_foreach (list, iter, n) { + r_strbuf_appendf (&buf, " 0x%08" PFMT64x, *n); + } + char *s = strdup (r_strbuf_get (&buf)); + r_strbuf_fini (&buf); + return s; +} + +static RList *get_calls(RAnalBlock *block) { + RList *list = NULL; + RAnalOp op; + ut8 *data = malloc (block->size); + if (data) { + block->anal->iob.read_at (block->anal->iob.io, block->addr, data, block->size); + size_t i; + for (i = 0; i < block->size; i++) { + int ret = r_anal_op (block->anal, &op, block->addr + i, data + i, block->size - i, R_ANAL_OP_MASK_HINT); + if (ret < 1) { + continue; + } + if (op.type == R_ANAL_OP_TYPE_CALL) { + if (!list) { + list = r_list_newf (free); + } + r_list_push (list, ut64_new (op.jump)); + } + r_anal_op_fini (&op); + if (op.size > 0) { + i += op.size - 1; + } + } + + } + return list; +} + +static void anal_bb_list(RCore *core, const char *input) { + const int mode = *input; + PJ *pj = NULL; + RTable *table = NULL; + RBIter iter; + RAnalBlock *block; + if (mode == 'j') { + pj = pj_new (); + pj_o (pj); + pj_ka (pj, "blocks"); + } else if (mode == ',' || mode == 't') { + table = r_table_new (); + RTableColumnType *s = r_table_type ("string"); + RTableColumnType *n = r_table_type ("number"); + r_table_add_column (table, n, "addr", 0); + r_table_add_column (table, n, "size", 0); + r_table_add_column (table, n, "traced", 0); + r_table_add_column (table, n, "ninstr", 0); + r_table_add_column (table, s, "jump", 0); + r_table_add_column (table, s, "fail", 0); + r_table_add_column (table, s, "fcns", 0); + r_table_add_column (table, s, "calls", 0); + r_table_add_column (table, s, "xrefs", 0); + } + + r_rbtree_foreach (core->anal->bb_tree, iter, block, RAnalBlock, _rb) { + RList *xrefs = get_xrefs (block); + RList *calls = get_calls (block); + switch (mode) { + case 'j': + pj_o (pj); + char *addr = r_str_newf ("0x%" PFMT64x, block->addr); + pj_ks (pj, "addr", addr); + free (addr); + pj_kb (pj, "traced", block->traced); + pj_kn (pj, "ninstr", block->ninstr); + pj_kn (pj, "size", block->size); + if (block->jump != UT64_MAX) { + pj_kn (pj, "jump", block->jump); + } + if (block->fail != UT64_MAX) { + pj_kn (pj, "fail", block->fail); + } + if (xrefs) { + pj_ka (pj, "xrefs"); + RListIter *iter2; + ut64 *addr; + r_list_foreach (xrefs, iter2, addr) { + pj_n (pj, *addr); + } + pj_end (pj); + } + if (calls) { + pj_ka (pj, "calls"); + RListIter *iter2; + ut64 *addr; + r_list_foreach (calls, iter2, addr) { + pj_n (pj, *addr); + } + pj_end (pj); + } + pj_ka (pj, "fcns"); + RListIter *iter2; + RAnalFunction *fcn; + r_list_foreach (block->fcns, iter2, fcn) { + pj_n (pj, fcn->addr); + } + pj_end (pj); + pj_end (pj); + break; + case ',': + case 't': + { + char *jump = block->jump != UT64_MAX? r_str_newf ("0x%08" PFMT64x, block->jump): strdup (""); + char *fail = block->fail != UT64_MAX? r_str_newf ("0x%08" PFMT64x, block->fail): strdup (""); + char *call = ut64join (calls); + char *xref = ut64join (calls); + char *fcns = fcnjoin (block->fcns); + r_table_add_rowf (table, "xdddsssss", + block->addr, + block->size, + block->traced, + block->ninstr, + jump, + fail, + fcns, + call, + xref + ); + free (jump); + free (fail); + free (call); + free (xref); + free (fcns); + } + break; + case 'q': + r_cons_printf ("0x%08" PFMT64x"\n", block->addr); + break; + default: + r_cons_printf ("0x%08" PFMT64x , block->addr); + if (block->jump != UT64_MAX) { + r_cons_printf (" .j 0x%08" PFMT64x, block->jump); + } + if (block->fail != UT64_MAX) { + r_cons_printf (" .f 0x%08" PFMT64x, block->fail); + } + if (xrefs) { + RListIter *iter2; + r_cons_printf (" .x"); + ut64 *addr; + r_list_foreach (xrefs, iter2, addr) { + r_cons_printf (" 0x%08" PFMT64x, *addr); + } + } + if (calls) { + r_cons_printf (" .c"); + RListIter *iter2; + ut64 *addr; + r_list_foreach (calls, iter2, addr) { + r_cons_printf (" 0x%08" PFMT64x, *addr); + } + } + if (block->fcns) { + RListIter *iter2; + RAnalFunction *fcn; + r_list_foreach (block->fcns, iter2, fcn) { + r_cons_printf (" .u 0x%" PFMT64x, fcn->addr); + } + } + r_cons_printf (" .s %" PFMT64d "\n", block->size); + } + r_list_free (calls); + } + if (mode == 'j') { + pj_end (pj); + pj_end (pj); + char *j = pj_drain (pj); + r_cons_println (j); + free (j); + } else if (mode == 't' || mode == ',') { + char *q = strchr (input, ' '); + if (q) { + r_table_query (table, q + 1); + } + char *s = r_table_tofancystring (table); + r_cons_println (s); + free (s); + r_table_free (table); + } +} + static bool anal_fcn_list_bb(RCore *core, const char *input, bool one) { RDebugTracepoint *tp = NULL; RListIter *iter; @@ -2572,7 +2807,7 @@ static void r_core_anal_nofunclist (RCore *core, const char *input) { if (code_size < 1) { return; } - bitmap = calloc (1, code_size+64); + bitmap = calloc (1, code_size + 64); if (!bitmap) { return; } @@ -7047,7 +7282,7 @@ static void cmd_anal_syscall(RCore *core, const char *input) { } } -static void anal_axg (RCore *core, const char *input, int level, Sdb *db, int opts, PJ* pj) { +static void anal_axg(RCore *core, const char *input, int level, Sdb *db, int opts, PJ* pj) { char arg[32], pre[128]; RListIter *iter; RAnalRef *ref; @@ -9113,7 +9348,7 @@ static void cmd_anal_abt(RCore *core, const char *input) { break; } case '\0': - eprintf ("Usage abt?\n"); + r_core_cmdf (core, "abl, addr/eq/0x%08"PFMT64x, core->offset); break; } } @@ -10207,25 +10442,47 @@ static int cmd_anal(void *data, const char *input) { } break; case 'b': // "ab" - if (input[1] == 'a') { // "aba" + switch (input[1]) { + case '.': // "ab." + r_core_cmd0 (core, "ab $$"); + break; + case 'a': // "aba" r_core_cmdf (core, "aeab%s", input + 1); - } else if (input[1] == 'b') { // "abb" + break; + case 'b': // "abb" core_anal_bbs (core, input + 2); - } else if (input[1] == 'r') { // "abr" + break; + case 'r': // "abr" core_anal_bbs_range (core, input + 2); - } else if (input[1] == 't') { + break; + case ',': // "ab," + case 't': // "abt" cmd_anal_abt (core, input+2); - } else if (input[1] == 'j') { // "abj" + break; + case 'l': // "abl" + if (input[2] == '?') { + r_core_cmd_help (core, help_msg_abl); + } else { + anal_bb_list (core, input + 2); + } + break; + case 'j': // "abj" anal_fcn_list_bb (core, input + 1, false); - } else if (input[1] == ' ' || !input[1] || input[1] == '.') { + break; + case 0: + case ' ': // "ab " // find block + { ut64 addr = core->offset; if (input[1] && input[1] != '.') { addr = r_num_math (core->num, input + 1); } r_core_cmdf (core, "afbi @ 0x%"PFMT64x, addr); - } else { + } + break; + default: r_core_cmd_help (core, help_msg_ab); + break; } break; case 'c': // "ac" diff --git a/test/db/cmd/cmd_ab b/test/db/cmd/cmd_ab new file mode 100644 index 0000000000..95b15af3fc --- /dev/null +++ b/test/db/cmd/cmd_ab @@ -0,0 +1,266 @@ +NAME=ablt +FILE=bins/mach0/mac-ls2 +CMDS=<