From e209b9147a983c5f80d1ef9bd07a06a12e23b62f Mon Sep 17 00:00:00 2001 From: Luca Di Bartolomeo Date: Sun, 8 Jul 2018 09:29:56 +0200 Subject: [PATCH] Improve jmptbl edges, second try (#10662) * Improve jmptbl edge positioning * Merged edges with the same origin/destination * Fix callgraph --- libr/core/cconfig.c | 1 - libr/core/graph.c | 61 +++++++++++++++++++++++++++++++++---------- libr/include/r_cons.h | 1 - libr/util/graph.c | 12 +++++---- 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/libr/core/cconfig.c b/libr/core/cconfig.c index 0fbc8e17a8ad5..b3a89d38e0362 100644 --- a/libr/core/cconfig.c +++ b/libr/core/cconfig.c @@ -2828,7 +2828,6 @@ R_API int r_core_config_init(RCore *core) { SETCB ("graph.extension", "gif", &cb_graphformat, "Graph extension when using 'w' format (png, jpg, pdf, ps, svg, json)"); SETPREF ("graph.refs", "false", "Graph references in callgraphs (.agc*;aggi)"); SETI ("graph.edges", 2, "0=no edges, 1=simple edges, 2=avoid collisions"); - SETPREF ("graph.altedgepos", "false", "Switch to alternative (very experimental) positioning of edges"); SETI ("graph.layout", 0, "Graph layout (0=vertical, 1=horizontal)"); SETI ("graph.linemode", 1, "Graph edges (0=diagonal, 1=square)"); SETPREF ("graph.font", "Courier", "Font for dot graphs"); diff --git a/libr/core/graph.c b/libr/core/graph.c index a1f421b0e397c..ad1230390bec0 100644 --- a/libr/core/graph.c +++ b/libr/core/graph.c @@ -2641,6 +2641,24 @@ static void agraph_print_edges_simple(RAGraph *g) { } } +static int first_x_cmp (RGraphNode *ga, RGraphNode *gb) { + RANode *a = (RANode*) ga->data; + RANode *b = (RANode*) gb->data; + if (b->y < a->y) { + return -1; + } + if (b->y > a->y) { + return 1; + } + if (a->x < b->x) { + return 1; + } else if (a->x > b->x) { + return -1; + } else { + return 0; + } +} + static void agraph_print_edges(RAGraph *g) { if (!g->edgemode) { return; @@ -2649,7 +2667,7 @@ static void agraph_print_edges(RAGraph *g) { agraph_print_edges_simple (g); return; } - int out_nth, in_nth; + int out_nth, in_nth, bendpoint; RListIter *itn, *itm, *ito; RCanvasLineStyle style = {0}; const RList *nodes = r_graph_get_nodes (g->graph); @@ -2706,13 +2724,27 @@ static void agraph_print_edges(RAGraph *g) { } } - bool many = r_list_length (neighbours) > 2; + + if (many && !g->is_callgraph) { + ga->out_nodes->sorted = false; + r_list_sort (neighbours, first_x_cmp); + } + graph_foreach_anode (neighbours, itn, gb, b) { out_nth = get_edge_number (g, a, b, true); in_nth = get_edge_number (g, a, b, false); - if (many) { + bool parent_many = false; + if (a->is_dummy) { + RANode *in = (RANode *) (((RGraphNode *)r_list_first (ga->in_nodes))->data); + while (in && in->is_dummy) { + in = (RANode *) (((RGraphNode *)r_list_first ((in->gnode)->in_nodes))->data); + } + parent_many = r_list_length ((in->gnode)->out_nodes) > 2; + } + + if (many || parent_many) { style.color = LINE_UNCJMP; } else { switch (out_nth) { @@ -2739,20 +2771,22 @@ static void agraph_print_edges(RAGraph *g) { a_x_inc = R_EDGES_X_INC + 2 * (out_nth + 1); b_x_inc = R_EDGES_X_INC + 2 * (in_nth + 1); - if (g->altedgepos) { - ax = a->is_dummy ? a->x : (a->x + a->w - a_x_inc); - bx = b->is_dummy ? b->x : (b->x + b_x_inc); + bx = b->is_dummy ? b->x : (b->x + b_x_inc); + ay = a->y + a->h; + by = b->y - 1; + + if (many && !g->is_callgraph) { + int t = R_EDGES_X_INC + 2 * (neighbours->length + 1); + ax = a->is_dummy ? a->x : (a->x + a->w/2 + (t/2 - a_x_inc)); + bendpoint = bx < ax ? neighbours->length - out_nth : out_nth; } else { ax = a->is_dummy ? a->x : (a->x + a_x_inc); - bx = b->is_dummy ? b->x : (b->x + a_x_inc); + bendpoint = tm->edgectr; } - ay = a->y + a->h; - by = b->y - 1; - if (!a->is_dummy && itn == neighbours->head && out_nth == 0 && bx > ax) { a_x_inc += 4; - ax += g->altedgepos ? -4 : 4; + ax += (many && !g->is_callgraph) ? 0 : 4; } if (a->h < a->layer_height) { r_cons_canvas_line (g->can, ax, ay, ax, ay + a->layer_height - a->h, &style); @@ -2760,14 +2794,14 @@ static void agraph_print_edges(RAGraph *g) { style.symbol = LINE_NOSYM_VERT; } if (by >= ay) { - r_cons_canvas_line_square_defined (g->can, ax, ay, bx, by, &style, tm->edgectr, true); + r_cons_canvas_line_square_defined (g->can, ax, ay, bx, by, &style, bendpoint, true); } else { struct tmpbackedgeinfo *tmp = calloc (1, sizeof (struct tmpbackedgeinfo)); tmp->ax = ax; tmp->bx = bx; tmp->ay = ay; tmp->by = by; - tmp->edgectr = tm->edgectr; + tmp->edgectr = bendpoint; tmp->fromlayer = a->layer; tmp->tolayer = b->layer; tmp->style = style; @@ -3731,7 +3765,6 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int g->on_curnode_change = (RANodeCallback) seek_to_node; g->on_curnode_change_data = core; g->edgemode = r_config_get_i (core->config, "graph.edges"); - g->altedgepos = r_config_get_i (core->config, "graph.altedgepos"); g->is_interactive = is_interactive; bool asm_comments = r_config_get_i (core->config, "asm.comments"); r_config_set (core->config, "asm.comments", diff --git a/libr/include/r_cons.h b/libr/include/r_cons.h index 5680772b3fa12..c14209b743883 100644 --- a/libr/include/r_cons.h +++ b/libr/include/r_cons.h @@ -906,7 +906,6 @@ typedef struct r_ascii_graph_t { bool is_tiny; bool is_dis; int edgemode; - bool altedgepos; int mode; bool is_callgraph; bool is_interactive; diff --git a/libr/util/graph.c b/libr/util/graph.c index 3de7b89db4bb9..a750515f88d4f 100644 --- a/libr/util/graph.c +++ b/libr/util/graph.c @@ -182,11 +182,13 @@ R_API void r_graph_add_edge (RGraph *t, RGraphNode *from, RGraphNode *to) { R_API void r_graph_add_edge_at (RGraph *t, RGraphNode *from, RGraphNode *to, int nth) { if (from && to) { - r_list_insert (from->out_nodes, nth, to); - r_list_append (from->all_neighbours, to); - r_list_append (to->in_nodes, from); - r_list_append (to->all_neighbours, from); - t->n_edges++; + if (!r_list_contains (from->out_nodes, to)) { + r_list_insert (from->out_nodes, nth, to); + r_list_append (from->all_neighbours, to); + r_list_append (to->in_nodes, from); + r_list_append (to->all_neighbours, from); + t->n_edges++; + } } }