radare2/libr/util/graph.c
pancake 7c2a6e63b4 * Initial implementation of r_debug_map_protect()
- Bind to dmp command
  - Only w32 + osx, needs more work
* Added new api r_graph
* Added dtc and dtg
* Some minor makeup in RList
2011-11-25 04:32:32 +01:00

182 lines
4.1 KiB
C

/* radare - LGPL - Copyright 2007-2011 pancake<nopcode.org> */
/* graph with stack facilities implementation */
#include <r_util.h>
R_API RGraphNode *r_graph_node_new (ut64 addr, void *data) {
RGraphNode *p = R_NEW0 (RGraphNode);
p->parents = r_list_new ();
p->children = r_list_new ();
p->addr = addr;
p->data = data;
p->refs = 0;
return p;
}
R_API void r_graph_node_free (RGraphNode *n) {
r_list_free (n->parents);
r_list_free (n->children);
if (n->free)
n->free (n->data);
free (n);
}
static void walk_children (RGraph *t, RGraphNode *tn, int level) {
int i;
RListIter *iter;
RGraphNode *n;
if (r_list_contains (t->path, tn)) {
// do not repeat pushed nodes
return;
}
for (i=0; i<level; i++)
eprintf (" ");
eprintf ("%d: 0x%08"PFMT64x" refs %d\n",
level, tn->addr, tn->refs);
r_list_foreach (tn->parents, iter, n) {
for (i=0; i<level; i++)
eprintf (" ");
eprintf (" ^ 0x%08"PFMT64x"\n", n->addr);
}
r_list_push (t->path, tn);
r_list_foreach (tn->children, iter, n) {
walk_children (t, n, level+1);
}
r_list_pop (t->path);
}
R_API void r_graph_traverse(RGraph *t) {
RListIter *iter;
RGraphNode *root;
RList *path = t->path;
t->path = r_list_new ();
r_list_foreach (t->roots, iter, root) {
walk_children (t, root, 0);
}
r_list_free (t->path);
t->path = path;
}
R_API RGraph * r_graph_new () {
RGraph *t = R_NEW0 (RGraph);
t->path = r_list_new ();
t->nodes = r_list_new ();
t->roots = r_list_new ();
t->nodes->free = (RListFree)r_graph_node_free;
t->root = NULL;
t->cur = NULL;
return t;
}
R_API void r_graph_free (RGraph* t) {
r_list_free (t->nodes);
r_list_free (t->path);
free (t);
}
R_API RGraphNode* r_graph_get_current (RGraph *t, ut64 addr) {
return t->cur? t->cur->data: NULL;
}
R_API RGraphNode* r_graph_get_node (RGraph *t, ut64 addr, boolt c) {
RListIter *iter;
RGraphNode *n;
r_list_foreach (t->nodes, iter, n) {
if (n->addr == addr)
return n;
}
if (c) {
n = r_graph_node_new (addr, NULL);
r_list_append (t->nodes, n);
return n;
}
return NULL;
}
R_API void r_graph_reset (RGraph *t) {
r_list_free (t->nodes);
t->nodes = r_list_new ();
t->nodes->free = (RListFree)r_graph_node_free;
r_list_free (t->roots);
t->roots = r_list_new ();
t->root = NULL;
}
// g.add (0x804840, 0x804408, null);
R_API void r_graph_add (RGraph *t, ut64 from, ut64 addr, void *data) {
RGraphNode *n, *f = r_graph_get_node (t, from, R_TRUE);
n = r_graph_get_node (t, addr, R_TRUE);
n->data = data;
if (!r_list_contains (f->children, n))
r_list_append (f->children, n);
if (!r_list_contains (f->parents, n))
r_list_append (n->parents, f);
}
// plant: to set new root :)
R_API void r_graph_plant(RGraph *t) {
t->root = NULL;
}
R_API void r_graph_push (RGraph *t, ut64 addr, void *data) {
RGraphNode *c, *n = r_graph_get_node (t, addr, R_FALSE);
t->level++;
if (!n) {
n = r_graph_node_new (addr, data);
r_list_append (t->nodes, n);
if (t->root == NULL) {
t->root = n;
r_list_append (t->roots, n);
}
} else {
n->refs++;
n->data = data; // update data if already pushed?
}
if (!t->cur)
t->cur = r_list_contains (t->nodes, n);
c = t->cur->data;
if (!r_list_contains (c->children, n))
r_list_append (c->children, n);
if (c->addr && !r_list_contains (n->parents, c))
r_list_append (n->parents, c);
t->cur = r_list_append (t->path, n);
}
R_API RGraphNode* r_graph_pop(RGraph *t) {
RListIter *p;
if (!t || !t->path || !t->cur)
return NULL;
// TODO: handle null
t->level--;
if (t->level<0) {
eprintf ("Negative pop!\n");
return NULL;
}
p = t->cur->p;
r_list_delete (t->path, t->cur);
t->cur = p;
return (RGraphNode*)t->cur;
}
#if TEST
// usage
main () {
RGraph *t = r_graph_new ();
r_graph_push (t, 0x8048590, NULL);
r_graph_push (t, 0x8048230, NULL);
r_graph_pop (t);
r_graph_push (t, 0x8044300, NULL);
r_graph_push (t, 0x8046300, NULL);
r_graph_pop (t);
r_graph_push (t, 0x8046388, NULL);
r_graph_pop (t);
r_graph_push (t, 0x8046388, NULL);
r_graph_push (t, 0x8046388, NULL);
r_graph_push (t, 0x8046300, NULL);
r_graph_push (t, 0x8046300, NULL);
r_graph_pop (t);
r_graph_traverse (t);
r_graph_free (t);
}
#endif