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
7BEGIN {
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
18BEG_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
30E [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
89N [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
105END_G {
106	write($);
107}
108