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 }