From b279f282bae6cfc6101c313efcbc2bea19bdaf8b Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 12 Jun 2015 11:08:05 +0200 Subject: [PATCH] Refactoring ascii art graph util/stack: extend stack api with r_stack_size core/graph: use RStack instead of a custom implementation util/graph: change implementation to use lists and extend api core/cmd_debug: avoid free r_graph_get_nodes core/graph: rename some functions and use typedefs for graph struct core/graph: use RGraph for the ascii art graph util/list: add const whenever possible util/graph: add const on r_graph_get_nodes/neighbours core/graph,core/cmd_debug: use const core/graph: clean the code (add comments, use const, remove magic nums) * use r_graph_node_iter for the current node * reset graph when reloading nodes * on callgraph edges printing, nth should be 0 * force seek of current node when reloading nodes * use graph_foreach_node * core/graph: remove get_current_node because useless --- libr/core/cmd_debug.c | 5 +- libr/core/graph.c | 709 +++++++++++++++++---------------------- libr/include/r_list.h | 20 +- libr/include/r_util.h | 13 +- libr/util/graph.c | 131 ++++---- libr/util/list.c | 22 +- libr/util/stack.c | 4 + libr/util/t/test_graph.c | 1 - libr/util/t/test_stack.c | 43 ++- 9 files changed, 445 insertions(+), 503 deletions(-) diff --git a/libr/core/cmd_debug.c b/libr/core/cmd_debug.c index 973e99bf33..2b765b299e 100644 --- a/libr/core/cmd_debug.c +++ b/libr/core/cmd_debug.c @@ -96,7 +96,7 @@ static void dot_trace_traverse(RCore *core, RTree *t) { const char *gfont = r_config_get (core->config, "graph.font"); struct dot_trace_ght aux_data; RTreeVisitor vis = { 0 }; - RList *nodes; + const RList *nodes; RListIter *iter; RGraphNode *n; @@ -117,7 +117,7 @@ static void dot_trace_traverse(RCore *core, RTree *t) { " shape=box fontname=\"%s\" fontsize=\"8\"];\n", gfont); r_list_foreach (nodes, iter, n) { struct trace_node *tn = (struct trace_node *)n->data; - RList *neighbours = r_graph_get_neighbours (aux_data.graph, n); + const RList *neighbours = r_graph_get_neighbours (aux_data.graph, n); RListIter *it_n; RGraphNode *w; @@ -136,7 +136,6 @@ static void dot_trace_traverse(RCore *core, RTree *t) { } } r_cons_printf ("}\n"); - r_list_free (nodes); r_graph_free (aux_data.graph); sdb_free (aux_data.graphnodes); diff --git a/libr/core/graph.c b/libr/core/graph.c index 6835947d3f..eeea1e0f23 100644 --- a/libr/core/graph.c +++ b/libr/core/graph.c @@ -9,15 +9,25 @@ static int mousemode = 0; #define BORDER_HEIGHT 3 #define MARGIN_TEXT_X 2 #define MARGIN_TEXT_Y 2 +#define HORIZONTAL_NODE_SPACING 12 +#define VERTICAL_NODE_SPACING 4 #define MAX_NODE_WIDTH 18 +#define INIT_HISTORY_CAPACITY 16 +#define TITLE_LEN 128 -#define OS_SIZE 128 -struct ostack { - int nodes[OS_SIZE]; - int size; -}; +#define history_push(stack, x) (r_stack_push (stack, (void *)(size_t)x)) +#define history_pop(stack) ((RGraphNode *)r_stack_pop (stack)) -typedef struct { +#define gn2addr(sdb,addr,gn) (sdb_num_set (sdb, sdb_fmt (0, "%lld", addr), (ut64)(size_t)gn, 0)) +#define addr2gn(sdb,addr) ((RGraphNode *)(size_t)sdb_num_get (sdb, sdb_fmt (0, "%lld", addr), NULL)) + +#define get_gn(iter) ((RGraphNode *)r_list_iter_get_data(iter)) +#define get_anode(iter) ((ANode *)get_gn(iter)->data) + +#define graph_foreach_node(list, it, pos, anode) \ + if (list) for (it = list->head; it && (pos = it->data) && (pos) && (anode = (ANode *)pos->data); it = it->n) + +typedef struct ascii_node { int x; int y; int w; @@ -25,38 +35,28 @@ typedef struct { ut64 addr; int depth; char *text; -} Node; +} ANode; -typedef struct { - int nth; - int from; - int to; -} Edge; - -struct graph { +typedef struct ascii_graph { RCore *core; RConsCanvas *can; RAnalFunction *fcn; - Node *nodes; - Edge *edges; - int n_nodes; - int n_edges; + RGraph *graph; + RListIter *curnode; + int is_callgraph; int is_instep; int is_simple_mode; int is_small_nodes; - unsigned int curnode; - - struct ostack ostack; + RStack *history; + ANode *update_seek_on; int need_reload_nodes; - int need_update_seek; - int update_seek_on; int force_update_seek; -}; +} AGraph; -struct graph_refresh_data { - struct graph *g; +struct agraph_refresh_data { + AGraph *g; int fs; }; @@ -70,24 +70,13 @@ struct graph_refresh_data { #define L2(x,y,x2,y2) r_cons_canvas_line(g->can, x,y,x2,y2,2) #define F(x,y,x2,y2,c) r_cons_canvas_fill(g->can, x,y,x2,y2,c,0) -static void ostack_init(struct ostack *os) { - os->size = 0; - os->nodes[0] = 0; -} +static void update_node_dimension(RGraph *g, int is_small) { + const RList *nodes = r_graph_get_nodes (g); + RGraphNode *gn; + RListIter *it; + ANode *n; -static void ostack_push(struct ostack *os, int el) { - if (os->size < OS_SIZE - 1) - os->nodes[++os->size] = el; -} - -static int ostack_pop(struct ostack *os) { - return os->size > 0 ? os->nodes[--os->size] : 0; -} - -static void update_node_dimension(Node nodes[], int nodes_size, int is_small) { - int i; - for (i = 0; i < nodes_size; ++i) { - Node *n = &nodes[i]; + graph_foreach_node (nodes, it, gn, n) { if (is_small) { n->w = n->h = 0; } else { @@ -99,8 +88,8 @@ static void update_node_dimension(Node nodes[], int nodes_size, int is_small) { } } -static void small_Node_print(struct graph *g, Node *n, int cur) { - char title[128]; +static void small_ANode_print(AGraph *g, ANode *n, int cur) { + char title[TITLE_LEN]; if (!G (n->x + 2, n->y - 1)) return; @@ -118,8 +107,8 @@ static void small_Node_print(struct graph *g, Node *n, int cur) { return; } -static void normal_Node_print(struct graph *g, Node *n, int cur) { - char title[128]; +static void normal_ANode_print(AGraph *g, ANode *n, int cur) { + char title[TITLE_LEN]; char *text; int delta_x = 0; int delta_y = 0; @@ -164,7 +153,7 @@ static void normal_Node_print(struct graph *g, Node *n, int cur) { } // TODO: check if node is traced or not and hsow proper color - // This info must be stored inside Node* from RCore* + // This info must be stored inside ANode* from RCore* if (cur) { B1 (n->x, n->y, n->w, n->h); } else { @@ -172,218 +161,216 @@ static void normal_Node_print(struct graph *g, Node *n, int cur) { } } -static Node *get_current_node(struct graph *g) { - return &g->nodes[g->curnode]; -} - -static int count_exit_edges(struct graph *g, int n) { - int i, count = 0; - for (i = 0; i < g->n_edges; i++) { - if (g->edges[i].from == n) { - count++; - } - } - return count; -} - -static int find_edge_node(struct graph *g, int cur, int nth) { - if (g->edges) { - int i; - for (i = 0; i < g->n_edges; i++) { - if (g->edges[i].from == cur && g->edges[i].nth == nth) - return g->edges[i].to; - } - } - return -1; -} - -static int find_node_idx(struct graph *g, ut64 addr) { - if (g->nodes) { - int i; - for (i = 0; i < g->n_nodes; i++) { - if (g->nodes[i].addr == addr) - return i; - } - } - return -1; -} - -static void set_layout_bb_depth(struct graph *g, int nth, int depth) { - int j, f, old_d; - if (nth >= g->n_nodes) +static void set_layout_bb_depth(AGraph *g, RGraphNode *gn, int depth) { + ANode *n; + RGraphNode *next; + int old_d; + if (!gn || !gn->data) return; - old_d = g->nodes[nth].depth; - g->nodes[nth].depth = depth; + n = gn->data; + old_d = n->depth; + n->depth = depth; if (old_d != -1) return; - j = find_edge_node (g, nth, 0); - if (j != -1) - set_layout_bb_depth (g, j, depth + 1); - f = find_edge_node (g, nth, 1); - if (f != -1) - set_layout_bb_depth (g, f, depth + 1); + next = r_graph_nth_neighbour (g->graph, gn, 0); + if (next) + set_layout_bb_depth (g, next, depth + 1); + next = r_graph_nth_neighbour (g->graph, gn, 1); + if (next) + set_layout_bb_depth (g, next, depth + 1); // TODO: support more than two destination points (switch tables?) } -static void set_layout_bb(struct graph *g) { - int i, j, rh, nx; +static void set_layout_bb(AGraph *g) { + int i, rh, nx; int *rowheight = NULL; int maxdepth = 0; - const int h_spacing = 12; - const int v_spacing = 4; + const int h_spacing = HORIZONTAL_NODE_SPACING; + const int v_spacing = VERTICAL_NODE_SPACING; + const RList *nodes = r_graph_get_nodes (g->graph); + RGraphNode *gn; + RListIter *it; + ANode *n; - set_layout_bb_depth (g, 0, 0); + set_layout_bb_depth (g, (RGraphNode *)r_list_get_bottom(nodes), 0); // identify max depth - for (i = 0; i < g->n_nodes; i++) { - if (g->nodes[i].depth > maxdepth) - maxdepth = g->nodes[i].depth; + graph_foreach_node (nodes, it, gn, n) { + if (n->depth > maxdepth) + maxdepth = n->depth; } + // identify row height rowheight = malloc (sizeof (int) * maxdepth); for (i = 0; i < maxdepth; i++) { rh = 0; - for (j = 0; j < g->n_nodes; j++) { - if (g->nodes[j].depth == i) - if (g->nodes[j].h > rh) - rh = g->nodes[j].h; + graph_foreach_node (nodes, it, gn, n) { + if (n->depth == i) + if (n->h > rh) + rh = n->h; } rowheight[i] = rh; } // vertical align // depe - for (i = 0; i < g->n_nodes; i++) { - g->nodes[i].y = 1; - for (j = 0; j < g->nodes[i].depth; j++) - g->nodes[i].y += rowheight[j] + v_spacing; + graph_foreach_node (nodes, it, gn, n) { + n->y = 1; + for (i = 0; i < n->depth; i++) + n->y += rowheight[i] + v_spacing; } // horitzontal align for (i = 0; i < maxdepth; i++) { nx = (i % 2) * 10; - for (j = 0; j < g->n_nodes; j++) { - if (g->nodes[j].depth == i) { - g->nodes[j].x = nx; - nx += g->nodes[j].w + h_spacing; + graph_foreach_node (nodes, it, gn, n) { + if (n->depth == i) { + n->x = nx; + nx += n->w + h_spacing; } } } free (rowheight); } -static void set_layout_callgraph(struct graph *g) { +static void set_layout_callgraph(AGraph *g) { + const RList *nodes = r_graph_get_nodes (g->graph); + RGraphNode *gn; + RListIter *it; + ANode *prev_n = NULL, *n; int y = 5, x = 20; - int i; - for (i = 0; i < g->n_nodes; i++) { + graph_foreach_node (nodes, it, gn, n) { // wrap to width 'w' - if (i > 0) { - if (g->nodes[i].x < g->nodes[i-1].x) { - y += 10; - x = 0; - } + if (prev_n && n->x < prev_n->x) { + y += 10; + x = 0; } - g->nodes[i].x = x; - g->nodes[i].y = i? y: 2; + n->x = x; + n->y = prev_n ? y : 2; x += 30; + prev_n = n; } } -static int get_bbnodes(struct graph *g) { +/* build the RGraph inside the AGraph g, starting from the Basic Blocks */ +static int get_bbnodes(AGraph *g) { RAnalBlock *bb; RListIter *iter; - Node *nodes; - int i; + Sdb *g_nodes = sdb_new0 (); + if (!g_nodes) return R_FALSE; - nodes = calloc(r_list_length (g->fcn->bbs), sizeof(Node)); - if (!nodes) - return R_FALSE; - - i = 0; r_list_foreach (g->fcn->bbs, iter, bb) { + RGraphNode *gn; + ANode *node; + if (bb->addr == UT64_MAX) continue; + node = R_NEW0 (ANode); + if (!node) return R_FALSE; + if (g->is_simple_mode) { - nodes[i].text = r_core_cmd_strf (g->core, + node->text = r_core_cmd_strf (g->core, "pI %d @ 0x%08"PFMT64x, bb->size, bb->addr); }else { - nodes[i].text = r_core_cmd_strf (g->core, + node->text = r_core_cmd_strf (g->core, "pDi %d @ 0x%08"PFMT64x, bb->size, bb->addr); } - nodes[i].addr = bb->addr; - nodes[i].depth = -1; - nodes[i].x = 0; - nodes[i].y = 0; - nodes[i].w = 0; - nodes[i].h = 0; - i++; + node->addr = bb->addr; + node->depth = -1; + node->x = 0; + node->y = 0; + node->w = 0; + node->h = 0; + + gn = r_graph_add_node (g->graph, node); + if (!gn) return R_FALSE; + gn2addr (g_nodes, bb->addr, gn); } - if (g->nodes) - free(g->nodes); - g->nodes = nodes; - g->n_nodes = i; + r_list_foreach (g->fcn->bbs, iter, bb) { + RGraphNode *u, *v; + if (bb->addr == UT64_MAX) + continue; + + u = addr2gn (g_nodes, bb->addr); + if (bb->jump != UT64_MAX) { + v = addr2gn (g_nodes, bb->jump); + r_graph_add_edge (g->graph, u, v); + } + if (bb->fail != UT64_MAX) { + v = addr2gn (g_nodes, bb->fail); + r_graph_add_edge (g->graph, u, v); + } + } + + g->curnode = r_list_iterator (r_graph_get_nodes(g->graph)); + sdb_free (g_nodes); return R_TRUE; } -static int get_cgnodes(struct graph *g) { - int i = 0; +/* build the RGraph inside the AGraph g, starting from the Call Graph + * information */ +static int get_cgnodes(AGraph *g) { #if FCN_OLD - int j; - char *code; - RAnalRef *ref; + Sdb *g_nodes = sdb_new0 (); + RGraphNode *fcn_gn; RListIter *iter; - Node *nodes; + RAnalRef *ref; + ANode *node; + char *code; - int fcn_refs_length = r_list_length (g->fcn->refs); - nodes = calloc (fcn_refs_length + 2, sizeof(Node)); - if (!nodes) - return R_FALSE; - - nodes[i].text = strdup (""); - nodes[i].addr = g->fcn->addr; - nodes[i].depth = -1; - nodes[i].x = 10; - nodes[i].y = 3; - nodes[i].w = 0; - nodes[i].h = 0; - i++; + node = R_NEW0 (ANode); + if (!node) return R_FALSE; + node->text = strdup (""); + node->addr = g->fcn->addr; + node->depth = -1; + node->x = 10; + node->y = 3; + node->w = 0; + node->h = 0; + fcn_gn = r_graph_add_node (g->graph, node); + if (!fcn_gn) return R_FALSE; + gn2addr (g_nodes, g->fcn->addr, fcn_gn); r_list_foreach (g->fcn->refs, iter, ref) { /* XXX: something is broken, why there are duplicated * nodes here?! goto check fcn->refs!! */ /* avoid dups wtf */ - for (j = 0; j < i; j++) { - if (ref->addr == nodes[j].addr) - continue; - } + RGraphNode *gn; + gn = addr2gn (g_nodes, ref->addr); + if (gn) continue; + RFlagItem *fi = r_flag_get_at (g->core->flags, ref->addr); + node = R_NEW0 (ANode); + if (!node) return R_FALSE; if (fi) { - nodes[i].text = strdup (fi->name); - nodes[i].text = r_str_concat (nodes[i].text, ":\n"); + node->text = strdup (fi->name); + node->text = r_str_concat (node->text, ":\n"); } else { - nodes[i].text = strdup (""); + node->text = strdup (""); } code = r_core_cmd_strf (g->core, "pi 4 @ 0x%08"PFMT64x, ref->addr); - nodes[i].text = r_str_concat (nodes[i].text, code); + node->text = r_str_concat (node->text, code); + node->text = r_str_concat (node->text, "...\n"); + node->addr = ref->addr; + node->depth = -1; + node->x = 10; + node->y = 10; + node->w = 0; + node->h = 0; free (code); - nodes[i].text = r_str_concat (nodes[i].text, "...\n"); - nodes[i].addr = ref->addr; - nodes[i].depth = -1; - nodes[i].x = 10; - nodes[i].y = 10; - nodes[i].w = 0; - nodes[i].h = 0; - i++; + gn = r_graph_add_node (g->graph, node); + if (!gn) return R_FALSE; + gn2addr (g_nodes, ref->addr, gn); + + r_graph_add_edge (g->graph, fcn_gn, gn); } - if (g->nodes) - free(g->nodes); - g->nodes = nodes; - g->n_nodes = i; + g->curnode = r_list_iterator (r_graph_get_nodes (g->graph)); + sdb_free (g_nodes); #else eprintf ("Must be sdbized\n"); #endif @@ -391,104 +378,24 @@ static int get_cgnodes(struct graph *g) { return R_TRUE; } -static int get_bbedges(struct graph *g) { - Edge *edges = NULL; - RListIter *iter; - RAnalBlock *bb; - int i, n_edges; - - n_edges = 0; - r_list_foreach (g->fcn->bbs, iter, bb) { - if (bb->jump != UT64_MAX) - n_edges++; - if (bb->fail != UT64_MAX) - n_edges++; - } - - edges = calloc(n_edges, sizeof(Edge)); - if (!edges && n_edges != 0) - return R_FALSE; - - i = 0; - r_list_foreach (g->fcn->bbs, iter, bb) { - // add edge from bb->addr to bb->jump / bb->fail - if (bb->jump != UT64_MAX) { - edges[i].nth = 0; - edges[i].from = find_node_idx (g, bb->addr); - edges[i].to = find_node_idx (g, bb->jump); - i++; - } - if (bb->fail != UT64_MAX) { - edges[i].nth = 1; - edges[i].from = find_node_idx (g, bb->addr); - edges[i].to = find_node_idx (g, bb->fail); - i++; - } - } - - if (g->edges) - free(g->edges); - g->edges = edges; - g->n_edges = i; - return R_TRUE; -} - -static int get_cgedges(struct graph *g) { - int i = 0; -#if FCN_OLD - Edge *edges = NULL; - RAnalRef *ref; - RListIter *iter; - int refs_length; - - refs_length = r_list_length(g->fcn->refs); - edges = calloc(refs_length, sizeof(Edge)); - if (!edges && refs_length != 0) - return R_FALSE; - - r_list_foreach (g->fcn->refs, iter, ref) { - edges[i].nth = 0; - edges[i].from = find_node_idx (g, g->fcn->addr); - edges[i].to = find_node_idx (g, ref->addr); - i++; - } - - if (g->edges) - free(g->edges); - g->edges = edges; - g->n_edges = i; -#else - #warning cgEdges not sdbized for fcn refs -#endif - - return R_TRUE; -} - -static int reload_nodes(struct graph *g) { +static int reload_nodes(AGraph *g) { int ret; if (g->is_callgraph) { ret = get_cgnodes(g); if (!ret) return R_FALSE; - ret = get_cgedges(g); - if (!ret) - return R_FALSE; } else { ret = get_bbnodes(g); if (!ret) return R_FALSE; - - ret = get_bbedges(g); - if (!ret) - return R_FALSE; } - update_node_dimension(g->nodes, g->n_nodes, g->is_small_nodes); + update_node_dimension(g->graph, g->is_small_nodes); return R_TRUE; } -static void update_seek(RConsCanvas *can, Node *n, int force) { +static void update_seek(RConsCanvas *can, ANode *n, int force) { int x, y, w, h; int doscroll = R_FALSE; @@ -511,47 +418,54 @@ static void update_seek(RConsCanvas *can, Node *n, int force) { } } -static void graph_set_layout(struct graph *g) { +static void agraph_set_layout(AGraph *g) { if (g->is_callgraph) set_layout_callgraph(g); else set_layout_bb(g); } -static void graph_update_seek(struct graph *g, int node_index, int force) { - g->need_update_seek = R_TRUE; - g->update_seek_on = node_index; +/* set the willing to center the screen on a particular node */ +static void agraph_update_seek(AGraph *g, ANode *n, int force) { + g->update_seek_on = n; g->force_update_seek = force; } -static void graph_free(struct graph *g) { - if (g->nodes) - free(g->nodes); - if (g->edges) - free(g->edges); +static void agraph_free(AGraph *g) { + r_graph_free (g->graph); + r_stack_free (g->history); free(g); } -static void graph_print_node(struct graph *g, Node *n) { - int cur = get_current_node(g) == n; +static void agraph_print_node(AGraph *g, ANode *n) { + const int cur = get_anode (g->curnode) == n; if (g->is_small_nodes) - small_Node_print(g, n, cur); + small_ANode_print(g, n, cur); else - normal_Node_print(g, n, cur); + normal_ANode_print(g, n, cur); } -static void graph_print_nodes(struct graph *g) { - int i; - for (i = 0; i < g->n_nodes; ++i) - if (i != g->curnode) - graph_print_node(g, &g->nodes[i]); +static void agraph_print_nodes(AGraph *g) { + const RList *nodes = r_graph_get_nodes (g->graph); + RGraphNode *gn; + RListIter *it; + ANode *n; + + graph_foreach_node (nodes, it, gn, n) { + if (gn != get_gn (g->curnode)) + agraph_print_node(g, n); + } /* draw current node now to make it appear on top */ - graph_print_node (g, &g->nodes[g->curnode]); + agraph_print_node (g, get_anode(g->curnode)); } -static void graph_print_edge(struct graph *g, Node *a, Node *b, int nth) { +/* print an edge between two nodes. + * nth: specifies if the edge is the true(1)/false(2) branch or if it's the + * only edge for that node(0), so that a different style will be applied + * to the drawn line */ +static void agraph_print_edge(AGraph *g, ANode *a, ANode *b, int nth) { int x, y, x2, y2; int xinc = 3 + 2 * (nth + 1); x = a->x + xinc; @@ -569,94 +483,116 @@ static void graph_print_edge(struct graph *g, Node *a, Node *b, int nth) { } } -static void graph_print_edges(struct graph *g) { - int i; - if (g->edges) { - for (i = 0; i < g->n_edges; i++) { - if (g->edges[i].from == -1 || g->edges[i].to == -1) - continue; +static void agraph_print_edges(AGraph *g) { + const RList *nodes = r_graph_get_nodes (g->graph); + RGraphNode *gn, *gv; + RListIter *it, *itn; + ANode *u, *v; - Node *a = &g->nodes[g->edges[i].from]; - Node *b = &g->nodes[g->edges[i].to]; - int nth = g->edges[i].nth; - if (count_exit_edges(g, g->edges[i].from) == 1) - nth = -1; // blue line + graph_foreach_node (nodes, it, gn, u) { + const RList *neighbours = r_graph_get_neighbours (g->graph, gn); + const int exit_edges = r_list_length (neighbours); + int nth = 0; - graph_print_edge (g, a, b, nth); + graph_foreach_node (neighbours, itn, gv, v) { + int cur_nth = nth; + if (g->is_callgraph) { + /* hack: we don't support more than two exit edges from a node + * yet, so set nth to zero, to make every edge appears as the + * "true" edge of the node */ + cur_nth = 0; + } else if (exit_edges == 1) { + cur_nth = -1; + } + agraph_print_edge (g, u, v, cur_nth); + nth++; } } } -static void graph_toggle_small_nodes(struct graph *g) { +static void agraph_toggle_small_nodes(AGraph *g) { g->is_small_nodes = !g->is_small_nodes; g->need_reload_nodes = R_TRUE; } -static void graph_toggle_simple_mode(struct graph *g) { +static void agraph_toggle_simple_mode(AGraph *g) { g->is_simple_mode = !g->is_simple_mode; g->need_reload_nodes = R_TRUE; } -static void graph_toggle_callgraph(struct graph *g) { +static void agraph_toggle_callgraph(AGraph *g) { g->is_callgraph = !g->is_callgraph; g->need_reload_nodes = R_TRUE; } -static int graph_reload_nodes(struct graph *g) { +/* reload all the info in the nodes, depending on the type of the graph + * (callgraph, CFG, etc.), set the default layout for these nodes and center + * the screen on the selected one */ +static int agraph_reload_nodes(AGraph *g) { int ret; + r_graph_reset (g->graph); ret = reload_nodes(g); if (!ret) return R_FALSE; - graph_set_layout(g); + agraph_set_layout(g); + g->update_seek_on = get_anode(g->curnode); return R_TRUE; } -static void follow_nth(struct graph *g, int nth) { - int cn = find_edge_node (g, g->curnode, nth); - if (cn != -1) { - g->curnode = cn; - ostack_push (&g->ostack, cn); +static void follow_nth(AGraph *g, int nth) { + const RGraphNode *cn = r_graph_nth_neighbour (g->graph, get_gn(g->curnode), nth); + if (cn) { + history_push (g->history, get_gn (g->curnode)); + g->curnode = r_graph_node_iter (g->graph, cn->idx); } } -static void graph_follow_true(struct graph *g) { +static void agraph_follow_true(AGraph *g) { follow_nth(g, 0); - graph_update_seek(g, g->curnode, R_FALSE); + agraph_update_seek(g, get_anode(g->curnode), R_FALSE); } -static void graph_follow_false(struct graph *g) { +static void agraph_follow_false(AGraph *g) { follow_nth(g, 1); - graph_update_seek(g, g->curnode, R_FALSE); + agraph_update_seek(g, get_anode(g->curnode), R_FALSE); } -static void graph_undo_node(struct graph *g) { - g->curnode = ostack_pop(&g->ostack); - graph_update_seek (g, g->curnode, R_FALSE); +/* go back in the history of selected nodes, if we can */ +static void agraph_undo_node(AGraph *g) { + const RGraphNode *p = history_pop (g->history); + if (p) { + g->curnode = r_graph_node_iter (g->graph, p->idx); + agraph_update_seek (g, p->data, R_FALSE); + } } -static void graph_next_node(struct graph *g) { - g->curnode = (g->curnode + 1) % g->n_nodes; - ostack_push (&g->ostack, g->curnode); - graph_update_seek (g, g->curnode, R_FALSE); +/* pushes the current node in the history and makes g->curnode the next node in + * the order given by r_graph_get_nodes */ +static void agraph_next_node(AGraph *g) { + if (!g->curnode->n) return; + history_push (g->history, get_gn(g->curnode)); + g->curnode = g->curnode->n; + agraph_update_seek (g, get_anode(g->curnode), R_FALSE); } -static void graph_prev_node(struct graph *g) { - if (g->curnode == 0) - g->curnode = g->n_nodes - 1; - else - g->curnode = g->curnode - 1; - ostack_push (&g->ostack, g->curnode); - graph_update_seek (g, g->curnode, R_FALSE); +/* pushes the current node in the history and makes g->curnode the prev node in + * the order given by r_graph_get_nodes */ +static void agraph_prev_node(AGraph *g) { + if (!g->curnode->p) return; + history_push (g->history, get_gn(g->curnode)); + g->curnode = g->curnode->p; + agraph_update_seek (g, get_anode(g->curnode), R_FALSE); } -static int graph_refresh(struct graph_refresh_data *grd) { - char title[128]; - struct graph *g = grd->g; - int fs = grd->fs; +static int agraph_refresh(struct agraph_refresh_data *grd) { + char title[TITLE_LEN]; + AGraph *g = grd->g; + const int fs = grd->fs; int h, w = r_cons_get_size (&h); int ret; + /* allow to change the current function only during debugging */ if (g->is_instep && g->core->io->debug) { RAnalFunction *f; r_core_cmd0 (g->core, "sr pc"); @@ -670,16 +606,15 @@ static int graph_refresh(struct graph_refresh_data *grd) { /* look for any change in the state of the graph * and update what's necessary */ if (g->need_reload_nodes) { - ret = graph_reload_nodes(g); + ret = agraph_reload_nodes(g); if (!ret) return R_FALSE; g->need_reload_nodes = R_FALSE; } - if (g->need_update_seek) { - update_seek(g->can, &g->nodes[g->update_seek_on], g->force_update_seek); - g->need_update_seek = R_FALSE; - g->update_seek_on = 0; + if (g->update_seek_on) { + update_seek(g->can, g->update_seek_on, g->force_update_seek); + g->update_seek_on = NULL; g->force_update_seek = R_FALSE; } @@ -691,15 +626,15 @@ static int graph_refresh(struct graph_refresh_data *grd) { r_cons_canvas_resize (g->can, w, h); r_cons_canvas_clear (g->can); - graph_print_edges(g); - graph_print_nodes(g); + agraph_print_edges(g); + agraph_print_nodes(g); if (fs) { (void)G (-g->can->sx, -g->can->sy); snprintf (title, sizeof (title)-1, "[0x%08"PFMT64x"]> %d VV @ %s (nodes %d edges %d) %s mouse:%s", - g->fcn->addr, g->ostack.size, g->fcn->name, - g->n_nodes, g->n_edges, g->is_callgraph?"CG":"BB", + g->fcn->addr, r_stack_size (g->history), g->fcn->name, + g->graph->n_nodes, g->graph->n_edges, g->is_callgraph?"CG":"BB", mousemodes[mousemode]); W (title); } @@ -720,27 +655,23 @@ static int graph_refresh(struct graph_refresh_data *grd) { return R_TRUE; } -static void graph_init(struct graph *g) { - g->nodes = NULL; - g->edges = NULL; - +static void agraph_init(AGraph *g) { g->is_callgraph = R_FALSE; g->is_instep = R_FALSE; g->is_simple_mode = R_TRUE; g->is_small_nodes = R_FALSE; g->need_reload_nodes = R_TRUE; - g->curnode = 0; - g->need_update_seek = R_TRUE; - g->update_seek_on = g->curnode; + g->curnode = NULL; + g->update_seek_on = NULL; g->force_update_seek = R_TRUE; - - ostack_init(&g->ostack); + g->history = r_stack_new (INIT_HISTORY_CAPACITY); + g->graph = r_graph_new (); } -static struct graph *graph_new(RCore *core, RConsCanvas *can, RAnalFunction *fcn) { - struct graph *g; +static AGraph *agraph_new(RCore *core, RConsCanvas *can, RAnalFunction *fcn) { + AGraph *g; - g = (struct graph *)malloc(sizeof(struct graph)); + g = (AGraph *)malloc(sizeof(AGraph)); if (!g) return NULL; @@ -748,18 +679,18 @@ static struct graph *graph_new(RCore *core, RConsCanvas *can, RAnalFunction *fcn g->can = can; g->fcn = fcn; - graph_init(g); + agraph_init(g); return g; } R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interactive) { int exit_graph = R_FALSE, is_error = R_FALSE; - struct graph_refresh_data *grd; + struct agraph_refresh_data *grd; int okey, key, wheel; RAnalFunction *fcn; const char *key_s; RConsCanvas *can; - struct graph *g; + AGraph *g; int wheelspeed; int w, h; int ret; @@ -780,22 +711,22 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti // disable colors in disasm because canvas doesnt supports ansi text yet r_config_set_i (core->config, "scr.color", 0); - g = graph_new (core, can, fcn); + g = agraph_new (core, can, fcn); if (!g) { is_error = R_TRUE; goto err_graph_new; } - grd = (struct graph_refresh_data *)malloc (sizeof(*grd)); + grd = (struct agraph_refresh_data *)malloc (sizeof(*grd)); grd->g = g; grd->fs = is_interactive; core->cons->event_data = grd; - core->cons->event_resize = (RConsEvent)graph_refresh; + core->cons->event_resize = (RConsEvent)agraph_refresh; while (!exit_graph && !is_error) { w = r_cons_get_size (&h); - ret = graph_refresh (grd); + ret = agraph_refresh (grd); if (!ret) { is_error = R_TRUE; break; @@ -835,10 +766,10 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti } break; case 'O': - graph_toggle_simple_mode(g); + agraph_toggle_simple_mode(g); break; case 'V': - graph_toggle_callgraph(g); + agraph_toggle_callgraph(g); break; case 'z': g->is_instep = R_TRUE; @@ -851,13 +782,13 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti else r_core_cmd0 (core, "aes;.dr*"); } - ret = graph_reload_nodes(g); + ret = agraph_reload_nodes(g); if (!ret) is_error = R_TRUE; break; case 'Z': if (okey == 27) { - graph_prev_node(g); + agraph_prev_node(g); } else { // 'Z' g->is_instep = R_TRUE; @@ -866,7 +797,7 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti else r_core_cmd0 (core, "aeso;.dr*"); - ret = graph_reload_nodes(g); + ret = agraph_reload_nodes(g); if (!ret) is_error = R_TRUE; } @@ -880,7 +811,7 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti exit_graph = R_TRUE; break; case 9: // tab - graph_next_node(g); + agraph_next_node(g); break; case '?': r_cons_clear00 (); @@ -905,7 +836,7 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti break; case 'R': case 'r': - graph_set_layout (g); + agraph_set_layout (g); break; case 'j': if (r_cons_singleton()->mouse_event) { @@ -917,14 +848,14 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti can->sx += wheelspeed; break; case 2: // node-y - get_current_node(g)->y += wheelspeed; + get_anode(g->curnode)->y += wheelspeed; break; case 3: // node-x - get_current_node(g)->x += wheelspeed; + get_anode(g->curnode)->x += wheelspeed; break; } } else { - get_current_node(g)->y++; + get_anode(g->curnode)->y++; } break; case 'k': @@ -937,14 +868,14 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti can->sx -= wheelspeed; break; case 2: // node-y - get_current_node(g)->y -= wheelspeed; + get_anode(g->curnode)->y -= wheelspeed; break; case 3: // node-x - get_current_node(g)->x -= wheelspeed; + get_anode(g->curnode)->x -= wheelspeed; break; } } else { - get_current_node(g)->y--; + get_anode(g->curnode)->y--; } break; case 'm': @@ -957,12 +888,12 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti if (mousemode<0) mousemode = 3; break; - case 'h': get_current_node(g)->x--; break; - case 'l': get_current_node(g)->x++; break; - case 'J': get_current_node(g)->y += 5; break; - case 'K': get_current_node(g)->y -= 5; break; - case 'H': get_current_node(g)->x -= 5; break; - case 'L': get_current_node(g)->x += 5; break; + case 'h': get_anode(g->curnode)->x--; break; + case 'l': get_anode(g->curnode)->x++; break; + case 'J': get_anode(g->curnode)->y += 5; break; + case 'K': get_anode(g->curnode)->y -= 5; break; + case 'H': get_anode(g->curnode)->x -= 5; break; + case 'L': get_anode(g->curnode)->x += 5; break; // scroll case '0': can->sx = can->sy = 0; break; case 'w': can->sy -= 1; break; @@ -977,20 +908,20 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti can->linemode = !!!can->linemode; break; case 'p': - graph_toggle_small_nodes(g); + agraph_toggle_small_nodes(g); break; case 'u': - graph_undo_node(g); + agraph_undo_node(g); break; case '.': - graph_update_seek (g, g->curnode, R_TRUE); + agraph_update_seek (g, get_anode(g->curnode), R_TRUE); g->is_instep = R_TRUE; break; case 't': - graph_follow_true(g); + agraph_follow_true(g); break; case 'f': - graph_follow_false(g); + agraph_follow_false(g); break; case '/': r_core_cmd0 (core, "?i highlight;e scr.highlight=`?y`"); @@ -1012,13 +943,7 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti case 27: // ESC if (r_cons_readchar () == 91) { if (r_cons_readchar () == 90) { - if (g->curnode < 1) { - int i; - for (i = 0; i < g->n_nodes; i++) ; - g->curnode = i - 1; - } else { - g->curnode--; - } + agraph_prev_node (g); } } break; @@ -1029,7 +954,7 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn, int is_interacti } } - graph_free(g); + agraph_free(g); err_graph_new: free (can); r_config_set_i (core->config, "scr.color", can->color); diff --git a/libr/include/r_list.h b/libr/include/r_list.h index 95e2461fad..ed2305a5bc 100644 --- a/libr/include/r_list.h +++ b/libr/include/r_list.h @@ -64,8 +64,8 @@ R_API int r_list_set_n(RList *list, int n, void *p); R_API void *r_list_iter_get_data(RListIter *list); R_API RListIter *r_list_append(RList *list, void *data); R_API RListIter *r_list_prepend(RList *list, void *data); -R_API int r_list_length(RList *list); -R_API void* r_list_first(RList *list); +R_API int r_list_length(const RList *list); +R_API void* r_list_first(const RList *list); R_API RListIter *r_list_add_sorted(RList *list, void *data, RListComparator cmp); R_API void r_list_sort(RList *list, RListComparator cmp); @@ -79,20 +79,20 @@ R_API RListIter *r_list_item_new (void *data); R_API void r_list_split (RList *list, void *ptr); R_API void r_list_split_iter (RList *list, RListIter *iter); R_API int r_list_join (RList *list1, RList *list2); -R_API void *r_list_get_n (RList *list, int n); +R_API void *r_list_get_n (const RList *list, int n); R_API int r_list_del_n (RList *list, int n); -R_API void *r_list_get_top (RList *list); -R_API void *r_list_get_bottom (RList *list); +R_API void *r_list_get_top (const RList *list); +R_API void *r_list_get_bottom (const RList *list); R_API void *r_list_pop (RList *list); R_API void r_list_reverse (RList *list); R_API RList *r_list_clone (RList *list); /* hashlike api */ -R_API void *r_list_get_by_int(RList *list, int off, int n); -R_API void *r_list_get_by_int64(RList *list, int off, ut64 n); -R_API void *r_list_get_by_string(RList *list, int off, const char *str); -R_API RListIter *r_list_contains (RList *list, void *p); -R_API RListIter *r_list_find (RList *list, void *p, RListComparator cmp); +R_API void *r_list_get_by_int(const RList *list, int off, int n); +R_API void *r_list_get_by_int64(const RList *list, int off, ut64 n); +R_API void *r_list_get_by_string(const RList *list, int off, const char *str); +R_API RListIter *r_list_contains (const RList *list, void *p); +R_API RListIter *r_list_find (const RList *list, void *p, RListComparator cmp); /* rlistflist */ // TODO: rename to init or so.. #define r_oflist_new() R_NEW(ROFList);memset diff --git a/libr/include/r_util.h b/libr/include/r_util.h index f593c80fd1..8251b9e9af 100644 --- a/libr/include/r_util.h +++ b/libr/include/r_util.h @@ -261,10 +261,10 @@ typedef struct r_graph_node_t { typedef struct r_graph_t { unsigned int n_nodes; - unsigned int capacity; + unsigned int n_edges; int last_index; - RGraphNode **nodes; - RList **adjacency; + RList *nodes; /* RGraphNode */ + RList *adjacency; } RGraph; #ifdef R_API @@ -273,6 +273,7 @@ R_API void r_stack_free (RStack *s); R_API int r_stack_push (RStack *s, void *el); R_API void *r_stack_pop (RStack *s); R_API int r_stack_is_empty (RStack *s); +R_API unsigned int r_stack_size (RStack *s); R_API RQueue *r_queue_new (int n); R_API void r_queue_free (RQueue *q); @@ -288,13 +289,15 @@ R_API void r_tree_dfs (RTree *t, RTreeVisitor *vis); R_API void r_tree_bfs (RTree *t, RTreeVisitor *vis); R_API RGraphNode *r_graph_get_node (RGraph *g, unsigned int idx); -R_API RList *r_graph_get_nodes (RGraph *g); +R_API RListIter *r_graph_node_iter (RGraph *g, unsigned int idx); +R_API const RList *r_graph_get_nodes (RGraph *g); R_API RGraph *r_graph_new (void); R_API void r_graph_free (RGraph* g); R_API void r_graph_reset (RGraph *g); R_API RGraphNode *r_graph_add_node (RGraph *g, void *data); R_API void r_graph_add_edge (RGraph *g, RGraphNode *from, RGraphNode *to); -R_API RList *r_graph_get_neighbours (RGraph *g, RGraphNode *n); +R_API const RList *r_graph_get_neighbours (RGraph *g, RGraphNode *n); +R_API RGraphNode *r_graph_nth_neighbour (RGraph *g, RGraphNode *n, int nth); R_API int r_graph_adjacent (RGraph *g, RGraphNode *from, RGraphNode *to); R_API int r_file_is_abspath(const char *file); diff --git a/libr/util/graph.c b/libr/util/graph.c index 7b8699e4b7..f2ca39b9a8 100644 --- a/libr/util/graph.c +++ b/libr/util/graph.c @@ -2,14 +2,10 @@ #include -#define INITIAL_CAPACITY 16 - -/* TODO: allow deletion of nodes and update the "is_in_range" - * function to "is_valid_index" function, that checks if - * the node really exists */ -static int is_in_range (RGraph *g, unsigned int idx) { - return idx < g->n_nodes; -} +struct adjacency_t { + unsigned int idx; + RList *adj; +}; static RGraphNode *r_graph_node_new (void *data) { RGraphNode *p = R_NEW0 (RGraphNode); @@ -24,93 +20,102 @@ static void r_graph_node_free (RGraphNode *n) { free (n); } +static void adjancency_free (struct adjacency_t *a) { + r_list_free (a->adj); + free (a); +} + +static int node_cmp (unsigned int idx, RGraphNode *b) { + return idx == b->idx ? 0 : -1; +} + +static int adj_cmp (unsigned int idx, struct adjacency_t *b) { + return idx == b->idx ? 0 : -1; +} + +static RList *get_adjacency (RList *l, unsigned int idx) { + RListIter *it = r_list_find (l, (void *)(size_t)idx, (RListComparator)adj_cmp); + if (!it) + return NULL; + + struct adjacency_t *a = (struct adjacency_t *)it->data; + return a->adj; +} + R_API RGraph *r_graph_new () { RGraph *t = R_NEW0 (RGraph); - t->capacity = INITIAL_CAPACITY; - t->nodes = R_NEWS0 (RGraphNode *, t->capacity); - t->adjacency = R_NEWS0 (RList *, t->capacity); + t->nodes = r_list_new (); + t->nodes->free = (RListFree)r_graph_node_free; + t->adjacency = r_list_new (); + t->adjacency->free = (RListFree)adjancency_free; t->n_nodes = 0; - t->last_index = -1; + t->last_index = 0; return t; } R_API void r_graph_free (RGraph* t) { - unsigned i; - - for (i = 0; i < t->capacity; ++i) { - if (t->nodes[i] != NULL) { - r_list_free (t->adjacency[i]); - r_graph_node_free (t->nodes[i]); - } - } - - free (t->nodes); - free (t->adjacency); + r_list_free (t->nodes); + r_list_free (t->adjacency); free (t); } R_API RGraphNode *r_graph_get_node (RGraph *t, unsigned int idx) { - return t->nodes[idx]; + RListIter *it = r_list_find (t->nodes, (void *)(size_t)idx, (RListComparator)node_cmp); + if (!it) + return NULL; + + return (RGraphNode *)it->data; +} + +R_API RListIter *r_graph_node_iter (RGraph *t, unsigned int idx) { + return r_list_find (t->nodes, (void *)(size_t)idx, (RListComparator)node_cmp); } R_API void r_graph_reset (RGraph *t) { - unsigned i; + r_list_free (t->nodes); + r_list_free (t->adjacency); - for (i = 0; i < t->capacity; ++i) { - if (t->adjacency[i]) - r_list_free (t->adjacency[i]); - if (t->nodes[i]) - r_graph_node_free (t->nodes[i]); - } - free (t->nodes); - t->capacity = INITIAL_CAPACITY; - t->nodes = R_NEWS0 (RGraphNode *, t->capacity); - t->adjacency = R_NEWS0 (RList *, t->capacity); + t->nodes = r_list_new (); + t->nodes->free = (RListFree)r_graph_node_free; + t->adjacency = r_list_new (); + t->adjacency->free = (RListFree)adjancency_free; t->n_nodes = 0; + t->n_edges = 0; + t->last_index = 0; } R_API RGraphNode *r_graph_add_node (RGraph *t, void *data) { RGraphNode *n = r_graph_node_new (data); + struct adjacency_t *a = R_NEW (struct adjacency_t); - if (t->n_nodes == t->capacity) { - int new_capacity = t->capacity * 2; - t->adjacency = realloc (t->adjacency, new_capacity * sizeof(RList *)); - t->nodes = realloc (t->nodes, new_capacity * sizeof (RGraphNode *)); - memset (t->nodes + t->capacity, 0, (new_capacity - t->capacity) * sizeof (RGraphNode *)); - t->capacity = new_capacity; - } - - n->idx = ++t->last_index; - t->adjacency[n->idx] = r_list_new(); - t->adjacency[n->idx]->free = NULL; - t->nodes[n->idx] = n; + n->idx = t->last_index++; + r_list_append (t->nodes, n); + a->idx = n->idx; + a->adj = r_list_new (); + r_list_append (t->adjacency, a); t->n_nodes++; return n; } R_API void r_graph_add_edge (RGraph *t, RGraphNode *from, RGraphNode *to) { - if (is_in_range(t, from->idx)) - r_list_append(t->adjacency[from->idx], to); + RList *a = get_adjacency (t->adjacency, from->idx); + if (!a) return; + r_list_append(a, to); + t->n_edges++; } -R_API RList *r_graph_get_neighbours (RGraph *g, RGraphNode *n) { - return is_in_range(g, n->idx) ? g->adjacency[n->idx] : NULL; +R_API const RList *r_graph_get_neighbours (RGraph *g, RGraphNode *n) { + return get_adjacency (g->adjacency, n->idx); } -/* returns a list with all the nodes in the graph - * NOTE: the user should free the list */ -R_API RList *r_graph_get_nodes (RGraph *g) { - RList *res; - unsigned int i; +R_API RGraphNode *r_graph_nth_neighbour (RGraph *g, RGraphNode *n, int nth) { + return (RGraphNode *)r_list_get_n (get_adjacency (g->adjacency, n->idx), nth); +} - res = r_list_new (); - res->free = NULL; - for (i = 0; i < g->capacity; ++i) - if (g->nodes[i]) - r_list_append (res, g->nodes[i]); - return res; +R_API const RList *r_graph_get_nodes (RGraph *g) { + return g->nodes; } R_API int r_graph_adjacent (RGraph *g, RGraphNode *from, RGraphNode *to) { - return r_list_contains (g->adjacency[from->idx], to) ? R_TRUE : R_FALSE; + return r_list_contains (get_adjacency (g->adjacency, from->idx), to) ? R_TRUE : R_FALSE; } diff --git a/libr/util/list.c b/libr/util/list.c index d779f815ee..68a040ff49 100644 --- a/libr/util/list.c +++ b/libr/util/list.c @@ -23,7 +23,7 @@ void *r_list_iter_get_data(RListIter *list) { return list->data; } -RListIter *r_list_iterator (RList *list) { +RListIter *r_list_iterator (const RList *list) { return list? list->head: NULL; } @@ -35,7 +35,7 @@ RListIter *r_list_get_next (RListIter *list) { return list ? list->n : NULL; } -R_API void* r_list_first(RList *list) { +R_API void* r_list_first(const RList *list) { if (list && list->head) { return list->head->data; } @@ -48,7 +48,7 @@ R_API void r_list_init(RList *list) { list->free = NULL; } -R_API int r_list_length(RList *list) { +R_API int r_list_length(const RList *list) { int count = 0; RListIter *iter = r_list_iterator (list); while (iter) { @@ -246,12 +246,12 @@ R_API int r_list_del_n(RList *list, int n) { return R_FALSE; } -R_API void *r_list_get_top(RList *list) { +R_API void *r_list_get_top(const RList *list) { if (list && list->tail) return list->tail->data; return NULL; } -R_API void *r_list_get_bottom(RList *list) { +R_API void *r_list_get_bottom(const RList *list) { if (list && list->head) return list->head->data; return NULL; @@ -335,7 +335,7 @@ R_API int r_list_set_n(RList *list, int n, void *p) { return R_FALSE; } -R_API void *r_list_get_n(RList *list, int n) { +R_API void *r_list_get_n(const RList *list, int n) { RListIter *it; int i; if (list) @@ -345,7 +345,7 @@ R_API void *r_list_get_n(RList *list, int n) { return NULL; } -R_API void *r_list_get_by_int(RList *list, int off, int n) { +R_API void *r_list_get_by_int(const RList *list, int off, int n) { ut8 *p; RListIter *iter; r_list_foreach (list, iter, p) { @@ -355,7 +355,7 @@ R_API void *r_list_get_by_int(RList *list, int off, int n) { return NULL; } -R_API void *r_list_get_by_int64(RList *list, int off, ut64 n) { +R_API void *r_list_get_by_int64(const RList *list, int off, ut64 n) { ut8 *p; RListIter *iter; r_list_foreach (list, iter, p) { @@ -365,7 +365,7 @@ R_API void *r_list_get_by_int64(RList *list, int off, ut64 n) { return NULL; } -R_API void *r_list_get_by_string(RList *list, int off, const char *str) { +R_API void *r_list_get_by_string(const RList *list, int off, const char *str) { char *p; RListIter *iter; r_list_foreach (list, iter, p) { @@ -376,7 +376,7 @@ R_API void *r_list_get_by_string(RList *list, int off, const char *str) { return NULL; } -R_API RListIter *r_list_contains (RList *list, void *p) { +R_API RListIter *r_list_contains (const RList *list, void *p) { void *q; RListIter *iter; r_list_foreach (list, iter, q) { @@ -386,7 +386,7 @@ R_API RListIter *r_list_contains (RList *list, void *p) { return NULL; } -R_API RListIter *r_list_find (RList *list, void *p, RListComparator cmp) { +R_API RListIter *r_list_find (const RList *list, void *p, RListComparator cmp) { void *q; RListIter *iter; r_list_foreach (list, iter, q) { diff --git a/libr/util/stack.c b/libr/util/stack.c index 1cd7492773..3f97540d39 100644 --- a/libr/util/stack.c +++ b/libr/util/stack.c @@ -45,3 +45,7 @@ R_API void *r_stack_pop (RStack *s) { R_API int r_stack_is_empty (RStack *s) { return s->top == -1; } + +R_API unsigned int r_stack_size (RStack *s) { + return (unsigned int)(s->top + 1); +} diff --git a/libr/util/t/test_graph.c b/libr/util/t/test_graph.c index 1ee40e7673..31cc4e82a5 100644 --- a/libr/util/t/test_graph.c +++ b/libr/util/t/test_graph.c @@ -79,7 +79,6 @@ int main(int argc, char **argv) { check(g->n_nodes, 10, "n_nodes.again"); check_list(nodes, exp_nodes, "get_all_nodes"); r_list_free(exp_nodes); - r_list_free(nodes); r_graph_free (g); return 0; diff --git a/libr/util/t/test_stack.c b/libr/util/t/test_stack.c index b98852087f..57a44fbc03 100644 --- a/libr/util/t/test_stack.c +++ b/libr/util/t/test_stack.c @@ -1,10 +1,11 @@ #include -void check (int n, int exp) { +void check (int n, int exp, char *descr) { + descr = descr == NULL ? "" : descr; if (n == exp) { - printf("[+] test passed (actual: %d; expected: %d)\n", n, exp); + printf("[+][%s] test passed (actual: %d; expected: %d)\n", descr, n, exp); } else { - printf("[-] test failed (actual: %d; expected: %d)\n", n, exp); + printf("[-][%s] test failed (actual: %d; expected: %d)\n", descr, n, exp); } } @@ -20,9 +21,11 @@ int main(int argc, char **argv) { RStack *s = r_stack_new(5); int n; + check(r_stack_size(s), 0, "stack.0"); r_stack_push(s, (void *)10); r_stack_push(s, (void *)1); r_stack_push(s, (void *)2); + check(r_stack_size(s), 3, "stack.3"); r_stack_push(s, (void *)3); r_stack_push(s, (void *)4); r_stack_push(s, (void *)5); @@ -31,32 +34,36 @@ int main(int argc, char **argv) { r_stack_push(s, (void *)9); r_stack_push(s, (void *)6); n = (int)r_stack_pop(s); - check(n, 6); + check(n, 6, NULL); n = (int)r_stack_pop(s); - check(n, 9); + check(n, 9, NULL); n = (int)r_stack_pop(s); - check(n, 8); + check(n, 8, NULL); n = (int)r_stack_pop(s); - check(n, 6); + check(n, 6, NULL); n = (int)r_stack_pop(s); - check(n, 5); + check(n, 5, NULL); n = (int)r_stack_pop(s); - check(n, 4); + check(n, 4, NULL); n = (int)r_stack_pop(s); - check(n, 3); + check(n, 3, NULL); n = (int)r_stack_pop(s); - check(n, 2); - n = (int)r_stack_pop(s); - check(n, 1); - check_empty(s, R_FALSE); - n = (int)r_stack_pop(s); - check(n, 10); + check(n, 2, NULL); + check(r_stack_size(s), 2, "stack.2"); + n = (int)r_stack_pop(s); + check(n, 1, NULL); + check_empty(s, R_FALSE); + check(r_stack_size(s), 1, "stack.1"); + n = (int)r_stack_pop(s); + check(n, 10, NULL); + + check(r_stack_size(s), 0, "stack.0.2"); check_empty(s, R_TRUE); n = (int)r_stack_pop(s); - check(n, 0); + check(n, 0, NULL); n = (int)r_stack_pop(s); - check(n, 0); + check(n, 0, NULL); check_empty(s, R_TRUE); r_stack_push(s, (void *)10);