scripts/xldd.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Nov 23 21:35:10 2010 +0100 (2010-11-23)
changeset 2186 78d2f99d403f
parent 2184 e826624966a1
child 2187 9cdb153ff9df
child 2198 6d909657dbdf
permissions -rwxr-xr-x
scripts/xldd: stop at first match

Break the library search loop as soon as a match is found.
Previously, if a library was present in different places,
then the last occurence would be returned, when the first
one would have been used at runtime.

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 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 )"
   136 
   137 do_report_needed_found() {
   138     local needed="${1}"
   139     local path="${2}"
   140     local system="${3}"
   141     local loadaddr
   142     local sys
   143 
   144     if [ -z "${system}" ]; then
   145         loadaddr="${fake_load_addr}"
   146     else
   147         loadaddr="${fake_load_addr_sys}"
   148         if [ -n "${show_system}" ]; then
   149             sys=" [*]"
   150         fi
   151     fi
   152 
   153     # 8 to fake a 32-bit load address
   154     printf "%8s%s => %s (0x%0*x)%s\n"   \
   155            ""                           \
   156            "${needed}"                  \
   157            "${path}"                    \
   158            8                            \
   159            "${loadaddr}"                \
   160            "${sys}"
   161 }
   162 
   163 # Search a needed file, scanning ${lib_dir} in the root directory
   164 do_find_needed() {
   165     local needed="${1}"
   166     local found
   167     local found_sysroot
   168     local d
   169 
   170     for d in "${needed_search_path[@]}"; do
   171         if [ -f "${root}${d}/${needed}" ]; then
   172             found="${d}/${needed}"
   173             break
   174         fi
   175     done
   176     if [ -z "${found}" ]; then
   177     for d in "${needed_search_path[@]}"; do
   178         if [ -f "${sysroot}${d}/${needed}" ]; then
   179             found_sysroot="${d}/${needed}"
   180             break
   181         fi
   182     done
   183     fi
   184 
   185     if [ -n "${found}" ]; then
   186         do_report_needed_found "${needed}" "${found}"
   187         do_process_file "${root}${found}"
   188     elif [ -n "${found_sysroot}" ]; then
   189         do_report_needed_found "${needed}" "${found_sysroot}" "sys"
   190         do_process_file "${sysroot}${found_sysroot}"
   191     else
   192         printf "%8c%s not found\n" "" "${needed}"
   193     fi
   194 }
   195 
   196 # Scan a file for all NEEDED tags
   197 do_process_file() {
   198     local file="${1}"
   199 
   200     "${readelf}" -d "${file}"                                           \
   201     |"${grep}" -E '\(NEEDED\)'                                          \
   202     |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[(.*)\]$/\1/;'    \
   203     |while read needed; do
   204         do_find_needed "${needed}"
   205      done
   206 }
   207 
   208 # Build up the full list of search directories
   209 declare -a needed_search_path
   210 ld_library_path="${ld_library_path}:"
   211 while [ -n "${ld_library_path}" ]; do
   212     d="${ld_library_path%%:*}"
   213     [ -n "${d}" ] && needed_search_path+=( "${d}" )
   214     ld_library_path="${ld_library_path#*:}"
   215 done
   216 
   217 do_process_file "${1}"