return-paths 2.1 KB

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