5
# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules
6
# and print various interesting listings, such as:
8
# - which names are used but not defined in the set (and used where),
9
# - which names are defined in the set (and where),
10
# - which modules use which other modules,
11
# - which modules are used by which other modules.
13
# Usage: objgraph [-cdu] [file] ...
14
# -c: print callers per objectfile
15
# -d: print callees per objectfile
16
# -u: print usage of undefined symbols
17
# If none of -cdu is specified, all are assumed.
18
# Use "nm -o" to generate the input (on IRIX: "nm -Bo"),
19
# e.g.: nm -o /lib/libc.a | objgraph
29
definitions = 'TRGDSBAEC'
31
ignore = 'Nntrgdsbavuc'
33
# Regular expression to parse "nm -o" output.
35
matcher = re.compile('(.*):\t?........ (.) (.*)$')
37
# Store "item" in "dict" under "key".
38
# The dictionary maps keys to lists of items.
39
# If there is no list for the key yet, it is created.
41
def store(dict, key, item):
43
dict[key].append(item)
47
# Return a flattened version of a list of strings: the concatenation
48
# of its elements with intervening spaces.
56
# Global variables mapping defined/undefined names to files and back.
63
# Read one input file and merge the data into the tables.
64
# Argument is an open file.
71
# If you get any output from this line,
72
# it is probably caused by an unexpected input line:
73
if matcher.search(s) < 0: s; continue # Shouldn't happen
74
(ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4]
75
fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b]
76
if type in definitions:
77
store(def2file, name, fn)
78
store(file2def, fn, name)
79
elif type in externals:
80
store(file2undef, fn, name)
81
store(undef2file, name, fn)
82
elif not type in ignore:
83
print fn + ':' + name + ': unknown type ' + type
85
# Print all names that were undefined in some module and where they are
89
flist = file2undef.keys()
91
for filename in flist:
93
elist = file2undef[filename]
100
if not def2file.has_key(ext):
101
print '\t' + ext + tabs + ' *undefined'
103
print '\t' + ext + tabs + flat(def2file[ext])
105
# Print for each module the names of the other modules that use it.
108
files = file2def.keys()
110
for filename in files:
112
for label in file2def[filename]:
113
if undef2file.has_key(label):
114
callers = callers + undef2file[label]
124
print filename + ': unused'
126
# Print undefined names and where they are used.
130
for filename in file2undef.keys():
131
for ext in file2undef[filename]:
132
if not def2file.has_key(ext):
133
store(undefs, ext, filename)
134
elist = undefs.keys()
140
for filename in flist:
141
print '\t' + filename
143
# Print warning messages about names defined in more than one file.
146
savestdout = sys.stdout
147
sys.stdout = sys.stderr
148
names = def2file.keys()
151
if len(def2file[name]) > 1:
152
print 'warning:', name, 'multiply defined:',
153
print flat(def2file[name])
154
sys.stdout = savestdout
160
optlist, args = getopt.getopt(sys.argv[1:], 'cdu')
162
sys.stdout = sys.stderr
163
print 'Usage:', os.path.basename(sys.argv[0]),
164
print '[-cdu] [file] ...'
165
print '-c: print callers per objectfile'
166
print '-d: print callees per objectfile'
167
print '-u: print usage of undefined symbols'
168
print 'If none of -cdu is specified, all are assumed.'
169
print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),'
170
print 'e.g.: nm -o /lib/libc.a | objgraph'
172
optu = optc = optd = 0
173
for opt, void in optlist:
180
if optu == optc == optd == 0:
181
optu = optc = optd = 1
184
for filename in args:
188
readinput(open(filename, 'r'))
192
more = (optu + optc + optd > 1)
195
print '---------------All callees------------------'
199
print '---------------Undefined callees------------'
203
print '---------------All Callers------------------'
207
# Call the main program.
208
# Use its return value as exit status.
209
# Catch interrupts to avoid stack trace.
211
if __name__ == '__main__':
214
except KeyboardInterrupt: