Initial implementation of VVV for ascii-art callgraphs

This commit is contained in:
pancake 2014-07-09 05:05:22 +02:00
parent be34dbf9cd
commit 0f24b905f6
5 changed files with 163 additions and 47 deletions

View File

@ -11,7 +11,7 @@ typedef struct {
int h;
ut64 addr;
int depth;
const char *text;
char *text;
} Node;
typedef struct {
@ -171,46 +171,11 @@ static void Layout_depth(Node *nodes, Edge *edges) {
free (rowheight);
}
R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn) {
RAnalFunction *fcn;
RConsCanvas *can;
static int bbEdges (RAnalFunction *fcn, Node *nodes, Edge **e) {
Edge *edges = NULL;
RListIter *iter;
RAnalBlock *bb;
Node *nodes;
Edge *edges;
int cn, prevnode = curnode;
int w, h, i, n_nodes, n_edges;
char title[128];
fcn = _fcn?_fcn:r_anal_get_fcn_at (core->anal, core->offset);
if (!fcn) {
eprintf ("No function in current seek\n");
return R_FALSE;
}
w = r_cons_get_size (&h);
can = r_cons_canvas_new (w-1, h-1);
nodes = malloc (sizeof(Node)*(r_list_length (fcn->bbs)+1));
if (!nodes)
return R_FALSE;
i = 0;
r_list_foreach (fcn->bbs, iter, bb) {
nodes[i].text = r_core_cmd_strf (core,
"pI %d @ 0x%08"PFMT64x, bb->size, bb->addr);
nodes[i].addr = bb->addr;
nodes[i].depth = -1;
nodes[i].x = 10;
nodes[i].y = 3;
nodes[i].w = 0;
nodes[i].h = 0;
i++;
}
nodes[i].text = NULL;
n_nodes = i;
i = 0;
edges = NULL;
n_edges = 0;
int i = 0;
r_list_foreach (fcn->bbs, iter, bb) {
// add edge from bb->addr to bb->jump / bb->fail
if (bb->jump != UT64_MAX) {
@ -230,7 +195,124 @@ R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn) {
}
if (edges)
edges[i].nth = -1;
n_edges = i;
free (*e);
*e = edges;
return i;
}
static int cgNodes (RCore *core, RAnalFunction *fcn, Node **n) {
int j, i = 0;
char *code;
RAnalRef *ref;
RListIter *iter;
Node *nodes = calloc (1, sizeof(Node)*(r_list_length (fcn->refs)+2));
if (!nodes)
return R_FALSE;
nodes[i].text = strdup ("");
nodes[i].addr = fcn->addr;
nodes[i].depth = -1;
nodes[i].x = 10;
nodes[i].y = 3;
nodes[i].w = 0;
nodes[i].h = 0;
i++;
r_list_foreach (fcn->refs, iter, ref) {
/* avoid dups wtf */
for (j=0; j<i; j++) {
if (ref->addr == nodes[j].addr)
goto sin;
}
RFlagItem *fi = r_flag_get_at (core->flags, ref->addr);
if (fi) {
nodes[i].text = strdup (fi->name);
nodes[i].text = r_str_concat (nodes[i].text, ":\n");
} else {
nodes[i].text = strdup ("");
}
code = r_core_cmd_strf (core,
"pi 4 @ 0x%08"PFMT64x, ref->addr);
nodes[i].text = r_str_concat (nodes[i].text, code);
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++;
sin:
continue;
}
free (*n);
*n = nodes;
return i;
}
static int cgEdges (RAnalFunction *fcn, Node *nodes, Edge **e) {
int i = 0;
Edge *edges = NULL;
RAnalRef *ref;
RListIter *iter;
r_list_foreach (fcn->refs, iter, ref) {
edges = realloc (edges, sizeof (Edge)*(i+2));
edges[i].nth = 0;
edges[i].from = Node_find (nodes, fcn->addr);
edges[i].to = Node_find (nodes, ref->addr);
i++;
}
if (edges)
edges[i].nth = -1;
free (*e);
*e = edges;
return i;
}
static int bbNodes (RCore *core, RAnalFunction *fcn, Node **n) {
int i;
RAnalBlock *bb;
RListIter *iter;
Node *nodes = malloc (sizeof(Node)*(r_list_length (fcn->bbs)+1));
if (!nodes)
return R_FALSE;
i = 0;
r_list_foreach (fcn->bbs, iter, bb) {
nodes[i].text = r_core_cmd_strf (core,
"pI %d @ 0x%08"PFMT64x, bb->size, bb->addr);
nodes[i].addr = bb->addr;
nodes[i].depth = -1;
nodes[i].x = 10;
nodes[i].y = 3;
nodes[i].w = 0;
nodes[i].h = 0;
i++;
}
free (*n);
*n = nodes;
nodes[i].text = NULL;
return i;
}
R_API int r_core_visual_graph(RCore *core, RAnalFunction *_fcn) {
RAnalFunction *fcn;
RConsCanvas *can;
Node *nodes = NULL;
Edge *edges = NULL;
int key, cn, prevnode = curnode;
int w, h, i, n_nodes, n_edges;
int callgraph = 0;
char title[128];
fcn = _fcn?_fcn:r_anal_get_fcn_at (core->anal, core->offset);
if (!fcn) {
eprintf ("No function in current seek\n");
return R_FALSE;
}
w = r_cons_get_size (&h);
can = r_cons_canvas_new (w-1, h-1);
n_nodes = bbNodes (core, fcn, &nodes);
n_edges = bbEdges (fcn, nodes, &edges);
// hack to make layout happy
for (i=0;nodes[i].text;i++) {
@ -253,21 +335,52 @@ repeat:
Edge_print (can, a, b, edges[i].nth);
}
if (nodes)
for (i=0;nodes[i].text;i++) {
//for (i=0;nodes[i].text;i++) {
for (i=0;i<n_nodes;i++) {
Node_print (can, &nodes[i], i==curnode);
}
G (-can->sx, -can->sy);
snprintf (title, sizeof(title)-1, "[0x%08"PFMT64x"]> VV @ %s (nodes %d)",
fcn->addr, fcn->name, n_nodes);
snprintf (title, sizeof(title)-1, "[0x%08"PFMT64x"]> VV @ %s (nodes %d) %s",
fcn->addr, fcn->name, n_nodes, callgraph?"CG":"BB");
W (title);
r_cons_canvas_print (can);
r_cons_flush ();
int key = r_cons_readchar ();
key = r_cons_readchar ();
#define N nodes[curnode]
prevnode = curnode;
switch (key) {
case 'V':
callgraph = !!!callgraph;
if (callgraph) {
int y = 5, x = 20;
n_nodes = cgNodes (core, fcn, &nodes);
n_edges = cgEdges (fcn, nodes, &edges);
// callgraph layout
for (i=0;nodes[i].text;i++) {
// wrap to width 'w'
if (i>0) {
if (nodes[i].x<nodes[i-1].x) {
y+=10;
x = 0;
}
}
nodes[i].x = x;
nodes[i].y = i?y:2;
x += 30;
}
} else {
n_nodes = bbNodes (core, fcn, &nodes);
n_edges = bbEdges (fcn, nodes, &edges);
curnode = 0;
// hack to make the layout happy
for (i=0;nodes[i].text;i++) {
Node_print (can, &nodes[i], i==curnode);
}
Layout_depth (nodes, edges);
}
break;
case 9: curnode++;
if (!nodes[curnode].text)
curnode = 0;
@ -280,6 +393,7 @@ prevnode = curnode;
" tab - select next node\n"
" TAB - select previous node\n"
" t/f - follow true/false edges\n"
" V - toggle basicblock / call graphs\n"
" R - relayout\n");
r_cons_flush();
r_cons_any_key();

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2007-2013 - pancake */
/* radare - LGPL - Copyright 2007-2014 - pancake */
#include <r_flags.h>
#include <r_util.h>

View File

@ -184,7 +184,7 @@ R_API int r_run_parseline (RRunProfile *p, char *b);
R_API const char *r_run_help();
R_API int r_run_start(RRunProfile *p);
R_API void r_run_reset(RRunProfile *p);
R_API int r_run_parsefile (RRunProfile *p, char *b);
R_API int r_run_parsefile (RRunProfile *p, const char *b);
#endif

View File

@ -170,7 +170,7 @@ static void setASLR(int enabled) {
#endif
}
R_API int r_run_parsefile (RRunProfile *p, char *b) {
R_API int r_run_parsefile (RRunProfile *p, const char *b) {
int ret;
char *s = r_file_slurp (b, NULL);
if (s) {

View File

@ -1365,6 +1365,8 @@ R_API const char *r_str_closer_chr (const char *b, const char *s) {
R_API int r_str_bounds(const char *str, int *h) {
int W = 0, H = 0;
int cw = 0;
if (!str)
return W;
while (*str) {
if (*str=='\n') {
H++;