-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathlddtree.sh
executable file
·167 lines (145 loc) · 3.43 KB
/
lddtree.sh
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/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
}
unset c_last_needed_by
unset c_ldso_paths
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
# XXX: This lacks ELF EM/EI_CLASS/EI_DATA/... checking (multilib)
if [[ -e ${path}/${elf} ]] ; then
echo "${path}/${elf}"
return 0
fi
done
return 1
}
if [[ ${c_last_needed_by} != ${needed_by} ]] ; then
c_last_needed_by=${needed_by}
c_last_needed_by_rpaths=$(scanelf -qF '#F%r' "${needed_by}" | sed 's|:| |g')
fi
check_paths "${elf}" ${c_last_needed_by_rpaths} && return 0
if [[ -n ${LD_LIBRARY_PATH} ]] ; then
# Need to handle empty paths as $PWD,
# and handle spaces in between the colons
local p path=${LD_LIBRARY_PATH}
while : ; do
p=${path%%:*}
check_paths "${elf}" "${path:-${PWD}}" && return 0
[[ ${path} == *:* ]] || break
path=${path#*:}
done
fi
if [[ -z ${c_ldso_paths} ]] ; then
if [[ -r /etc/ld.so.conf ]] ; then
read_ldso_conf() {
local line p
for p in "$@" ; do
while read line ; do
case ${line} in
"#"*) ;;
"include "*) read_ldso_conf ${line#* } ;;
*) c_ldso_paths="${c_ldso_paths} ${line}" ;;
esac
done <"${p}"
done
}
# the 'include' command is relative
pushd /etc >/dev/null
read_ldso_conf /etc/ld.so.conf
popd >/dev/null
fi
: ${c_ldso_paths:= }
fi
if [[ ${c_ldso_paths} != " " ]] ; then
check_paths "${elf}" ${c_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
while getopts hax OPT ; do
case ${OPT} in
a) SHOW_ALL=true;;
x) SET_X=true;;
h) usage;;
?) usage 1;;
esac
done
shift $((OPTIND - 1))
[[ -z $1 ]] && usage 1
${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