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
= regex
.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()
93 elist
= file2undef
[file]
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()
112 for label
in file2def
[file]:
113 if undef2file
.has_key(label
):
114 callers
= callers
+ undef2file
[label
]
124 print file + ': unused'
126 # Print undefine names and where they are used.
130 for file in file2undef
.keys():
131 for ext
in file2undef
[file]:
132 if not def2file
.has_key(ext
):
133 store(undefs
, ext
, file)
134 elist
= undefs
.keys()
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
188 readinput(open(file, '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.
213 except KeyboardInterrupt: