File indexing completed on 2024-12-01 23:40:44
0001
0002
0003 import networkx as nx
0004 import collections
0005 import os
0006 import re
0007 import subprocess
0008
0009 addr_re = r"(?P<address>[0-9a-f]{1,16})?"
0010 code_re = r"(?P<code>[a-zA-Z])"
0011 symbol_re = r"(?P<symbol>[a-zA-Z0-9_.$@]+)"
0012 symbol_demunged_re = r"(?P<symbol>[a-zA-Z0-9_.$@:&()<>{}\[\]|^!%,~*+-=# ]+)"
0013 symbols_re_skip = re.compile("(@@)")
0014 nm_line_re = re.compile(r"\s+".join([addr_re, code_re, symbol_re]) + r"\s*$",
0015 re.I)
0016 ldd_line_re = re.compile(r"\s+(.*) => (.*) \(0x")
0017
0018 requires = collections.defaultdict(set)
0019 provides = collections.defaultdict(set)
0020 dependencies = collections.defaultdict(set)
0021 libraries = collections.defaultdict(set)
0022
0023
0024 def get_symbols(fname):
0025 lines = subprocess.check_output(["nm", "-g", fname])
0026 for line in lines.splitlines():
0027 m = nm_line_re.match(line)
0028 if not m:
0029 continue
0030 symbol = m.group('symbol')
0031 if m.group('code') == 'U':
0032 requires[os.path.basename(fname)].add(symbol)
0033 else:
0034 provides[symbol].add(os.path.basename(fname))
0035
0036
0037 def get_libraries(fname):
0038 lines = subprocess.check_output(["ldd", fname])
0039 for line in lines.splitlines():
0040 m = ldd_line_re.match(line)
0041 if not m:
0042 continue
0043 library = m.group(2)
0044 libraries[os.path.basename(fname)].add(
0045 os.path.basename(library.rstrip('\r\n')))
0046
0047
0048 paths = os.environ['LD_LIBRARY_PATH'].split(':')
0049
0050 for p in paths:
0051 for dirpath, dirnames, filenames in os.walk(p):
0052 for f in filenames:
0053 fpth = os.path.realpath(os.path.join(dirpath, f))
0054 filetype = subprocess.check_output(["file", fpth])
0055 if filetype.find("dynamically linked") >= 0:
0056 get_symbols(fpth)
0057 get_libraries(fpth)
0058
0059 for fname, symbols in requires.items():
0060 deps = set()
0061 for library in libraries[fname]:
0062 for s in symbols:
0063 if library in provides[s]:
0064 deps.add(library)
0065 dependencies[fname] = deps
0066 print(fname + ' : primary dependencies : ' +
0067 ', '.join(sorted(dependencies[fname]))+'\n')
0068 unmet = set()
0069 demangled = set()
0070 for s in symbols:
0071 if s not in provides and not symbols_re_skip.search(s):
0072 unmet.add(s)
0073 for u in sorted(unmet):
0074 dm = subprocess.check_output(["c++filt", u])
0075 demangled.add(dm.rstrip('\r\n'))
0076 if demangled:
0077 print(fname + ': undefined : ' + ', '.join(sorted(demangled)))
0078
0079 G = nx.DiGraph()
0080 for key, values in dependencies.items():
0081 G.add_node(key)
0082 for val in values:
0083 G.add_edge(key, val)
0084
0085 for node in nx.nodes_iter(G):
0086 s = nx.dfs_successors(G, node)
0087 deps = set()
0088 if s:
0089 for key, vals in s.items():
0090 if key != node:
0091 deps.add(key)
0092 for v in vals:
0093 deps.add(v)
0094 print(node + ': primary and secondary dependencies :' + ', '.join(sorted(deps)))
0095
0096
0097 H = nx.DiGraph()
0098 for key, values in dependencies.items():
0099 H.add_node(os.path.basename(key))
0100 for val in values:
0101 H.add_edge(os.path.basename(key), os.path.basename(val))
0102 for node in nx.nodes_iter(H):
0103 T = nx.dfs_tree(H, node)
0104 name = node + ".dot"
0105 nx.write_dot(T, name)