kpatch-build: clang support

Add support for clang-built kernels. This is completely automatic, we
check if the kernel was built with clang by looking for
CONFIG_CC_IS_CLANG in config.

This has almost no effect on non-clang built kernels with one exception:
we now do compliler checks _after_ we download kernel sources which is a
waste of resources in case when compilers don't match.

Signed-off-by: Artem Savkov <asavkov@redhat.com>
This commit is contained in:
Artem Savkov 2021-01-27 11:41:49 +01:00
parent 2af31916ce
commit 41de9e763a
5 changed files with 111 additions and 48 deletions

View File

@ -62,7 +62,7 @@ vagrant-integration-quick:
$(MAKE) -C $(INTEGRATION_DIR) vagrant-quick $(MAKE) -C $(INTEGRATION_DIR) vagrant-quick
check: check:
shellcheck kpatch/kpatch kpatch-build/kpatch-build kpatch-build/kpatch-gcc shellcheck kpatch/kpatch kpatch-build/kpatch-build kpatch-build/kpatch-cc
shellcheck test/difftree.sh test/integration/kpatch-test \ shellcheck test/difftree.sh test/integration/kpatch-test \
test/integration/lib.sh test/integration/rebase-patches \ test/integration/lib.sh test/integration/rebase-patches \
test/integration/test-vagrant \ test/integration/test-vagrant \

View File

@ -40,7 +40,7 @@ $(PLUGIN): gcc-plugins/ppc64le-plugin.c
install: all install: all
$(INSTALL) -d $(LIBEXECDIR) $(INSTALL) -d $(LIBEXECDIR)
$(INSTALL) $(TARGETS) kpatch-gcc $(LIBEXECDIR) $(INSTALL) $(TARGETS) kpatch-cc $(LIBEXECDIR)
$(INSTALL) -d $(BINDIR) $(INSTALL) -d $(BINDIR)
$(INSTALL) kpatch-build $(BINDIR) $(INSTALL) kpatch-build $(BINDIR)

View File

