scripts/xldd.in
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Fri Nov 09 19:42:32 2012 +0100 (2012-11-09)
changeset 3104 7da91f9ba328
parent 3025 d25fb5bf6615
child 3134 863723936e24
permissions -rwxr-xr-x
cc/gcc: fix patches for 4.6.{0,1}

Remove the sparc part, as it touches code that does not exist in
those versions of gcc (it was added at 4.6.2).

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