summaryrefslogtreecommitdiff
path: root/lib/python2.7/Tools/scripts/objgraph.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/Tools/scripts/objgraph.py')
-rw-r--r--lib/python2.7/Tools/scripts/objgraph.py215
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/python2.7/Tools/scripts/objgraph.py b/lib/python2.7/Tools/scripts/objgraph.py
new file mode 100644
index 0000000..dd58f15
--- /dev/null
+++ b/lib/python2.7/Tools/scripts/objgraph.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python2
+
+# objgraph
+#
+# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules
+# and print various interesting listings, such as:
+#
+# - which names are used but not defined in the set (and used where),
+# - which names are defined in the set (and where),
+# - which modules use which other modules,
+# - which modules are used by which other modules.
+#
+# Usage: objgraph [-cdu] [file] ...
+# -c: print callers per objectfile
+# -d: print callees per objectfile
+# -u: print usage of undefined symbols
+# If none of -cdu is specified, all are assumed.
+# Use "nm -o" to generate the input (on IRIX: "nm -Bo"),
+# e.g.: nm -o /lib/libc.a | objgraph
+
+
+import sys
+import os
+import getopt
+import re
+
+# Types of symbols.
+#
+definitions = 'TRGDSBAEC'
+externals = 'UV'
+ignore = 'Nntrgdsbavuc'
+
+# Regular expression to parse "nm -o" output.
+#
+matcher = re.compile('(.*):\t?........ (.) (.*)$')
+
+# Store "item" in "dict" under "key".
+# The dictionary maps keys to lists of items.
+# If there is no list for the key yet, it is created.
+#
+def store(dict, key, item):
+ if dict.has_key(key):
+ dict[key].append(item)
+ else:
+ dict[key] = [item]
+
+# Return a flattened version of a list of strings: the concatenation
+# of its elements with intervening spaces.
+#
+def flat(list):
+ s = ''
+ for item in list:
+ s = s + ' ' + item
+ return s[1:]
+
+# Global variables mapping defined/undefined names to files and back.
+#
+file2undef = {}
+def2file = {}
+file2def = {}
+undef2file = {}
+
+# Read one input file and merge the data into the tables.
+# Argument is an open file.
+#
+def readinput(fp):
+ while 1:
+ s = fp.readline()
+ if not s:
+ break
+ # If you get any output from this line,
+ # it is probably caused by an unexpected input line:
+ if matcher.search(s) < 0: s; continue # Shouldn't happen
+ (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4]
+ fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b]
+ if type in definitions:
+ store(def2file, name, fn)
+ store(file2def, fn, name)
+ elif type in externals:
+ store(file2undef, fn, name)
+ store(undef2file, name, fn)
+ elif not type in ignore:
+ print fn + ':' + name + ': unknown type ' + type
+
+# Print all names that were undefined in some module and where they are
+# defined.
+#
+def printcallee():
+ flist = file2undef.keys()
+ flist.sort()
+ for filename in flist:
+ print filename + ':'
+ elist = file2undef[filename]
+ elist.sort()
+ for ext in elist:
+ if len(ext) >= 8:
+ tabs = '\t'
+ else:
+ tabs = '\t\t'
+ if not def2file.has_key(ext):
+ print '\t' + ext + tabs + ' *undefined'
+ else:
+ print '\t' + ext + tabs + flat(def2file[ext])
+
+# Print for each module the names of the other modules that use it.
+#
+def printcaller():
+ files = file2def.keys()
+ files.sort()
+ for filename in files:
+ callers = []
+ for label in file2def[filename]:
+ if undef2file.has_key(label):
+ callers = callers + undef2file[label]
+ if callers:
+ callers.sort()
+ print filename + ':'
+ lastfn = ''
+ for fn in callers:
+ if fn <> lastfn:
+ print '\t' + fn
+ lastfn = fn
+ else:
+ print filename + ': unused'
+
+# Print undefined names and where they are used.
+#
+def printundef():
+ undefs = {}
+ for filename in file2undef.keys():
+ for ext in file2undef[filename]:
+ if not def2file.has_key(ext):
+ store(undefs, ext, filename)
+ elist = undefs.keys()
+ elist.sort()
+ for ext in elist:
+ print ext + ':'
+ flist = undefs[ext]
+ flist.sort()
+ for filename in flist:
+ print '\t' + filename
+
+# Print warning messages about names defined in more than one file.
+#
+def warndups():
+ savestdout = sys.stdout
+ sys.stdout = sys.stderr
+ names = def2file.keys()
+ names.sort()
+ for name in names:
+ if len(def2file[name]) > 1:
+ print 'warning:', name, 'multiply defined:',
+ print flat(def2file[name])
+ sys.stdout = savestdout
+
+# Main program
+#
+def main():
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'cdu')
+ except getopt.error:
+ sys.stdout = sys.stderr
+ print 'Usage:', os.path.basename(sys.argv[0]),
+ print '[-cdu] [file] ...'
+ print '-c: print callers per objectfile'
+ print '-d: print callees per objectfile'
+ print '-u: print usage of undefined symbols'
+ print 'If none of -cdu is specified, all are assumed.'
+ print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),'
+ print 'e.g.: nm -o /lib/libc.a | objgraph'
+ return 1
+ optu = optc = optd = 0
+ for opt, void in optlist:
+ if opt == '-u':
+ optu = 1
+ elif opt == '-c':
+ optc = 1
+ elif opt == '-d':
+ optd = 1
+ if optu == optc == optd == 0:
+ optu = optc = optd = 1
+ if not args:
+ args = ['-']
+ for filename in args:
+ if filename == '-':
+ readinput(sys.stdin)
+ else:
+ readinput(open(filename, 'r'))
+ #
+ warndups()
+ #
+ more = (optu + optc + optd > 1)
+ if optd:
+ if more:
+ print '---------------All callees------------------'
+ printcallee()
+ if optu:
+ if more:
+ print '---------------Undefined callees------------'
+ printundef()
+ if optc:
+ if more:
+ print '---------------All Callers------------------'
+ printcaller()
+ return 0
+
+# Call the main program.
+# Use its return value as exit status.
+# Catch interrupts to avoid stack trace.
+#
+if __name__ == '__main__':
+ try:
+ sys.exit(main())
+ except KeyboardInterrupt:
+ sys.exit(1)