#!/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); }