diff --git a/.gitignore b/.gitignore index 4524524..129fbb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /v0.9.4.tar.gz +/v0.9.7.tar.gz /kpatch-dnf-v0.4.tar.gz diff --git a/0100-kpatch-build-for-clang-use-.strtab-if-no-.shstrtab.patch b/0100-kpatch-build-for-clang-use-.strtab-if-no-.shstrtab.patch new file mode 100644 index 0000000..dc9a279 --- /dev/null +++ b/0100-kpatch-build-for-clang-use-.strtab-if-no-.shstrtab.patch @@ -0,0 +1,99 @@ +From 5f6c5965f117cb9b2b21749da49b22b23305d114 Mon Sep 17 00:00:00 2001 +From: Pete Swain +Date: Tue, 27 Sep 2022 15:56:06 -0400 +Subject: [PATCH 100/108] kpatch-build: for clang, use .strtab if no .shstrtab + +While gcc puts strings in .strtab and .shstrtab sections, +llvm toolchain just uses .strtab. + +Adapt kpatch to handle both styles. + +Signed-off-by: Pete Swain +Signed-off-by: Joe Lawrence [small changes] +--- + kpatch-build/kpatch-elf.c | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c +index 58dbe1a..c7d12ec 100644 +--- a/kpatch-build/kpatch-elf.c ++++ b/kpatch-build/kpatch-elf.c +@@ -607,7 +607,7 @@ void kpatch_create_shstrtab(struct kpatch_elf *kelf) + + shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); + if (!shstrtab) +- ERROR("find_section_by_name"); ++ return; + + /* determine size of string table */ + size = 1; /* for initial NULL terminator */ +@@ -648,7 +648,7 @@ void kpatch_create_shstrtab(struct kpatch_elf *kelf) + + void kpatch_create_strtab(struct kpatch_elf *kelf) + { +- struct section *strtab; ++ struct section *strtab, *shstrtab; + struct symbol *sym; + size_t size = 0, offset = 0, len; + char *buf; +@@ -657,6 +657,8 @@ void kpatch_create_strtab(struct kpatch_elf *kelf) + if (!strtab) + ERROR("find_section_by_name"); + ++ shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); ++ + /* determine size of string table */ + list_for_each_entry(sym, &kelf->symbols, list) { + if (sym->type == STT_SECTION) +@@ -664,6 +666,15 @@ void kpatch_create_strtab(struct kpatch_elf *kelf) + size += strlen(sym->name) + 1; /* include NULL terminator */ + } + ++ /* and when covering for missing .shstrtab ... */ ++ if (!shstrtab) { ++ /* factor out into common (sh)strtab feeder */ ++ struct section *sec; ++ ++ list_for_each_entry(sec, &kelf->sections, list) ++ size += strlen(sec->name) + 1; /* include NULL terminator */ ++ } ++ + /* allocate data buffer */ + buf = malloc(size); + if (!buf) +@@ -682,8 +693,20 @@ void kpatch_create_strtab(struct kpatch_elf *kelf) + offset += len; + } + ++ if (!shstrtab) { ++ struct section *sec; ++ ++ /* populate string table and link with section header */ ++ list_for_each_entry(sec, &kelf->sections, list) { ++ len = strlen(sec->name) + 1; ++ sec->sh.sh_name = (unsigned int)offset; ++ memcpy(buf + offset, sec->name, len); ++ offset += len; ++ } ++ } ++ + if (offset != size) +- ERROR("shstrtab size mismatch"); ++ ERROR("strtab size mismatch"); + + strtab->data->d_buf = buf; + strtab->data->d_size = size; +@@ -928,7 +951,9 @@ void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile, + + shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); + if (!shstrtab) +- ERROR("missing .shstrtab section"); ++ shstrtab = find_section_by_name(&kelf->sections, ".strtab"); ++ if (!shstrtab) ++ ERROR("missing .shstrtab, .strtab sections"); + + ehout.e_shstrndx = (unsigned short)shstrtab->index; + +-- +2.37.3 + diff --git a/0101-create-diff-object-ignore-clang-s-.llvm_addrsig-sect.patch b/0101-create-diff-object-ignore-clang-s-.llvm_addrsig-sect.patch new file mode 100644 index 0000000..02a0ea9 --- /dev/null +++ b/0101-create-diff-object-ignore-clang-s-.llvm_addrsig-sect.patch @@ -0,0 +1,29 @@ +From 37040572440efb95db9a3193d3b51d7597e1badd Mon Sep 17 00:00:00 2001 +From: Pete Swain +Date: Tue, 27 Sep 2022 15:56:06 -0400 +Subject: [PATCH 101/108] create-diff-object: ignore clang's .llvm_addrsig + sections + +Signed-off-by: Pete Swain +Signed-off-by: Joe Lawrence [subject line] +--- + kpatch-build/create-diff-object.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 918d21c..fa7e07f 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2717,7 +2717,8 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) + /* Ignore any discarded sections */ + list_for_each_entry(sec, &kelf->sections, list) { + if (!strncmp(sec->name, ".discard", 8) || +- !strncmp(sec->name, ".rela.discard", 13)) ++ !strncmp(sec->name, ".rela.discard", 13) || ++ !strncmp(sec->name, ".llvm_addrsig", 13)) + sec->ignore = 1; + } + +-- +2.37.3 + diff --git a/0102-create-diff-object-ignore-.llvm.-sections.patch b/0102-create-diff-object-ignore-.llvm.-sections.patch new file mode 100644 index 0000000..5deef12 --- /dev/null +++ b/0102-create-diff-object-ignore-.llvm.-sections.patch @@ -0,0 +1,32 @@ +From 85781b7ea79fb4122efbb51f0bf573ed5fab03e1 Mon Sep 17 00:00:00 2001 +From: Pete Swain +Date: Tue, 27 Sep 2022 15:56:06 -0400 +Subject: [PATCH 102/108] create-diff-object: ignore .llvm.* sections + +Clang FDO adds a new, ignorable ELF section, .llvm.call-graph-profile + +Generalize to ignore all .llvm.* + +Signed-off-by: Pete Swain +Signed-off-by: Joe Lawrence [subject line] +--- + kpatch-build/create-diff-object.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index fa7e07f..cdcc13b 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2718,7 +2718,8 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) + list_for_each_entry(sec, &kelf->sections, list) { + if (!strncmp(sec->name, ".discard", 8) || + !strncmp(sec->name, ".rela.discard", 13) || +- !strncmp(sec->name, ".llvm_addrsig", 13)) ++ !strncmp(sec->name, ".llvm_addrsig", 13) || ++ !strncmp(sec->name, ".llvm.", 6)) + sec->ignore = 1; + } + +-- +2.37.3 + diff --git a/0103-gcc-plugin-update-headers-for-gcc-12.patch b/0103-gcc-plugin-update-headers-for-gcc-12.patch new file mode 100644 index 0000000..ac3745c --- /dev/null +++ b/0103-gcc-plugin-update-headers-for-gcc-12.patch @@ -0,0 +1,49 @@ +From 13182e50b027c70bd63f53ca43598557d6b41e2e Mon Sep 17 00:00:00 2001 +From: Joe Lawrence +Date: Tue, 27 Sep 2022 16:41:48 -0400 +Subject: [PATCH 103/108] gcc-plugin: update headers for gcc-12 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix build error seen on gcc (GCC) 12.1.1 20220507 (Red Hat 12.1.1-1): + + g++ -MMD -MP -I../kmod/patch -Iinsn -Wall -Wsign-compare -Wno-sign-conversion -g -Werror -shared -I/usr/lib/gcc/ppc64le-redhat-linux/12/plugin/include -Igcc-plugins -fPIC -fno-rtti -O2 -Wall gcc-plugins/ppc64le-plugin.c -o gcc-plugins/ppc64le-plugin.so + In file included from /usr/include/features.h:490, + from /usr/include/bits/libc-header-start.h:33, + from /usr/include/stdio.h:27, + from /usr/lib/gcc/ppc64le-redhat-linux/12/plugin/include/system.h:46, + from /usr/lib/gcc/ppc64le-redhat-linux/12/plugin/include/gcc-plugin.h:28, + from gcc-plugins/gcc-common.h:6, + from gcc-plugins/ppc64le-plugin.c:1: + /usr/include/bits/error-ldbl.h:23:1: error: type of ‘error’ is unknown + 23 | __LDBL_REDIR_DECL (error) + | ^~~~~~~~~~~~~~~~~ + /usr/include/bits/error-ldbl.h:23:1: error: ‘int error’ redeclared as different kind of entity + 23 | __LDBL_REDIR_DECL (error) + | ^~~~~~~~~~~~~~~~~ + In file included from gcc-plugins/ppc64le-plugin.c:2: + /usr/include/error.h:31:13: note: previous declaration ‘void error(int, int, const char*, ...)’ + 31 | extern void error (int __status, int __errnum, const char *__format, ...) + | ^~~~~ + make[1]: *** [Makefile:39: gcc-plugins/ppc64le-plugin.so] Error 1 + +Signed-off-by: Joe Lawrence +--- + kpatch-build/gcc-plugins/ppc64le-plugin.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kpatch-build/gcc-plugins/ppc64le-plugin.c b/kpatch-build/gcc-plugins/ppc64le-plugin.c +index e3ec20f..ba4a01e 100644 +--- a/kpatch-build/gcc-plugins/ppc64le-plugin.c ++++ b/kpatch-build/gcc-plugins/ppc64le-plugin.c +@@ -1,5 +1,5 @@ +-#include "gcc-common.h" + #include ++#include "gcc-common.h" + + #define PLUGIN_NAME "ppc64le-plugin" + +-- +2.37.3 + diff --git a/0104-kpatch-cc-Add-more-file-ignores.patch b/0104-kpatch-cc-Add-more-file-ignores.patch new file mode 100644 index 0000000..cf69849 --- /dev/null +++ b/0104-kpatch-cc-Add-more-file-ignores.patch @@ -0,0 +1,51 @@ +From 1ead10d2b214ec5545ee2cdb25d5b0cdb3b4f735 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Wed, 17 Aug 2022 12:10:39 -0700 +Subject: [PATCH 104/108] kpatch-cc: Add more file ignores + +These files aren't in the kernel proper, and can be ignored. + +Signed-off-by: Josh Poimboeuf +--- + kpatch-build/kpatch-cc | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/kpatch-build/kpatch-cc b/kpatch-build/kpatch-cc +index 6f0063e..d2bccdd 100755 +--- a/kpatch-build/kpatch-cc ++++ b/kpatch-build/kpatch-cc +@@ -31,22 +31,22 @@ if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; th + vmlinux.o|\ + .tmp_kallsyms1.o|\ + .tmp_kallsyms2.o|\ +- init/version.o|\ +- arch/x86/boot/version.o|\ +- arch/x86/boot/compressed/eboot.o|\ +- arch/x86/boot/header.o|\ +- arch/x86/boot/compressed/efi_stub_64.o|\ +- arch/x86/boot/compressed/piggy.o|\ +- kernel/system_certificates.o|\ +- arch/x86/vdso/*|\ ++ arch/x86/boot/*|\ + arch/x86/entry/vdso/*|\ +- drivers/firmware/efi/libstub/*|\ ++ arch/x86/purgatory/*|\ ++ arch/x86/realmode/*|\ ++ arch/x86/tools/*|\ ++ arch/x86/vdso/*|\ + arch/powerpc/kernel/prom_init.o|\ + arch/powerpc/kernel/vdso64/*|\ + arch/s390/boot/*|\ + arch/s390/purgatory/*|\ + arch/s390/kernel/vdso64/*|\ ++ drivers/firmware/efi/libstub/*|\ ++ init/version.o|\ ++ kernel/system_certificates.o|\ + lib/*|\ ++ tools/*|\ + .*.o|\ + */.lib_exports.o) + break +-- +2.37.3 + diff --git a/0105-kpatch-build-Add-find_kobj-short-circuit-for-OOT-mod.patch b/0105-kpatch-build-Add-find_kobj-short-circuit-for-OOT-mod.patch new file mode 100644 index 0000000..fef1169 --- /dev/null +++ b/0105-kpatch-build-Add-find_kobj-short-circuit-for-OOT-mod.patch @@ -0,0 +1,60 @@ +From 7861240f482aa41bfad41fbb57ac1990cd6b6960 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Wed, 17 Aug 2022 12:17:19 -0700 +Subject: [PATCH 105/108] kpatch-build: Add find_kobj() short-circuit for OOT + modules + +When patching an OOT module, the parent object is always the OOT module. +Hard-code that to prevent the need for any further special casing in +find_kobj() (e.g., commit 9143e88f16a1 ("kpatch-build: fix +find_parent_obj")). + +Signed-off-by: Josh Poimboeuf +--- + kpatch-build/kpatch-build | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 296fa48..5435a19 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -479,6 +479,12 @@ find_parent_obj() { + + find_kobj() { + arg="$1" ++ ++ if [[ -n $OOT_MODULE ]]; then ++ KOBJFILE="$OOT_MODULE" ++ return ++ fi ++ + KOBJFILE="$arg" + DEEP_FIND=0 + ERROR_IF_DIFF= +@@ -1093,17 +1099,17 @@ for i in $FILES; do + find_kobj "$i" + cd "$TEMPDIR" || die + if [[ -e "orig/$i" ]]; then +- if [[ "$(basename "$KOBJFILE")" = vmlinux ]]; then +- KOBJFILE_NAME=vmlinux +- KOBJFILE_PATH="$VMLINUX" +- SYMTAB="${TEMPDIR}/${KOBJFILE_NAME}.symtab" +- SYMVERS_FILE="$BUILDDIR/Module.symvers" +- elif [[ "$(basename "$KOBJFILE")" = "$(basename "$OOT_MODULE")" ]]; then ++ if [[ -n $OOT_MODULE ]]; then + KOBJFILE_NAME="$(basename --suffix=.ko "$OOT_MODULE")" + KOBJFILE_NAME="${KOBJFILE_NAME//-/_}" + KOBJFILE_PATH="$OOT_MODULE" + SYMTAB="${TEMPDIR}/module/${KOBJFILE_NAME}.symtab" + SYMVERS_FILE="$TEMPDIR/Module.symvers" ++ elif [[ "$(basename "$KOBJFILE")" = vmlinux ]]; then ++ KOBJFILE_NAME=vmlinux ++ KOBJFILE_PATH="$VMLINUX" ++ SYMTAB="${TEMPDIR}/${KOBJFILE_NAME}.symtab" ++ SYMVERS_FILE="$BUILDDIR/Module.symvers" + else + KOBJFILE_NAME=$(basename "${KOBJFILE%.ko}") + KOBJFILE_NAME="${KOBJFILE_NAME//-/_}" +-- +2.37.3 + diff --git a/0106-kpatch-build-support-Linux-5.19-.cmd-file-format.patch b/0106-kpatch-build-support-Linux-5.19-.cmd-file-format.patch new file mode 100644 index 0000000..94f1a7c --- /dev/null +++ b/0106-kpatch-build-support-Linux-5.19-.cmd-file-format.patch @@ -0,0 +1,299 @@ +From 1d7e8a74bb6c282ebe6c9193e4bd0218ec689e46 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Wed, 17 Aug 2022 12:21:04 -0700 +Subject: [PATCH 106/108] kpatch-build: support Linux 5.19 .cmd file format + +Rewrite kobj_find() to deal with Linux 5.19, where the .cmd files use +object file paths relative to the .cmd file rather than relative to the +root of the kernel tree. + +While at it, add several performance enhancements to prevent all +currently known deep finds. + +This is all quite fiddly. But it works. + +Fixes #1277. + +Signed-off-by: Josh Poimboeuf +--- + kpatch-build/kpatch-build | 243 +++++++++++++++++++++++++++++--------- + 1 file changed, 188 insertions(+), 55 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 5435a19..bec8010 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -434,82 +434,215 @@ find_special_section_data() { + return + } + +-filter_parent_obj() +-{ +- local dir="${1}" +- local file="${2}" ++# path of file, relative to dir ++# adapted from https://stackoverflow.com/a/24848739 ++relpath() { ++ local file="$1" ++ local dir="$2" ++ ++ local filedir ++ local common ++ local result ++ ++ filedir="$(dirname "$(readlink -f "$file")")" ++ common="$(readlink -f "$dir")" ++ ++ if [[ "$filedir" = "$common" ]]; then ++ basename "$file" ++ return ++ fi ++ ++ while [[ "${filedir#$common/}" = "$filedir" ]]; do ++ common="$(dirname "$common")" ++ result="../$result" ++ done + +- grep -v "\.mod\.cmd$" | grep -Fv "${dir}/.${file}.cmd" ++ result="${result}${filedir#$common/}" ++ echo "${result}/$(basename "$file")" + } + +-find_parent_obj() { +- dir="$(dirname "$1")" +- absdir="$(readlink -f "$dir")" +- pwddir="$(readlink -f .)" +- pdir="${absdir#$pwddir/}" +- file="$(basename "$1")" +- grepname="${1%.o}" +- grepname="$grepname\\.o" +- if [[ "$DEEP_FIND" -eq 1 ]]; then +- num=0 +- if [[ -n "$last_deep_find" ]]; then +- parent="$(grep -lw "$grepname" "$last_deep_find"/.*.cmd | filter_parent_obj "${pdir}" "${file}" | head -n1)" +- num="$(grep -lw "$grepname" "$last_deep_find"/.*.cmd | filter_parent_obj "${pdir}" "${file}" | wc -l)" ++cmd_file_to_o_file() { ++ local parent="$1" ++ ++ # convert cmd file name to corresponding .o ++ parent_dir="$(dirname "$parent")" ++ parent_dir="${parent_dir#./}" ++ parent="$(basename "$parent")" ++ parent="${parent#.}" ++ parent="${parent%.cmd}" ++ parent="$parent_dir/$parent" ++ ++ [[ -f $parent ]] || die "can't find $parent associated with $1" ++ ++ echo "$parent" ++} ++ ++get_parent_from_parents() { ++ local parents=("$@") ++ ++ [[ ${#parents[@]} -eq 0 ]] && PARENT="" && return ++ [[ ${#parents[@]} -eq 1 ]] && PARENT="${parents[0]}" && return ++ ++ # multiple parents: ++ local parent ++ local mod_name="${parents[0]%.*}" ++ local mod_file ++ for parent in "${parents[@]}"; do ++ # for modules, there can be multiple matches. Some ++ # combination of foo.o, foo.mod, and foo.ko, depending ++ # on kernel version and whether the module is single or ++ # multi-object. Make sure a .mod and/or .ko exists, and no ++ # more than one .mod/.ko exists. ++ ++ [[ $parent = *.o ]] && continue ++ ++ if [[ ${parent%.*} != "$mod_name" ]]; then ++ mod_file="" ++ break + fi +- if [[ "$num" -eq 0 ]]; then +- parent="$(find . -name ".*.cmd" -print0 | xargs -0 grep -lw "$grepname" | filter_parent_obj "${pdir}" "${file}" | cut -c3- | head -n1)" +- num="$(find . -name ".*.cmd" -print0 | xargs -0 grep -lw "$grepname" | filter_parent_obj "${pdir}" "${file}" | wc -l)" +- [[ "$num" -eq 1 ]] && last_deep_find="$(dirname "$parent")" ++ ++ if [[ $parent = *.mod || $parent = *.ko ]]; then ++ mod_file=$parent ++ continue + fi ++ ++ mod_file="" ++ break ++ done ++ ++ if [[ -n $mod_file ]]; then ++ PARENT="$mod_file" ++ return ++ fi ++ ++ ERROR_IF_DIFF="multiple parent matches for $file: ${parents[*]}" ++ PARENT="${parents[0]}" ++} ++ ++__find_parent_obj_in_dir() { ++ local file="$1" ++ local dir="$2" ++ ++ declare -a parents ++ ++ while IFS='' read -r parent; do ++ parent="$(cmd_file_to_o_file "$parent")" ++ [[ $parent -ef $file ]] && continue ++ parents+=("$parent") ++ done < <(grep -El "[ ]${file/./\\.}([ \)]|$)" "$dir"/.*.cmd) ++ ++ get_parent_from_parents "${parents[@]}" ++} ++ ++find_parent_obj_in_dir() { ++ local file="$1" ++ local dir="$2" ++ ++ # make sure the dir has .cmd files ++ if ! compgen -G "$dir"/.*.cmd > /dev/null; then ++ PARENT="" ++ return ++ fi ++ ++ # 5.19+: ../acp/acp_hw.o ++ __find_parent_obj_in_dir "$(relpath "$file" "$dir")" "$dir" ++ [[ -n $PARENT ]] && return ++ ++ # pre-5.19 (and 5.19+ single-object modules): ++ if [[ $file == $dir* ]]; then ++ # arch/x86/kernel/smp.o ++ __find_parent_obj_in_dir "$file" "$dir" + else +- parent="$(grep -lw "$grepname" "$dir"/.*.cmd | filter_parent_obj "${dir}" "${file}" | head -n1)" +- num="$(grep -lw "$grepname" "$dir"/.*.cmd | filter_parent_obj "${dir}" "${file}" | wc -l)" ++ # drivers/gpu/drm/amd/amdgpu/../acp/acp_hw.o ++ __find_parent_obj_in_dir "$dir"/"$(relpath "$file" "$dir")" "$dir" + fi ++} + +- [[ "$num" -eq 0 ]] && PARENT="" && return +- [[ "$num" -gt 1 ]] && ERROR_IF_DIFF="two parent matches for $1" ++find_parent_obj() { ++ local file="$1" ++ ++ # common case: look in same directory ++ find_parent_obj_in_dir "$file" "$(dirname "$file")" ++ [[ -n $PARENT ]] && return + +- dir="$(dirname "$parent")" +- PARENT="$(basename "$parent")" +- PARENT="${PARENT#.}" +- PARENT="${PARENT%.cmd}" +- [[ $dir != "." ]] && PARENT="$dir/$PARENT" +- [[ ! -e "$PARENT" ]] && die "ERROR: can't find parent $PARENT for $1" ++ # if we previously had a successful deep find, try that dir first ++ if [[ -n "$LAST_DEEP_FIND_DIR" ]]; then ++ find_parent_obj_in_dir "$file" "$LAST_DEEP_FIND_DIR" ++ [[ -n "$PARENT" ]] && return ++ fi ++ ++ # prevent known deep finds ++ if [[ $file = drivers/gpu/drm/amd/* ]]; then ++ find_parent_obj_in_dir "$file" "drivers/gpu/drm/amd/amdgpu" ++ [[ -n "$PARENT" ]] && return ++ fi ++ if [[ $file = virt/kvm/* ]]; then ++ find_parent_obj_in_dir "$file" "arch/x86/kvm" ++ [[ -n "$PARENT" ]] && return ++ fi ++ if [[ $file = drivers/oprofile/* ]]; then ++ find_parent_obj_in_dir "$file" "arch/x86/oprofile" ++ [[ -n "$PARENT" ]] && return ++ fi ++ ++ # check higher-level dirs ++ local dir ++ dir="$(dirname "$file")" ++ while [[ ! $dir -ef . ]]; do ++ dir="$(dirname "$dir")" ++ find_parent_obj_in_dir "$file" "$dir" ++ [[ -n $PARENT ]] && return ++ done ++ ++ # slow path: search the entire tree ("deep find") ++ echo 'doing "deep find" for parent object' ++ declare -a parents ++ while IFS= read -r -d '' dir; do ++ find_parent_obj_in_dir "$file" "$dir" ++ if [[ -n $PARENT ]]; then ++ parents+=("$PARENT") ++ LAST_DEEP_FIND_DIR="$dir" ++ fi ++ done < <(find . -type d -print0) ++ ++ get_parent_from_parents "${parents[@]}" + } + ++# find vmlinux or .ko associated with a .o file + find_kobj() { +- arg="$1" ++ local file="$1" + + if [[ -n $OOT_MODULE ]]; then + KOBJFILE="$OOT_MODULE" + return + fi + +- KOBJFILE="$arg" +- DEEP_FIND=0 ++ KOBJFILE="$file" + ERROR_IF_DIFF= + while true; do ++ case "$KOBJFILE" in ++ *.mod) ++ KOBJFILE=${PARENT/.mod/.ko} ++ [[ -e $KOBJFILE ]] || die "can't find .ko for $PARENT" ++ return ++ ;; ++ *.ko) ++ return ++ ;; ++ */built-in.o|\ ++ */built-in.a|\ ++ arch/x86/kernel/ebda.o|\ ++ arch/x86/kernel/head*.o|\ ++ arch/x86/kernel/platform-quirks.o|\ ++ arch/x86/lib/lib.a|\ ++ lib/lib.a) ++ KOBJFILE=vmlinux ++ return ++ ;; ++ esac ++ + find_parent_obj "$KOBJFILE" +- [[ -n "$PARENT" ]] && DEEP_FIND=0 +- if [[ -z "$PARENT" ]]; then +- [[ "$KOBJFILE" = *.ko ]] && return +- case "$KOBJFILE" in +- */built-in.o|\ +- */built-in.a|\ +- arch/x86/lib/lib.a|\ +- arch/x86/kernel/head*.o|\ +- arch/x86/kernel/ebda.o|\ +- arch/x86/kernel/platform-quirks.o|\ +- lib/lib.a) +- KOBJFILE=vmlinux +- return +- esac +- if [[ "$DEEP_FIND" -eq 0 ]]; then +- DEEP_FIND=1 +- continue; +- fi +- die "invalid ancestor $KOBJFILE for $arg" +- fi ++ [[ -z "$PARENT" ]] && die "invalid ancestor $KOBJFILE for $file" + KOBJFILE="$PARENT" + done + } +-- +2.37.3 + diff --git a/0107-create-diff-object-compare-section-name-with-kpatch_.patch b/0107-create-diff-object-compare-section-name-with-kpatch_.patch new file mode 100644 index 0000000..5d016ac --- /dev/null +++ b/0107-create-diff-object-compare-section-name-with-kpatch_.patch @@ -0,0 +1,52 @@ +From ce97c8ef720bd288fbc53aad51969571a1c2c1e6 Mon Sep 17 00:00:00 2001 +From: Song Liu +Date: Wed, 13 Oct 2021 00:10:20 -0700 +Subject: [PATCH 107/108] create-diff-object: compare section name with + kpatch_section_function_name + +Profile-Guided Optimization (PGO) uses profiling data to help the compiler +to evaluate the properties of a function, and thus adds different prefixes +to the section/function. For example, with -ffunction-sections, the +compiler will prefix some sectiones with .text.unlikely. However, if a +function changes from the version in the profiling data, the compiler may +ignore the profiling data. This often happens to the patched function +when kpatch-build builds the patch. As a result, the original function +and the patch function may have different prefix, i.e., one of them has +.text, the other has .text.unlikely. + +To correlate these functions properly, use kpatch_section_function_name() +in kpatch_correlate_sections() to find matching sections. + +Signed-off-by: Song Liu +--- + kpatch-build/create-diff-object.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 1967bd8..6f08c4d 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -986,6 +986,8 @@ static void kpatch_correlate_section(struct section *sec_orig, + kpatch_correlate_symbol(sec_orig->sym, sec_patched->sym); + } + ++static char *kpatch_section_function_name(struct section *sec); ++ + static void kpatch_correlate_sections(struct list_head *seclist_orig, + struct list_head *seclist_patched) + { +@@ -995,8 +997,9 @@ static void kpatch_correlate_sections(struct list_head *seclist_orig, + if (sec_orig->twin) + continue; + list_for_each_entry(sec_patched, seclist_patched, list) { +- if (kpatch_mangled_strcmp(sec_orig->name, sec_patched->name) || +- sec_patched->twin) ++ if (sec_patched->twin || ++ kpatch_mangled_strcmp(kpatch_section_function_name(sec_orig), ++ kpatch_section_function_name(sec_patched))) + continue; + + if (is_special_static(is_rela_section(sec_orig) ? +-- +2.37.3 + diff --git a/0108-kpatch-build-add-support-for-clang-pgo.patch b/0108-kpatch-build-add-support-for-clang-pgo.patch new file mode 100644 index 0000000..b88c922 --- /dev/null +++ b/0108-kpatch-build-add-support-for-clang-pgo.patch @@ -0,0 +1,73 @@ +From db5d32876a6c89454aab9e8e9412435fc5b3facd Mon Sep 17 00:00:00 2001 +From: Song Liu +Date: Wed, 13 Oct 2021 01:03:55 -0700 +Subject: [PATCH 108/108] kpatch-build: add support for clang pgo + +For clang with Profile-Guided Optimization (PGO), profile data is needed +to compile the livepatch properly. Add option -p|--profile-data, which +specifies the profile data file. This option is only valid with +CONFIG_CC_IS_CLANG and CONFIG_PGO_CLANG. + +Signed-off-by: Song Liu +--- + kpatch-build/kpatch-build | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index bec8010..13bccab 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -677,9 +677,10 @@ usage() { + echo " --skip-cleanup Skip post-build cleanup" >&2 + echo " --skip-compiler-check Skip compiler version matching check" >&2 + echo " (not recommended)" >&2 ++ echo " -p, --profile-data specify profile data for PGO (clang only)" >&2 + } + +-options="$(getopt -o ha:r:s:c:v:j:t:n:o:dR -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,oot-module-src:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup,non-replace" -- "$@")" || die "getopt failed" ++options="$(getopt -o ha:r:s:c:v:j:t:n:o:dRp: -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,oot-module-src:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup,non-replace,profile-data" -- "$@")" || die "getopt failed" + + eval set -- "$options" + +@@ -761,6 +762,10 @@ while [[ $# -gt 0 ]]; do + echo "WARNING: Skipping compiler version matching check (not recommended)" + SKIPCOMPILERCHECK=1 + ;; ++ -p|--profile-data) ++ PROFILE_DATA="$(readlink -f "$2")" ++ shift ++ ;; + *) + [[ "$1" = "--" ]] && shift && continue + [[ ! -f "$1" ]] && die "patch file '$1' not found" +@@ -1056,6 +1061,16 @@ fi + + if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then + echo "WARNING: Clang support is experimental" ++ if [[ -z "$PROFILE_DATA" ]] && [[ -n "$CONFIG_PGO_CLANG" ]]; then ++ die "Please specify profile-data for CONFIG_PGO_CLANG" ++ fi ++ if [[ -n "$PROFILE_DATA" ]] && [[ -z "$CONFIG_PGO_CLANG" ]]; then ++ echo "WARNING profile-data specified w/o CONFIG_PGO_CLANG, ignore it" ++ fi ++else ++ if [[ -n "$PROFILE_DATA" ]]; then ++ die "Only supports profile-data with Clang" ++ fi + fi + + if [[ "$SKIPCOMPILERCHECK" -eq 0 ]]; then +@@ -1107,6 +1122,10 @@ declare -a MAKEVARS + if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then + MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${CLANG}") + MAKEVARS+=("HOSTCC=clang") ++ if [[ -n "$CONFIG_PGO_CLANG" ]]; then ++ MAKEVARS+=("CFLAGS_PGO_CLANG=-fprofile-use=$PROFILE_DATA") ++ MAKEVARS+=("LLVM=1") ++ fi + else + MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${GCC}") + fi +-- +2.37.3 + diff --git a/kpatch.spec b/kpatch.spec index 0d4e72f..fbbcd37 100644 --- a/kpatch.spec +++ b/kpatch.spec @@ -1,8 +1,8 @@ %define kpatch_dnf_ver 0.4 Name: kpatch -Version: 0.9.4 -Release: 3%{?dist} +Version: 0.9.7 +Release: 1.1%{?dist} Summary: Dynamic kernel patch manager Group: System Environment/Kernel @@ -16,8 +16,16 @@ Patch0: 0001-contrib-disable-upstart-kpatch.conf-install.patch Patch1: 0002-kpatch-clarify-unload-unsupport.patch Patch2: 0003-do-not-rm-selinux-rpm-owned-directory.patch -# Upstream backports (inactive -- for future reference) -#Patch100: 0100-xxx.patch +# Upstream backports +Patch100: 0100-kpatch-build-for-clang-use-.strtab-if-no-.shstrtab.patch +Patch101: 0101-create-diff-object-ignore-clang-s-.llvm_addrsig-sect.patch +Patch102: 0102-create-diff-object-ignore-.llvm.-sections.patch +Patch103: 0103-gcc-plugin-update-headers-for-gcc-12.patch +Patch104: 0104-kpatch-cc-Add-more-file-ignores.patch +Patch105: 0105-kpatch-build-Add-find_kobj-short-circuit-for-OOT-mod.patch +Patch106: 0106-kpatch-build-support-Linux-5.19-.cmd-file-format.patch +Patch107: 0107-create-diff-object-compare-section-name-with-kpatch_.patch +Patch108: 0108-kpatch-build-add-support-for-clang-pgo.patch # kpatch-dnf backports (inactive -- for future reference) #Patch200: 0200-foo-bar-etcetera.patch @@ -67,7 +75,15 @@ kpatch-patch packages updates. %patch1 -p1 %patch2 -p1 # Use this to apply upstream patches to kpatch -#%patch100 -p1 +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 %setup -D -T -a 1 @@ -110,6 +126,10 @@ echo "To enable automatic kpatch-patch subscription, run:" echo -e "\t$ dnf kpatch auto" %changelog +* Tue Oct 25 2022 Davide Cavalca - 0.9.7-1.1 +- Update to 0.9.7 +- Backport patches for clang PGO + * Fri Jun 10 2022 Yannick Cote 0.9.4-3 - Do not rm selinux rpm owned directory (rhbz#2053413) diff --git a/sources b/sources index 0cf3072..670583b 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (v0.9.4.tar.gz) = 647509fb9772b7564c0533ea043a15a66e29d413e045258036e78890c1d9cb072622bf458dda9bd4a87fe0855522c9b6ec3761f9bb4ab7e08157a179abfbaa62 +SHA512 (v0.9.7.tar.gz) = c876d9b1e5f6e6ab858fa6f302e78152beb3e50cedd93f3c61ab6f747e32199b0601ad4a36d426d43d0e9a37d9bf1d6bbfddccc86df4b31d5e3e6edead6cded3 SHA512 (kpatch-dnf-v0.4.tar.gz) = d76b2ec5595e06fd560ae928f43ad275b4ce07574a1fc829d184d56c5f09a88ce0cb1d1b05e58eb53e6d934a879886b7f0149f782950d7856fbb99c61ce436c3