scripts/xldd.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat Jan 22 23:20:18 2011 +0100 (2011-01-22)
changeset 2305 2ed26c646568
parent 2192 cbd4539a86ca
child 2546 ecd9d85a4f2e
permissions -rwxr-xr-x
scripts: create the makeinfo wrapper before we set PATH

If we set PATH to the tools wrappers before we create the
makeinfo wrapper, then we may well wrap an existing wrapper
from a previous run.

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