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 <[EMAIL PROTECTED]>
---
 gvpr/return-paths |  106 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gvpr/subg-fwd     |   78 +++++++++++++++++++++++++++++++++++++++
 gvpr/subg-rev     |  100 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+), 0 deletions(-)

diff --git a/gvpr/return-paths b/gvpr/return-paths
new file mode 100644
index 0000000..a91525b
--- /dev/null
+++ b/gvpr/return-paths
@@ -0,0 +1,106 @@
+// Split call sites into call site and return site nodes and add
+// return edges
+// 
+// Run with graph ... | gvpr -f return-paths
+
+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 {
+       node_t calls[]; // Crude hash table for tracking who calls what
+       graph_t g,g2;
+       edge_t e,e2;
+       string idx;
+       node_t n, n2;
+       int i;
+  
+       $tvtype = TV_en;
+}
+
+// Each call edge which hasn't already been seen
+E [op == "call" && tail.split != 1] {
+       int offset=0;
+
+       // Clear the label of this call
+       label = "";
+       g = find_owner(tail, $G);
+
+       // Consider each outgoing call. Split the node accordingly
+       n = tail;
+       for (e = fstout(tail); e; e = nxtout(e)) {
+               if (e.op == "call") {
+         
+                       // Split node
+                       n2 = node(g, sprintf("%s%s%d", tail.name, "x", 
offset++));
+                       copyA(tail, n2);
+                       n2.line = e.line;
+                       n2.label = e.line;
+                       n2.col = e.col;
+                       n2.split = 1;
+                       n2.op = "target";
+
+                       // Record this call
+                       g2 = find_owner(e.head, $G);
+                       i = 0;
+                       while(calls[sprintf("%s%d", g2.name, ++i)]) {
+                       }
+                       calls[sprintf("%s%d", g2.name, i)] = n2;
+
+                       // Connect original to split
+                       e2 = edge(n, n2, "call");
+                       e2.style = "dotted";
+                       e2.weight = 50;
+         
+                       // Replace this outedge
+                       if (n != tail) {
+                               e2 = edge(n, e.head, "transformed-call");
+                               copyA(e,e2);
+                               e2.label = "";
+                               delete($G,e);
+                       }
+
+                       // Record where we were
+                       n = n2;
+               }
+       }
+
+       // Consider the outgoing control flow: move down to the bottom of
+       // the call sequence nodes
+       for (e = fstout(tail); e; e = nxtout(e)) {
+               if (e.op == "br") {
+                       // Replace this outedge
+                       e2 = edge(n,e.head,"transformed");
+                       copyA(e,e2);
+                       delete($G,e);
+               }
+       }
+}
+
+// Each return node: add edges back to the caller
+N [op == "ret"] {
+       for (g = fstsubg($G); g; g = nxtsubg(g)) {
+               if(isIn(g,$)) {
+                       i = 0;
+                       while(calls[sprintf("%s%d", g.name, ++i)]) {
+                               e = edge($, calls[sprintf("%s%d", g.name, i)], 
"return"); 
+                               e.style = "dotted";
+                               e.op = "ret";
+                               e.line = e.tail.line;
+                               e.weight = 5;
+                       }
+               }
+       }
+}
+
+
+END_G {
+       write($);
+}
diff --git a/gvpr/subg-fwd b/gvpr/subg-fwd
new file mode 100644
index 0000000..aefe73e
--- /dev/null
+++ b/gvpr/subg-fwd
@@ -0,0 +1,78 @@
+// Compute the forward partition of the chosen function
+// 
+// Run with graph ... | gvpr -f return-paths | gvpr -f subg-fwd -a functionname
+//       or graph ... | gvpr -f subg-fwd
+
+
+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 sg = subg ($, sprintf("incoming-%s", ARGV[0]));
+       graph_t returns = graph("return-edges", ""); // Temporary graph to hold 
return edges
+       graph_t target, g, g2;
+       node_t n;
+       edge_t e;
+       int i;
+  
+       $tvtype = TV_fwd;
+  
+       // find the ep corresponding to ARG[0]
+       for (g = fstsubg($G); g; g = nxtsubg(g)) {
+               if(g.fun == ARGV[0]) {
+                       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);
+       }
+}
+
+// Preserve external functions
+E [op == "extern"] {
+       subnode (sg, head);
+}
+
+// Move unused return edges into a separate graph so they don't get followed
+N [op == "ret"] {
+       for (e = fstout($); e; e = nxtout(e))
+               if (e.op == "ret" && !isIn(sg, e.head)) {
+                       clone(returns, e);
+                       delete($G, e);
+               }
+}
+
+// Recover elided return edge for this target node
+N [op == "target" && indegree == 1] {
+       n = copy(returns, $);
+       e = fstin(n); // each target node can only have one return edge
+       e = edge(copy(sg, e.tail), $, "recovered"); // clone should work here, 
but doesn't
+       copyA(fstin(n), e);
+}      
+
+// Copy relevant nodes
+N {
+       $tvroot = NULL;
+
+       g = find_owner($, $G);
+       if(g && g != sg)
+               subnode (copy(sg, g), $);
+}
+
+END_G {
+       induce(sg);
+       write(sg);
+}
diff --git a/gvpr/subg-rev b/gvpr/subg-rev
new file mode 100644
index 0000000..e63fcb1
--- /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);
+}
-- 
1.4.4.2

-
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to