aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/gvpr/subg-rev
diff options
authorDan Sheridan <djs@postman.org.uk>2007-05-15 12:28:08 +0100
committerJosh Triplett <josh@freedesktop.org>2007-05-22 14:58:29 -0700
commitfdbc0f5de7663893f6fcfe9cbcccb52b9d093db1 (patch)
tree51b8812047efc3be78b8d6b682dd2b314445edd3 /gvpr/subg-rev
parentbb7ff206a0a1afca8eefbf3fedd7b5962cdec6f1 (diff)
downloadsparse-dev-fdbc0f5de7663893f6fcfe9cbcccb52b9d093db1.tar.gz
Add gvpr-based post-processing for graphs
Three gvpr scripts for post-processing the dot files generated by graph.c: return-paths: splits each call site and adds return edges to complete the control flow graph subg-fwd: find the subgraph reachable from a given function subg-rev: find the subgraph which can reach a given function Signed-off-by: Dan Sheridan <djs@adelard.com>
Diffstat (limited to 'gvpr/subg-rev')
-rw-r--r--gvpr/subg-rev100
1 files changed, 100 insertions, 0 deletions
diff --git a/gvpr/subg-rev b/gvpr/subg-rev
new file mode 100644
index 00000000..add3b820
--- /dev/null
+++ b/gvpr/subg-rev
@@ -0,0 +1,100 @@
+// Compute the reverse partition of the chosen function
+//
+// Run with graph ... | gvpr -f return-paths | gvpr -f 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);
+}