3 # NON-CONFIGURABLE STUFF!
5 version="@@CT_VERSION@@"
10 my_name="$( basename "${0}" )"
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"
20 printf "%s: %s\n" "${my_name}" "$*" >&2
25 printf "Try \`%s --help' for more information\n" "${my_name}" >&2
31 [ -z "${CT_XLDD_VERBOSE}" ] && return 0
33 for((depth=0; "${#FUNCNAME[$((depth+1))]}" != 0; depth++)); do :; done
34 printf "%*s" $((4*(depth-1))) "" >&2
39 # Fake a real ldd, just in case some dumb script would check
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.
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 '[+]'
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
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.
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.
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).
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
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.
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
90 For NEEDED libraries that were found, the output will look like:
91 libneeded.so => /path/to/libneeded.so (0xloadaddr)
93 and for those that were not found, the output will look like:
94 libneeded.so not found
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...).
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).
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
111 # See also this thread:
112 # http://sourceware.org/ml/crossgcc/2008-09/msg00057.html
115 # Parse command line options
116 root="${CT_XLDD_ROOT}"
139 do_opt_error "unrecognized option \`${1}'"
150 if [ -z "${root}" ]; then
151 do_opt_error "no root given"
154 if [ ! -d "${root}" ]; then
155 do_error "\`${root}': no such file or directory"
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$::;' \
165 if [ -z "${sysroot}" ]; then
166 do_error "unable to find sysroot for \`${gcc}'"
169 do_report_needed_found() {
178 loadaddr="${fake_load_addr_root}"
181 loadaddr="${fake_load_addr_rpath}"
182 if [ -n "${show_system}" ]; then
187 loadaddr="${fake_load_addr_sysroot}"
188 if [ -n "${show_system}" ]; then
194 printf "%8s%s => %s (0x%0*x)%s\n" \
203 # Search a needed file, scanning ${lib_dir} in the root directory
213 do_trace "Searching for '%s'\n" "${needed}"
215 # rpath shall come first!
219 "sysroot:${sysroot}" \
222 for i in "${list[@]}"; do
225 if [ "${where}" = "rpath" ]; then
226 dirs=( "${search_rpath[@]}" )
228 dirs=( "${needed_search_path[@]}" )
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"
240 if [ -n "${found}" ]; then
241 do_report_needed_found "${needed}" "${found}" "${where}"
242 do_process_file "${base}${found}"
244 printf "%8s%s not found\n" "" "${needed}"
247 do_trace "Done searching for '%s'\n" "${needed}"
250 # Scan a file for all NEEDED tags
253 local -a save_search_rpath
257 do_trace "Parsing file '%s'\n" "${file}"
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/;'\
264 do_trace "-> adding rpath '%s'\n" "${n}"
265 search_rpath+=( "${n}" )
267 do_trace ": search path:\n"
268 for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do
269 do_trace ": - '%s'\n" "${n}"
271 do_trace ": end search path"
273 for n in $( "${readelf}" -d "${file}" \
274 |"${grep}" -E '\(NEEDED\)' \
275 |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[(.*)\]$/\1/;' \
278 for m in "${needed_list[@]}"; do
279 [ "${n}" = "${m}" ] && found=1 && break
281 if [ ${found} -ne 0 ]; then
282 do_trace "-> skipping already known dependency '%s'\n" "${n}"
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}"
291 search_rpath=( "${save_search_rpath[@]}" )
293 do_trace "Finished parsing file '%s'\n" "${file}"
296 # Recursively scan a /etc/ld.so.conf file
297 do_scan_etc_ldsoconf() {
298 local ldsoconf="${1}"
302 [ -f "${ldsoconf}" ] || return 0
303 do_trace "Parsing ld.so.conf: '%s'\n" "${ldsoconf}"
308 g="${root}${line#include }"
309 do_trace "-> handling include directive '%s'\n" "${g}"
311 do_scan_etc_ldsoconf "${f}"
313 do_trace "-> finished handling include directive '%s'\n" "${g}"
318 do_trace "-> adding search dir '%s'\n" "${line}"
319 needed_search_path+=( "${line}" )
324 do_trace "Finished parsing ld.so.conf: '%s'\n" "${ldsoconf}"
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}" )
337 ld_library_path="${ld_library_path#*:}"
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}"
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}"