JSCOnly/CrossBuildAndRemoteTestJSCLinux: cross-ldd

File cross-ldd, 11.5 KB (added by clopez@igalia.com, 4 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}"