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
30 definitions
= 'TRGDSBAEC'
32 ignore
= 'Nntrgdsbavuc'
34 # Regular expression to parse "nm -o" output.
36 matcher
= regex
.compile('\(.*\):\t?........ \(.\) \(.*\)$')
38 # Store "item" in "dict" under "key".
39 # The dictionary maps keys to lists of items.
40 # If there is no list for the key yet, it is created.
42 def store(dict, key
, item
):
44 dict[key
].append(item
)
48 # Return a flattened version of a list of strings: the concatenation
49 # of its elements with intervening spaces.
57 # Global variables mapping defined/undefined names to files and back.
64 # Read one input file and merge the data into the tables.
65 # Argument is an open file.
72 # If you get any output from this line,
73 # it is probably caused by an unexpected input line:
74 if matcher
.search(s
) < 0: s
; continue # Shouldn't happen
75 (ra
, rb
), (r1a
, r1b
), (r2a
, r2b
), (r3a
, r3b
) = matcher
.regs
[:4]
76 fn
, name
, type = s
[r1a
:r1b
], s
[r3a
:r3b
], s
[r2a
:r2b
]
77 if type in definitions
:
78 store(def2file
, name
, fn
)
79 store(file2def
, fn
, name
)
80 elif type in externals
:
81 store(file2undef
, fn
, name
)
82 store(undef2file
, name
, fn
)
83 elif not type in ignore
:
84 print fn
+ ':' + name
+ ': unknown type ' + type
86 # Print all names that were undefined in some module and where they are
90 flist
= file2undef
.keys()
94 elist
= file2undef
[file]
101 if not def2file
.has_key(ext
):
102 print '\t' + ext
+ tabs
+ ' *undefined'
104 print '\t' + ext
+ tabs
+ flat(def2file
[ext
])
106 # Print for each module the names of the other modules that use it.
109 files
= file2def
.keys()
113 for label
in file2def
[file]:
114 if undef2file
.has_key(label
):
115 callers
= callers
+ undef2file
[label
]
125 print file + ': unused'
127 # Print undefine names and where they are used.
131 for file in file2undef
.keys():
132 for ext
in file2undef
[file]:
133 if not def2file
.has_key(ext
):
134 store(undefs
, ext
, file)
135 elist
= undefs
.keys()
144 # Print warning messages about names defined in more than one file.
147 savestdout
= sys
.stdout
148 sys
.stdout
= sys
.stderr
149 names
= def2file
.keys()
152 if len(def2file
[name
]) > 1:
153 print 'warning:', name
, 'multiply defined:',
154 print flat(def2file
[name
])
155 sys
.stdout
= savestdout
161 optlist
, args
= getopt
.getopt(sys
.argv
[1:], 'cdu')
163 sys
.stdout
= sys
.stderr
164 print 'Usage:', os
.path
.basename(sys
.argv
[0]),
165 print '[-cdu] [file] ...'
166 print '-c: print callers per objectfile'
167 print '-d: print callees per objectfile'
168 print '-u: print usage of undefined symbols'
169 print 'If none of -cdu is specified, all are assumed.'
170 print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),'
171 print 'e.g.: nm -o /lib/libc.a | objgraph'
173 optu
= optc
= optd
= 0
174 for opt
, void
in optlist
:
181 if optu
== optc
== optd
== 0:
182 optu
= optc
= optd
= 1
189 readinput(open(file, 'r'))
193 more
= (optu
+ optc
+ optd
> 1)
196 print '---------------All callees------------------'
200 print '---------------Undefined callees------------'
204 print '---------------All Callers------------------'
208 # Call the main program.
209 # Use its return value as exit status.
210 # Catch interrupts to avoid stack trace.
214 except KeyboardInterrupt: