diff --git a/libr/core/canal.c b/libr/core/canal.c index 24c81b2cedc33..eeef11662daea 100644 --- a/libr/core/canal.c +++ b/libr/core/canal.c @@ -1579,6 +1579,134 @@ R_API int r_core_anal_fcn_clean(RCore *core, ut64 addr) { return true; } +static char *get_title(ut64 addr) { + return r_str_newf ("0x%"PFMT64x, addr); +} + +R_API int r_core_print_bb_custom(RCore *core, RAnalFunction *fcn) { + RAnalBlock *bb; + RListIter *iter; + if (!fcn) { + return false; + } + + RConfigHold *hc = r_config_hold_new (core->config); + r_config_save_num (hc, "scr.color", "scr.utf8", "asm.marks", "asm.offset", "asm.lines", + "asm.cmt.right", "asm.cmt.col", "asm.fcnlines", "asm.bytes", NULL); + /*r_config_set_i (core->config, "scr.color", 0);*/ + r_config_set_i (core->config, "scr.utf8", 0); + r_config_set_i (core->config, "asm.marks", 0); + r_config_set_i (core->config, "asm.offset", 0); + r_config_set_i (core->config, "asm.lines", 0); + r_config_set_i (core->config, "asm.cmt.right", 0); + r_config_set_i (core->config, "asm.cmt.col", 0); + r_config_set_i (core->config, "asm.fcnlines", 0); + r_config_set_i (core->config, "asm.bytes", 0); + + r_list_foreach (fcn->bbs, iter, bb) { + if (bb->addr == UT64_MAX) { + continue; + } + + char *title = get_title (bb->addr); + char *body = r_core_cmd_strf (core, "pdb @ 0x%08"PFMT64x, bb->addr); + char *body_b64 = r_base64_encode_dyn (body, -1); + + if (!title || !body || !body_b64) { + return false; + } + + body_b64 = r_str_prefix (body_b64, "base64:"); + r_cons_printf ("agn %s %s\n", title, body_b64); + + free (body); + free (body_b64); + free (title); + } + + r_config_restore (hc); + r_config_hold_free (hc); + + r_list_foreach (fcn->bbs, iter, bb) { + if (bb->addr == UT64_MAX) { + continue; + } + + char *u = get_title (bb->addr), *v = NULL; + if (bb->jump != UT64_MAX) { + v = get_title (bb->jump); + r_cons_printf ("age %s %s\n", u, v); + } + if (bb->fail != UT64_MAX) { + v = get_title (bb->fail); + r_cons_printf ("age %s %s\n", u, v); + } + if (bb->switch_op) { + RListIter *it; + RAnalCaseOp *cop; + r_list_foreach (bb->switch_op->cases, it, cop) { + v = get_title (cop->addr); + r_cons_printf ("age %s %s\n", u, v); + } + } + free (u); + free (v); + } + return true; +} + +R_API int r_core_print_bb_gml(RCore *core, RAnalFunction *fcn) { + RAnalBlock *bb; + RListIter *iter; + if (!fcn) { + return false; + } + + r_cons_printf ("graph\n[\n" "hierarchic 1\n" "label \"\"\n" "directed 1\n"); + + r_list_foreach (fcn->bbs, iter, bb) { + RFlagItem *flag = r_flag_get_i (core->flags, bb->addr); + char *msg = flag? strdup (flag->name): r_str_newf ("0x%08"PFMT64x, bb->addr); + r_cons_printf ("\tnode [\n" + "\t\tid\t%"PFMT64d"\n" + "\t\tlabel\t\"%s\"\n" + "\t]\n", bb->addr, msg); + } + + r_list_foreach (fcn->bbs, iter, bb) { + if (bb->addr == UT64_MAX) { + continue; + } + + if (bb->jump != UT64_MAX) { + r_cons_printf ("\tedge [\n" + "\t\tsource %"PFMT64d"\n" + "\t\ttarget %"PFMT64d"\n" + "\t]\n", bb->addr, bb->jump + ); + } + if (bb->fail != UT64_MAX) { + r_cons_printf ("\tedge [\n" + "\t\tsource %"PFMT64d"\n" + "\t\ttarget %"PFMT64d"\n" + "\t]\n", bb->addr, bb->fail + ); + } + if (bb->switch_op) { + RListIter *it; + RAnalCaseOp *cop; + r_list_foreach (bb->switch_op->cases, it, cop) { + r_cons_printf ("\tedge [\n" + "\t\tsource %"PFMT64d"\n" + "\t\ttarget %"PFMT64d"\n" + "\t]\n", bb->addr, cop->addr + ); + } + } + } + return true; +} + R_API void r_core_anal_codexrefs(RCore *core, ut64 addr, int fmt) { RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, -1); if (fcn) { diff --git a/libr/core/cmd_anal.c b/libr/core/cmd_anal.c index c4ab59460da27..b3d155321263b 100644 --- a/libr/core/cmd_anal.c +++ b/libr/core/cmd_anal.c @@ -5776,14 +5776,61 @@ static void cmd_anal_graph(RCore *core, const char *input) { switch (input[0]) { case 'f': // "agf" switch (input[1]) { + case 0:// "agf" + r_core_visual_graph (core, NULL, NULL, false); + break; + case 'v':// "agfv" + eprintf ("\rRendering graph..."); + r_core_visual_graph (core, NULL, NULL, 1); + r_cons_show_cursor (true); + break; case 't':// "agft" - tiny graph r_core_visual_graph (core, NULL, NULL, 2); break; - case 0: - r_core_visual_graph (core, NULL, NULL, false); + case 'd':// "agfd" + if (input[2] == 'm') { + r_core_anal_graph (core, r_num_math (core->num, input + 2), + R_CORE_ANAL_GRAPHLINES); + } else { + r_core_anal_graph (core, r_num_math (core->num, input + 1), + R_CORE_ANAL_GRAPHBODY); + } + break; + case 'j':// "agfj" + r_core_anal_graph (core, r_num_math (core->num, input + 1), R_CORE_ANAL_JSON); + break; + case 'J':// "agfJ" + r_core_anal_graph (core, r_num_math (core->num, input + 1), + R_CORE_ANAL_JSON | R_CORE_ANAL_JSON_FORMAT_DISASM); + case 'g':{// "agfg" + ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset; + RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0); + r_core_print_bb_gml (core, fcn); + break; + } + case 'k':// "agfk" + r_core_cmd0 (core, "ag-; .agf*; aggk"); + break; + case '*':{// "agf*" + ut64 off_fcn = (*(input + 2)) ? r_num_math (core->num, input + 2) : core->offset; + RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, off_fcn, 0); + r_core_print_bb_custom (core, fcn); + break; + } + case 'w':// "agfw" + if (r_config_get_i (core->config, "graph.web")) { + r_core_cmd0 (core, "=H /graph/"); + } else { + const char *cmd = r_config_get (core->config, "cmd.graph"); + if (cmd && *cmd) { + r_core_cmd0 (core, cmd); + } else { + eprintf ("Command cmd.graph not valid\n"); + } + } break; default: - eprintf ("Usage: agf or agft (for tiny)\n"); + eprintf ("Usage: see ag?"); break; } break; diff --git a/libr/include/r_core.h b/libr/include/r_core.h index 6b344c75bdc81..40eca5d309e1e 100644 --- a/libr/include/r_core.h +++ b/libr/include/r_core.h @@ -417,6 +417,8 @@ R_API int r_core_anal_fcn_list(RCore *core, const char *input, const char *rad); R_API int r_core_anal_fcn_list_size(RCore *core); R_API void r_core_anal_fcn_labels(RCore *core, RAnalFunction *fcn, int rad); R_API int r_core_anal_fcn_clean(RCore *core, ut64 addr); +R_API int r_core_print_bb_custom(RCore *core, RAnalFunction *fcn); +R_API int r_core_print_bb_gml(RCore *core, RAnalFunction *fcn); R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts); R_API int r_core_anal_graph_fcn(RCore *core, char *input, int opts); R_API RList* r_core_anal_graph_to(RCore *core, ut64 addr, int n);