1 #!/usr/bin/gvpr -f
   2 // Split call sites into call site and return site nodes and add
   3 // return edges
   4 //
   5 // Run with graph ... | return-paths
   6 
   7 BEGIN {
   8         // Find the immediate parent subgraph of this object
   9         graph_t find_owner(obj_t o, graph_t g)
  10         {
  11                 graph_t g1;
  12                 for (g1 = fstsubg(g); g1; g1 = nxtsubg(g1))
  13                         if(isIn(g1,o)) return g1;
  14                 return NULL;
  15         }
  16 }
  17 
  18 BEG_G {
  19         node_t calls[]; // Crude hash table for tracking who calls what
  20         graph_t g,g2;
  21         edge_t e,e2;
  22         string idx;
  23         node_t n, n2;
  24         int i;
  25 
  26         $tvtype = TV_en;
  27 }
  28 
  29 // Each call edge which hasn't already been seen
  30 E [op == "call" && tail.split != 1] {
  31         int offset=0;
  32 
  33         // Clear the label of this call
  34         label = "";
  35         g = find_owner(tail, $G);
  36 
  37         // Consider each outgoing call. Split the node accordingly
  38         n = tail;
  39         for (e = fstout(tail); e; e = nxtout(e)) {
  40                 if (e.op == "call") {
  41 
  42                         // Split node
  43                         n2 = node(g, sprintf("%s%s%d", tail.name, "x", offset++));
  44                         copyA(tail, n2);
  45                         n2.line = e.line;
  46                         n2.label = e.line;
  47                         n2.col = e.col;
  48                         n2.split = 1;
  49                         n2.op = "target";
  50 
  51                         // Record this call
  52                         g2 = find_owner(e.head, $G);
  53                         i = 0;
  54                         while(calls[sprintf("%s%d", g2.name, ++i)]) {
  55                         }
  56                         calls[sprintf("%s%d", g2.name, i)] = n2;
  57 
  58                         // Connect original to split
  59                         e2 = edge(n, n2, "call");
  60                         e2.style = "dotted";
  61                         e2.weight = 50;
  62 
  63                         // Replace this outedge
  64                         if (n != tail) {
  65                                 e2 = edge(n, e.head, "transformed-call");
  66                                 copyA(e,e2);
  67                                 e2.label = "";
  68                                 delete($G,e);
  69                         }
  70 
  71                         // Record where we were
  72                         n = n2;
  73                 }
  74         }
  75 
  76         // Consider the outgoing control flow: move down to the bottom of
  77         // the call sequence nodes
  78         for (e = fstout(tail); e; e = nxtout(e)) {
  79                 if (e.op == "br") {
  80                         // Replace this outedge
  81                         e2 = edge(n,e.head,"transformed");
  82                         copyA(e,e2);
  83                         delete($G,e);
  84                 }
  85         }
  86 }
  87 
  88 // Each return node: add edges back to the caller
  89 N [op == "ret"] {
  90         for (g = fstsubg($G); g; g = nxtsubg(g)) {
  91                 if(isIn(g,$)) {
  92                         i = 0;
  93                         while(calls[sprintf("%s%d", g.name, ++i)]) {
  94                                 e = edge($, calls[sprintf("%s%d", g.name, i)], "return");
  95                                 e.style = "dotted";
  96                                 e.op = "ret";
  97                                 e.line = e.tail.line;
  98                                 e.weight = 5;
  99                         }
 100                 }
 101         }
 102 }
 103 
 104 
 105 END_G {
 106         write($);
 107 }