scripts/xldd.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Nov 23 21:35:28 2010 +0100 (2010-11-23)
branch1.9
changeset 2198 6d909657dbdf
parent 2186 78d2f99d403f
permissions -rwxr-xr-x
scripts/xldd: better find sysroot with old gcc

Only starting with 4.4 does gcc have a -print-sysroot option.
For 4.3 or before, we have to play some tricks:
- ask gcc where libc.so is,
(we expect it in ${sysroot}/usr/lib/libc.so)
- trim /usr/lib/libc.so from the result

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
(transplanted from aa2305c5b2a57fbcda9a1b5bb5fb3a476ac49a13)
     1 #!@@CT_bash@@
     2 
     3 # NON-CONFIGURABLE STUFF!
     4 export LC_ALL=C
     5 version="@@CT_VERSION@@"
     6 sed="@@CT_sed@@"
     7 grep="@@CT_grep@@"
     8 my_name="$( basename "${0}" )"
     9 prefix="${0%-ldd}"
    10 gcc="${prefix}-gcc"
    11 readelf="${prefix}-readelf"
    12 fake_load_addr="$((0xdeadbeef))"
    13 fake_load_addr_sys="$((0x8badf00d))"
    14 ld_library_path="/lib:/usr/lib"
    15 
    16 do_error() {
    17     printf "%s: %s\n" "${my_name}" "$*" >&2
    18 }
    19 
    20 do_opt_error() {
    21     do_error "$@"
    22     printf "Try \`%s --help' for more information\n" >&2
    23 }
    24 
    25 show_version() {
    26     # Fake a real ldd, just in case some dumb script would check
    27     cat <<_EOF_
    28 ldd (crosstool-NG) ${version}
    29 Copyright (C) 2010 "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
    30 This is free software; see the source for copying conditions.  There is NO
    31 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    32 Licensed under the GPLv2, see the file LICENSES in the top-directory of the
    33 sources for this package.
    34 _EOF_
    35 }
    36 
    37 show_help() {
    38     cat <<_EOF_
    39 Usage: ${my_name} [OPTION]... --root DIR FILE...
    40       --help              print this help and exit
    41       --version           print version information and exit
    42       --root dir          treat dir as being the root of the target
    43   -s, --show-system       mark libs from the sysroot with a trailing '[*]'
    44 
    45 _EOF_
    46     cat <<_EOF_ |fmt
    47 ${my_name} tries to mimick the behavior of a real native ldd, but can be
    48 used in a cross-development environment. Here is how it differs from a
    49 real native ldd:
    50 
    51 The LD_LIBRARY_PATH variable is not used, as it can not reliably be
    52 guessed except at runtime, and we can't run.
    53 
    54 ${my_name} does not scan /etc/ld.so.cache, but instead uses /etc/ld.so.conf
    55 (it understands the include directives therein for libces that have that).
    56 [Note: this is missing for now...]
    57 
    58 ${my_name} will search the directory specified with --root for libraries
    59 to resolve the NEEDED tags. If --root is not set, then ${my_name} will
    60 use the value in the environment variable \${CT_XLDD_ROOT}. If neither
    61 is set, then this is an error.
    62 
    63 If NEEDED libraries can't be found in the specified root directory, then
    64 ${my_name} will also look in the sysroot of the toolchain to see if it
    65 can find them.
    66 
    67 For NEEDED libraries that were found, the output will look like:
    68         libneeded.so => /path/to/libneeded.so (0xloadaddr)
    69 
    70 and for those that were not found, the output will look like:
    71         libneeded.so not found
    72 
    73 The paths are relative to the specified root directory, or to the sysroot
    74 (eg. /lib/libneeded.so, /usr/lib/libneeded.so, and so on...).
    75 
    76 The expected load address 'loadaddr' is a faked address to match the output
    77 of the real ldd, but has no actual meaning (set to some constants for now,
    78 0x8badf00d for libraries from the sysroot, 0xdeadbeef for others).
    79 _EOF_
    80 
    81 # Unimplemeted yet:
    82 #  -d, --data-relocs       process data relocations
    83 #  -r, --function-relocs   process data and function relocations
    84 #  -u, --unused            print unused direct dependencies
    85 #  -v, --verbose           print all information
    86 
    87 # See also this thread:
    88 #  http://sourceware.org/ml/crossgcc/2008-09/msg00057.html
    89 }
    90 
    91 # Parse command line options
    92 root="${CT_XLDD_ROOT}"
    93 show_system=
    94 while true; do
    95     case "${1}" in
    96         --help)
    97             show_help
    98             exit 0
    99             ;;
   100         --version)
   101             show_version
   102             exit 0
   103             ;;
   104         --root)
   105             root="$2"
   106             shift
   107             ;;
   108         --root=*)
   109             root="${1#--root=}"
   110             ;;
   111         --show-system|-s)
   112             show_system=1
   113             ;;
   114         -*)
   115             do_opt_error "unrecognized option \`${1}'"
   116             exit 1
   117             ;;
   118         *)
   119             break
   120             ;;
   121     esac
   122     shift
   123 done
   124 
   125 # Sanity checks
   126 if [ -z "${root}" ]; then
   127     do_opt_error "no root given"
   128     exit 1
   129 fi
   130 if [ ! -d "${root}" ]; then
   131     do_error "\`${root}': no such file or directory"
   132     exit 1
   133 fi
   134 
   135 sysroot="$( "${gcc}" -print-sysroot 2>/dev/null )"
   136 if [ -z "${sysroot}" ]; then
   137     sysroot="$( "${gcc}" -print-file-name=libc.so 2>/dev/null   \
   138                 |sed -r -e 's:/usr/lib/libc.so$::;'             \
   139               )"
   140 fi
   141 if [ -z "${sysroot}" ]; then
   142     do_error "unable to find sysroot for \`${gcc}'"
   143 fi
   144 
   145 do_report_needed_found() {
   146     local needed="${1}"
   147     local path="${2}"
   148     local system="${3}"
   149     local loadaddr
   150     local sys
   151 
   152     if [ -z "${system}" ]; then
   153         loadaddr="${fake_load_addr}"
   154     else
   155         loadaddr="${fake_load_addr_sys}"
   156         if [ -n "${show_system}" ]; then
   157             sys=" [*]"
   158         fi
   159     fi
   160 
   161     # 8 to fake a 32-bit load address
   162     printf "%8s%s => %s (0x%0*x)%s\n"   \
   163            ""                           \
   164            "${needed}"                  \
   165            "${path}"                    \
   166            8                            \
   167            "${loadaddr}"                \
   168            "${sys}"
   169 }
   170 
   171 # Search a needed file, scanning ${lib_dir} in the root directory
   172 do_find_needed() {
   173     local needed="${1}"
   174     local found
   175     local found_sysroot
   176     local d
   177 
   178     for d in "${needed_search_path[@]}"; do
   179         if [ -f "${root}${d}/${needed}" ]; then
   180             found="${d}/${needed}"
   181             break
   182         fi
   183     done
   184     if [ -z "${found}" ]; then
   185     for d in "${needed_search_path[@]}"; do
   186         if [ -f "${sysroot}${d}/${needed}" ]; then
   187             found_sysroot="${d}/${needed}"
   188             break
   189         fi
   190     done
   191     fi
   192 
   193     if [ -n "${found}" ]; then
   194         do_report_needed_found "${needed}" "${found}"
   195         do_process_file "${root}${found}"
   196     elif [ -n "${found_sysroot}" ]; then
   197         do_report_needed_found "${needed}" "${found_sysroot}" "sys"
   198         do_process_file "${sysroot}${found_sysroot}"
   199     else
   200         printf "%8c%s not found\n" "" "${needed}"
   201     fi
   202 }
   203 
   204 # Scan a file for all NEEDED tags
   205 do_process_file() {
   206     local file="${1}"
   207 
   208     "${readelf}" -d "${file}"                                           \
   209     |"${grep}" -E '\(NEEDED\)'                                          \
   210     |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[(.*)\]$/\1/;'    \
   211     |while read needed; do
   212         do_find_needed "${needed}"
   213      done
   214 }
   215 
   216 # Build up the full list of search directories
   217 declare -a needed_search_path
   218 ld_library_path="${ld_library_path}:"
   219 while [ -n "${ld_library_path}" ]; do
   220     d="${ld_library_path%%:*}"
   221     [ -n "${d}" ] && needed_search_path+=( "${d}" )
   222     ld_library_path="${ld_library_path#*:}"
   223 done
   224 
   225 do_process_file "${1}"