scripts/xldd.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Nov 23 21:35:41 2010 +0100 (2010-11-23)
changeset 2189 52e1698ac243
parent 2188 aa2305c5b2a5
child 2190 9b9a0bb51cfb
permissions -rwxr-xr-x
scripts/xldd: parse /etc/ld.so.conf

Scan /etc/ld.so.conf for paths to search for libraries.
Also follow include directives in there.

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 
    59 ${my_name} will search the directory specified with --root for libraries
    60 to resolve the NEEDED tags. If --root is not set, then ${my_name} will
    61 use the value in the environment variable \${CT_XLDD_ROOT}. If neither
    62 is set, then this is an error.
    63 
    64 If NEEDED libraries can't be found in the specified root directory, then
    65 ${my_name} will also look in the sysroot of the toolchain to see if it
    66 can find them.
    67 
    68 For NEEDED libraries that were found, the output will look like:
    69         libneeded.so => /path/to/libneeded.so (0xloadaddr)
    70 
    71 and for those that were not found, the output will look like:
    72         libneeded.so not found
    73 
    74 The paths are relative to the specified root directory, or to the sysroot
    75 (eg. /lib/libneeded.so, /usr/lib/libneeded.so, and so on...).
    76 
    77 The expected load address 'loadaddr' is a faked address to match the output
    78 of the real ldd, but has no actual meaning (set to some constants for now,
    79 0x8badf00d for libraries from the sysroot, 0xdeadbeef for others).
    80 _EOF_
    81 
    82 # Unimplemeted yet:
    83 #  -d, --data-relocs       process data relocations
    84 #  -r, --function-relocs   process data and function relocations
    85 #  -u, --unused            print unused direct dependencies
    86 #  -v, --verbose           print all information
    87 
    88 # See also this thread:
    89 #  http://sourceware.org/ml/crossgcc/2008-09/msg00057.html
    90 }
    91 
    92 # Parse command line options
    93 root="${CT_XLDD_ROOT}"
    94 show_system=
    95 while true; do
    96     case "${1}" in
    97         --help)
    98             show_help
    99             exit 0
   100             ;;
   101         --version)
   102             show_version
   103             exit 0
   104             ;;
   105         --root)
   106             root="$2"
   107             shift
   108             ;;
   109         --root=*)
   110             root="${1#--root=}"
   111             ;;
   112         --show-system|-s)
   113             show_system=1
   114             ;;
   115         -*)
   116             do_opt_error "unrecognized option \`${1}'"
   117             exit 1
   118             ;;
   119         *)
   120             break
   121             ;;
   122     esac
   123     shift
   124 done
   125 
   126 # Sanity checks
   127 if [ -z "${root}" ]; then
   128     do_opt_error "no root given"
   129     exit 1
   130 fi
   131 if [ ! -d "${root}" ]; then
   132     do_error "\`${root}': no such file or directory"
   133     exit 1
   134 fi
   135 
   136 sysroot="$( "${gcc}" -print-sysroot 2>/dev/null )"
   137 if [ -z "${sysroot}" ]; then
   138     sysroot="$( "${gcc}" -print-file-name=libc.so 2>/dev/null   \
   139                 |sed -r -e 's:/usr/lib/libc.so$::;'             \
   140               )"
   141 fi
   142 if [ -z "${sysroot}" ]; then
   143     do_error "unable to find sysroot for \`${gcc}'"
   144 fi
   145 
   146 do_report_needed_found() {
   147     local needed="${1}"
   148     local path="${2}"
   149     local system="${3}"
   150     local loadaddr
   151     local sys
   152 
   153     if [ -z "${system}" ]; then
   154         loadaddr="${fake_load_addr}"
   155     else
   156         loadaddr="${fake_load_addr_sys}"
   157         if [ -n "${show_system}" ]; then
   158             sys=" [*]"
   159         fi
   160     fi
   161 
   162     printf "%8s%s => %s (0x%0*x)%s\n"   \
   163            ""                           \
   164            "${needed}"                  \
   165            "${path}"                    \
   166            "$((bits/4))"                \
   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 # Recursively scan a /etc/ld.so.conf file
   217 do_scan_etc_ldsoconf() {
   218     local ldsoconf="${1}"
   219     local g
   220     local f
   221 
   222     [ -f "${ldsoconf}" ] || return 0
   223 
   224     while read line; do
   225         case "${line}" in
   226             include\ *)
   227                 g="${root}${line#include }"
   228                 for f in ${g}; do
   229                     do_scan_etc_ldsoconf "${f}"
   230                 done
   231                 ;;
   232             \#*|"")
   233                 ;;
   234             *)
   235                 needed_search_path+=( "${line}" )
   236                 ;;
   237         esac
   238     done <"${ldsoconf}"
   239 }
   240 
   241 # Build up the full list of search directories
   242 declare -a needed_search_path
   243 ld_library_path="${ld_library_path}:"
   244 while [ -n "${ld_library_path}" ]; do
   245     d="${ld_library_path%%:*}"
   246     [ -n "${d}" ] && needed_search_path+=( "${d}" )
   247     ld_library_path="${ld_library_path#*:}"
   248 done
   249 do_scan_etc_ldsoconf "${root}/etc/ld.so.conf"
   250 
   251 do_process_file "${1}"