d353d30dee
Somewhere between binutils 2.35 and 2.37, some functionality was added in readelf to parse more DWARF information. Unfortunately, as reported in binutils bug 28981 ("https://sourceware.org/bugzilla/show_bug.cgi?id=28981"), this feature causes a number of fairly scary warnings to be displayed when running readelf on binaries built with Clang, such as the pre-built rustc and rustdoc binaries part of the host-rust-bin package. It looks like this: readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x23 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Bogus end-of-siblings marker detected at offset 2f in .debug_info section readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Bogus end-of-siblings marker detected at offset 10b in .debug_info section readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Bogus end-of-siblings marker detected at offset 10c in .debug_info section readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Further warnings about bogus end-of-sibling markers suppressed readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x23 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x23 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x23 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x23 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: Unrecognized form: 0x22 readelf: /home/thomas/projets/buildroot/output/host/bin/rustc: Warning: DIE at offset 0x1da refers to abbreviation number 5827 which does not exist These warnings are caused by the readelf calls done by the support/scripts/check-host-rpath script. The annoying thing is that once host-rust-bin has been installed in $(HOST_DIR), this warning appears after the installation of every single host package, because support/scripts/check-host-rpath rescans all binaries every time. To avoid showing those scary warnings, this commit sends the error output of readelf to /dev/null. Of course, it would be nicer to only filter out those warnings, but filtering the error output without merging the error output into the standard output is tricky, so let's keep things simple. If there is really an error, readelf will abort. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
112 lines
4.2 KiB
Bash
Executable File
112 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# This script scans $(HOST_DIR)/{bin,sbin} for all ELF files, and checks
|
|
# they have an RPATH to $(HOST_DIR)/lib if they need libraries from
|
|
# there.
|
|
|
|
# Override the user's locale so we are sure we can parse the output of
|
|
# readelf(1) and file(1)
|
|
export LC_ALL=C
|
|
|
|
main() {
|
|
local pkg="${1}"
|
|
local hostdir="${2}"
|
|
local perpackagedir="${3}"
|
|
local file ret
|
|
|
|
# Remove duplicate and trailing '/' for proper match
|
|
hostdir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${hostdir}" )"
|
|
|
|
ret=0
|
|
while read file; do
|
|
is_elf "${file}" || continue
|
|
elf_needs_rpath "${file}" "${hostdir}" || continue
|
|
check_elf_has_rpath "${file}" "${hostdir}" "${perpackagedir}" && continue
|
|
if [ ${ret} -eq 0 ]; then
|
|
ret=1
|
|
printf "***\n"
|
|
printf "*** ERROR: package %s installs executables without proper RPATH:\n" "${pkg}"
|
|
fi
|
|
printf "*** %s\n" "${file}"
|
|
done < <( find "${hostdir}"/{bin,sbin} -type f 2>/dev/null )
|
|
|
|
return ${ret}
|
|
}
|
|
|
|
is_elf() {
|
|
local f="${1}"
|
|
|
|
readelf -l "${f}" 2>/dev/null \
|
|
|grep -E 'Requesting program interpreter:' >/dev/null 2>&1
|
|
}
|
|
|
|
# This function tells whether a given ELF executable (first argument)
|
|
# needs a RPATH pointing to the host library directory or not. It
|
|
# needs such an RPATH if at least of the libraries used by the ELF
|
|
# executable is available in the host library directory. This function
|
|
# returns 0 when a RPATH is needed, 1 otherwise.
|
|
#
|
|
# With per-package directory support, ${hostdir} will point to the
|
|
# current package per-package host directory, and this is where this
|
|
# function will check if the libraries needed by the executable are
|
|
# located (or not). In practice, the ELF executable RPATH may point to
|
|
# another package per-package host directory, but that is fine because
|
|
# if such an executable is within the current package per-package host
|
|
# directory, its libraries will also have been copied into the current
|
|
# package per-package host directory.
|
|
elf_needs_rpath() {
|
|
local file="${1}"
|
|
local hostdir="${2}"
|
|
local lib
|
|
|
|
while read lib; do
|
|
[ -e "${hostdir}/lib/${lib}" ] && return 0
|
|
done < <( readelf -d "${file}" 2>/dev/null \
|
|
|sed -r -e '/^.* \(NEEDED\) .*Shared library: \[(.+)\]$/!d;' \
|
|
-e 's//\1/;' \
|
|
)
|
|
|
|
return 1
|
|
}
|
|
|
|
# This function checks whether at least one of the RPATH of the given
|
|
# ELF executable (first argument) properly points to the host library
|
|
# directory (second argument), either through an absolute RPATH or a
|
|
# relative RPATH. In the context of per-package directory support,
|
|
# ${hostdir} (second argument) points to the current package host
|
|
# directory. However, it is perfectly valid for an ELF binary to have
|
|
# a RPATH pointing to another package per-package host directory,
|
|
# which is why such RPATH is also accepted (the per-package directory
|
|
# gets passed as third argument). Having a RPATH pointing to the host
|
|
# directory will make sure the ELF executable will find at runtime the
|
|
# shared libraries it depends on. This function returns 0 when a
|
|
# proper RPATH was found, or 1 otherwise.
|
|
check_elf_has_rpath() {
|
|
local file="${1}"
|
|
local hostdir="${2}"
|
|
local perpackagedir="${3}"
|
|
local rpath dir
|
|
|
|
while read rpath; do
|
|
for dir in ${rpath//:/ }; do
|
|
# Remove duplicate and trailing '/' for proper match
|
|
dir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${dir}" )"
|
|
[ "${dir}" = "${hostdir}/lib" ] && return 0
|
|
[ "${dir}" = "\$ORIGIN/../lib" ] && return 0
|
|
# This check is done even for builds where
|
|
# BR2_PER_PACKAGE_DIRECTORIES is disabled. In this case,
|
|
# PER_PACKAGE_DIR and therefore ${perpackagedir} points to
|
|
# a non-existent directory, and this check will always be
|
|
# false.
|
|
[[ ${dir} =~ "${perpackagedir}/"[^/]+/host/lib ]] && return 0
|
|
done
|
|
done < <( readelf -d "${file}" 2>/dev/null \
|
|
|sed -r -e '/.* \(R(UN)?PATH\) +Library r(un)?path: \[(.+)\]$/!d' \
|
|
-e 's//\3/;' \
|
|
)
|
|
|
|
return 1
|
|
}
|
|
|
|
main "${@}"
|