smatch_extra: improve and fix assignment handling
[smatch.git] / gvpr / return-paths
blob5815fc70b78a4c307bc799182f3605b34d3c18f1
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
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         }
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;
26         $tvtype = TV_en;
29 // Each call edge which hasn't already been seen
30 E [op == "call" && tail.split != 1] {
31         int offset=0;
33         // Clear the label of this call
34         label = "";
35         g = find_owner(tail, $G);
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") {
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";
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;
58                         // Connect original to split
59                         e2 = edge(n, n2, "call");
60                         e2.style = "dotted";
61                         e2.weight = 50;
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                         }
71                         // Record where we were
72                         n = n2;
73                 }
74         }
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         }
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         }
105 END_G {
106         write($);