analyze_callgraph.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #!/usr/bin/python
  2. import re
  3. import sys
  4. import copy
  5. import cPickle
  6. import os
  7. class Parser:
  8. def __init__(self):
  9. self.calls = {}
  10. def enter_func(self, name):
  11. if self.infunc and not self.extern:
  12. self.calls.setdefault(self.infunc, set()).update( self.calledfns )
  13. self.calledfns = set()
  14. self.infunc = name
  15. self.extern = False
  16. def parse_callgraph_file(self, inp):
  17. self.infunc = None
  18. self.extern = False
  19. self.calledfns = set()
  20. for line in inp:
  21. m = re.match(r"Call graph node for function: '([^']+)'", line)
  22. if m:
  23. self.enter_func(m.group(1))
  24. continue
  25. m = re.match(r" CS<[^>]+> calls external node", line)
  26. if m:
  27. self.extern = True
  28. m = re.match(r" CS<[^>]+> calls function '([^']+)'", line)
  29. if m:
  30. self.calledfns.add(m.group(1))
  31. self.enter_func(None)
  32. def extract_callgraph(self):
  33. c = self.calls
  34. self.calls = {}
  35. return c
  36. def transitive_closure(g):
  37. changed = True
  38. g = copy.deepcopy(g)
  39. while changed:
  40. changed = False
  41. print "X"
  42. for k in g.keys():
  43. newset = g[k].copy()
  44. for fn in g[k]:
  45. newset.update(g.get(fn, set()))
  46. if len(newset) != len(g[k]):
  47. g[k].update( newset )
  48. changed = True
  49. return g
  50. if __name__ == '__main__':
  51. p = Parser()
  52. for fname in sys.argv[1:]:
  53. with open(fname, 'r') as f:
  54. p.parse_callgraph_file(f)
  55. callgraph = p.extract_callgraph()
  56. closure = transitive_closure(callgraph)
  57. with open('callgraph.cp', 'w') as f:
  58. cPickle.dump(callgraph, f)
  59. with open('callgraph_closure.cp', 'w') as f:
  60. cPickle.dump(closure, f)