Skip to content

Instantly share code, notes, and snippets.

@juster
Last active August 29, 2015 14:07
Show Gist options
  • Save juster/94c3342a645938c8a026 to your computer and use it in GitHub Desktop.
Save juster/94c3342a645938c8a026 to your computer and use it in GitHub Desktop.
Print min spanning tree of dep graph for dynamic libraries.
#!/usr/bin/awk -f
##
# sotree
# Prints a dynamic library dependency graph as a minimum spanning tree.
# Justin Davis 10/14/14
##
BEGIN {
libdircnt = split("/lib:/usr/lib:" ENVIRON["LD_LIBRARY_PATH"], libdirs, /:/)
if(!libdirs[libdircnt]) --libdircnt
}
function filechk(path)
{
return !system("test -f " path)
}
# Search for soname in libdirs and rpaths.
function findso(soname, j)
{
for(j = 1; j <= rpathcnt[soname]; j++){
if(filechk(rpaths[elf, j] "/" soname))
return rpaths[elf, j] "/" soname
}
for(j = 1; j <= libdircnt; j++){
if(filechk(libdirs[j] "/" soname))
return libdirs[j] "/" soname
}
return ""
}
function readelf(elf)
{
if(elf in depcnt) return
while(("readelf --dynamic " elf) | getline > 0){
if($2 == "(NEEDED)"){
deps[elf, ++depcnt[elf]] = substr($5, 2, length($5)-2)
}else if($2 == "(RPATH)"){
rpaths[elf, ++rpathcnt[elf]] = substr($5, 2, length($5)-2)
}
# TODO: RUNPATHs for executables?
}
}
function ignso(so)
{
return so ~ /^ld-linux[.]|^libc[.]/
}
function storedeps(start, i, top)
{
S[1] = start
split("", stored)
for(top = 1; top > 0; ){
elf = S[top--]
readelf(elf)
for(i = 1; i <= depcnt[elf]; i++){
d = deps[elf, i]
if(ignso(d)){
# Remove ignored .so deps from the graph.
deps[elf, i--] = deps[elf, depcnt[elf]--]
continue
}else if(d in stored){
# Avoid cycles by leaving traversed nodes as filename.so.
continue
}
# Find .so file. Add to search stack or mark as missing.
path = findso(d)
stored[d] = "" # mark as stored
if(path){
S[++top] = deps[elf, i] = path
}else{
deps[elf, i] = "\33[1;97m" d " \33[5;91mMISSING\33[0m"
}
}
}
}
function dfsout(parent, x, indent, i)
{
horz = (depcnt[deps[parent, x]] ? "==" : "--")
elbw = (x == depcnt[parent] ? "`" : "|") horz " "
print indent elbw deps[parent, x]
indent = indent (x == depcnt[parent] ? " " : "|") " "
parent = deps[parent, x]
for(i = 1; i <= depcnt[parent]; i++) dfsout(parent, i, indent)
}
function treeout(root, i)
{
print root
for(i = 1; i <= depcnt[root]; i++) dfsout(root, i, "")
}
BEGIN {
if(ARGC < 2){
print "usage: sotree [.so paths ...]"
exit(2)
}
for(i = 1; i < ARGC; i++){
storedeps(ARGV[i]); treeout(ARGV[i]); print ""
ARGV[i] = ""
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment