From a0354d4cfda993c55d9d8124eb4d1b502e3fa37b Mon Sep 17 00:00:00 2001 From: dodococo Date: Fri, 16 Aug 2019 20:21:11 +0530 Subject: [PATCH] Implement `agd*` based commands (#14809) * ag* commands fully functional * Indent and r_return usage * All agd* commands functional now * Graphs are pretty now * Refactoring the code * Fixed assertion error * Fixed broken agf --- libr/cons/pal.c | 10 + libr/core/agraph.c | 95 +++--- libr/core/canal.c | 635 +++++++++++++++++++++++----------------- libr/core/cmd_anal.c | 89 +++--- libr/include/r_agraph.h | 2 + libr/include/r_cons.h | 8 + libr/include/r_core.h | 1 + 7 files changed, 491 insertions(+), 349 deletions(-) diff --git a/libr/cons/pal.c b/libr/cons/pal.c index 91848b5d3b..a290d71ef2 100644 --- a/libr/cons/pal.c +++ b/libr/cons/pal.c @@ -72,6 +72,11 @@ static struct { { "graph.current", r_offsetof (RConsPrintablePalette, graph_current), r_offsetof (RConsPalette, graph_current) }, { "graph.traced", r_offsetof (RConsPrintablePalette, graph_traced), r_offsetof (RConsPalette, graph_traced) }, + { "graph.diff.unknown", r_offsetof (RConsPrintablePalette, graph_diff_unknown), r_offsetof (RConsPalette, graph_diff_unknown) }, + { "graph.diff.new", r_offsetof (RConsPrintablePalette, graph_diff_new), r_offsetof (RConsPalette, graph_diff_new) }, + { "graph.diff.match", r_offsetof (RConsPrintablePalette, graph_diff_match), r_offsetof (RConsPalette, graph_diff_match) }, + { "graph.diff.unmatch", r_offsetof (RConsPrintablePalette, graph_diff_unmatch), r_offsetof (RConsPalette, graph_diff_unmatch) }, + { "gui.cflow", r_offsetof (RConsPrintablePalette, gui_cflow), r_offsetof (RConsPalette, gui_cflow) }, { "gui.dataoffset", r_offsetof (RConsPrintablePalette, gui_dataoffset), r_offsetof (RConsPalette, gui_dataoffset) }, { "gui.background", r_offsetof (RConsPrintablePalette, gui_background), r_offsetof (RConsPalette, gui_background) }, @@ -227,6 +232,11 @@ R_API void r_cons_pal_init(RConsContext *ctx) { ctx->cpal.graph_trufae = (RColor) RColor_BLUE; // single jump ctx->cpal.graph_traced = (RColor) RColor_YELLOW; ctx->cpal.graph_current = (RColor) RColor_BLUE; + ctx->cpal.graph_diff_unknown = (RColor) RColor_MAGENTA; + ctx->cpal.graph_diff_new = (RColor) RColor_RED; + ctx->cpal.graph_diff_match = (RColor) RColor_GRAY; + ctx->cpal.graph_diff_unmatch = (RColor) RColor_YELLOW; + r_cons_pal_free (ctx); ctx->pal.reset = Color_RESET; // reset is not user accessible, const char* is ok diff --git a/libr/core/agraph.c b/libr/core/agraph.c index 546f5d1253..f86c8395c5 100644 --- a/libr/core/agraph.c +++ b/libr/core/agraph.c @@ -317,6 +317,16 @@ static void tiny_RANode_print(const RAGraph *g, const RANode *n, int cur) { } } +static char *get_node_color (int color, int cur) { + RCons *cons = r_cons_singleton (); + if (color == -1) { + return cur ? cons->context->pal.graph_box2 : cons->context->pal.graph_box; + } + return color ? (\ + color==R_ANAL_DIFF_TYPE_MATCH ? cons->context->pal.graph_diff_match: + color==R_ANAL_DIFF_TYPE_UNMATCH? cons->context->pal.graph_diff_unmatch : cons->context->pal.graph_diff_new): cons->context->pal.graph_diff_unknown; +} + static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) { ut32 center_x = 0, center_y = 0; ut32 delta_x = 0, delta_txt_x = 0; @@ -324,6 +334,7 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) { char title[TITLE_LEN]; char *body; int x, y; + int color = n->difftype; const bool showTitle = g->show_node_titles; const bool showBody = g->show_node_body; @@ -401,18 +412,17 @@ static void normal_RANode_print(const RAGraph *g, const RANode *n, int cur) { // TODO: check if node is traced or not and show proper color // This info must be stored inside RANode* from RCore* - RCons *cons = r_cons_singleton (); if (g->show_node_bubble) { if (cur) { - r_cons_canvas_circle (g->can, n->x, n->y, n->w, n->h, cons->context->pal.graph_box2); + r_cons_canvas_circle (g->can, n->x, n->y, n->w, n->h, get_node_color(color, cur)); } else { - r_cons_canvas_circle(g->can, n->x, n->y, n->w, n->h, cons->context->pal.graph_box); + r_cons_canvas_circle(g->can, n->x, n->y, n->w, n->h, get_node_color(color, cur)); } } else { if (cur) { - r_cons_canvas_box (g->can, n->x, n->y, n->w, n->h, cons->context->pal.graph_box2); + r_cons_canvas_box (g->can, n->x, n->y, n->w, n->h, get_node_color(color, cur)); } else { - r_cons_canvas_box (g->can, n->x, n->y, n->w, n->h, cons->context->pal.graph_box); + r_cons_canvas_box (g->can, n->x, n->y, n->w, n->h, get_node_color(color, cur)); } } } @@ -3673,42 +3683,47 @@ R_API void r_agraph_set_title(RAGraph *g, const char *title) { sdb_set (g->db, "agraph.title", g->title, 0); } -R_API RANode *r_agraph_add_node(const RAGraph *g, const char *title, const char *body) { - RANode *res = r_agraph_get_node (g, title); - if (res) { - return res; - } - res = R_NEW0 (RANode); - if (!res) { - return NULL; - } +R_API RANode *r_agraph_add_node_with_color(const RAGraph *g, const char *title, const char *body, int color) { + RANode *res = r_agraph_get_node (g, title); + if (res) { + return res; + } + res = R_NEW0 (RANode); + if (!res) { + return NULL; + } - res->title = title? r_str_trunc_ellipsis (title, 255) : strdup (""); - res->body = body? strdup (body): strdup (""); - res->layer = -1; - res->pos_in_layer = -1; - res->is_dummy = false; - res->is_reversed = false; - res->klass = -1; - res->gnode = r_graph_add_node (g->graph, res); - sdb_num_set (g->nodes, res->title, (ut64) (size_t) res, 0); - if (res->title) { - char *s, *estr, *b; - size_t len; - sdb_array_add (g->db, "agraph.nodes", res->title, 0); - b = strdup (res->body); - len = strlen (b); - if (len > 0 && b[len - 1] == '\n') { - b[len - 1] = '\0'; - } - estr = sdb_encode ((const void *) b, -1); - //s = sdb_fmt ("base64:%s", estr); - s = r_str_newf ("base64:%s", estr); - free (estr); - free (b); - sdb_set (g->db, sdb_fmt ("agraph.nodes.%s.body", res->title), s, 0); - } - return res; + res->title = title? r_str_trunc_ellipsis (title, 255) : strdup (""); + res->body = body? strdup (body): strdup (""); + res->layer = -1; + res->pos_in_layer = -1; + res->is_dummy = false; + res->is_reversed = false; + res->klass = -1; + res->difftype = color; + res->gnode = r_graph_add_node (g->graph, res); + sdb_num_set (g->nodes, res->title, (ut64) (size_t) res, 0); + if (res->title) { + char *s, *estr, *b; + size_t len; + sdb_array_add (g->db, "agraph.nodes", res->title, 0); + b = strdup (res->body); + len = strlen (b); + if (len > 0 && b[len - 1] == '\n') { + b[len - 1] = '\0'; + } + estr = sdb_encode ((const void *) b, -1); + //s = sdb_fmt ("base64:%s", estr); + s = r_str_newf ("base64:%s", estr); + free (estr); + free (b); + sdb_set (g->db, sdb_fmt ("agraph.nodes.%s.body", res->title), s, 0); + } + return res; +} + +R_API RANode *r_agraph_add_node(const RAGraph *g, const char *title, const char *body) { + return r_agraph_add_node_with_color(g, title, body, -1); } R_API bool r_agraph_del_node(const RAGraph *g, const char *title) { diff --git a/libr/core/canal.c b/libr/core/canal.c index 24daa5ed87..06ef7ef8c6 100644 --- a/libr/core/canal.c +++ b/libr/core/canal.c @@ -970,6 +970,10 @@ error: return false; } +static char *get_title(ut64 addr) { + return r_str_newf ("0x%"PFMT64x, addr); +} + /* decode and return the RAnalOp at the address addr */ R_API RAnalOp* r_core_anal_op(RCore *core, ut64 addr, int mask) { int len; @@ -1235,6 +1239,9 @@ static char *core_anal_graph_label(RCore *core, RAnalBlock *bb, int opts) { } oline = line; } + } else if (opts & R_CORE_ANAL_STAR) { + snprintf (cmd, sizeof (cmd), "pdb %d @ 0x%08" PFMT64x, bb->size, bb->addr); + str = r_core_cmd_str (core, cmd); } else if (opts & R_CORE_ANAL_GRAPHBODY) { const bool scrColor = r_config_get (core->config, "scr.color"); const bool scrUtf8 = r_config_get (core->config, "scr.utf8"); @@ -1244,10 +1251,10 @@ static char *core_anal_graph_label(RCore *core, RAnalBlock *bb, int opts) { cmdstr = r_core_cmd_str (core, cmd); r_config_set_i (core->config, "scr.color", scrColor); r_config_set_i (core->config, "scr.utf8", scrUtf8); - } - if (cmdstr) { - str = r_str_escape_dot (cmdstr); - free (cmdstr); + if (cmdstr) { + str = r_str_escape_dot (cmdstr); + free (cmdstr); + } } return str; } @@ -1272,18 +1279,347 @@ static void core_anal_color_curr_node(RCore *core, RAnalBlock *bbi) { free (pal_curr); } +static int core_anal_graph_construct_edges (RCore *core, RAnalFunction *fcn, int opts, PJ *pj, Sdb *DB) { + RAnalBlock *bbi; + RListIter *iter; + int is_keva = opts & R_CORE_ANAL_KEYVALUE; + int is_star = opts & R_CORE_ANAL_STAR; + int is_json = opts & R_CORE_ANAL_JSON; + int is_html = r_cons_singleton ()->is_html; + char *pal_jump = palColorFor ("graph.true"); + char *pal_fail = palColorFor ("graph.false"); + char *pal_trfa = palColorFor ("graph.trufae"); + int nodes = 0; + r_list_foreach (fcn->bbs, iter, bbi) { + if (bbi->jump != UT64_MAX) { + nodes++; + if (is_keva) { + char key[128]; + char val[128]; + snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".to", bbi->addr); + if (bbi->fail != UT64_MAX) { + snprintf (val, sizeof (val), "0x%08"PFMT64x, bbi->jump); + } else { + snprintf (val, sizeof (val), "0x%08"PFMT64x ",0x%08"PFMT64x, + bbi->jump, bbi->fail); + } + // bb..to=, + sdb_set (DB, key, val, 0); + } else if (is_html) { + r_cons_printf ("
\n" + "
\n", + bbi->addr, bbi->jump); + } else if (!is_json && !is_keva) { + if (is_star) { + char *from = get_title (bbi->addr); + char *to = get_title (bbi->jump); + r_cons_printf ("age %s %s\n", from, to); + } else { + r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " + "[color=\"%s\"];\n", bbi->addr, bbi->jump, + bbi->fail != -1 ? pal_jump : pal_trfa); + core_anal_color_curr_node (core, bbi); + } + } + } + if (bbi->fail != -1) { + nodes++; + if (is_html) { + r_cons_printf ("
\n" + "
\n", + bbi->addr, bbi->fail); + } else if (!is_keva && !is_json) { + if (is_star) { + char *from = get_title (bbi->addr); + char *to = get_title (bbi->fail); + r_cons_printf ("age %s %s\n", from, to); + } else { + r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " + "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail); + core_anal_color_curr_node (core, bbi); + } + } + } + if (bbi->switch_op) { + RAnalCaseOp *caseop; + RListIter *iter; + + if (bbi->fail != UT64_MAX) { + if (is_html) { + r_cons_printf ("
\n" + "
\n", + bbi->addr, bbi->fail); + } else if (!is_keva && !is_json) { + if (is_star) { + char *from = get_title (bbi->addr); + char *to = get_title (bbi->fail); + r_cons_printf ("%age %s %s\n", from, to); + } else { + r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " + "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail); + core_anal_color_curr_node (core, bbi); + } + } + } + r_list_foreach (bbi->switch_op->cases, iter, caseop) { + nodes++; + if (is_keva) { + char key[128]; + snprintf (key, sizeof (key), + "bb.0x%08"PFMT64x".switch.%"PFMT64d, + bbi->addr, caseop->value); + sdb_num_set (DB, key, caseop->jump, 0); + snprintf (key, sizeof (key), + "bb.0x%08"PFMT64x".switch", bbi->addr); + sdb_array_add_num (DB, key, caseop->value, 0); + } else if (is_html) { + r_cons_printf ("
\n" + "
\n", + caseop->addr, caseop->jump); + } else if (!is_json && !is_keva){ + if (is_star) { + char *from = get_title (caseop->addr); + char *to = get_title (caseop->jump); + r_cons_printf ("age %s %s\n", from ,to); + } else { + r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " \ + "[color2=\"%s\"];\n", caseop->addr, caseop->jump, pal_fail); + core_anal_color_curr_node (core, bbi); + } + } + } + } + } + return nodes; +} + +static int core_anal_graph_construct_nodes (RCore *core, RAnalFunction *fcn, int opts, PJ *pj, Sdb *DB) { + RAnalBlock *bbi; + RListIter *iter; + int is_keva = opts & R_CORE_ANAL_KEYVALUE; + int is_star = opts & R_CORE_ANAL_STAR; + int is_json = opts & R_CORE_ANAL_JSON; + int is_html = r_cons_singleton ()->is_html; + int left = 300; + int top = 0; + + int is_json_format_disasm = opts & R_CORE_ANAL_JSON_FORMAT_DISASM; + char *pal_curr = palColorFor ("graph.current"); + char *pal_traced = palColorFor ("graph.traced"); + char *pal_box4 = palColorFor ("graph.box4"); + const char *font = r_config_get (core->config, "graph.font"); + bool color_current = r_config_get_i (core->config, "graph.gv.current"); + char *str; + int nodes = 0; + r_list_foreach (fcn->bbs, iter, bbi) { + if (is_keva) { + char key[128]; + sdb_array_push_num (DB, "bbs", bbi->addr, 0); + snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".size", bbi->addr); + sdb_num_set (DB, key, bbi->size, 0); // bb..size= + } else if (is_json) { + RDebugTracepoint *t = r_debug_trace_get (core->dbg, bbi->addr); + ut8 *buf = malloc (bbi->size); + pj_o (pj); + pj_kn (pj, "offset", bbi->addr); + pj_kn (pj, "size", bbi->size); + if (bbi->jump != UT64_MAX) { + pj_kn (pj, "jump", bbi->jump); + } + if (bbi->fail != -1) { + pj_kn (pj, "fail", bbi->fail); + } + if (bbi->switch_op) { + RAnalSwitchOp *op = bbi->switch_op; + pj_k (pj, "switchop"); + pj_o (pj); + pj_kn (pj, "offset", op->addr); + pj_kn (pj, "defval", op->def_val); + pj_kn (pj, "maxval", op->max_val); + pj_kn (pj, "minval", op->min_val); + pj_k (pj, "cases"); + pj_a (pj); + RAnalCaseOp *case_op; + RListIter *case_iter; + r_list_foreach (op->cases, case_iter, case_op) { + pj_o (pj); + pj_kn (pj, "offset", case_op->addr); + pj_kn (pj, "value", case_op->value); + pj_kn (pj, "jump", case_op->jump); + pj_end (pj); + } + pj_end (pj); + pj_end (pj); + } + if (t) { + pj_k (pj, "trace"); + pj_o (pj); + pj_ki (pj, "count", t->count); + pj_ki (pj, "times", t->times); + pj_end (pj); + } + pj_kn (pj, "colorize", bbi->colorize); + pj_k (pj, "ops"); + pj_a (pj); + if (buf) { + r_io_read_at (core->io, bbi->addr, buf, bbi->size); + if (is_json_format_disasm) { + r_core_print_disasm (core->print, core, bbi->addr, buf, bbi->size, bbi->size, 0, 1, true, pj, NULL); + } else { + r_core_print_disasm_json (core, bbi->addr, buf, bbi->size, 0, pj); + } + free (buf); + } else { + eprintf ("cannot allocate %d byte(s)\n", bbi->size); + } + pj_end (pj); + pj_end (pj); + continue; + } + if ((str = core_anal_graph_label (core, bbi, opts))) { + if (opts & R_CORE_ANAL_GRAPHDIFF) { + const char *difftype = bbi->diff? (\ + bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "lightgray": + bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "yellow": "red"): "orange"; + const char *diffname = bbi->diff? (\ + bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "match": + bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "unmatch": "new"): "unk"; + if (is_keva) { + sdb_set (DB, "diff", diffname, 0); + sdb_set (DB, "label", str, 0); + } else if (!is_json) { + nodes++; + RConfigHold *hc = r_config_hold_new (core->config); + r_config_hold_i (hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines", + "asm.cmt.right", "asm.lines.fcn", "asm.bytes", NULL); + RDiff *d = r_diff_new (); + 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.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.lines.fcn", 0); + r_config_set_i (core->config, "asm.bytes", 0); + + if (bbi->diff && bbi->diff->type != R_ANAL_DIFF_TYPE_MATCH && core->c2) { + RCore *c = core->c2; + RConfig *oc = c->config; + char *str = r_core_cmd_strf (core, "pdb @ 0x%08"PFMT64x, bbi->addr); + c->config = core->config; + // XXX. the bbi->addr doesnt needs to be in the same address in core2 + char *str2 = r_core_cmd_strf (c, "pdb @ 0x%08"PFMT64x, bbi->diff->addr); + char *diffstr = r_diff_buffers_to_string (d, + (const ut8*)str, strlen (str), + (const ut8*)str2, strlen(str2)); + + if (diffstr) { + char *nl = strchr (diffstr, '\n'); + if (nl) { + nl = strchr (nl + 1, '\n'); + if (nl) { + nl = strchr (nl + 1, '\n'); + if (nl) { + r_str_cpy (diffstr, nl + 1); + } + } + } + } + diffstr = r_str_replace (diffstr, "\n", "\\l", 1); + diffstr = r_str_replace (diffstr, "\"", "'", 1); + if (is_star) { + char *title = get_title (bbi->addr); + char *body_b64 = r_base64_encode_dyn (diffstr, -1); + + if (!title || !body_b64) { + free (body_b64); + free (title); + return false; + } + body_b64 = r_str_prepend (body_b64, "base64:"); + r_cons_printf ("agn %s %s %d\n", title, body_b64, bbi->diff->type); + } else { + r_cons_printf(" \"0x%08"PFMT64x"\" [fillcolor=\"%s\"," + "color=\"black\", fontname=\"Courier\"," + " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n", + bbi->addr, difftype, diffstr, fcn->name, + bbi->addr); + } + free (diffstr); + c->config = oc; + } else { + if (is_star) { + char *title = get_title (bbi->addr); + char *body_b64 = r_base64_encode_dyn (str, -1); + + if (!title || !body_b64) { + free (body_b64); + free (title); + return false; + } + body_b64 = r_str_prepend (body_b64, "base64:"); + r_cons_printf ("agn %s %s %d\n", title, body_b64, bbi->diff->type); + } else { + r_cons_printf(" \"0x%08"PFMT64x"\" [fillcolor=\"%s\"," + "color=\"black\", fontname=\"Courier\"," + " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n", + bbi->addr, difftype, str, fcn->name, bbi->addr); + } + } + r_diff_free (d); + r_config_set_i (core->config, "scr.color", 1); + r_config_hold_free (hc); + } + } else { + if (is_html) { + nodes++; + r_cons_printf ("

\n%s

\n", + top, left, bbi->addr, str); + left = left? 0: 600; + if (!left) { + top += 250; + } + } else if (!is_json && !is_keva) { + bool current = r_anal_bb_is_in_offset (bbi, core->offset); + const char *label_color = bbi->traced + ? pal_traced + : (current && color_current) + ? pal_curr + : pal_box4; + const char *fill_color = (current || label_color == pal_traced)? pal_traced: "white"; + nodes++; + if (is_star) { + char *title = get_title (bbi->addr); + char *body_b64 = r_base64_encode_dyn (str, -1); + + if (!title || !body_b64) { + free (body_b64); + free (title); + return false; + } + body_b64 = r_str_prepend (body_b64, "base64:"); + r_cons_printf ("agn %s %s %d\n", title, body_b64, bbi->diff->type); + } else { + r_cons_printf ("\t\"0x%08"PFMT64x"\" [" + "URL=\"%s/0x%08"PFMT64x"\", fillcolor=\"%s\"," + "color=\"%s\", fontname=\"%s\"," + "label=\"%s\"]\n", + bbi->addr, fcn->name, bbi->addr, + fill_color, label_color, font, str); + } + } + } + free (str); + } + } + return nodes; +} + static int core_anal_graph_nodes(RCore *core, RAnalFunction *fcn, int opts, PJ *pj) { - int is_html = r_cons_singleton ()->is_html; int is_json = opts & R_CORE_ANAL_JSON; - int is_json_format_disasm = opts & R_CORE_ANAL_JSON_FORMAT_DISASM; int is_keva = opts & R_CORE_ANAL_KEYVALUE; - RAnalBlock *bbi; - RListIter *iter; - int left = 300; - int count = 0; int nodes = 0; - int top = 0; - char *str; Sdb *DB = NULL; char *pal_jump = palColorFor ("graph.true"); char *pal_fail = palColorFor ("graph.false"); @@ -1291,8 +1627,6 @@ static int core_anal_graph_nodes(RCore *core, RAnalFunction *fcn, int opts, PJ * char *pal_curr = palColorFor ("graph.current"); char *pal_traced = palColorFor ("graph.traced"); char *pal_box4 = palColorFor ("graph.box4"); - const char *font = r_config_get (core->config, "graph.font"); - bool color_current = r_config_get_i (core->config, "graph.gv.current"); if (!fcn || !fcn->bbs) { eprintf ("No fcn\n"); return -1; @@ -1338,266 +1672,14 @@ static int core_anal_graph_nodes(RCore *core, RAnalFunction *fcn, int opts, PJ * pj_kn (pj, "size", r_anal_fcn_size (fcn)); pj_ki (pj, "stack", fcn->maxstack); pj_ks (pj, "type", r_anal_fcn_type_tostring (fcn->type)); - //pj_ki (pj, "cc", fcn->call) // TODO: calling convention if (fcn->dsc) { pj_ks (pj, "signature", fcn->dsc); } pj_k (pj, "blocks"); pj_a (pj); } - r_list_foreach (fcn->bbs, iter, bbi) { - count ++; - if (is_keva) { - char key[128]; - sdb_array_push_num (DB, "bbs", bbi->addr, 0); - snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".size", bbi->addr); - sdb_num_set (DB, key, bbi->size, 0); // bb..size= - } else if (is_json) { - RDebugTracepoint *t = r_debug_trace_get (core->dbg, bbi->addr); - ut8 *buf = malloc (bbi->size); - pj_o (pj); - pj_kn (pj, "offset", bbi->addr); - pj_kn (pj, "size", bbi->size); - if (bbi->jump != UT64_MAX) { - pj_kn (pj, "jump", bbi->jump); - } - if (bbi->fail != -1) { - pj_kn (pj, "fail", bbi->fail); - } - if (bbi->switch_op) { - RAnalSwitchOp *op = bbi->switch_op; - pj_k (pj, "switchop"); - pj_o (pj); - pj_kn (pj, "offset", op->addr); - pj_kn (pj, "defval", op->def_val); - pj_kn (pj, "maxval", op->max_val); - pj_kn (pj, "minval", op->min_val); - pj_k (pj, "cases"); - pj_a (pj); - RAnalCaseOp *case_op; - RListIter *case_iter; - r_list_foreach (op->cases, case_iter, case_op) { - pj_o (pj); - pj_kn (pj, "offset", case_op->addr); - pj_kn (pj, "value", case_op->value); - pj_kn (pj, "jump", case_op->jump); - pj_end (pj); - } - pj_end (pj); - pj_end (pj); - } - if (t) { - pj_k (pj, "trace"); - pj_o (pj); - pj_ki (pj, "count", t->count); - pj_ki (pj, "times", t->times); - pj_end (pj); - } - pj_kn (pj, "colorize", bbi->colorize); - pj_k (pj, "ops"); - pj_a (pj); - if (buf) { - r_io_read_at (core->io, bbi->addr, buf, bbi->size); - if (is_json_format_disasm) { - r_core_print_disasm (core->print, core, bbi->addr, buf, bbi->size, bbi->size, 0, 1, true, pj, NULL); - } else { - r_core_print_disasm_json (core, bbi->addr, buf, bbi->size, 0, pj); - } - free (buf); - } else { - eprintf ("cannot allocate %d byte(s)\n", bbi->size); - } - pj_end (pj); - pj_end (pj); - continue; - } - if (bbi->jump != UT64_MAX) { - nodes++; - if (is_keva) { - char key[128]; - char val[128]; - snprintf (key, sizeof (key), "bb.0x%08"PFMT64x".to", bbi->addr); - if (bbi->fail != UT64_MAX) { - snprintf (val, sizeof (val), "0x%08"PFMT64x, bbi->jump); - } else { - snprintf (val, sizeof (val), "0x%08"PFMT64x ",0x%08"PFMT64x, - bbi->jump, bbi->fail); - } - // bb..to=, - sdb_set (DB, key, val, 0); - } else if (is_html) { - r_cons_printf ("
\n" - "
\n", - bbi->addr, bbi->jump); - } else if (!is_json) { - //r_cons_printf ("\t\"0x%08"PFMT64x"_0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"_0x%08"PFMT64x"\" " - // "[color=\"%s\"];\n", fcn->addr, bbi->addr, fcn->addr, bbi->jump, - // bbi->fail != -1 ? "green" : "blue"); - r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " - "[color=\"%s\"];\n", bbi->addr, bbi->jump, - bbi->fail != -1 ? pal_jump : pal_trfa); - core_anal_color_curr_node (core, bbi); - } - } - if (bbi->fail != -1) { - nodes++; - if (is_html) { - r_cons_printf ("
\n" - "
\n", - bbi->addr, bbi->fail); - } else if (!is_keva) { - //r_cons_printf ("\t\"0x%08"PFMT64x"_0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"_0x%08"PFMT64x"\" " - // "[color=\"red\"];\n", fcn->addr, bbi->addr, fcn->addr, bbi->fail); - r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " - "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail); - core_anal_color_curr_node (core, bbi); - } - } - if (bbi->switch_op) { - RAnalCaseOp *caseop; - RListIter *iter; - - if (is_html) { - r_cons_printf ("
\n" - "
\n", - bbi->addr, bbi->fail); - } else if (!is_keva) { - //r_cons_printf ("\t\"0x%08"PFMT64x"_0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"_0x%08"PFMT64x"\" " - // "[color=\"red\"];\n", fcn->addr, bbi->addr, fcn->addr, bbi->fail); - r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " - "[color=\"%s\"];\n", bbi->addr, bbi->fail, pal_fail); - core_anal_color_curr_node (core, bbi); - } - - r_list_foreach (bbi->switch_op->cases, iter, caseop) { - nodes++; - if (is_keva) { - char key[128]; - snprintf (key, sizeof (key), - "bb.0x%08"PFMT64x".switch.%"PFMT64d, - bbi->addr, caseop->value); - sdb_num_set (DB, key, caseop->jump, 0); - snprintf (key, sizeof (key), - "bb.0x%08"PFMT64x".switch", bbi->addr); - sdb_array_add_num (DB, key, caseop->value, 0); - } else if (is_html) { - r_cons_printf ("
\n" - "
\n", - caseop->addr, caseop->jump); - } else { - //r_cons_printf ("\t\"0x%08"PFMT64x"_0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"_0x%08"PFMT64x"\" " - // "[color=\"red\"];\n", fcn->addr, caseop->addr, fcn->addr, caseop->jump); - r_cons_printf ("\t\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x"\" " - "[color2=\"%s\"];\n", caseop->addr, caseop->jump, pal_fail); - core_anal_color_curr_node (core, bbi); - } - } - } - if ((str = core_anal_graph_label (core, bbi, opts))) { - if (opts & R_CORE_ANAL_GRAPHDIFF) { - const char *difftype = bbi->diff? (\ - bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "lightgray": - bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "yellow": "red"): "orange"; - const char *diffname = bbi->diff? (\ - bbi->diff->type==R_ANAL_DIFF_TYPE_MATCH? "match": - bbi->diff->type==R_ANAL_DIFF_TYPE_UNMATCH? "unmatch": "new"): "unk"; - if (is_keva) { - sdb_set (DB, "diff", diffname, 0); - sdb_set (DB, "label", str, 0); - } else if (!is_json) { - nodes++; - //r_cons_printf (" \"0x%08"PFMT64x"_0x%08"PFMT64x"\" [color=\"%s\"," - // " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n", - // fcn->addr, bbi->addr, difftype, str, fcn->name, bbi->addr); - RConfigHold *hc = r_config_hold_new (core->config); - r_config_hold_i (hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines", - "asm.cmt.right", "asm.lines.fcn", "asm.bytes", NULL); - RDiff *d = r_diff_new (); - 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.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.lines.fcn", 0); - r_config_set_i (core->config, "asm.bytes", 0); - - if (bbi->diff && bbi->diff->type != R_ANAL_DIFF_TYPE_MATCH && core->c2) { - RCore *c = core->c2; - RConfig *oc = c->config; - char *str = r_core_cmd_strf (core, "pdb @ 0x%08"PFMT64x, bbi->addr); - c->config = core->config; - // XXX. the bbi->addr doesnt needs to be in the same address in core2 - char *str2 = r_core_cmd_strf (c, "pdb @ 0x%08"PFMT64x, bbi->diff->addr); - char *diffstr = r_diff_buffers_to_string (d, - (const ut8*)str, strlen (str), - (const ut8*)str2, strlen(str2)); - if (diffstr) { - char *nl = strchr (diffstr, '\n'); - if (nl) { - nl = strchr (nl + 1, '\n'); - if (nl) { - nl = strchr (nl + 1, '\n'); - if (nl) { - r_str_cpy (diffstr, nl + 1); - } - } - } - } - diffstr = r_str_replace (diffstr, "\n", "\\l", 1); - diffstr = r_str_replace (diffstr, "\"", "'", 1); - // eprintf ("%s\n", diffstr? diffstr: ""); - r_cons_printf (" \"0x%08"PFMT64x"\" [fillcolor=\"%s\"," - "color=\"black\", fontname=\"Courier\"," - " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n", - bbi->addr, difftype, diffstr, fcn->name, bbi->addr); - free (diffstr); - c->config = oc; - } else { - r_cons_printf (" \"0x%08"PFMT64x"\" [fillcolor=\"%s\"," - "color=\"black\", fontname=\"Courier\"," - " label=\"%s\", URL=\"%s/0x%08"PFMT64x"\"]\n", - bbi->addr, difftype, str, fcn->name, bbi->addr); - } - r_diff_free (d); - r_config_set_i (core->config, "scr.color", 1); - r_config_hold_free (hc); - } - } else { - if (is_html) { - nodes++; - r_cons_printf ("

\n%s

\n", - top, left, bbi->addr, str); - left = left? 0: 600; - if (!left) { - top += 250; - } - } else if (!is_json && !is_keva) { - bool current = r_anal_bb_is_in_offset (bbi, core->offset); - const char *label_color = bbi->traced - ? pal_traced - : (current && color_current) - ? pal_curr - : pal_box4; - const char *fill_color = (current || label_color == pal_traced)? pal_traced: "white"; - nodes++; - //r_cons_printf (" \"0x%08"PFMT64x"_0x%08"PFMT64x"\" [" - // "URL=\"%s/0x%08"PFMT64x"\", color=\"%s\", label=\"%s\"]\n", - // fcn->addr, bbi->addr, - // fcn->name, bbi->addr, - // bbi->traced?"yellow":"lightgray", str); - r_cons_printf ("\t\"0x%08"PFMT64x"\" [" - "URL=\"%s/0x%08"PFMT64x"\", fillcolor=\"%s\"," - "color=\"%s\", fontname=\"%s\"," - "label=\"%s\"]\n", - bbi->addr, fcn->name, bbi->addr, - fill_color, label_color, font, str); - } - } - free (str); - } - } + nodes += core_anal_graph_construct_nodes (core, fcn, opts, pj, DB); + nodes += core_anal_graph_construct_edges (core, fcn, opts, pj, DB); if (is_json) { pj_end (pj); pj_end (pj); @@ -1855,10 +1937,6 @@ 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; @@ -1886,7 +1964,6 @@ R_API int r_core_print_bb_custom(RCore *core, RAnalFunction *fcn) { 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) { free (body_b64); free (body); @@ -3338,6 +3415,7 @@ R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) { int is_json = opts & R_CORE_ANAL_JSON; int is_json_format_disasm = opts & R_CORE_ANAL_JSON_FORMAT_DISASM; int is_keva = opts & R_CORE_ANAL_KEYVALUE; + int is_star = opts & R_CORE_ANAL_STAR; RConfigHold *hc; RAnalFunction *fcni; RListIter *iter; @@ -3363,7 +3441,7 @@ R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) { r_config_hold_i (hc, "asm.bytes", NULL); r_config_set_i (core->config, "asm.bytes", 0); } - if (!is_html && !is_json && !is_keva) { + if (!is_html && !is_json && !is_keva && !is_star) { const char * gv_edge = r_config_get (core->config, "graph.gv.edge"); const char * gv_node = r_config_get (core->config, "graph.gv.node"); const char * gv_spline = r_config_get (core->config, "graph.gv.spline"); @@ -3406,10 +3484,15 @@ R_API int r_core_anal_graph(RCore *core, ut64 addr, int opts) { if (!nodes) { if (!is_html && !is_json && !is_keva) { RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, 0); - r_cons_printf ("\t\"0x%08"PFMT64x"\";\n", fcn? fcn->addr: addr); + if (is_star) { + char *name = get_title(fcn ? fcn->addr: addr); + r_cons_printf ("agn %s;", name); + }else { + r_cons_printf ("\t\"0x%08"PFMT64x"\";\n", fcn? fcn->addr: addr); + } } } - if (!is_keva && !is_html && !is_json) { + if (!is_keva && !is_html && !is_json && !is_star) { r_cons_printf ("}\n"); } if (is_json) { diff --git a/libr/core/cmd_anal.c b/libr/core/cmd_anal.c index 62d4a7f9c8..0ff89e0747 100644 --- a/libr/core/cmd_anal.c +++ b/libr/core/cmd_anal.c @@ -7160,9 +7160,10 @@ static void cmd_agraph_node(RCore *core, const char *input) { char *newbody = NULL; char **args, *body; int n_args, B_LEN = strlen ("base64:"); + int color = -1; input++; args = r_str_argv (input, &n_args); - if (n_args < 1 || n_args > 2) { + if (n_args < 1 || n_args > 3) { r_cons_printf ("Wrong arguments\n"); r_str_argv_free (args); break; @@ -7182,10 +7183,13 @@ static void cmd_agraph_node(RCore *core, const char *input) { body = newbody; } body = r_str_append (body, "\n"); + if (n_args > 2) { + color = atoi(args[2]); + } } else { body = strdup (""); } - r_agraph_add_node (core->graph, args[0], body); + r_agraph_add_node_with_color (core->graph, args[0], body, color); r_str_argv_free (args); free (body); //free newbody it's not necessary since r_str_append reallocate the space @@ -7717,37 +7721,56 @@ static void cmd_anal_graph(RCore *core, const char *input) { break; } break; - case 'd': // "agd" - switch (input[1]) { - case 'v': - case 't': - case 'j': - case 'J': - case 'g': - case 'k': - case '*': - case ' ': - case 0: - eprintf ("Currently the only supported formats for the diff graph are 'agdd' and 'agdw'\n"); - break; - case 'd': { - ut64 addr = input[2]? r_num_math (core->num, input + 2): core->offset; - r_core_gdiff_fcn (core, addr, core->offset); - r_core_anal_graph (core, addr, R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF); - break; - } - case 'w': { - char *cmdargs = r_str_newf ("agdd 0x%"PFMT64x, core->offset); - char *cmd = graph_cmd (core, cmdargs, input + 2); - if (cmd && *cmd) { - r_core_cmd0 (core, cmd); - } - free (cmd); - free (cmdargs); - break; - } - } - break; + case 'd': {// "agd" + int diff_opt = R_CORE_ANAL_GRAPHBODY | R_CORE_ANAL_GRAPHDIFF; + switch (input[1]) { + case 'j': { + ut64 addr = input[2] ? r_num_math(core->num, input + 2) : core->offset; + r_core_gdiff_fcn(core, addr, core->offset); + r_core_anal_graph(core, addr, diff_opt | R_CORE_ANAL_JSON); + break; + } + case 'J': { + ut64 addr = input[2] ? r_num_math(core->num, input + 2) : core->offset; + r_core_gdiff_fcn(core, addr, core->offset); + r_core_anal_graph(core, addr, diff_opt | R_CORE_ANAL_JSON | R_CORE_ANAL_JSON_FORMAT_DISASM); + break; + } + case '*': { + ut64 addr = input[2] ? r_num_math(core->num, input + 2) : core->offset; + r_core_gdiff_fcn(core, addr, core->offset); + r_core_anal_graph(core, addr, diff_opt | R_CORE_ANAL_STAR); + break; + } + case ' ': + case 0: + case 't': + case 'k': + case 'v': + case 'g': { + ut64 addr = input[2] ? r_num_math(core->num, input + 2) : core->offset; + r_core_cmdf (core, "ag-; .agd* @ %"PFMT64u"; agg%s;", addr, input + 1); + break; + } + case 'd': { + ut64 addr = input[2] ? r_num_math(core->num, input + 2) : core->offset; + r_core_gdiff_fcn(core, addr, core->offset); + r_core_anal_graph(core, addr, diff_opt); + break; + } + case 'w': { + char *cmdargs = r_str_newf("agdd 0x%"PFMT64x, core->offset); + char *cmd = graph_cmd(core, cmdargs, input + 2); + if (cmd && *cmd) { + r_core_cmd0(core, cmd); + } + free(cmd); + free(cmdargs); + break; + } + } + break; + } case 'v': // "agv" alias for "agfv" r_core_cmdf (core, "agfv%s", input + 1); break; diff --git a/libr/include/r_agraph.h b/libr/include/r_agraph.h index 00ff869b8d..0fbaf4d1f8 100644 --- a/libr/include/r_agraph.h +++ b/libr/include/r_agraph.h @@ -22,6 +22,7 @@ typedef struct r_ascii_node_t { int is_dummy; int is_reversed; int klass; + int difftype; bool is_mini; } RANode; @@ -90,6 +91,7 @@ R_API void r_agraph_set_title(RAGraph *g, const char *title); R_API RANode *r_agraph_get_first_node(const RAGraph *g); R_API RANode *r_agraph_get_node(const RAGraph *g, const char *title); R_API RANode *r_agraph_add_node(const RAGraph *g, const char *title, const char *body); +R_API RANode *r_agraph_add_node_with_color(const RAGraph *g, const char *title, const char *body, int color); R_API bool r_agraph_del_node(const RAGraph *g, const char *title); R_API void r_agraph_add_edge(const RAGraph *g, RANode *a, RANode *b); R_API void r_agraph_add_edge_at(const RAGraph *g, RANode *a, RANode *b, int nth); diff --git a/libr/include/r_cons.h b/libr/include/r_cons.h index 48d6b2b915..d583b34d51 100644 --- a/libr/include/r_cons.h +++ b/libr/include/r_cons.h @@ -254,6 +254,10 @@ typedef struct r_cons_palette_t { RColor graph_trufae; RColor graph_traced; RColor graph_current; + RColor graph_diff_match; + RColor graph_diff_unmatch; + RColor graph_diff_unknown; + RColor graph_diff_new; } RConsPalette; typedef struct r_cons_printable_palette_t { @@ -321,6 +325,10 @@ typedef struct r_cons_printable_palette_t { char *graph_box2; char *graph_box3; char *graph_box4; + char *graph_diff_match; + char *graph_diff_unmatch; + char *graph_diff_unknown; + char *graph_diff_new; char *graph_true; char *graph_false; char *graph_trufae; diff --git a/libr/include/r_core.h b/libr/include/r_core.h index 854e4d7760..f915a5c2b2 100644 --- a/libr/include/r_core.h +++ b/libr/include/r_core.h @@ -46,6 +46,7 @@ R_LIB_VERSION_HEADER(r_core); #define R_CORE_ANAL_JSON 8 #define R_CORE_ANAL_KEYVALUE 16 #define R_CORE_ANAL_JSON_FORMAT_DISASM 32 +#define R_CORE_ANAL_STAR 64 #define R_FLAGS_FS_CLASSES "classes" #define R_FLAGS_FS_FUNCTIONS "functions"