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