JSCOnly/CrossBuildAndRemoteTestJSCLinux: cross-ldd

File cross-ldd, 11.5 KB (added by clopez@igalia.com, 7 years ago)

cross-ldd script

Line 
1#!/bin/bash
2version="1.23"
3export LC_ALL=C
4my_name="$( basename "${0}" )"
5
6
7print_error() {
8 printf "%s: %s\n" "${my_name}" "$*" >&2
9}
10
11print_opt_error() {
12 print_error "$@"
13 printf "Try \`%s --help' for more information.\n" "${my_name}" >&2
14}
15
16do_trace() {
17 local depth=0
18
19 [ -z "${CT_XLDD_VERBOSE}" ] && return 0
20
21 for((depth=0; "${#FUNCNAME[$((depth+1))]}" != 0; depth++)); do :; done
22 printf "%*s" $((4*(depth-1))) "" >&2
23 printf -- "$@" >&2
24}
25
26show_version() {
27 # Fake a real ldd, just in case some dumb script would check
28 cat <<_EOF_
29ldd (crosstool-NG) ${version}
30Copyright (C) 2010 "Yann E. MORIN" <yann.morin.1998@free.fr>
31This is free software; see the source for copying conditions. There is NO
32warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
33Licensed under the GPLv2, see the file LICENSES in the top-directory of the
34sources for this package.
35_EOF_
36}
37
38show_help() {
39 cat <<_EOF_
40Usage: ${my_name} [OPTION]... --root DIR FILE...
41 --help print this help and exit
42 --version print version information and exit
43 --root dir treat dir as being the root of the target
44 -s, --show-system mark libs from the sysroot with a trailing '[*]'
45 and libs found via RPATH with a trailing '[+]'
46
47_EOF_
48 cat <<_EOF_ |fmt
49${my_name} tries to mimick the behavior of a real native ldd, but can be
50used in a cross-development environment. Here is how it differs from a
51real native ldd:
52
53This program expects the environment variables \$CC and \$READELF defined
54with the name of the program (in the path) that should be used to build
55binaries for the target architecture and a working readelf program for
56that architecture.
57
58Example:
59
60CC=mipsel-buildroot-linux-gnu-gcc
61READELF=mipsel-buildroot-linux-gnu-readelf
62
63If any of this two variables are not defined, the program tries to guess the name
64of them using the environment variable CROSS_COMPILE. So on the example above you
65could just set
66
67CROSS_COMPILE=mipsel-buildroot-linux-gnu-
68
69
70If the CT_XLDD_VERBOSE variable is set and non-empty, then ${my_name} will
71print a lot of debug messages, explaining how it builds the library
72search path, and how each library was found and why.
73
74The LD_LIBRARY_PATH variable is not used, as it can not reliably be
75guessed except at runtime, and we can't run.
76
77${my_name} does not scan /etc/ld.so.cache, but instead uses /etc/ld.so.conf
78(it understands the include directives therein for libces that have that).
79
80${my_name} also interprets (tries to!) the RPATH/RUNPATH records found in
81the dynamic ELF section. Such paths are searched for only relative to
82the specified root, not from the sysroot (see below). Also, those paths
83are searched for not only for the file they appear in, but also for its
84dependencies.
85
86${my_name} will search the directory specified with --root for libraries
87to resolve the NEEDED tags. If --root is not set, then ${my_name} will
88use the value in the environment variable \${CT_XLDD_ROOT}. If neither
89is set, then it will use as root the sysroot path from the cross-compiler.
90That it obtains by running "\${CC} -print-sysroot".
91
92If NEEDED libraries can't be found in the specified root directory, then
93${my_name} will also look in the sysroot of the toolchain to see if it
94can find them.
95
96For NEEDED libraries that were found, the output will look like:
97 libneeded.so => /path/to/libneeded.so (0xloadaddr)
98
99and for those that were not found, the output will look like:
100 libneeded.so not found
101
102The expected load address 'loadaddr' is a faked address to match the output
103of the real ldd, but has no actual meaning (set to some constants for now,
1040x8badf00d for libraries from the sysroot, 0xdeadc0de for those found via
105the RPATH/RUNPATH records, and 0xdeadbeef for others).
106
107_EOF_
108
109# Unimplemeted yet:
110# -d, --data-relocs process data relocations
111# -r, --function-relocs process data and function relocations
112# -u, --unused print unused direct dependencies
113# -v, --verbose print all information
114
115# See also this thread:
116# http://sourceware.org/ml/crossgcc/2008-09/msg00057.html
117}
118
119# Parse command line options
120root="${CT_XLDD_ROOT}"
121show_system=
122while true; do
123 case "${1}" in
124 --help)
125 show_help
126 exit 0
127 ;;
128 --version)
129 show_version
130 exit 0
131 ;;
132 --root)
133 root="$2"
134 shift
135 ;;
136 --root=*)
137 root="${1#--root=}"
138 ;;
139 --show-system|-s)
140 show_system=1
141 ;;
142 -*)
143 print_opt_error "unrecognized option \`${1}'"
144 exit 1
145 ;;
146 *)
147 break
148 ;;
149 esac
150 shift
151done
152
153# Sanity checks
154
155if [[ -z ${CC} ]]; then
156 if [[ -n ${CROSS_COMPILE} ]]; then
157 CC="${CROSS_COMPILE}gcc"
158 else
159 print_opt_error "Environment variable CC not defined. Please set it to your cross-compiler name"
160 exit 1
161 fi
162fi
163
164if [[ -z ${READELF} ]]; then
165 if [[ -n ${CROSS_COMPILE} ]]; then
166 READELF="${CROSS_COMPILE}readelf"
167 else
168 print_opt_error "Environment variable READELF not defined. Please set it to your cross-compiled readelf"
169 exit 1
170 fi
171fi
172
173if ! test -x "$(which ${READELF})"; then
174 print_error "Cant find readelf program ${READELF} in PATH=${PATH}"
175 exit 1
176fi
177
178fake_load_addr_root="$((0xdeadbeef))"
179fake_load_addr_rpath="$((0xdeadc0de))"
180fake_load_addr_sysroot="$((0x8badf00d))"
181ld_library_path="/lib:/usr/lib"
182
183bits="32"
184if "${CC}" -dM -E - < /dev/null | grep -q "#define __SIZEOF_POINTER__ 8"; then
185 bits="64"
186fi
187
188sysroot="$( "${CC}" -print-sysroot 2>/dev/null )"
189if [ -z "${sysroot}" ]; then
190 sysroot="$( "${CC}" -print-file-name=libc.so 2>/dev/null )"
191fi
192if [ -z "${sysroot}" ]; then
193 print_error "unable to find sysroot for \`${CC}'"
194
195fi
196
197if [ -z "${root}" ]; then
198 do_trace "root not defined. Assuming root = sysroot"
199 root="${sysroot}"
200fi
201
202do_report_needed_found() {
203 local needed="${1}"
204 local path="${2}"
205 local origin="${3}"
206 local loadaddr
207 local sys
208
209 case "${origin}" in
210 root)
211 loadaddr="${fake_load_addr_root}"
212 ;;
213 rpath)
214 loadaddr="${fake_load_addr_rpath}"
215 if [ -n "${show_system}" ]; then
216 sys=" [+]"
217 fi
218 ;;
219 sysroot)
220 loadaddr="${fake_load_addr_sysroot}"
221 if [ -n "${show_system}" ]; then
222 sys=" [*]"
223 fi
224 ;;
225 esac
226
227 printf "%8s%s => %s (0x%0*x)%s\n" \
228 "" \
229 "${needed}" \
230 "${path}" \
231 "$((bits/4))" \
232 "${loadaddr}" \
233 "${sys}"
234}
235
236joinpath() {
237 echo "${1%%/}/${2##/}"
238}
239
240# Search a needed file, scanning ${lib_dir} in the root directory
241do_find_needed() {
242 local needed="${1}"
243 local -a list
244 local -a dirs
245 local found="false"
246 local where
247 local base
248 local d i
249
250 do_trace "Searching for '%s'\n" "${needed}"
251
252 # rpath shall come first!
253 list=( \
254 "rpath:${root}" \
255 "root:${root}" \
256 "sysroot:${sysroot}" \
257 )
258
259 for i in "${list[@]}"; do
260 where="${i%%:*}"
261 base="${i#*:}"
262 if [ "${where}" = "rpath" ]; then
263 dirs=( "${search_rpath[@]}" )
264 else
265 dirs=( "${needed_search_path[@]}" )
266 fi
267 for d in "${dirs[@]}"; do
268 do_trace "-> looking in '%s' (%s)\n" "${d}" "${where}"
269
270 pathfound="$(joinpath ${d} ${needed})"
271 if [ "${where}" != "rpath" ]; then
272 pathfound="$(joinpath ${base} ${pathfound})"
273 fi
274
275 if [ -f "${pathfound}" ]; then
276 found="true"
277 do_trace "---> found\n"
278 break 2
279 fi
280
281 done
282 done
283
284 if ${found}; then
285 do_report_needed_found "${needed}" "${pathfound}" "${where}"
286 do_process_file "${pathfound}"
287 else
288 printf "%8s%s not found\n" "" "${needed}"
289 fi
290
291 do_trace "Done searching for '%s'\n" "${needed}"
292}
293
294# Scan a file for all NEEDED tags
295do_process_file() {
296 local file="${1}"
297 local -a save_search_rpath
298 local n m
299 local found
300
301 do_trace "Parsing file '%s'\n" "${file}"
302
303 save_search_rpath=( "${search_rpath[@]}" )
304 for n in $( "${READELF}" -d "${file}" \
305 |grep -E '\((RPATH|RUNPATH)\)' \
306 |sed -r -e 's/^.*Library r(|un)path:[[:space:]]+\[(.*)\]$/\2/;' \
307 |sed "s/:/\ /g" \
308 ); do
309 do_trace "-> adding rpath '%s'\n" "${n}"
310 search_rpath+=( "${n}" )
311 done
312 do_trace ": search path:\n"
313 for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do
314 do_trace ": - '%s'\n" "${n}"
315 done
316 do_trace ": end search path\n"
317
318 for n in $( "${READELF}" -d "${file}" \
319 |grep -E '\(NEEDED\)' \
320 |sed -r -e 's/^.*Shared library:[[:space:]]+\[([^]]+)\].*/\1/;' \
321 ); do
322 found=0
323 for m in "${needed_list[@]}"; do
324 [ "${n}" = "${m}" ] && found=1 && break
325 done
326 if [ ${found} -ne 0 ]; then
327 do_trace "-> skipping already known dependency '%s'\n" "${n}"
328 continue
329 fi
330 do_trace "-> handling new dependency '%s'\n" "${n}"
331 needed_list+=( "${n}" )
332 do_find_needed "${n}"
333 do_trace "-> do_find_needed: ${n}"
334 do_trace "-> done handling dependency '%s'\n" "${n}"
335 done
336
337 search_rpath=( "${save_search_rpath[@]}" )
338
339 do_trace "Finished parsing file '%s'\n" "${file}"
340}
341
342# Recursively scan a /etc/ld.so.conf file
343do_scan_etc_ldsoconf() {
344 local ldsoconf="${1}"
345 local g
346 local f
347
348 [ -f "${ldsoconf}" ] || return 0
349 do_trace "Parsing ld.so.conf: '%s'\n" "${ldsoconf}"
350
351 while read line; do
352 case "${line}" in
353 include\ *)
354 g="${root}${line#include }"
355 do_trace "-> handling include directive '%s'\n" "${g}"
356 for f in ${g}; do
357 do_scan_etc_ldsoconf "${f}"
358 done
359 do_trace "-> finished handling include directive '%s'\n" "${g}"
360 ;;
361 \#*|"")
362 ;;
363 *)
364 do_trace "-> adding search dir '%s'\n" "${line}"
365 needed_search_path+=( "${line}" )
366 ;;
367 esac
368 done <"${ldsoconf}"
369
370 do_trace "Finished parsing ld.so.conf: '%s'\n" "${ldsoconf}"
371}
372
373# Build up the full list of search directories
374declare -a needed_search_path
375do_trace "Adding basic lib dirs\n"
376ld_library_path="${ld_library_path}:"
377while [ -n "${ld_library_path}" ]; do
378 d="${ld_library_path%%:*}"
379 if [ -n "${d}" ]; then
380 do_trace "-> adding search dir '%s'\n" "${d}"
381 needed_search_path+=( "${d}" )
382 fi
383 ld_library_path="${ld_library_path#*:}"
384done
385do_trace "Done adding basic lib dirs\n"
386do_trace "Scanning '/etc/ld.so.conf'\n"
387do_scan_etc_ldsoconf "${root}/etc/ld.so.conf"
388do_trace "Done scanning '/etc/ld.so.conf'\n"
389do_trace "Search path:\n"
390for p in "${needed_search_path[@]}"; do
391 do_trace "-> '%s'\n" "${p}"
392done
393
394declare -a needed_list
395declare -a search_rpath
396do_trace "Scanning file '%s'\n" "${1}"
397if [ -z "${1}" ]; then
398 print_opt_error "missing file arguments"
399 exit 1
400fi
401do_process_file "${1}"
402do_trace "Done scanning file '%s'\n" "${1}"