Last active
August 22, 2024 16:20
-
-
Save ntfshard/c78167ae6b0123a44f0cdd09f9c969de to your computer and use it in GitHub Desktop.
LD_DEBUG=all to graphviz visualizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
''' | |
Usage: | |
> LD_DEBUG=all LD_DEBUG_OUTPUT=logname ${COMMAND} ${ARGS}... | |
> cat logname.${PID} | parse.py | dot -Tsvg > output.svg | |
Or copy output of script to online visualizer, like this https://dreampuf.github.io/GraphvizOnline | |
(dot is from graphviz package) | |
Legend: | |
Arrows goes from from executable/library to it dependency; | |
If we looked for some symbols from library it will have such fields in description: | |
* symbols: how much symbols was exported from this library | |
* syms_miss: how many attempts was done to find this symbol in other libraries (too high? reorder libraries) | |
* file_miss: hom many path was checked to find a library location (too high? clean LD_LIBRARY_PATH) | |
''' | |
import sys | |
def clearName(name): | |
return name.split('/')[-1].split('.')[0] | |
def assignSplit(exp): | |
return exp.split('=')[1] | |
def wrapName(name): | |
return '"' + name + '"' | |
symbolMissCounter = {} | |
libraryHitCounter = {} | |
print("digraph Libraries {") | |
for line in sys.stdin: | |
vals = line.split() | |
length = len(vals) | |
if length == 3: | |
# 55046: trying file=/usr/lib/x86_64-linux-gnu/libtinyxml.so.2.6.2 | |
if vals[1] == "trying": | |
lib = clearName(assignSplit(vals[2])) | |
rec = libraryHitCounter.get(lib, {"syms_found":0, "syms_miss":0, "library_path_miss":0}) | |
rec["library_path_miss"] = rec["library_path_miss"] + 1 | |
libraryHitCounter[lib] = rec | |
if length == 6: | |
# 55046: symbol=stdup; lookup in file=/usr/libcurl.so.4 [0] | |
if vals[2] == "lookup": | |
sym = assignSplit(vals[1])[0:-1] # remove `;` symbol at the end | |
symbolMissCounter[sym] = symbolMissCounter.get(sym, 0) + 1 | |
if length == 7 or length == 8: | |
# 55046: file=libgz-sim7.so.7 [0]; needed by ./app_exe [0] | |
# 55046: file=/lib/libgdal.so.30 [0]; needed by /usr/libpoppler.so.118 [0] (relocation dependency) | |
if vals[3] == "needed": | |
want = clearName(assignSplit(vals[1])) | |
requester = clearName(vals[5]) | |
print('{} -> {};'.format(wrapName(requester), wrapName(want))) | |
if length == 11 or length == 12: | |
# 55046: binding file /usr/libgeos.so.3.10.2 [0] to /usr/libgeos.so.3.10.2 [0]: normal symbol `strdup' | |
# 55046: binding file /usr/libcurl-gnutls.so.4 [0] to /usr/libc.so.6 [0]: normal symbol `getenv' [GLIBC_2.2.5] | |
if vals[1] == "binding": | |
sym = vals[10][1:-1] # remove quotes around symbol | |
lib = clearName(vals[6]) | |
rec = libraryHitCounter.get(lib, {"syms_found":0, "syms_miss":0, "library_path_miss":0}) | |
rec["syms_found"] = rec["syms_found"] + 1 | |
rec["syms_miss"] = rec["syms_miss"] + symbolMissCounter.get(sym, 0) | |
libraryHitCounter[lib] = rec | |
print() | |
for lib, stat in libraryHitCounter.items(): | |
print('{} [label="{}\\nsymbols={}\\nsyms_miss={}\\nfile_miss={}"];'.format(wrapName(lib), lib, stat["syms_found"], stat["syms_miss"], stat["library_path_miss"])) | |
print("}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment