04a4af896d
Since the section retrieval code is implemented inside the awk script now, the next step is to eliminate external iteration over the section list and just retrieve the required sections inside awk on demand. This allows calling (and processing the output of) objdump -t just once, which saves around 8-12% of time on kernels that store modversions as non-absolute symbols: $ for i in ./lib/modules/*; do \ echo "====== $i ====="; \ diff -u <(find $i | ./find-provides.ksyms.old) <(find $i | ./find-provides.ksyms.new); \ echo -n "old: "; find $i | time ./find-provides.ksyms.old > /dev/null; \ echo -n "new: "; find $i | time ./find-provides.ksyms.new > /dev/null; \ done ====== ./lib/modules/4.18.0-372.57.1.el8_6.s390x ===== old: ../find-provides.ksyms.old > /dev/null 4.41s user 3.46s system 136% cpu 5.756 total new: ../find-provides.ksyms.new > /dev/null 3.90s user 2.94s system 129% cpu 5.279 total ====== ./lib/modules/4.18.0-372.57.1.el8_6.x86_64 ===== old: ../find-provides.ksyms.old > /dev/null 6.04s user 3.88s system 124% cpu 7.993 total new: ../find-provides.ksyms.new > /dev/null 6.08s user 3.91s system 124% cpu 8.012 total ====== ./lib/modules/5.14.0-284.15.1.el9_2.s390x ===== old: ../find-provides.ksyms.old > /dev/null 5.09s user 3.51s system 133% cpu 6.452 total new: ../find-provides.ksyms.new > /dev/null 4.65s user 2.89s system 126% cpu 5.949 total ====== ./lib/modules/5.14.0-284.15.1.el9_2.x86_64 ===== old: ../find-provides.ksyms.old > /dev/null 6.52s user 4.14s system 123% cpu 8.638 total new: ../find-provides.ksyms.new > /dev/null 6.64s user 4.12s system 123% cpu 8.690 total ====== ./lib/modules/6.4.0-0.rc1.20230511git80e62bc8487b.19.eln126.s390x ===== old: ../find-provides.ksyms.old > /dev/null 4.45s user 3.29s system 136% cpu 5.661 total new: ../find-provides.ksyms.new > /dev/null 3.84s user 2.54s system 127% cpu 4.980 total ====== ./lib/modules/6.4.0-0.rc1.20230511git80e62bc8487b.19.eln126.x86_64 ===== old: ../find-provides.ksyms.old > /dev/null 7.34s user 4.33s system 129% cpu 9.019 total new: ../find-provides.ksyms.new > /dev/null 6.67s user 3.51s system 122% cpu 8.278 total * find-provides.ksyms: Remove "objdump -t" section loop, do not supply sectname to the awk script, treat sectdata as an array keyed on section name, convert section retrieval to a function with a section name as an argument, call it if a section name is not present in sectdata. * find-requires.ksyms (all_provides): Likewise. Resolves: #2178935 Signed-off-by: Eugene Syromiatnikov <esyr@redhat.com>
195 lines
7.0 KiB
Bash
195 lines
7.0 KiB
Bash
#! /bin/bash
|
|
#
|
|
# This script is called during external module building to create dependencies
|
|
# both upon the RHEL kernel, and on additional external modules. Symbols that
|
|
# cannot be reconciled against those provided by the kernel are assumed to be
|
|
# provided by an external module and "ksym" replaces th regular "kernel" dep.
|
|
|
|
IFS=$'\n'
|
|
export LC_ALL=C
|
|
|
|
# Prevent elfutils from trying to download debuginfos
|
|
unset DEBUGINFOD_URLS
|
|
|
|
|
|
# Extract all of the symbols provided by this module.
|
|
all_provides() {
|
|
for module in "$@"; do
|
|
tmpfile=""
|
|
if [ "x${module%.ko}" = "x${module}" ]; then
|
|
tmpfile=$(mktemp -t ${0##*/}.XXXXXX.ko)
|
|
proc_bin=
|
|
case "${module##*.}" in
|
|
zst)
|
|
proc_bin=zstd
|
|
;;
|
|
xz)
|
|
proc_bin=xz
|
|
;;
|
|
bz2)
|
|
proc_bin=bzip2
|
|
;;
|
|
gz)
|
|
proc_bin=gzip
|
|
;;
|
|
esac
|
|
|
|
[ -n "$proc_bin" ] || continue
|
|
|
|
"$proc_bin" -d -c - < "$module" > "$tmpfile" || continue
|
|
module="$tmpfile"
|
|
fi
|
|
|
|
# awk script return code:
|
|
# 0 - absolute __crc_* symbols have been found, output has been
|
|
# generated;
|
|
# 23 - a non-absolute __crc_* symbold has been found;
|
|
# 42 - no __crc_* symbols have been found.
|
|
nm "$module" \
|
|
| awk \
|
|
-v 'dep_pfx='"$dep_pfx" \
|
|
--non-decimal-data \
|
|
'BEGIN { exit_code = 42 }
|
|
match($0, /^([0-9a-f]+) (.) __crc_(.+)/, a) {
|
|
if (a[2] == "A") {
|
|
printf("%s(%s) = 0x%08x\n", dep_pfx, a[3], strtonum("0x" a[1]));
|
|
exit_code = 0;
|
|
} else {
|
|
exit_code = 23;
|
|
exit;
|
|
}
|
|
}
|
|
END { exit exit_code }'
|
|
|
|
[ 23 = "$?" ] && {
|
|
kmod_elf_hdr="$(readelf -h "$module")"
|
|
[ "x$kmod_elf_hdr" = "x${kmod_elf_hdr%Data:*little endian*}" ]
|
|
revbytes="$?"
|
|
|
|
objdump -t "$module" \
|
|
| awk \
|
|
-v 'dep_pfx='"$dep_pfx" \
|
|
-v 'module='"$module" \
|
|
-v 'revbytes='"$revbytes" \
|
|
--non-decimal-data \
|
|
'function readsect(name, a, t) {
|
|
a = "";
|
|
while (("readelf -R \"" name "\" \"" module "\"" | getline t) > 0) {
|
|
if (match(t, /^ 0x[0-9a-f]{8}/))
|
|
a = a substr(t, 14, 8) substr(t, 23, 8) substr(t, 32, 8) substr(t, 41, 8);
|
|
}
|
|
if (revbytes) { a = gensub(/(..)(..)(..)(..)/, "\\4\\3\\2\\1", "g", a); }
|
|
sectdata[name] = a;
|
|
}
|
|
|
|
match($0, /^([0-9a-f]+) [gl]...... (.*) [0-9a-f]+ __crc_(.*)$/, a) {
|
|
if (!(a[2] in sectdata)) { readsect(a[2]) }
|
|
printf("%s(%s) = 0x%08s\n", dep_pfx, a[3], substr(sectdata[a[2]], (strtonum("0x" a[1]) * 2) + 1, 8))
|
|
}'
|
|
}
|
|
|
|
[ -z "$tmpfile" ] || rm -f -- "$tmpfile"
|
|
done \
|
|
| sort -k1,1 -u
|
|
}
|
|
|
|
# Extract all of the requirements of this module.
|
|
all_requires() {
|
|
for module in "$@"; do
|
|
set -- $(/sbin/modinfo -F vermagic "$module" | sed -e 's: .*::' -e q)
|
|
/sbin/modprobe --dump-modversions "$module" \
|
|
| awk --non-decimal-data '
|
|
BEGIN { FS = "\t" ; OFS = "\t" }
|
|
{printf("%s:0x%08x\n", $2, $1)}' \
|
|
| sed -r -e 's:$:\t'"$1"':'
|
|
done \
|
|
| sort -k1,1 -u
|
|
}
|
|
|
|
# Filter out requirements fulfilled by the module itself.
|
|
mod_requires() {
|
|
join -t $'\t' -j 1 -v 1 \
|
|
<(all_requires "$@") \
|
|
<(all_provides "$@") \
|
|
| sort -k1,1 -u
|
|
}
|
|
|
|
if ! [ -e /sbin/modinfo -a -e /sbin/modprobe ]; then
|
|
cat > /dev/null
|
|
exit 0
|
|
fi
|
|
|
|
check_kabi() {
|
|
arch=$(uname -m)
|
|
kabi_file="/lib/modules/kabi-current/kabi_stablelist_$arch"
|
|
|
|
# If not installed, output a warning and return (continue)
|
|
if [ ! -f "$kabi_file" ]; then
|
|
echo "" >&2
|
|
echo "********************************************************************************" >&2
|
|
echo "*********************** KERNEL ABI COMPATIBILITY WARNING ***********************" >&2
|
|
echo "********************************************************************************" >&2
|
|
echo "The kernel ABI reference files (provided by "kabi-stablelists") were not found." >&2
|
|
echo "No compatibility check was performed. Please install the kABI reference files" >&2
|
|
echo "and rebuild if you would like to verify compatibility with kernel ABI." >&2
|
|
echo "" >&2
|
|
return
|
|
fi
|
|
|
|
unset non_kabi
|
|
for symbol in "$@"; do
|
|
if ! egrep "^[[:space:]]$symbol\$" $kabi_file >/dev/null; then
|
|
non_kabi=("${non_kabi[@]}" "$symbol")
|
|
fi
|
|
done
|
|
|
|
if [ ${#non_kabi[@]} -gt 0 ]; then
|
|
echo "" >&2
|
|
echo "********************************************************************************" >&2
|
|
echo "*********************** KERNEL ABI COMPATIBILITY WARNING ***********************" >&2
|
|
echo "********************************************************************************" >&2
|
|
echo "The following kernel symbols are not guaranteed to remain compatible with" >&2
|
|
echo "future kernel updates to this RHEL release:" >&2
|
|
echo "" >&2
|
|
for symbol in "${non_kabi[@]}"; do
|
|
printf "\t$symbol\n" >&2
|
|
done
|
|
echo "" >&2
|
|
echo "Red Hat recommends that you consider using only official kernel ABI symbols" >&2
|
|
echo "where possible. Requests for additions to the kernel ABI can be filed with" >&2
|
|
echo "your partner or customer representative (component: driver-update-program)." >&2
|
|
echo "" >&2
|
|
fi
|
|
}
|
|
|
|
modules=($(grep -E '/lib/modules/.+\.ko(\.gz|\.bz2|\.xz|\.zst)?$') "$@")
|
|
if [ ${#modules[@]} -gt 0 ]; then
|
|
kernel=$(/sbin/modinfo -F vermagic "${modules[0]}" | sed -e 's: .*::' -e q)
|
|
|
|
# get all that kernel provides
|
|
symvers=$(mktemp -t ${0##*/}.XXXXX)
|
|
|
|
cat /usr/src/kernels/$kernel/Module.symvers | awk '
|
|
BEGIN { FS = "\t" ; OFS = "\t" }
|
|
{ print $2 ":" $1 }
|
|
' \
|
|
| sed -r -e 's:$:\t'"$kernel"':' \
|
|
| sort -k1,1 -u > $symvers
|
|
|
|
# Symbols matching with the kernel get a "kernel" dependency
|
|
mod_req=$(mktemp -t mod_req.XXXXX)
|
|
mod_requires "${modules[@]}" > "$mod_req"
|
|
join -t $'\t' -j 1 $symvers "$mod_req" | sort -u \
|
|
| awk 'BEGIN { FS = "[\t:]" ; OFS = "\t" } { print "kernel(" $1 ") = " $2 }'
|
|
|
|
# Symbols from elsewhere get a "ksym" dependency
|
|
join -t $'\t' -j 1 -v 2 $symvers "$mod_req" | sort -u \
|
|
| awk 'BEGIN { FS = "[\t:]" ; OFS = "\t" } { print "ksym(" $1 ") = " $2 }'
|
|
|
|
# Check kABI if the kabi-stablelists package is installed
|
|
# Do this last so we can try to output this error at the end
|
|
kabi_check_symbols=($(join -t $'\t' -j 1 $symvers "$mod_req" | sort -u \
|
|
| awk 'BEGIN { FS = "[\t:]" ; OFS = "\t" } { print $1 }'))
|
|
check_kabi "${kabi_check_symbols[@]}"
|
|
fi
|