From c03ac58aca82f9a1249978f8b686f85d9a27dba8 Mon Sep 17 00:00:00 2001 From: "Yann E. MORIN\"" Date: Thu, 22 Jul 2010 23:26:08 +0200 Subject: scripts: add a cross-ldd-like Add a cross-ldd that mimicks a native ldd. diff --git a/config/libc.in b/config/libc.in index 2ee46ba..5397f23 100644 --- a/config/libc.in +++ b/config/libc.in @@ -81,6 +81,20 @@ config THREADS_NONE endchoice +config LIBC_XLDD + bool + prompt "Install a cross ldd-like helper" + default y + help + Say 'Y' here if you want to have a ldd-like helper that + you can run on your build system, and that will (try to) + resolve shared libraries dependencies as if run on the + target. + + Note that the cross-ldd helper is not a full replacement + for the native ldd. Please see the help, by running it + with '--help' for more explanations. + source "config.gen/libc.in.2" endif # ! LIBC_none diff --git a/scripts/build/internals.sh b/scripts/build/internals.sh index 84c8798..3e5ee5d 100644 --- a/scripts/build/internals.sh +++ b/scripts/build/internals.sh @@ -21,6 +21,19 @@ do_finish() { CT_DoExecLog ALL chmod 755 "${CT_PREFIX_DIR}/bin/${CT_TARGET}-populate" fi + if [ "${CT_LIBC_XLDD}" = "y" ]; then + CT_DoLog EXTRA "Installing a cross-ldd helper" + sed -r -e 's|@@CT_TARGET@@|'"${CT_TARGET}"'|g;' \ + -e 's|@@CT_install@@|'"${install}"'|g;' \ + -e 's|@@CT_bash@@|'"${bash}"'|g;' \ + -e 's|@@CT_grep@@|'"${grep}"'|g;' \ + -e 's|@@CT_make@@|'"${make}"'|g;' \ + -e 's|@@CT_sed@@|'"${sed}"'|g;' \ + "${CT_LIB_DIR}/scripts/xldd.in" \ + >"${CT_PREFIX_DIR}/bin/${CT_TARGET}-ldd" + CT_DoExecLog ALL chmod 755 "${CT_PREFIX_DIR}/bin/${CT_TARGET}-ldd" + fi + # Create the aliases to the target tools CT_DoLog EXTRA "Creating toolchain aliases" CT_Pushd "${CT_PREFIX_DIR}/bin" diff --git a/scripts/xldd.in b/scripts/xldd.in new file mode 100755 index 0000000..9a28294 --- /dev/null +++ b/scripts/xldd.in @@ -0,0 +1,214 @@ +#!@@CT_bash@@ + +# NON-CONFIGURABLE STUFF! +export LC_ALL=C +sed="@@CT_sed@@" +grep="@@CT_grep@@" +my_name="$( basename "${0}" )" +prefix="${0%-ldd}" +gcc="${prefix}-gcc" +readelf="${prefix}-readelf" +fake_load_addr="$((0xdeadbeef))" +fake_load_addr_sys="$((0x8badf00d))" +ld_library_path="/lib:/usr/lib" + +do_error() { + printf "%s: %s\n" "${my_name}" "$*" >&2 +} + +do_opt_error() { + do_error "$@" + printf "Try \`%s --help' for more information\n >&2" +} + +show_version() { + # Fake a real ldd, just in case some dumb script would check + cat <<_EOF_ +ldd (crosstool-NG) 1.8.0 +Copyright (C) 2010 "Yann E. MORIN" +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +Licensed under the GPLv2, see the file LICENSES in the top-directory of the +sources for this package. +_EOF_ +} + +show_help() { + cat <<_EOF_ +Usage: ${my_name} [OPTION]... --root DIR FILE... + --help print this help and exit + --version print version information and exit + --root dir treat dir as being the root of the target + -s, --show-system mark libs from the sysroot with a trailing '[*]' + +_EOF_ + cat <<_EOF_ |fmt +${my_name} tries to mimick the behavior of a real native ldd, but can be +used in a cross-development environment. Here is how it differs from a +real native ldd: + +The LD_LIBRARY_PATH variable is not used, as it can not reliably be +guessed except at runtime, and we can't run. + +${my_name} does not scan /etc/ld.so.cache, but instead uses /etc/ld.so.conf +(it understands the include directives therein for libces that have that). +[Note: this is missing for now...] + +${my_name} will search the directory specified with --root for libraries +to resolve the NEEDED tags. If --root is not set, then ${my_name} will +use the value in the environment variable \${CT_XLDD_ROOT}. If neither +is set, then this is an error. + +If NEEDED libraries can't be found in the specified root directory, then +${my_name} will also look in the sysroot of the toolchain to see if it +can find them. + +For NEEDED libraries that were found, the output will look like: + libneeded.so => /path/to/libneeded.so (0xloadaddr) + +and for those that were not found, the output will look like: + libneeded.so not found + +The paths are relative to the specified root directory, or to the sysroot +(eg. /lib/libneeded.so, /usr/lib/libneeded.so, and so on...). + +The expected load address 'loadaddr' is a faked address to match the output +of the real ldd, but has no actual meaning (set to some constants for now, +0x8badf00d for libraries from the sysroot, 0xdeadbeff for others). +_EOF_ + +# Unimplemeted yet: +# -d, --data-relocs process data relocations +# -r, --function-relocs process data and function relocations +# -u, --unused print unused direct dependencies +# -v, --verbose print all information + +# See also this thread: +# http://sourceware.org/ml/crossgcc/2008-09/msg00057.html +} + +# Parse command line options +root="${CT_XLDD_ROOT}" +show_system= +while true; do + case "${1}" in + --help) + show_help + exit 0 + ;; + --version) + show_version + exit 0 + ;; + --root) + root="$2" + shift + ;; + --root=*) + root="${1#--root=}" + ;; + --show-system|-s) + show_system=1 + ;; + -*) + do_opt_error "unrecognized option \`${1}'" + exit 1 + ;; + *) + break + ;; + esac + shift +done + +# Sanity checks +if [ -z "${root}" ]; then + do_opt_error "no root given" + exit 1 +fi +if [ ! -d "${root}" ]; then + do_error "\`${root}': no such file or directory" + exit 1 +fi + +sysroot="$( "${gcc}" -print-sysroot )" + +do_report_needed_found() { + local needed="${1}" + local path="${2}" + local system="${3}" + local loadaddr + local sys + + if [ -z "${system}" ]; then + loadaddr="${fake_load_addr}" + else + loadaddr="${fake_load_addr_sys}" + if [ -n "${show_system}" ]; then + sys=" [*]" + fi + fi + + # 8 to fake a 32-bit load address + printf "%8s%s => %s (0x%0*x)%s\n" \ + "" \ + "${needed}" \ + "${path}" \ + 8 \ + "${loadaddr}" \ + "${sys}" +} + +# Search a needed file, scanning ${lib_dir} in the root directory +do_find_needed() { + local needed="${1}" + local found + local found_sysroot + local d + + for d in "${needed_search_path[@]}"; do + if [ -f "${root}${d}/${needed}" ]; then + found="${d}/${needed}" + fi + done + if [ -z "${found}" ]; then + for d in "${needed_search_path[@]}"; do + if [ -f "${sysroot}${d}/${needed}" ]; then + found_sysroot="${d}/${needed}" + fi + done + fi + + if [ -n "${found}" ]; then + do_report_needed_found "${needed}" "${found}" + do_process_file "${root}${found}" + elif [ -n "${found_sysroot}" ]; then + do_report_needed_found "${needed}" "${found_sysroot}" "sys" + do_process_file "${sysroot}${found_sysroot}" + else + printf "%8c%s not found\n" "" "${needed}" + fi +} + +# Scan a file for all NEEDED tags +do_process_file() { + local file="${1}" + + "${readelf}" -d "${file}" \ + |"${grep}" -E '\(NEEDED\)' \ + |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[(.*)\]$/\1/;' \ + |while read needed; do + do_find_needed "${needed}" + done +} + +# Build up the full list of search directories +declare -a needed_search_path +ld_library_path="${ld_library_path}:" +while [ -n "${ld_library_path}" ]; do + d="${ld_library_path%%:*}" + [ -n "${d}" ] && needed_search_path+=( "${d}" ) + ld_library_path="${ld_library_path#*:}" +done + +do_process_file "${1}" -- cgit v0.10.2-6-g49f6