| 1 | #!/bin/bash |
1 | #!/bin/bash |
| 2 | # $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.sh,v 1.10 2011/03/23 02:23:34 vapier Exp $ |
2 | # $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.sh,v 1.11 2012/11/03 00:06:10 vapier Exp $ |
| 3 | |
3 | |
| 4 | argv0=${0##*/} |
4 | argv0=${0##*/} |
| 5 | |
5 | |
| 6 | usage() { |
6 | usage() { |
| 7 | cat <<-EOF |
7 | cat <<-EOF |
| … | |
… | |
| 21 | echo "${argv0}: $*" 1>&2 |
21 | echo "${argv0}: $*" 1>&2 |
| 22 | ret=1 |
22 | ret=1 |
| 23 | return 1 |
23 | return 1 |
| 24 | } |
24 | } |
| 25 | |
25 | |
| 26 | unset c_last_needed_by |
26 | elf_specs() { |
| 27 | unset c_ldso_paths |
27 | scanelf -BF '#F%a %M %D %I' "$1" |
|
|
28 | } |
|
|
29 | |
|
|
30 | lib_paths_fallback="/lib* /usr/lib* /usr/local/lib*" |
|
|
31 | c_ldso_paths_loaded='false' |
| 28 | find_elf() { |
32 | find_elf() { |
|
|
33 | _find_elf='' |
|
|
34 | |
| 29 | local elf=$1 needed_by=$2 |
35 | local elf=$1 needed_by=$2 |
| 30 | if [[ ${elf} == */* ]] && [[ -e ${elf} ]] ; then |
36 | if [[ ${elf} == */* ]] && [[ -e ${elf} ]] ; then |
| 31 | echo "${elf}" |
37 | _find_elf=${elf} |
| 32 | return 0 |
38 | return 0 |
| 33 | else |
39 | else |
| 34 | check_paths() { |
40 | check_paths() { |
| 35 | local elf=$1 ; shift |
41 | local elf=$1 ; shift |
| 36 | local path |
42 | local path pe |
| 37 | for path in "$@" ; do |
43 | for path ; do |
| 38 | # XXX: This lacks ELF EM/EI_CLASS/EI_DATA/... checking (multilib) |
44 | pe="${path%/}/${elf#/}" |
| 39 | if [[ -e ${path}/${elf} ]] ; then |
45 | if [[ -e ${pe} ]] ; then |
| 40 | echo "${path}/${elf}" |
46 | if [[ $(elf_specs "${pe}") == "${elf_specs}" ]] ; then |
|
|
47 | _find_elf=${pe} |
| 41 | return 0 |
48 | return 0 |
|
|
49 | fi |
| 42 | fi |
50 | fi |
| 43 | done |
51 | done |
| 44 | return 1 |
52 | return 1 |
| 45 | } |
53 | } |
| 46 | |
54 | |
| … | |
… | |
| 60 | [[ ${path} == *:* ]] || break |
68 | [[ ${path} == *:* ]] || break |
| 61 | path=${path#*:} |
69 | path=${path#*:} |
| 62 | done |
70 | done |
| 63 | fi |
71 | fi |
| 64 | |
72 | |
| 65 | if [[ -z ${c_ldso_paths} ]] ; then |
73 | if ! ${c_ldso_paths_loaded} ; then |
|
|
74 | c_ldso_paths_loaded='true' |
|
|
75 | c_ldso_paths=() |
| 66 | if [[ -r /etc/ld.so.conf ]] ; then |
76 | if [[ -r /etc/ld.so.conf ]] ; then |
| 67 | read_ldso_conf() { |
77 | read_ldso_conf() { |
| 68 | local line p |
78 | local line p |
| 69 | for p in "$@" ; do |
79 | for p ; do |
| 70 | # if the glob didnt match anything #360041, |
80 | # if the glob didnt match anything #360041, |
| 71 | # or the files arent readable, skip it |
81 | # or the files arent readable, skip it |
| 72 | [[ -r ${p} ]] || continue |
82 | [[ -r ${p} ]] || continue |
| 73 | while read line ; do |
83 | while read line ; do |
| 74 | case ${line} in |
84 | case ${line} in |
| 75 | "#"*) ;; |
85 | "#"*) ;; |
| 76 | "include "*) read_ldso_conf ${line#* } ;; |
86 | "include "*) read_ldso_conf ${line#* } ;; |
| 77 | *) c_ldso_paths="${c_ldso_paths} ${line}" ;; |
87 | *) c_ldso_paths+=( "${line}" ) ;; |
| 78 | esac |
88 | esac |
| 79 | done <"${p}" |
89 | done <"${p}" |
| 80 | done |
90 | done |
| 81 | } |
91 | } |
| 82 | # the 'include' command is relative |
92 | # the 'include' command is relative |
| 83 | pushd /etc >/dev/null |
93 | pushd /etc >/dev/null |
| 84 | read_ldso_conf /etc/ld.so.conf |
94 | read_ldso_conf /etc/ld.so.conf |
| 85 | popd >/dev/null |
95 | popd >/dev/null |
| 86 | fi |
96 | fi |
| 87 | : ${c_ldso_paths:= } |
|
|
| 88 | fi |
97 | fi |
| 89 | if [[ ${c_ldso_paths} != " " ]] ; then |
98 | if [[ ${#c_ldso_paths[@]} -gt 0 ]] ; then |
| 90 | check_paths "${elf}" ${c_ldso_paths} && return 0 |
99 | check_paths "${elf}" "${c_ldso_paths[@]}" && return 0 |
| 91 | fi |
100 | fi |
| 92 | |
101 | |
| 93 | check_paths "${elf}" /lib* /usr/lib* /usr/local/lib* && return 0 |
102 | check_paths "${elf}" ${lib_paths_ldso:-${lib_paths_fallback}} && return 0 |
| 94 | fi |
103 | fi |
| 95 | return 1 |
104 | return 1 |
| 96 | } |
105 | } |
| 97 | |
106 | |
| 98 | show_elf() { |
107 | show_elf() { |
| 99 | local elf=$1 indent=$2 parent_elfs=$3 |
108 | local elf=$1 indent=$2 parent_elfs=$3 |
| 100 | local rlib lib libs |
109 | local rlib lib libs |
| 101 | local interp resolved=$(find_elf "${elf}") |
110 | local interp resolved |
|
|
111 | find_elf "${elf}" |
|
|
112 | resolved=${_find_elf} |
| 102 | elf=${elf##*/} |
113 | elf=${elf##*/} |
| 103 | |
114 | |
| 104 | printf "%${indent}s%s => " "" "${elf}" |
115 | printf "%${indent}s%s => " "" "${elf}" |
| 105 | if [[ ,${parent_elfs}, == *,${elf},* ]] ; then |
116 | if [[ ,${parent_elfs}, == *,${elf},* ]] ; then |
| 106 | printf "!!! circular loop !!!\n" "" |
117 | printf "!!! circular loop !!!\n" "" |
| 107 | return |
118 | return |
| 108 | fi |
119 | fi |
| 109 | parent_elfs="${parent_elfs},${elf}" |
120 | parent_elfs="${parent_elfs},${elf}" |
| 110 | printf "${resolved:-not found}" |
121 | printf "${resolved:-not found}" |
| 111 | if [[ ${indent} -eq 0 ]] ; then |
122 | if [[ ${indent} -eq 0 ]] ; then |
|
|
123 | elf_specs=$(elf_specs "${resolved}") |
| 112 | interp=$(scanelf -qF '#F%i' "${resolved}") |
124 | interp=$(scanelf -qF '#F%i' "${resolved}") |
|
|
125 | |
| 113 | printf " (interpreter => ${interp:-none})" |
126 | printf " (interpreter => ${interp:-none})" |
|
|
127 | if [[ -r ${interp} ]] ; then |
|
|
128 | # Extract the default lib paths out of the ldso. |
|
|
129 | lib_paths_ldso=$(strings "${interp}" | grep '^/.*lib') |
|
|
130 | lib_paths_ldso=${lib_paths_ldso//:/ } |
|
|
131 | fi |
| 114 | interp=${interp##*/} |
132 | interp=${interp##*/} |
| 115 | fi |
133 | fi |
| 116 | printf "\n" |
134 | printf "\n" |
| 117 | |
135 | |
| 118 | [[ -z ${resolved} ]] && return |
136 | [[ -z ${resolved} ]] && return |
| … | |
… | |
| 126 | fi |
144 | fi |
| 127 | |
145 | |
| 128 | for lib in ${libs//,/ } ; do |
146 | for lib in ${libs//,/ } ; do |
| 129 | lib=${lib##*/} |
147 | lib=${lib##*/} |
| 130 | [[ ,${my_allhits}, == *,${lib},* ]] && continue |
148 | [[ ,${my_allhits}, == *,${lib},* ]] && continue |
| 131 | rlib=$(find_elf "${lib}" "${resolved}") |
149 | find_elf "${lib}" "${resolved}" |
|
|
150 | rlib=${_find_elf} |
| 132 | show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}" |
151 | show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}" |
| 133 | done |
152 | done |
| 134 | } |
153 | } |
| 135 | |
154 | |
| 136 | # XXX: internal hack |
155 | # XXX: internal hack |
| … | |
… | |
| 151 | [[ -z $1 ]] && usage 1 |
170 | [[ -z $1 ]] && usage 1 |
| 152 | |
171 | |
| 153 | ${SET_X} && set -x |
172 | ${SET_X} && set -x |
| 154 | |
173 | |
| 155 | ret=0 |
174 | ret=0 |
| 156 | for elf in "$@" ; do |
175 | for elf ; do |
|
|
176 | unset lib_paths_ldso |
|
|
177 | unset c_last_needed_by |
| 157 | if [[ ! -e ${elf} ]] ; then |
178 | if [[ ! -e ${elf} ]] ; then |
| 158 | error "${elf}: file does not exist" |
179 | error "${elf}: file does not exist" |
| 159 | elif [[ ! -r ${elf} ]] ; then |
180 | elif [[ ! -r ${elf} ]] ; then |
| 160 | error "${elf}: file is not readable" |
181 | error "${elf}: file is not readable" |
| 161 | elif [[ -d ${elf} ]] ; then |
182 | elif [[ -d ${elf} ]] ; then |