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" >&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@anciens.enib.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_DEBUG variable is set and non-empty, then ${myname} 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 '${needed}'\n"
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 '${d}' (${where})\n"
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}"
248 # Scan a file for all NEEDED tags
251 local -a save_search_rpath
255 do_trace "Parsing file '${file}'\n"
257 save_search_rpath=( "${search_rpath[@]}" )
258 for n in $( "${readelf}" -d "${file}" \
259 |"${grep}" -E '\((RPATH|RUNPATH)\)' \
260 |"${sed}" -r -e 's/^.*Library r(|un)path:[[:space:]]+\[(.*)\]$/\2/;'\
262 do_trace "-> adding rpath '${n}'\n"
263 search_rpath+=( "${n}" )
265 do_trace ": search path:\n"
266 for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do
267 do_trace ": - '${n}'\n"
270 for n in $( "${readelf}" -d "${file}" \
271 |"${grep}" -E '\(NEEDED\)' \
272 |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[(.*)\]$/\1/;' \
275 for m in "${needed_list[@]}"; do
276 [ "${n}" = "${m}" ] && found=1 && break
278 if [ ${found} -ne 0 ]; then
279 do_trace "-> skipping already known dependency '${n}'\n"
282 do_trace "-> handling new dependency '${n}'\n"
283 needed_list+=( "${n}" )
284 do_find_needed "${n}"
287 search_rpath=( "${save_search_rpath[@]}" )
290 # Recursively scan a /etc/ld.so.conf file
291 do_scan_etc_ldsoconf() {
292 local ldsoconf="${1}"
296 [ -f "${ldsoconf}" ] || return 0
297 do_trace "Parsing ld.so.conf: '${ldsoconf}'\n"
302 g="${root}${line#include }"
303 do_trace "-> handling include directive '${g}'\n"
305 do_scan_etc_ldsoconf "${f}"
311 do_trace "-> adding search dir '${line}'\n"
312 needed_search_path+=( "${line}" )
318 # Build up the full list of search directories
319 declare -a needed_search_path
320 do_trace "Adding basic lib dirs\n"
321 ld_library_path="${ld_library_path}:"
322 while [ -n "${ld_library_path}" ]; do
323 d="${ld_library_path%%:*}"
324 if [ -n "${d}" ]; then
325 do_trace "-> adding search dir '${d}'\n"
326 needed_search_path+=( "${d}" )
328 ld_library_path="${ld_library_path#*:}"
330 do_trace "Scanning '/etc/ld.so.conf'\n"
331 do_scan_etc_ldsoconf "${root}/etc/ld.so.conf"
332 do_trace "Search path:\n"
333 for p in "${needed_search_path[@]}"; do
334 do_trace "-> '${p}'\n"
337 do_trace "Scanning file '${1}'\n"
338 declare -a needed_list
339 declare -a search_rpath
340 do_process_file "${1}"