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