xaizek / objdeps (License: Apache-2.0) (since 2020-09-11)
This is a python script that analyzes output of `objdump` to understand connections between object files.
Commit 147a4faa826b83530038ffecee4aaca96de4c4cf

Implement basic file grouping
Author: xaizek
Author date (UTC): 2016-09-26 10:27
Committer name: xaizek
Committer date (UTC): 2016-09-26 10:27
Parent(s): 8c4e8652b467e35e263c3d2f3fd5ea3da7666222
Signing key: 99DC5E4DB05F6BE2
Tree: 88d182e9cc62ba295a81e91010039bc3530f723c
File Lines added Lines deleted
deps.py 41 3
ideas 1 1
run.sh 2 1
File deps.py changed (mode: 100755) (index 46cb5cb..6483943)
... ... symbols = {}
17 17 objects = [] objects = []
18 18
19 19 class objModule: class objModule:
20 def __init__(self, fileName):
20 def __init__(self, fileName, name = None):
21 21 self._fileName = fileName self._fileName = fileName
22 self._name = os.path.basename(fileName)
22 self._name = os.path.basename(fileName) if name is None else name
23 23 self._importTable = [] self._importTable = []
24 24 self._exportTable = [] self._exportTable = []
25 25 def addImport(self, entry): def addImport(self, entry):
 
... ... class function:
83 83 self._importCounter += 1 self._importCounter += 1
84 84 self.importedBy += [mod] self.importedBy += [mod]
85 85 def addExport(self, mod): def addExport(self, mod):
86 assert self._mod is None
86 assert self._mod is None, ("%s: %s & %s" %
87 (self.name, self._mod.getName(), mod.getName()))
87 88 self._exportCounter = 1 self._exportCounter = 1
88 89 self._mod = mod; self._mod = mod;
89 90 def isUsers(self): def isUsers(self):
 
... ... def listUserFuncs():
253 254 print '%s %s %s (%s)' % (func.name, func.getMod(), len(func.importedBy), print '%s %s %s (%s)' % (func.name, func.getMod(), len(func.importedBy),
254 255 lst) lst)
255 256
257 def dirGroupName(path, root):
258 if not root:
259 return os.path.dirname(path)
260 return os.path.relpath(os.path.dirname(path), root)
261
256 262 def main(): def main():
257 263 parser = argparse.ArgumentParser(description='Object file analyzer') parser = argparse.ArgumentParser(description='Object file analyzer')
258 264 parser.add_argument('--moddeps', dest='moddeps', action='store_true', parser.add_argument('--moddeps', dest='moddeps', action='store_true',
 
... ... def main():
275 281 help='List table of exported user symbols') help='List table of exported user symbols')
276 282 parser.add_argument('--unused', dest='unused', action='store_true', parser.add_argument('--unused', dest='unused', action='store_true',
277 283 help='List exported, but unused symbols') help='List exported, but unused symbols')
284 parser.add_argument('--group-dirs', dest='group_dirs', action='store_true',
285 help='Group files inside directories into units')
286 parser.add_argument('--root', dest='root',
287 help='Group files inside directories into units')
278 288 parser.add_argument('obj', nargs='+', parser.add_argument('obj', nargs='+',
279 289 help='Object file to get information from') help='Object file to get information from')
280 290 args = parser.parse_args() args = parser.parse_args()
 
... ... def main():
291 301 for mod in modulesList: for mod in modulesList:
292 302 objModules[mod.getName()] = mod objModules[mod.getName()] = mod
293 303
304 if args.group_dirs:
305 newObjModules = {}
306 newSymbols = {}
307 for mod in modulesList:
308 dirName = dirGroupName(mod.getFileName(), args.root)
309 newObjModules[dirName] = objModule(dirName, dirName + "/*")
310 for modA in modulesList:
311 modAdirName = dirGroupName(modA.getFileName(), args.root)
312 for export in modA.getAllExports():
313 name = export.name
314 if newSymbols.has_key(name):
315 func = newSymbols[name]
316 else:
317 func = function(name)
318 newSymbols[name] = func
319 newObjModules[modAdirName].addExport(func)
320
321 for modB in export.importedBy:
322 modBdirName = dirGroupName(modB.getFileName(), args.root)
323 newObjModules[modBdirName].addImport(func)
324
325 global symbols
326 global objects
327 symbols = newSymbols
328 objects = []
329
330 objModules = newObjModules
331
294 332 # add special system module # add special system module
295 333 sysMod = objModule('system') sysMod = objModule('system')
296 334 objModules['system'] = sysMod objModules['system'] = sysMod
File ideas changed (mode: 100644) (index 59536c8..9e54d2e)
... ... TODO:
3 3 - find absent #include directives (all needed header files should be imported - find absent #include directives (all needed header files should be imported
4 4 explicitly); explicitly);
5 5 - find unused #include directives; - find unused #include directives;
6 - ability to group modules by their location (e.g. meta-module "utils" for all modules under utils/).
6 - count number of intermodule relationships, to be used as some kind of complexity measurement.
7 7
8 8 Arguments: Arguments:
9 9 - list of object files - list of object files
File run.sh changed (mode: 100755) (index 3526541..c85c6c4)
1 ./deps.py `find ~/repos/vifm/src/ -name '*.o'` > tst.gv && \
1 ./deps.py --group-dirs --root ~/repos/vifm/ "$@" \
2 `find ~/repos/vifm/src/ -name '*.o'` > tst.gv && \
2 3 circo -Tpng tst.gv -o tst.png && \ circo -Tpng tst.gv -o tst.png && \
3 4 sxiv tst.png sxiv tst.png
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/objdeps

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/objdeps

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master