summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2015-07-30 12:23:28 -0400
committerNick Mathewson <nickm@torproject.org>2015-07-30 12:23:28 -0400
commit26c96911862f80ad228ec2655f8390c011705946 (patch)
tree65bac1d01d3759066c965b7b3bab0604582c42c7 /scripts
parentbeac91cf086de0178ef628778a90f3cec7e51e84 (diff)
downloadtor-26c96911862f80ad228ec2655f8390c011705946.tar.gz
tor-26c96911862f80ad228ec2655f8390c011705946.zip
Check in some scripts I use for callgraph analysis.
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/maint/analyze_callgraph.py72
-rwxr-xr-xscripts/maint/display_callgraph.py9
-rwxr-xr-xscripts/maint/generate_callgraph.sh13
3 files changed, 94 insertions, 0 deletions
diff --git a/scripts/maint/analyze_callgraph.py b/scripts/maint/analyze_callgraph.py
new file mode 100755
index 0000000000..afafe1430b
--- /dev/null
+++ b/scripts/maint/analyze_callgraph.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+import re
+import sys
+import copy
+import cPickle
+import os
+
+class Parser:
+ def __init__(self):
+ self.calls = {}
+
+ def enter_func(self, name):
+ if self.infunc and not self.extern:
+ self.calls.setdefault(self.infunc, set()).update( self.calledfns )
+
+ self.calledfns = set()
+ self.infunc = name
+ self.extern = False
+
+ def parse_callgraph_file(self, inp):
+ self.infunc = None
+ self.extern = False
+ self.calledfns = set()
+ for line in inp:
+ m = re.match(r"Call graph node for function: '([^']+)'", line)
+ if m:
+ self.enter_func(m.group(1))
+ continue
+ m = re.match(r" CS<[^>]+> calls external node", line)
+ if m:
+ self.extern = True
+ m = re.match(r" CS<[^>]+> calls function '([^']+)'", line)
+ if m:
+ self.calledfns.add(m.group(1))
+ self.enter_func(None)
+
+ def extract_callgraph(self):
+ c = self.calls
+ self.calls = {}
+ return c
+
+
+def transitive_closure(g):
+ changed = True
+ g = copy.deepcopy(g)
+ while changed:
+ changed = False
+ print "X"
+ for k in g.keys():
+ newset = g[k].copy()
+ for fn in g[k]:
+ newset.update(g.get(fn, set()))
+ if len(newset) != len(g[k]):
+ g[k].update( newset )
+ changed = True
+ return g
+
+if __name__ == '__main__':
+ p = Parser()
+ for fname in sys.argv[1:]:
+ with open(fname, 'r') as f:
+ p.parse_callgraph_file(f)
+ callgraph = p.extract_callgraph()
+
+ closure = transitive_closure(callgraph)
+
+ with open('callgraph.cp', 'w') as f:
+ cPickle.dump(callgraph, f)
+
+ with open('callgraph_closure.cp', 'w') as f:
+ cPickle.dump(closure, f)
diff --git a/scripts/maint/display_callgraph.py b/scripts/maint/display_callgraph.py
new file mode 100755
index 0000000000..4e4ea637ff
--- /dev/null
+++ b/scripts/maint/display_callgraph.py
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+import cPickle
+
+callgraph = cPickle.load(open("callgraph.cp"))
+closure = cPickle.load(open("callgraph_closure.cp"))
+
+for n_reachable, fn in sorted(list((len(r), fn) for fn, r in closure.iteritems())):
+ print "%s can reach %s other functions." %(fn, n_reachable)
diff --git a/scripts/maint/generate_callgraph.sh b/scripts/maint/generate_callgraph.sh
new file mode 100755
index 0000000000..97330cc949
--- /dev/null
+++ b/scripts/maint/generate_callgraph.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+C_FILES=`echo src/common/*.c src/or/*.c src/tools/*.c`
+CFLAGS="-Isrc/ext/trunnel -Isrc/trunnel -I. -Isrc/ext -Isrc/common -DLOCALSTATEDIR=\"\" -DSHARE_DATADIR=\"\" -Dinline="
+
+mkdir -p callgraph/src/common
+mkdir -p callgraph/src/or
+mkdir -p callgraph/src/tools
+
+for fn in $C_FILES; do
+ clang $CFLAGS -S -emit-llvm -fno-inline -o - $fn | \
+ opt -analyze -print-callgraph 2> "callgraph/${fn}allgraph"
+done