1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#!/bin/bash
argv0=${0##*/}
usage() {
cat <<-EOF
Display ELF dependencies as a tree
Usage: ${argv0} [options] <ELF file[s]>
Options:
-a Show all duplicated dependencies
-x Run with debugging
-h Show this help output
EOF
exit ${1:-0}
}
error() {
echo "${argv0}: $*" 1>&2
ret=1
return 1
}
find_elf() {
local elf=$1 needed_by=$2
if [[ ${elf} == */* ]] && [[ -e ${elf} ]] ; then
echo "${elf}"
return 0
else
check_paths() {
local elf=$1 ; shift
local path
for path in "$@" ; do
if [[ -e ${path}/${elf} ]] ; then
echo "${path}/${elf}"
return 0
fi
done
return 1
}
if [[ ${__last_needed_by} != ${needed_by} ]] ; then
__last_needed_by=${needed_by}
__last_needed_by_rpaths=$(scanelf -qF '#F%r' "${needed_by}" | sed 's|:| |g')
fi
check_paths "${elf}" ${__last_needed_by_rpaths} && return 0
if [[ -z ${__ldso_paths} ]] ; then
if [[ -r /etc/ld.so.conf ]] ; then
__ldso_paths=$(sed -e 's:^[[:space:]]*#.*::' /etc/ld.so.conf)
fi
: ${__ldso_paths:= }
fi
if [[ ${__ldso_paths} != " " ]] ; then
check_paths "${elf}" ${__ldso_paths} && return 0
fi
check_paths "${elf}" /lib* /usr/lib* /usr/local/lib* && return 0
fi
return 1
}
show_elf() {
local elf=$1 indent=$2 parent_elfs=$3
local rlib lib libs
local interp resolved=$(find_elf "${elf}")
elf=${elf##*/}
printf "%${indent}s%s => " "" "${elf}"
if [[ ,${parent_elfs}, == *,${elf},* ]] ; then
printf "!!! circular loop !!!\n" ""
return
fi
parent_elfs="${parent_elfs},${elf}"
printf "${resolved:-not found}"
if [[ ${indent} -eq 0 ]] ; then
interp=$(scanelf -qF '#F%i' "${resolved}")
printf " (interpreter => ${interp:-none})"
interp=${interp##*/}
fi
printf "\n"
[[ -z ${resolved} ]] && return
libs=$(scanelf -qF '#F%n' "${resolved}")
local my_allhits
if ! ${SHOW_ALL} ; then
my_allhits="${allhits}"
allhits="${allhits},${interp},${libs}"
fi
for lib in ${libs//,/ } ; do
lib=${lib##*/}
[[ ,${my_allhits}, == *,${lib},* ]] && continue
rlib=$(find_elf "${lib}" "${resolved}")
show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}"
done
}
# XXX: internal hack
if [[ $1 != "/../..source.lddtree" ]] ; then
SHOW_ALL=false
SET_X=false
([[ $1 == "" ]] || [[ $1 == --help ]]) && usage 1
opts="hax"
getopt -Q -- "${opts}" "$@" || exit 1
eval set -- $(getopt -- "${opts}" "$@")
while [[ -n $1 ]] ; do
case $1 in
-a) SHOW_ALL=true;;
-x) SET_X=true;;
-h) usage;;
--) shift; break;;
-*) usage 1;;
esac
shift
done
${SET_X} && set -x
ret=0
for elf in "$@" ; do
if [[ ! -e ${elf} ]] ; then
error "${elf}: file does not exist"
elif [[ ! -r ${elf} ]] ; then
error "${elf}: file is not readable"
elif [[ -d ${elf} ]] ; then
error "${elf}: is a directory"
else
allhits=""
[[ ${elf} != */* ]] && elf="./${elf}"
show_elf "${elf}" 0 ""
fi
done
exit ${ret}
fi
|