blob: cd9bdddd0bda396fd959285b9d54c856ad42fdc4 [file] [log] [blame]
#!/usr/bin/gvpr -f
// Compute the reverse partition of the chosen function
//
// Run with graph ... | return-paths | subg-rev -a functionname
BEGIN {
// Find the immediate parent subgraph of this object
graph_t find_owner(obj_t o, graph_t g)
{
graph_t g1;
for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
if(isIn(g1,o)) return g1;
return NULL;
}
}
BEG_G {
graph_t calls[]; // Crude hash table for tracking who calls what
graph_t sg = subg ($, "reachable");
graph_t target, g, g2;
edge_t e;
int i;
$tvtype = TV_rev;
// find the ep corresponding to ARG[0]
for (g = fstsubg($G); g; g = nxtsubg(g)) {
if(g.fun == ARGV[0]) {
node_t n;
n = node($,g.ep);
$tvroot = n;
n.style = "filled";
target = g;
break;
}
}
if(!target) {
printf(2, "Function %s not found\n", ARGV[0]);
exit(1);
}
// Add the incoming call edges to the allowed call list
i = 0;
for(e = fstin(n); e; e = nxtin(e)) {
if (e.op = "call") {
g2 = find_owner(e.tail, $G);
calls[sprintf("%s%d", g2.name, ++i)] = g;
}
}
}
E [op == "ret"] {
// This is a return edge. Allow the corresponding call
g = find_owner(head, $G);
i = 0;
while(calls[sprintf("%s%d", g.name, ++i)]) {
}
calls[sprintf("%s%d", g.name, i)] = find_owner(tail, $G);
g2 = find_owner(tail, $G);
}
N [split == 1] {
// Ignore returns back to the target function
for (e = fstin($); e; e = nxtin(e))
if (e.op == "ret" && isIn(target,e.tail))
delete($G,e);
}
N {
$tvroot = NULL;
for (e = fstin($); e; e = nxtin(e)) {
if (e.op == "call") {
int found = 0;
g = find_owner(e.tail, $G);
i = 0;
while(calls[sprintf("%s%d", g.name, ++i)]) {
if (isIn(calls[sprintf("%s%d", g.name, i)],e.head))
found = 1;
}
g2 = find_owner(e.head, $G);
if (!found) delete($G, e);
}
}
for (g = fstsubg($G); g; g = nxtsubg(g)) {
if(isIn(g,$) && g != sg) {
subnode (copy(sg, g), $);
}
}
}
END_G {
induce(sg);
write(sg);
}