@ -49,7 +49,7 @@ LOGFILE="$CACHEDIR/build.log"
RELEASE_FILE=/etc/os-release RELEASE_FILE=/etc/os-release
DEBUG=0 DEBUG=0
SKIPCLEANUP=0 SKIPCLEANUP=0
SKIPGCCCHECK=0 SKIPCOMPILERCHECK=0
ARCH_KCFLAGS="" ARCH_KCFLAGS=""
DEBUG_KCFLAGS="" DEBUG_KCFLAGS=""
declare -a PATCH_LIST declare -a PATCH_LIST
@ -219,10 +219,11 @@ find_core_symvers() {
} }
gcc_version_from_file() { gcc_version_from_file() {
readelf -p .comment "$1" | grep -o 'GCC:.*' | head -n 1 readelf -p .comment "$1" | grep -m 1 -o 'GCC:.*'
} }
gcc_version_check() { gcc_version_check() {
local target="$1"
local c="$TEMPDIR/test.c" o="$TEMPDIR/test.o" local c="$TEMPDIR/test.c" o="$TEMPDIR/test.o"
local out gccver kgccver local out gccver kgccver
@ -231,11 +232,7 @@ gcc_version_check() {
echo 'void main(void) {}' > "$c" echo 'void main(void) {}' > "$c"
out="$(gcc -c -pg -ffunction-sections -o "$o" "$c" 2>&1)" out="$(gcc -c -pg -ffunction-sections -o "$o" "$c" 2>&1)"
gccver="$(gcc_version_from_file "$o")" gccver="$(gcc_version_from_file "$o")"
if [[ -n "$OOT_MODULE" ]]; then kgccver="$(gcc_version_from_file "$target")"
kgccver="$(gcc_version_from_file "$OOT_MODULE")"
else
kgccver="$(gcc_version_from_file "$VMLINUX")"
fi
if [[ -n "$out" ]]; then if [[ -n "$out" ]]; then
warn "gcc >= 4.8 required for -pg -ffunction-settings" warn "gcc >= 4.8 required for -pg -ffunction-settings"
@ -254,7 +251,31 @@ gcc_version_check() {
warn "gcc/kernel version mismatch" warn "gcc/kernel version mismatch"
echo "gcc version: $gccver" echo "gcc version: $gccver"
echo "kernel version: $kgccver" echo "kernel version: $kgccver"
echo "Install the matching gcc version (recommended) or use --skip-gcc-check" echo "Install the matching gcc version (recommended) or use --skip-compiler-check"
echo "to skip the version matching enforcement (not recommended)"
return 1
fi
return
}
clang_version_from_file() {
readelf -p .comment "$1" | grep -m 1 -Eo 'clang version [0-9.]+'
}
clang_version_check() {
local target="$1"
local clangver kclangver
clangver=$(clang --version | grep -m 1 -Eo 'clang version [0-9.]+')
kclangver="$(clang_version_from_file "$target")"
# ensure clang version matches that used to build the kernel
if [[ "$clangver" != "$kclangver" ]]; then
warn "clang/kernel version mismatch"
echo "clang version: $clangver"
echo "kernel version: $kclangver"
echo "Install the matching clang version (recommended) or use --skip-compiler-check"
echo "to skip the version matching enforcement (not recommended)" echo "to skip the version matching enforcement (not recommended)"
return 1 return 1
fi fi
@ -456,11 +477,11 @@ usage() {
echo " -e, --oot-module Enable patching out-of-tree module," >&2 echo " -e, --oot-module Enable patching out-of-tree module," >&2
echo " specify current version of module" >&2 echo " specify current version of module" >&2
echo " --skip-cleanup Skip post-build cleanup" >&2 echo " --skip-cleanup Skip post-build cleanup" >&2
echo " --skip-gcc-check Skip gcc version matching check" >&2 echo " --skip-compiler-check Skip compiler version matching check" >&2
echo " (not recommended)" >&2 echo " (not recommended)" >&2
} }
options="$(getopt -o ha:r:s:c:v:j:t:n:o:de: -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,debug,skip-gcc-check,skip-cleanup" -- "$@")" || die "getopt failed" options="$(getopt -o ha:r:s:c:v:j:t:n:o:de: -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup" -- "$@")" || die "getopt failed"
eval set -- "$options" eval set -- "$options"
@ -528,8 +549,11 @@ while [[ $# -gt 0 ]]; do
SKIPCLEANUP=1 SKIPCLEANUP=1
;; ;;
--skip-gcc-check) --skip-gcc-check)
echo "WARNING: Skipping gcc version matching check (not recommended)" echo "DEPRECATED: --skip-gcc-check is deprecated, use --skip-compiler-check instead"
SKIPGCCCHECK=1 ;&
--skip-compiler-check)
echo "WARNING: Skipping compiler version matching check (not recommended)"
SKIPCOMPILERCHECK=1
;; ;;
*) *)
[[ "$1" = "--" ]] && shift && continue [[ "$1" = "--" ]] && shift && continue
@ -631,10 +655,6 @@ fi
find_dirs || die "can't find supporting tools" find_dirs || die "can't find supporting tools"
if [[ "$SKIPGCCCHECK" -eq 0 ]]; then
gcc_version_check || die
fi
if [[ -n "$USERSRCDIR" ]]; then if [[ -n "$USERSRCDIR" ]]; then
echo "Using source directory at $USERSRCDIR" echo "Using source directory at $USERSRCDIR"
@ -751,6 +771,8 @@ CONFIG_PARAVIRT=0
CONFIG_UNWINDER_ORC=0 CONFIG_UNWINDER_ORC=0
CONFIG_JUMP_LABEL=0 CONFIG_JUMP_LABEL=0
CONFIG_MODVERSIONS=0 CONFIG_MODVERSIONS=0
CONFIG_CC_IS_CLANG=0
CONFIG_LD_IS_LLD=0
if grep -q "CONFIG_LIVEPATCH=y" "$CONFIGFILE" && (kernel_is_rhel || kernel_version_gte 4.9.0); then if grep -q "CONFIG_LIVEPATCH=y" "$CONFIGFILE" && (kernel_is_rhel || kernel_version_gte 4.9.0); then
@ -777,6 +799,8 @@ grep -q "CONFIG_PARAVIRT=y" "$CONFIGFILE" && CONFIG_PARAVIRT=1
grep -q "CONFIG_UNWINDER_ORC=y" "$CONFIGFILE" && CONFIG_UNWINDER_ORC=1 grep -q "CONFIG_UNWINDER_ORC=y" "$CONFIGFILE" && CONFIG_UNWINDER_ORC=1
grep -q "CONFIG_JUMP_LABEL=y" "$CONFIGFILE" && CONFIG_JUMP_LABEL=1 grep -q "CONFIG_JUMP_LABEL=y" "$CONFIGFILE" && CONFIG_JUMP_LABEL=1
grep -q "CONFIG_MODVERSIONS=y" "$CONFIGFILE" && CONFIG_MODVERSIONS=1 grep -q "CONFIG_MODVERSIONS=y" "$CONFIGFILE" && CONFIG_MODVERSIONS=1
grep -q "CONFIG_CC_IS_CLANG=y" "$CONFIGFILE" && CONFIG_CC_IS_CLANG=1
grep -q "CONFIG_LD_IS_LLD=y" "$CONFIGFILE" && CONFIG_LD_IS_LLD=1
# unsupported kernel option checking # unsupported kernel option checking
grep -q "CONFIG_DEBUG_INFO_SPLIT=y" "$CONFIGFILE" && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported" grep -q "CONFIG_DEBUG_INFO_SPLIT=y" "$CONFIGFILE" && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported"
@ -791,6 +815,23 @@ if grep -q "CONFIG_DEBUG_INFO_BTF=y" "$CONFIGFILE" ; then
sed -i 's/CONFIG_DEBUG_INFO_BTF/DISABLED_FOR_KPATCH_BUILD/g' "$SRCDIR"/scripts/link-vmlinux.sh || die sed -i 's/CONFIG_DEBUG_INFO_BTF/DISABLED_FOR_KPATCH_BUILD/g' "$SRCDIR"/scripts/link-vmlinux.sh || die
fi fi
if [[ "$CONFIG_CC_IS_CLANG" -eq 1 ]]; then
echo "WARNING: Clang support is experimental"
fi
if [[ "$SKIPCOMPILERCHECK" -eq 0 ]]; then
if [[ -n "$OOT_MODULE" ]]; then
target="$OOT_MODULE"
else
target="$VMLINUX"
fi
if [[ "$CONFIG_CC_IS_CLANG" -eq 0 ]]; then
gcc_version_check "$target" || die
else
clang_version_check "$target" || die
fi
fi
echo "Testing patch file(s)" echo "Testing patch file(s)"
cd "$SRCDIR" || die cd "$SRCDIR" || die
verify_patch_files verify_patch_files
@ -816,9 +857,27 @@ fi
echo "Building original source" echo "Building original source"
[[ -n "$OOT_MODULE" ]] || ./scripts/setlocalversion --save-scmversion || die [[ -n "$OOT_MODULE" ]] || ./scripts/setlocalversion --save-scmversion || die
unset KPATCH_GCC_TEMPDIR unset KPATCH_GCC_TEMPDIR
KPATCH_CC_PREFIX="$TOOLSDIR/kpatch-cc "
declare -a MAKEVARS
if [ "$CONFIG_CC_IS_CLANG" -eq 1 ]; then
MAKEVARS+=("CC=${KPATCH_CC_PREFIX}clang")
MAKEVARS+=("HOSTCC=clang")
else
MAKEVARS+=("CC=${KPATCH_CC_PREFIX}gcc")
fi
if [ "$CONFIG_LD_IS_LLD" -eq 1 ]; then
MAKEVARS+=("LD=${KPATCH_CC_PREFIX}ld.lld")
MAKEVARS+=("HOSTLD=ld.lld")
else
MAKEVARS+=("LD=${KPATCH_CC_PREFIX}ld")
fi
# $TARGETS used as list, no quotes. # $TARGETS used as list, no quotes.
# shellcheck disable=SC2086 # shellcheck disable=SC2086
CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make "-j$CPUS" $TARGETS 2>&1 | logger || die make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die
# Save original module symvers # Save original module symvers
cp -f "$SRCDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die cp -f "$SRCDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die
@ -832,9 +891,7 @@ KPATCH_GCC_SRCDIR="$SRCDIR"
export KPATCH_GCC_SRCDIR export KPATCH_GCC_SRCDIR
# $TARGETS used as list, no quotes. # $TARGETS used as list, no quotes.
# shellcheck disable=SC2086 # shellcheck disable=SC2086
CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ KBUILD_MODPOST_WARN=1 make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die
KBUILD_MODPOST_WARN=1 \
make "-j$CPUS" $TARGETS 2>&1 | logger || die
# source.c:(.section+0xFF): undefined reference to `symbol' # source.c:(.section+0xFF): undefined reference to `symbol'
grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \ grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \
@ -1026,10 +1083,16 @@ if [[ -z "$OOT_MODULE" ]]; then
else else
KPATCH_BUILD="/lib/modules/$ARCHVERSION/build" KPATCH_BUILD="/lib/modules/$ARCHVERSION/build"
fi fi
# We no longer need kpatch-cc
for ((idx=0; idx<${#MAKEVARS[@]}; idx++)); do
MAKEVARS[$idx]=${MAKEVARS[$idx]/${KPATCH_CC_PREFIX}/}
done
KPATCH_BUILD="$KPATCH_BUILD" KPATCH_NAME="$MODNAME" \ KPATCH_BUILD="$KPATCH_BUILD" KPATCH_NAME="$MODNAME" \
KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \ KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \
KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \
make 2>&1 | logger || die make "${MAKEVARS[@]}" 2>&1 | logger || die
if [[ "$USE_KLP" -eq 1 ]]; then if [[ "$USE_KLP" -eq 1 ]]; then
if [[ "$USE_KLP_ARCH" -eq 0 ]]; then if [[ "$USE_KLP_ARCH" -eq 0 ]]; then

View File

@ -13,7 +13,7 @@ fi
declare -a args=("$@") declare -a args=("$@")
if [[ "$TOOLCHAINCMD" =~ "gcc" ]] ; then if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; then
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
if [ "$1" = "-o" ]; then if [ "$1" = "-o" ]; then
obj="$2" obj="$2"
@ -61,7 +61,7 @@ if [[ "$TOOLCHAINCMD" =~ "gcc" ]] ; then
fi fi
shift shift
done done
elif [[ "$TOOLCHAINCMD" = "ld" ]] ; then elif [[ "$TOOLCHAINCMD" =~ ^(.*-)?ld || "$TOOLCHAINCMD" =~ ^(.*-)?ld.lld ]] ; then
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
if [ "$1" = "-o" ]; then if [ "$1" = "-o" ]; then
obj="$2" obj="$2"

View File

@ -54,12 +54,12 @@ effect.
--skip-cleanup --skip-cleanup
Skip post-build cleanup Skip post-build cleanup
--skip-gcc-check --skip-compiler-check
Skips check that ensures that the system gcc version and Skips check that ensures that the system compiler version and
the gcc version that built the kernel match. Skipping this the compiler version that built the kernel match. Skipping this
check is not recommended, but is useful if the exact gcc check is not recommended, but is useful if the exact compiler
version is not available or is not easily installed. Use version is not available or is not easily installed. Use
only when confident that the two versions of gcc output only when confident that the two versions of compiler output
identical objects for a given target. Otherwise, use of identical objects for a given target. Otherwise, use of
this option might result in unexpected changed objects this option might result in unexpected changed objects
being detected. being detected.