File deps.py changed (mode: 100755) (index 5b2ce5d..3bc84e3) |
1 |
1 |
#!/usr/bin/env python |
#!/usr/bin/env python |
2 |
2 |
#-*- coding: utf-8 -*- |
#-*- coding: utf-8 -*- |
3 |
3 |
|
|
|
4 |
|
import argparse |
4 |
5 |
import os |
import os |
5 |
|
import sys |
|
6 |
6 |
|
|
7 |
7 |
EXPORT_EDGE = "edge [style=filled,weight=1];" |
EXPORT_EDGE = "edge [style=filled,weight=1];" |
8 |
8 |
IMPORT_EDGE = "edge [style=dashed];" |
IMPORT_EDGE = "edge [style=dashed];" |
|
... |
... |
IMPORT_EDGE = "edge [style=dashed];" |
10 |
10 |
INVALID = -1 |
INVALID = -1 |
11 |
11 |
EXPORT = 1 |
EXPORT = 1 |
12 |
12 |
IMPORT = 2 |
IMPORT = 2 |
13 |
|
OBJECT = 3 |
|
|
13 |
|
OBJECT_EXPORT = 3 |
|
14 |
|
OBJECT_IMPORT = 4 |
14 |
15 |
|
|
15 |
16 |
symbols = {} |
symbols = {} |
16 |
17 |
objects = [] |
objects = [] |
|
... |
... |
class objModule: |
25 |
26 |
self._importTable += [entry] |
self._importTable += [entry] |
26 |
27 |
entry.addImport(self) |
entry.addImport(self) |
27 |
28 |
def remImport(self, entry): |
def remImport(self, entry): |
28 |
|
self._importTable -= [entry] |
|
|
29 |
|
self._importTable.remove(entry) |
29 |
30 |
def addExport(self, entry): |
def addExport(self, entry): |
30 |
31 |
self._exportTable += [entry] |
self._exportTable += [entry] |
31 |
32 |
entry.addExport(self) |
entry.addExport(self) |
32 |
33 |
def remExport(self, entry): |
def remExport(self, entry): |
33 |
|
self._exportTable -= [entry] |
|
|
34 |
|
self._exportTable.remove(entry) |
34 |
35 |
def interactsWith(self, mod): |
def interactsWith(self, mod): |
35 |
36 |
for entry in self._importTable: |
for entry in self._importTable: |
36 |
37 |
if entry.belongsTo(mod): |
if entry.belongsTo(mod): |
|
... |
... |
class objModule: |
49 |
50 |
def getAllExports(self): |
def getAllExports(self): |
50 |
51 |
return self._exportTable |
return self._exportTable |
51 |
52 |
def printMe(self): |
def printMe(self): |
|
53 |
|
if len(self.getImports()) == 0 and len(self.getExports()) == 0: |
|
54 |
|
return |
|
55 |
|
|
52 |
56 |
if len(self.getImports()) == 0: |
if len(self.getImports()) == 0: |
53 |
57 |
color = 'green' |
color = 'green' |
54 |
58 |
elif len(self.getExports()) == 0: |
elif len(self.getExports()) == 0: |
|
... |
... |
class function: |
71 |
75 |
self._exportCounter = 0 |
self._exportCounter = 0 |
72 |
76 |
self._importCounter = 0 |
self._importCounter = 0 |
73 |
77 |
self._mod = None |
self._mod = None |
74 |
|
def __del__(self, name): |
|
75 |
|
for mod in self._importCounter: |
|
|
78 |
|
def remove(self): |
|
79 |
|
for mod in self.importedBy: |
76 |
80 |
mod.remImport(self) |
mod.remImport(self) |
77 |
81 |
self._mod.remExport(self) |
self._mod.remExport(self) |
78 |
82 |
def addImport(self, mod): |
def addImport(self, mod): |
79 |
83 |
self._importCounter += 1 |
self._importCounter += 1 |
80 |
84 |
self.importedBy += [mod] |
self.importedBy += [mod] |
81 |
85 |
def addExport(self, mod): |
def addExport(self, mod): |
82 |
|
self._exportCounter += 1 |
|
|
86 |
|
assert self._mod is None |
|
87 |
|
self._exportCounter = 1 |
83 |
88 |
self._mod = mod; |
self._mod = mod; |
84 |
89 |
def isUsers(self): |
def isUsers(self): |
85 |
90 |
return self._exportCounter > 0 and self._importCounter > 0 |
return self._exportCounter > 0 and self._importCounter > 0 |
|
... |
... |
def getFuncObjdump(line): |
110 |
115 |
if len(parts) == 6 and parts[1] == 'g' and parts[2] == 'F': |
if len(parts) == 6 and parts[1] == 'g' and parts[2] == 'F': |
111 |
116 |
return (EXPORT, parts[5]) |
return (EXPORT, parts[5]) |
112 |
117 |
elif len(parts) == 6 and parts[1] == 'g' and parts[2] == 'O': |
elif len(parts) == 6 and parts[1] == 'g' and parts[2] == 'O': |
113 |
|
return (OBJECT, parts[5]) |
|
|
118 |
|
return (OBJECT_EXPORT, parts[5]) |
114 |
119 |
elif len(parts) == 5 and parts[1] == 'O' and parts[2] == '*COM*': |
elif len(parts) == 5 and parts[1] == 'O' and parts[2] == '*COM*': |
115 |
|
return (OBJECT, parts[4]) |
|
|
120 |
|
return (OBJECT_IMPORT, parts[4]) |
116 |
121 |
elif len(parts) == 4 and parts[1] == '*UND*': |
elif len(parts) == 4 and parts[1] == '*UND*': |
117 |
122 |
return (IMPORT, parts[3]) |
return (IMPORT, parts[3]) |
118 |
123 |
else: |
else: |
|
... |
... |
def getTables(objFile): |
126 |
131 |
(lineType, name) = getFuncObjdump(line) |
(lineType, name) = getFuncObjdump(line) |
127 |
132 |
if lineType == INVALID: |
if lineType == INVALID: |
128 |
133 |
continue |
continue |
129 |
|
if lineType == OBJECT: |
|
|
134 |
|
if lineType == OBJECT_EXPORT or lineType == OBJECT_IMPORT: |
130 |
135 |
objects += [name] |
objects += [name] |
131 |
|
continue |
|
132 |
136 |
|
|
133 |
137 |
if symbols.has_key(name): |
if symbols.has_key(name): |
134 |
138 |
func = symbols[name] |
func = symbols[name] |
|
... |
... |
def getTables(objFile): |
136 |
140 |
func = function(name) |
func = function(name) |
137 |
141 |
symbols[name] = func |
symbols[name] = func |
138 |
142 |
|
|
139 |
|
if lineType == IMPORT: |
|
|
143 |
|
if lineType == IMPORT or lineType == OBJECT_IMPORT: |
140 |
144 |
objFile.addImport(func) |
objFile.addImport(func) |
141 |
|
else: |
|
|
145 |
|
elif lineType == EXPORT or lineType == OBJECT_EXPORT: |
142 |
146 |
objFile.addExport(func) |
objFile.addExport(func) |
143 |
147 |
|
|
144 |
148 |
def printFunctions(mod, funcs): |
def printFunctions(mod, funcs): |
145 |
149 |
for entry in funcs: |
for entry in funcs: |
146 |
150 |
print '"%s"->"%s";' % (mod, entry) |
print '"%s"->"%s";' % (mod, entry) |
147 |
151 |
|
|
148 |
|
def printFuncGraph(objModules): |
|
|
152 |
|
def printSymGraph(objModules): |
149 |
153 |
for mod in objModules: |
for mod in objModules: |
150 |
154 |
mod.printMe() |
mod.printMe() |
151 |
155 |
|
|
|
... |
... |
def analyzeMods(x, y): |
202 |
206 |
def printModGraph(objModules): |
def printModGraph(objModules): |
203 |
207 |
[analyzeMods(x, y) for x in objModules for y in objModules] |
[analyzeMods(x, y) for x in objModules for y in objModules] |
204 |
208 |
|
|
205 |
|
def printOneModGraph(mod, modules): |
|
|
209 |
|
def printSingleModGraph(mod, modules): |
206 |
210 |
for x in modules: |
for x in modules: |
207 |
211 |
if x != mod: |
if x != mod: |
208 |
212 |
analyzeMods(x, mod) |
analyzeMods(x, mod) |
|
... |
... |
def printOneInvModGraph(mod, modules): |
212 |
216 |
if x != mod: |
if x != mod: |
213 |
217 |
analyzeMods(mod, x) |
analyzeMods(mod, x) |
214 |
218 |
|
|
215 |
|
def printOneFuncGraph(func): |
|
|
219 |
|
def printSymbolGraph(func): |
216 |
220 |
func.getMod().printMe() |
func.getMod().printMe() |
217 |
221 |
|
|
218 |
222 |
# export |
# export |
|
... |
... |
def printLegend(): |
237 |
241 |
|
|
238 |
242 |
def listUnusedFuncs(mods): |
def listUnusedFuncs(mods): |
239 |
243 |
for mod in mods: |
for mod in mods: |
240 |
|
funcs = [x for x in mod.getAllExports() |
|
241 |
|
if x.isUnused() and str(x) != 'main'] |
|
|
244 |
|
funcs = [x for x in mod.getAllExports() if x.isUnused()] |
242 |
245 |
if len(funcs) == 0: |
if len(funcs) == 0: |
243 |
246 |
continue |
continue |
244 |
247 |
|
|
|
... |
... |
def listUserFuncs(): |
257 |
260 |
userFuncs = sorted(userFuncs, None, lambda x: x.name) |
userFuncs = sorted(userFuncs, None, lambda x: x.name) |
258 |
261 |
print 'Name ExportedFrom ImportedBy' |
print 'Name ExportedFrom ImportedBy' |
259 |
262 |
for func in userFuncs: |
for func in userFuncs: |
260 |
|
lst = '' |
|
261 |
|
for mod in func.importedBy: |
|
262 |
|
if lst == '': |
|
263 |
|
lst = str(mod) |
|
264 |
|
else: |
|
265 |
|
lst += ', ' + str(mod) |
|
|
263 |
|
lst = ', '.join(sorted(map(lambda x: str(x), func.importedBy))) |
266 |
264 |
print '%s %s %s (%s)' % (func.name, func.getMod(), len(func.importedBy), |
print '%s %s %s (%s)' % (func.name, func.getMod(), len(func.importedBy), |
267 |
265 |
lst) |
lst) |
268 |
266 |
|
|
269 |
267 |
def main(): |
def main(): |
|
268 |
|
parser = argparse.ArgumentParser(description='Object file analyzer') |
|
269 |
|
parser.add_argument('--moddeps', dest='moddeps', action='store_true', |
|
270 |
|
help='Generate module dependency graph') |
|
271 |
|
parser.add_argument('--symdeps', dest='symdeps', action='store_true', |
|
272 |
|
help='Generate symbol dependency graph') |
|
273 |
|
parser.add_argument('--module', dest='module', |
|
274 |
|
help='Generate graph for this module (its users)') |
|
275 |
|
parser.add_argument('--invert', dest='invert', action='store_true', |
|
276 |
|
help='Invert dependencies for --module') |
|
277 |
|
parser.add_argument('--symbols', dest='symbols', action='store_true', |
|
278 |
|
help='Detail symbols used by --module') |
|
279 |
|
parser.add_argument('--objects', dest='objects', action='store_true', |
|
280 |
|
help='Display information on objects') |
|
281 |
|
parser.add_argument('--symbol', dest='symbol', |
|
282 |
|
help='Generate graph for this symbol') |
|
283 |
|
parser.add_argument('--system', dest='system', action='store_true', |
|
284 |
|
help='List references to system symbols') |
|
285 |
|
parser.add_argument('--user', dest='user', action='store_true', |
|
286 |
|
help='List table of exported user symbols') |
|
287 |
|
parser.add_argument('--unused', dest='unused', action='store_true', |
|
288 |
|
help='List exported, but unused symbols') |
|
289 |
|
parser.add_argument('obj', nargs='+', |
|
290 |
|
help='Object file to get information from') |
|
291 |
|
args = parser.parse_args() |
|
292 |
|
|
|
293 |
|
if not args.unused and not args.system and not args.user and \ |
|
294 |
|
not args.symbol and not args.moddeps and not args.symdeps and \ |
|
295 |
|
not args.module: |
|
296 |
|
print 'No action selected' |
|
297 |
|
exit(1) |
|
298 |
|
|
270 |
299 |
# parse object files |
# parse object files |
271 |
|
modulesList = [makeModule(x) for x in sys.argv[1:]] |
|
|
300 |
|
modulesList = [makeModule(x) for x in args.obj] |
272 |
301 |
objModules = {} |
objModules = {} |
273 |
302 |
for mod in modulesList: |
for mod in modulesList: |
274 |
303 |
objModules[mod.getName()] = mod |
objModules[mod.getName()] = mod |
|
... |
... |
def main(): |
276 |
305 |
# add special system module |
# add special system module |
277 |
306 |
sysMod = objModule('system') |
sysMod = objModule('system') |
278 |
307 |
objModules['system'] = sysMod |
objModules['system'] = sysMod |
279 |
|
for func in symbols.values(): |
|
280 |
|
if func.isSystem(): |
|
281 |
|
func._mod = sysMod |
|
282 |
|
|
|
283 |
|
# remove objects from list of symbols |
|
284 |
|
for obj in objects: |
|
285 |
|
if symbols.has_key(obj): |
|
286 |
|
func = symbols[obj] |
|
287 |
|
del symbols[obj] |
|
288 |
|
del func |
|
289 |
|
|
|
290 |
|
# print 'digraph "funcdeps" {' |
|
291 |
|
# printFuncGraph(objModules.values()) |
|
292 |
|
# print '}' |
|
293 |
|
|
|
294 |
|
# print 'digraph "moddeps" {' |
|
295 |
|
# printModGraph(objModules.values()) |
|
296 |
|
# print '}' |
|
297 |
|
|
|
298 |
|
# print 'digraph "onemoddeps" {' |
|
299 |
|
# printOneModGraph(objModules['file_info.o'], objModules.values()) |
|
300 |
|
# print '}' |
|
301 |
|
|
|
302 |
|
# print 'digraph "oneinvmoddeps" {' |
|
303 |
|
# printOneInvModGraph(objModules['vifm.o'], objModules.values()) |
|
304 |
|
# print '}' |
|
305 |
|
|
|
306 |
|
# print 'digraph "onemodfuncdeps" {' |
|
307 |
|
# printOneModFuncGraph(objModules['utils.o']) |
|
308 |
|
# print '}' |
|
309 |
|
|
|
310 |
|
# print 'digraph "onemodinvfuncdeps" {' |
|
311 |
|
# printOneInvModFuncGraph(objModules['utils.o']) |
|
312 |
|
# print '}' |
|
313 |
|
|
|
314 |
|
# print 'digraph "onefuncdeps" {' |
|
315 |
|
# printOneFuncGraph(symbols['is_dir']) |
|
316 |
|
# print '}' |
|
|
308 |
|
for sym in symbols.values(): |
|
309 |
|
if sym.isSystem(): |
|
310 |
|
sysMod.addExport(sym) |
|
311 |
|
|
|
312 |
|
if 'main' in symbols: |
|
313 |
|
sysMod.addImport(symbols['main']) |
|
314 |
|
|
|
315 |
|
if args.objects: |
|
316 |
|
# remove non-objects from list of symbols |
|
317 |
|
for symname in symbols.keys(): |
|
318 |
|
if symname not in objects: |
|
319 |
|
symbols[symname].remove() |
|
320 |
|
del symbols[symname] |
|
321 |
|
else: |
|
322 |
|
# remove objects from list of symbols |
|
323 |
|
for obj in objects: |
|
324 |
|
if obj not in symbols: |
|
325 |
|
symbols[obj].remove() |
|
326 |
|
del symbols[obj] |
|
327 |
|
|
|
328 |
|
if args.symdeps: |
|
329 |
|
print 'digraph "symdeps" {' |
|
330 |
|
printSymGraph(objModules.values()) |
|
331 |
|
print '}' |
|
332 |
|
|
|
333 |
|
if args.moddeps: |
|
334 |
|
print 'digraph "moddeps" {' |
|
335 |
|
printModGraph(objModules.values()) |
|
336 |
|
print '}' |
|
337 |
|
|
|
338 |
|
if args.module: |
|
339 |
|
if args.symbols: |
|
340 |
|
if args.invert: |
|
341 |
|
print 'digraph "singlemodfuncdeps" {' |
|
342 |
|
printOneInvModFuncGraph(objModules[args.module]) |
|
343 |
|
print '}' |
|
344 |
|
else: |
|
345 |
|
print 'digraph "singlemodfuncusers" {' |
|
346 |
|
printOneModFuncGraph(objModules[args.module]) |
|
347 |
|
print '}' |
|
348 |
|
else: |
|
349 |
|
if args.invert: |
|
350 |
|
print 'digraph "singlemoddeps" {' |
|
351 |
|
printOneInvModGraph(objModules[args.module], |
|
352 |
|
objModules.values()) |
|
353 |
|
print '}' |
|
354 |
|
else: |
|
355 |
|
print 'digraph "singlemodusers" {' |
|
356 |
|
printSingleModGraph(objModules[args.module], |
|
357 |
|
objModules.values()) |
|
358 |
|
print '}' |
317 |
359 |
|
|
318 |
|
listUnusedFuncs(objModules.values()) |
|
|
360 |
|
if args.symbol: |
|
361 |
|
print 'digraph "onesymdeps" {' |
|
362 |
|
printSymbolGraph(symbols[args.symbol]) |
|
363 |
|
print '}' |
319 |
364 |
|
|
320 |
|
# listSystemFuncs() |
|
|
365 |
|
if args.unused: |
|
366 |
|
listUnusedFuncs(objModules.values()) |
321 |
367 |
|
|
322 |
|
# listUserFuncs() |
|
|
368 |
|
if args.system: |
|
369 |
|
listSystemFuncs() |
323 |
370 |
|
|
324 |
|
if len(sys.argv) == 1: |
|
325 |
|
print 'Usage: deps objfile...' |
|
326 |
|
sys.exit(1) |
|
|
371 |
|
if args.user: |
|
372 |
|
listUserFuncs() |
327 |
373 |
|
|
328 |
374 |
main() |
main() |