/[gentoo-projects]/pax-utils/lddtree.sh
Gentoo

Contents of /pax-utils/lddtree.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (show annotations) (download) (as text)
Thu Nov 15 20:35:04 2012 UTC (20 months, 1 week ago) by vapier
Branch: MAIN
Changes since 1.16: +4 -3 lines
File MIME type: text/x-sh
lddtree: implement $ORIGIN support

1 #!/bin/bash
2 # Copyright 2007-2012 Gentoo Foundation
3 # Copyright 2007-2012 Mike Frysinger <vapier@gentoo.org>
4 # Distributed under the terms of the GNU General Public License v2
5 # $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.sh,v 1.16 2012/11/13 01:09:06 vapier Exp $
6
7 argv0=${0##*/}
8
9 : ${ROOT:=/}
10 [[ ${ROOT} != */ ]] && ROOT="${ROOT}/"
11 [[ ${ROOT} != /* ]] && ROOT="${PWD}${ROOT}"
12
13 usage() {
14 cat <<-EOF
15 Display ELF dependencies as a tree
16
17 Usage: ${argv0} [options] <ELF file[s]>
18
19 Options:
20 -a Show all duplicated dependencies
21 -x Run with debugging
22 -R <root> Use this ROOT filesystem tree
23 -l Display output in a flat format
24 -h Show this help output
25 -V Show version information
26 EOF
27 exit ${1:-0}
28 }
29
30 version() {
31 local id='$Id: lddtree.sh,v 1.16 2012/11/13 01:09:06 vapier Exp $'
32 id=${id##*,v }
33 exec echo "lddtree-${id% * Exp*}"
34 }
35
36 error() {
37 echo "${argv0}: $*" 1>&2
38 ret=1
39 return 1
40 }
41
42 elf_specs() {
43 # With glibc, the NONE, SYSV, and LINUX OSABI's are compatible.
44 # NONE and SYSV are the same thing, so normalize LINUX to NONE. #442024
45 scanelf -BF '#F%a %M %D %I' "$1" | \
46 sed 's: LINUX$: NONE:'
47 }
48
49 lib_paths_fallback="${ROOT}lib* ${ROOT}usr/lib* ${ROOT}usr/local/lib*"
50 c_ldso_paths_loaded='false'
51 find_elf() {
52 _find_elf=''
53
54 local elf=$1 needed_by=$2
55 if [[ ${elf} == */* ]] && [[ -e ${elf} ]] ; then
56 _find_elf=${elf}
57 return 0
58 else
59 check_paths() {
60 local elf=$1 ; shift
61 local path pe
62 for path ; do
63 pe="${path%/}/${elf#/}"
64 if [[ -e ${pe} ]] ; then
65 if [[ $(elf_specs "${pe}") == "${elf_specs}" ]] ; then
66 _find_elf=${pe}
67 return 0
68 fi
69 fi
70 done
71 return 1
72 }
73
74 if [[ ${c_last_needed_by} != ${needed_by} ]] ; then
75 c_last_needed_by=${needed_by}
76 c_last_needed_by_rpaths=$(scanelf -qF '#F%r' "${needed_by}" | \
77 sed -e 's|:| |g' -e "s:[$]ORIGIN:${needed_by%/*}:")
78 fi
79 check_paths "${elf}" ${c_last_needed_by_rpaths} && return 0
80
81 if [[ -n ${LD_LIBRARY_PATH} ]] ; then
82 # Need to handle empty paths as $PWD,
83 # and handle spaces in between the colons
84 local p path=${LD_LIBRARY_PATH}
85 while : ; do
86 p=${path%%:*}
87 check_paths "${elf}" "${path:-${PWD}}" && return 0
88 [[ ${path} == *:* ]] || break
89 path=${path#*:}
90 done
91 fi
92
93 if ! ${c_ldso_paths_loaded} ; then
94 c_ldso_paths_loaded='true'
95 c_ldso_paths=()
96 if [[ -r ${ROOT}etc/ld.so.conf ]] ; then
97 read_ldso_conf() {
98 local line p
99 for p ; do
100 # if the glob didnt match anything #360041,
101 # or the files arent readable, skip it
102 [[ -r ${p} ]] || continue
103 while read line ; do
104 case ${line} in
105 "#"*) ;;
106 "include "*) read_ldso_conf ${line#* } ;;
107 *) c_ldso_paths+=( "${ROOT}${line#/}" ) ;;
108 esac
109 done <"${p}"
110 done
111 }
112 # the 'include' command is relative
113 pushd "${ROOT}"etc >/dev/null
114 read_ldso_conf "${ROOT}"etc/ld.so.conf
115 popd >/dev/null
116 fi
117 fi
118 if [[ ${#c_ldso_paths[@]} -gt 0 ]] ; then
119 check_paths "${elf}" "${c_ldso_paths[@]}" && return 0
120 fi
121
122 check_paths "${elf}" ${lib_paths_ldso:-${lib_paths_fallback}} && return 0
123 fi
124 return 1
125 }
126
127 show_elf() {
128 local elf=$1 indent=$2 parent_elfs=$3
129 local rlib lib libs
130 local interp resolved
131 find_elf "${elf}"
132 resolved=${_find_elf}
133 elf=${elf##*/}
134
135 ${LIST} || printf "%${indent}s%s => " "" "${elf}"
136 if [[ ,${parent_elfs}, == *,${elf},* ]] ; then
137 ${LIST} || printf "!!! circular loop !!!\n" ""
138 return
139 fi
140 parent_elfs="${parent_elfs},${elf}"
141 if ${LIST} ; then
142 echo "${resolved:-$1}"
143 else
144 printf "${resolved:-not found}"
145 fi
146 if [[ ${indent} -eq 0 ]] ; then
147 elf_specs=$(elf_specs "${resolved}")
148 interp=$(scanelf -qF '#F%i' "${resolved}")
149 [[ -n ${interp} ]] && interp="${ROOT}${interp#/}"
150
151 if ${LIST} ; then
152 [[ -n ${interp} ]] && echo "${interp}"
153 else
154 printf " (interpreter => ${interp:-none})"
155 fi
156 if [[ -r ${interp} ]] ; then
157 # Extract the default lib paths out of the ldso.
158 lib_paths_ldso=$(
159 strings "${interp}" | \
160 sed -nr -e "/^\/.*lib/{s|^/?|${ROOT}|;s|/$||;s|/?:/?|\n${ROOT}|g;p}"
161 )
162 fi
163 interp=${interp##*/}
164 fi
165 ${LIST} || printf "\n"
166
167 [[ -z ${resolved} ]] && return
168
169 libs=$(scanelf -qF '#F%n' "${resolved}")
170
171 local my_allhits
172 if ! ${SHOW_ALL} ; then
173 my_allhits="${allhits}"
174 allhits="${allhits},${interp},${libs}"
175 fi
176
177 for lib in ${libs//,/ } ; do
178 lib=${lib##*/}
179 [[ ,${my_allhits}, == *,${lib},* ]] && continue
180 find_elf "${lib}" "${resolved}"
181 rlib=${_find_elf}
182 show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}"
183 done
184 }
185
186 # XXX: internal hack
187 if [[ $1 != "/../..source.lddtree" ]] ; then
188
189 SHOW_ALL=false
190 SET_X=false
191 LIST=false
192
193 while getopts haxVR:l OPT ; do
194 case ${OPT} in
195 a) SHOW_ALL=true;;
196 x) SET_X=true;;
197 h) usage;;
198 V) version;;
199 R) ROOT="${OPTARG%/}/";;
200 l) LIST=true;;
201 ?) usage 1;;
202 esac
203 done
204 shift $((OPTIND - 1))
205 [[ -z $1 ]] && usage 1
206
207 ${SET_X} && set -x
208
209 ret=0
210 for elf ; do
211 unset lib_paths_ldso
212 unset c_last_needed_by
213 if [[ ! -e ${elf} ]] ; then
214 error "${elf}: file does not exist"
215 elif [[ ! -r ${elf} ]] ; then
216 error "${elf}: file is not readable"
217 elif [[ -d ${elf} ]] ; then
218 error "${elf}: is a directory"
219 else
220 allhits=""
221 [[ ${elf} != */* ]] && elf="./${elf}"
222 show_elf "${elf}" 0 ""
223 fi
224 done
225 exit ${ret}
226
227 fi

  ViewVC Help
Powered by ViewVC 1.1.20