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