objtool,livepatch: klp-build livepatch module generation
Subsystems (14)
Josh Poimboeuf
maintainerv4 cover objtool,livepatch: klp-build livepatch module generation
Changes since v3 (https://lore.kernel.org/[email protected]):
- Get rid of the SHF_MERGE+SHF_WRITE toolchain shenanigans in favor of simple .discard.annotate_data annotations
- Fix potential double free in elf_create_reloc()
- Sync interval_tree_generic.h (Peter)
- Refactor prefix symbol creation error handling
- Rebase on tip/master and fix new issue (--checksum getting added with --noabs)
(v3..v4 diff below)
----
This series introduces new objtool features and a klp-build script to generate livepatch modules using a source .patch as input.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
Key improvements compared to kpatch-build:
- Integrated with objtool: Leverages objtool's existing control-flow graph analysis to help detect changed functions.
- Works on vmlinux.o: Supports late-linked objects, making it compatible with LTO, IBT, and similar.
- Simplified code base: ~3k fewer lines of code.
- Upstream: No more out-of-tree #ifdef hacks, far less cruft.
- Cleaner internals: Vastly simplified logic for symbol/section/reloc inclusion and special section extraction.
- Robust __LINE__ macro handling: Avoids false positive binary diffs caused by the __LINE__ macro by introducing a fix-patch-lines script which injects #line directives into the source .patch to preserve the original line numbers at compile time.
The primary user interface is the klp-build script which does the following:
- Builds an original kernel with -function-sections and -fdata-sections, plus objtool function checksumming.
- Applies the .patch file and rebuilds the kernel using the same options.
- Runs 'objtool klp diff' to detect changed functions and generate intermediate binary diff objects.
- Builds a kernel module which links the diff objects with some livepatch module init code (scripts/livepatch/init.c).
- Finalizes the livepatch module (aka work around linker wreckage) using 'objtool klp post-link'.
I've tested with a variety of patches on defconfig and Fedora-config kernels with both GCC and Clang.
These patches can also be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux.git klp-build-v3
Please test!
[1] https://github.com/dynup/kpatch
Josh Poimboeuf (63):
s390/vmlinux.lds.S: Prevent thunk functions from getting placed with
normal text
vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros x86/module: Improve relocation error messages
x86/kprobes: Remove STACK_FRAME_NON_STANDARD annotation
compiler: Tweak __UNIQUE_ID() naming
compiler.h: Make addressable symbols less of an eyesore
elfnote: Change ELFNOTE() to use __UNIQUE_ID()
kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
modpost: Ignore unresolved section bounds symbols x86/alternative: Refactor INT3 call emulation selftest
interval_tree: Sync interval_tree_generic.h with tools
interval_tree: Fix ITSTATIC usage for *_subtree_search()
objtool: Make find_symbol_containing() less arbitrary
objtool: Fix broken error handling in read_symbols()
objtool: Propagate elf_truncate_section() error in elf_write()
objtool: Remove error handling boilerplate
objtool: Add empty symbols to the symbol tree again
objtool: Fix interval tree insertion for zero-length symbols
objtool: Fix weak symbol detection
objtool: Fix x86 addend calculation
objtool: Fix __pa_symbol() relocation handling
objtool: Fix "unexpected end of section" warning for alternatives
objtool: Check for missing annotation entries in read_annotate()
objtool: Const string cleanup
objtool: Clean up compiler flag usage
objtool: Remove .parainstructions reference
objtool: Convert elf iterator macros to use 'struct elf'
objtool: Add section/symbol type helpers
objtool: Mark .cold subfunctions
objtool: Fix weak symbol hole detection for .cold functions
objtool: Mark prefix functions
objtool: Simplify reloc offset calculation in unwind_read_hints()
objtool: Avoid emptying lists for duplicate sections
objtool: Rename --Werror to --werror
objtool: Resurrect --backup option
objtool: Reindent check_options[]
objtool: Refactor add_jump_destinations()
objtool: Simplify special symbol handling in elf_update_symbol()
objtool: Generalize elf_create_symbol()
objtool: Generalize elf_create_section()
objtool: Add elf_create_data()
objtool: Add elf_create_reloc() and elf_init_reloc()
objtool: Add elf_create_file()
objtool: Add annotype() helper
objtool: Move ANNOTATE* macros to annotate.h
objtool: Add ANNOTATE_DATA_SPECIAL
x86/asm: Annotate special section entries
objtool: Unify STACK_FRAME_NON_STANDARD entry sizes objtool/klp: Add --checksum option to generate per-function checksums objtool/klp: Add --debug-checksum=<funcs> to show per-instruction
checksums
objtool/klp: Introduce klp diff subcommand for diffing object files objtool/klp: Add --debug option to show cloning decisions objtool/klp: Add post-link subcommand to finalize livepatch modules
objtool: Refactor prefix symbol creation code
objtool: Add base objtool support for livepatch modules
livepatch: Add CONFIG_KLP_BUILD
kbuild,objtool: Defer objtool validation step for CONFIG_KLP_BUILD livepatch/klp-build: Introduce fix-patch-lines script to avoid
__LINE__ diff noise
livepatch/klp-build: Add stub init code for livepatch modules livepatch/klp-build: Introduce klp-build script for generating
livepatch modules
livepatch/klp-build: Add --debug option to show cloning decisions livepatch/klp-build: Add --show-first-changed option to show function
divergence
livepatch: Introduce source code helpers for livepatch modules
MAINTAINERS | 3 +- arch/s390/include/asm/nospec-insn.h | 2 +- arch/s390/kernel/vmlinux.lds.S | 2 +- arch/x86/Kconfig | 1 + arch/x86/include/asm/alternative.h | 4 + arch/x86/include/asm/asm.h | 5 + arch/x86/include/asm/bug.h | 1 + arch/x86/include/asm/cpufeature.h | 1 + arch/x86/include/asm/jump_label.h | 1 + arch/x86/kernel/alternative.c | 51 +- arch/x86/kernel/kprobes/opt.c | 4 - arch/x86/kernel/module.c | 15 +- include/asm-generic/vmlinux.lds.h | 40 +- include/linux/annotate.h | 134 ++ include/linux/compiler.h | 8 +- include/linux/elfnote.h | 13 +- include/linux/init.h | 3 +- include/linux/interval_tree.h | 4 + include/linux/interval_tree_generic.h | 2 +- include/linux/livepatch.h | 25 +- include/linux/livepatch_external.h | 76 + include/linux/livepatch_helpers.h | 77 + include/linux/mm.h | 2 + include/linux/objtool.h | 96 +- include/linux/objtool_types.h | 2 + kernel/livepatch/Kconfig | 12 + kernel/livepatch/core.c | 8 +- scripts/Makefile.lib | 7 +- scripts/Makefile.vmlinux_o | 2 +- scripts/link-vmlinux.sh | 3 +- scripts/livepatch/fix-patch-lines | 79 + scripts/livepatch/init.c | 108 ++ scripts/livepatch/klp-build | 827 ++++++++ scripts/mod/modpost.c | 5 + scripts/module.lds.S | 22 +- tools/include/linux/interval_tree_generic.h | 10 +- tools/include/linux/livepatch_external.h | 76 + tools/include/linux/objtool_types.h | 2 + tools/include/linux/string.h | 14 + tools/objtool/Build | 4 +- tools/objtool/Makefile | 48 +- tools/objtool/arch/loongarch/decode.c | 6 +- tools/objtool/arch/loongarch/orc.c | 1 - tools/objtool/arch/powerpc/decode.c | 7 +- tools/objtool/arch/x86/decode.c | 63 +- tools/objtool/arch/x86/orc.c | 1 - tools/objtool/arch/x86/special.c | 2 +- tools/objtool/builtin-check.c | 96 +- tools/objtool/builtin-klp.c | 53 + tools/objtool/check.c | 875 +++++---- tools/objtool/elf.c | 781 ++++++-- tools/objtool/include/objtool/arch.h | 5 +- tools/objtool/include/objtool/builtin.h | 11 +- tools/objtool/include/objtool/check.h | 6 +- tools/objtool/include/objtool/checksum.h | 43 + .../objtool/include/objtool/checksum_types.h | 25 + tools/objtool/include/objtool/elf.h | 196 +- tools/objtool/include/objtool/endianness.h | 9 +- tools/objtool/include/objtool/klp.h | 35 + tools/objtool/include/objtool/objtool.h | 4 +- tools/objtool/include/objtool/util.h | 19 + tools/objtool/include/objtool/warn.h | 40 + tools/objtool/klp-diff.c | 1723 +++++++++++++++++ tools/objtool/klp-post-link.c | 168 ++ tools/objtool/objtool.c | 42 +- tools/objtool/orc_dump.c | 1 - tools/objtool/orc_gen.c | 9 +- tools/objtool/special.c | 14 +- tools/objtool/sync-check.sh | 2 + tools/objtool/weak.c | 7 + 70 files changed, 5152 insertions(+), 891 deletions(-) create mode 100644 include/linux/annotate.h create mode 100644 include/linux/livepatch_external.h create mode 100644 include/linux/livepatch_helpers.h create mode 100755 scripts/livepatch/fix-patch-lines create mode 100644 scripts/livepatch/init.c create mode 100755 scripts/livepatch/klp-build create mode 100644 tools/include/linux/livepatch_external.h create mode 100644 tools/objtool/builtin-klp.c create mode 100644 tools/objtool/include/objtool/checksum.h create mode 100644 tools/objtool/include/objtool/checksum_types.h create mode 100644 tools/objtool/include/objtool/klp.h create mode 100644 tools/objtool/include/objtool/util.h create mode 100644 tools/objtool/klp-diff.c create mode 100644 tools/objtool/klp-post-link.c
Signature · 1 line
2.50.0
arch/Kconfig +0 -3
@@ -1368,9 +1368,6 @@ config HAVE_NOINSTR_HACK config HAVE_NOINSTR_VALIDATION bool -config NEED_MODULE_PERMISSIONS_FIX - bool - config HAVE_UACCESS_VALIDATION bool select OBJTOOL
arch/um/include/asm/Kbuild +1 -0
@@ -5,6 +5,7 @@ generic-y += device.h generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h +generic-y += extable.h generic-y += ftrace.h generic-y += hw_irq.h generic-y += irq_regs.h
arch/um/include/shared/common-offsets.h +0 -3
@@ -18,6 +18,3 @@ DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC);DEFINE (UM_KERN_GDT_ENTRY_TLS_ENTRIES ,GDT_ENTRY_TLS_ENTRIES );DEFINE (UM_SECCOMP_ARCH_NATIVE ,SECCOMP_ARCH_NATIVE ); - -DEFINE (ALT_INSTR_SIZE ,sizeof (struct alt_instr )); -DEFINE (EXTABLE_SIZE ,sizeof (struct exception_table_entry ));
arch/x86/Kconfig +0 -1
@@ -305,7 +305,6 @@ config X86 select HOTPLUG_SPLIT_STARTUP if SMP && X86_32 select IRQ_FORCED_THREADING select LOCK_MM_AND_FIND_VMA - select NEED_MODULE_PERMISSIONS_FIX select NEED_PER_CPU_EMBED_FIRST_CHUNK select NEED_PER_CPU_PAGE_FIRST_CHUNK select NEED_SG_DMA_LENGTH
arch/x86/include/asm/alternative.h +6 -3
@@ -197,8 +197,8 @@ static inline int alternatives_text_reserved(void *start, void *end) "773:\n"#define ALTINSTR_ENTRY (ft_flags) \ - ".pushsection .altinstructions, \"aM\", @progbits, " \ - __stringify(ALT_INSTR_SIZE) "\n" \ + ".pushsection .altinstructions,\"a\"\n" \ + ANNOTATE_DATA_SPECIAL \ " .long 771b - .\n"/* label */ \" .long 774f - .\n" /* new instruction */ \ " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
@@ -208,6 +208,7 @@ static inline int alternatives_text_reserved(void *start, void *end)#define ALTINSTR_REPLACEMENT (newinstr)/* replacement */ \ ".pushsection .altinstr_replacement, \"ax\"\n" \ + ANNOTATE_DATA_SPECIAL \ "# ALT: replacement\n" \ "774:\n\t" newinstr "\n775:\n" \ ".popsection\n"
@@ -338,6 +339,7 @@ void nop_func(void);* instruction. See apply_alternatives(). */ .macro altinstr_entry orig alt ft_flags orig_len alt_len + ANNOTATE_DATA_SPECIAL .long \orig - . .long \alt - . .4byte \ft_flags
@@ -361,11 +363,12 @@ void nop_func(void); 741: \ .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\ 742: \ - .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE ;\ + .pushsection .altinstructions,"a" ; \altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \ .popsection ; \ .pushsection .altinstr_replacement," ax" ; \ 743: \ +ANNOTATE_DATA_SPECIAL ; \ newinst ; \ 744: \ .popsection ;
arch/x86/include/asm/asm.h +13 -14
@@ -2,6 +2,8 @@#ifndef _ASM_X86_ASM_H#define _ASM_X86_ASM_H +#include <linux/annotate.h> +#ifdef __ASSEMBLER__# define __ASM_FORM (x, ...) x,## __VA_ARGS__# define __ASM_FORM_RAW (x, ...) x,## __VA_ARGS__
@@ -124,21 +126,18 @@ static __always_inline __pure void *rip_rel_ptr(void *p)#ifdef __KERNEL__ -#ifndef COMPILE_OFFSETS -#include <asm/asm-offsets.h> -#endif -# include <asm/extable_fixup_types.h> /* Exception table entry */ #ifdef __ASSEMBLER__ -# define _ASM_EXTABLE_TYPE (from, to, type) \ - .pushsection "__ex_table", "aM", @progbits, EXTABLE_SIZE; \ - .balign 4 ; \ - .long (from) - . ; \ - .long (to) - . ; \ - .long type ; \ +# define _ASM_EXTABLE_TYPE (from, to, type) \ + .pushsection "__ex_table","a" ; \ + .balign 4 ; \ + ANNOTATE_DATA_SPECIAL ; \ + .long (from) - . ; \ + .long (to) - . ; \ + .long type ; \ .popsection# ifdef CONFIG_KPROBES
@@ -181,18 +180,18 @@ static __always_inline __pure void *rip_rel_ptr(void *p) ".purgem extable_type_reg\n"# define _ASM_EXTABLE_TYPE (from, to, type) \ - " .pushsection __ex_table, \"aM\", @progbits, " \ - __stringify(EXTABLE_SIZE) "\n" \ + " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ " .long " __stringify(type) " \n" \ " .popsection\n"# define _ASM_EXTABLE_TYPE_REG (from, to, type, reg) \ - " .pushsection __ex_table, \"aM\", @progbits, " \ - __stringify(EXTABLE_SIZE) "\n" \ + " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ DEFINE_EXTABLE_TYPE_REG \
arch/x86/include/asm/bug.h +2 -1
@@ -56,7 +56,8 @@#define _BUG_FLAGS_ASM (ins, file, line, flags, size, extra) \ "1:\t" ins "\n" \ - ".pushsection __bug_table, \"aM\", @progbits, " size "\n" \ + ".pushsection __bug_table,\"aw\"\n" \ + ANNOTATE_DATA_SPECIAL \ __BUG_ENTRY(file, line, flags) \ "\t.org 2b + " size "\n" \ ".popsection\n" \
arch/x86/include/asm/cpufeature.h +1 -0
@@ -101,6 +101,7 @@ static __always_inline bool _static_cpu_has(u16 bit) asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]")".pushsection .altinstr_aux,\"ax\"\n" "6:\n" +ANNOTATE_DATA_SPECIAL " testb %[bitnum], %a[cap_byte]\n" " jnz %l[t_yes]\n" " jmp %l[t_no]\n"
arch/x86/include/asm/jump_label.h +7 -11
@@ -12,17 +12,13 @@#include <linux/stringify.h> #include <linux/types.h> -#ifndef COMPILE_OFFSETS -#include <generated/bounds.h> -#endif - -#define JUMP_TABLE_ENTRY (key, label) \ - ".pushsection __jump_table, \"aM\", @progbits, " \ - __stringify(JUMP_ENTRY_SIZE) "\n\t" \ - _ASM_ALIGN "\n\t" \ - ".long 1b - . \n\t" \ - ".long " label " - . \n\t" \ - _ASM_PTR " " key " - . \n\t" \ +#define JUMP_TABLE_ENTRY (key, label) \ + ".pushsection __jump_table, \"aw\" \n\t" \ + _ASM_ALIGN "\n\t" \ + ANNOTATE_DATA_SPECIAL \ + ".long 1b - . \n\t" \ + ".long " label " - . \n\t" \ + _ASM_PTR " " key " - . \n\t" \ ".popsection \n\t"/* This macro is also expanded on the Rust side. */
arch/x86/include/asm/static_call.h +1 -2
@@ -58,8 +58,7 @@ ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)#define ARCH_ADD_TRAMP_KEY (name) \ - asm(".pushsection .static_call_tramp_key, \"aM\", @progbits, " \ - __stringify(STATIC_CALL_TRAMP_KEY_SIZE) "\n" \ + asm(".pushsection .static_call_tramp_key, \"a\" \n" \ ".long " STATIC_CALL_TRAMP_STR(name) " - . \n" \ ".long " STATIC_CALL_KEY_STR(name) " - . \n" \ ".popsection \n")
arch/x86/kernel/asm-offsets.c +0 -3
@@ -124,7 +124,4 @@ static void __used common(void)OFFSET (ARIA_CTX_rounds, aria_ctx, rounds);#endif -BLANK (); -DEFINE (ALT_INSTR_SIZE ,sizeof (struct alt_instr )); -DEFINE (EXTABLE_SIZE ,sizeof (struct exception_table_entry )); }
arch/x86/um/shared/sysdep/kernel-offsets.h +0 -2
@@ -1,5 +1,4 @@/* SPDX-License-Identifier: GPL-2.0 */ -#define COMPILE_OFFSETS #include <linux/stddef.h> #include <linux/sched.h> #include <linux/elf.h>
@@ -8,7 +7,6 @@#include <linux/audit.h> #include <asm/mman.h> #include <asm/seccomp.h> -#include <asm/extable.h> /* workaround for a warning with -Wmissing-prototypes */ void foo (void );
include/linux/annotate.h new file +134 -0
134 lines not on this page · raw message
include/linux/interval_tree.h +4 -0
@@ -19,6 +19,10 @@ extern void interval_tree_remove(struct interval_tree_node *node, struct rb_root_cached *root); +extern struct interval_tree_node * +interval_tree_subtree_search (struct interval_tree_node *node, +unsigned long start,unsigned long last); +extern struct interval_tree_node *interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last);
include/linux/interval_tree_generic.h +1 -1
@@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \* Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \while (true) { \
include/linux/livepatch_helpers.h +0 -2
@@ -36,8 +36,6 @@__PASTE (__KLP_POST_UNPATCH_PREFIX,KLP_OBJNAME ) = func/* -* KLP_STATIC_CALL -* * Replace static_call() usage with this macro when create-diff-object * recommends it due to the original static call key living in a module. *
include/linux/mm.h +2 -0
@@ -3265,6 +3265,8 @@ void vma_interval_tree_insert_after(struct vm_area_struct *node, struct rb_root_cached *root);void vma_interval_tree_remove (struct vm_area_struct *node,struct rb_root_cached *root); +struct vm_area_struct *vma_interval_tree_subtree_search (struct vm_area_struct *node, +unsigned long start,unsigned long last);struct vm_area_struct *vma_interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last); struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node,
include/linux/objtool.h +5 -96
148 lines not on this page · raw message
include/linux/objtool_types.h +2 -0
@@ -67,4 +67,6 @@ struct unwind_hint {#define ANNOTYPE_REACHABLE 8#define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 +#endif /* _LINUX_OBJTOOL_TYPES_H */
include/linux/static_call.h +6 -0
@@ -172,6 +172,12 @@ struct static_call_mod {struct static_call_site *sites; }; +/* For finding the key associated with a trampoline */ +struct static_call_tramp_key { +s32 tramp; +s32 key; +}; +extern void __static_call_update (struct static_call_key *key,void *tramp,void *func);extern int static_call_mod_init (struct module *mod);extern int static_call_text_reserved (void *start,void *end);
include/linux/static_call_types.h +0 -6
@@ -34,12 +34,6 @@ struct static_call_site {s32 key; }; -/* For finding the key associated with a trampoline */ -struct static_call_tramp_key { -s32 tramp; -s32 key; -}; -#define DECLARE_STATIC_CALL (name, func) \ extern struct static_call_key STATIC_CALL_KEY(name); \ extern typeof(func) STATIC_CALL_TRAMP(name);
kernel/bounds.c +0 -13
@@ -6,16 +6,12 @@*/ #define __GENERATING_BOUNDS_H -#define COMPILE_OFFSETS /* Include headers that define the enum constants of interest */ #include <linux/page-flags.h> #include <linux/mmzone.h> #include <linux/kbuild.h> #include <linux/log2.h> #include <linux/spinlock_types.h> -#include <linux/jump_label.h> -#include <linux/static_call_types.h> -#include <linux/objtool_types.h> int main (void ) {
@@ -32,15 +28,6 @@ int main(void)#else DEFINE (LRU_GEN_WIDTH ,0 );DEFINE (__LRU_REFS_WIDTH,0 ); -#endif -#if defined(CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE ) && defined(CONFIG_JUMP_LABEL ) -DEFINE (JUMP_ENTRY_SIZE ,sizeof (struct jump_entry )); -#endif -#ifdef CONFIG_HAVE_STATIC_CALL_INLINE -DEFINE (STATIC_CALL_TRAMP_KEY_SIZE ,sizeof (struct static_call_tramp_key )); -#endif -#ifdef CONFIG_OBJTOOL -DEFINE (UNWIND_HINT_SIZE ,sizeof (struct unwind_hint ));#endif /* End of constants */
scripts/Makefile.lib +1 -0
@@ -173,6 +173,7 @@ ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool +objtool-args-$(CONFIG_KLP_BUILD) += --checksum objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) += --hacks=skylake
scripts/Makefile.modfinal +5 -14
@@ -28,24 +28,12 @@ ccflags-remove-y := $(CC_FLAGS_CFI) .module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_rule,cc_o_c) -ifdef CONFIG_NEED_MODULE_PERMISSIONS_FIX -cmd_fix_mod_permissions = \ - $(OBJCOPY) --set-section-flags __jump_table=alloc,data \ - --set-section-flags __bug_table=alloc,data $@ \ - --set-section-flags .static_call_sites=alloc,data $@ -endif - quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^) -define rule_ld_ko_o - $(call cmd_and_savecmd,ld_ko_o) - $(call cmd,fix_mod_permissions) -endef - quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ if [ ! -f $(objtree)/vmlinux ]; then \
@@ -58,11 +46,14 @@ quiet_cmd_btf_ko = BTF [M] $@ # Same as newer-prereqs, but allows to exclude specified extra dependencies newer_prereqs_except = $(filter-out $(PHONY) $(1),$?) -if_changed_rule_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check),$(rule_$(1)),@:) +# Same as if_changed, but allows to exclude specified extra dependencies +if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ + $(cmd); \ + printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) # Re-generate module BTFs if either module's .ko or vmlinux changed %.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE - +$(call if_changed_rule_except,ld_ko_o,$(objtree)/vmlinux) + +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif
scripts/livepatch/klp-build +2 -6
@@ -489,11 +489,8 @@ clean_kernel() { build_kernel() { local log="$TMP_DIR/build.log" - local objtool_args=() local cmd=() - objtool_args=("--checksum") - cmd=("make") # When a patch to a kernel module references a newly created unexported
@@ -516,7 +513,6 @@ build_kernel() { cmd+=("$VERBOSE") cmd+=("-j$JOBS") cmd+=("KCFLAGS=-ffunction-sections -fdata-sections") - cmd+=("OBJTOOL_ARGS=${objtool_args[*]}") cmd+=("vmlinux") cmd+=("modules")
@@ -794,7 +790,7 @@ process_args "$@" do_init if (( SHORT_CIRCUIT <= 1 )); then - status "Validating patches" + status "Validating patch(es)" validate_patches status "Building original kernel" clean_kernel
@@ -804,7 +800,7 @@ if (( SHORT_CIRCUIT <= 1 )); then fi if (( SHORT_CIRCUIT <= 2 )); then - status "Fixing patches" + status "Fixing patch(es)" fix_patches apply_patches status "Building patched kernel"
scripts/mod/devicetable-offsets.c +0 -1
@@ -1,5 +1,4 @@// SPDX-License-Identifier: GPL-2.0 -#define COMPILE_OFFSETS #include <linux/kbuild.h> #include <linux/mod_devicetable.h>
tools/include/linux/interval_tree_generic.h +2 -6
@@ -104,12 +104,8 @@ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \if (ITSTART (node) <= last) {/* Cond1 */ \if (start <=ITLAST (node))/* Cond2 */ \return node;/* node is leftmost match */ \ -if (node->ITRB.rb_right) { \ - node =rb_entry (node->ITRB.rb_right, \ -ITSTRUCT ,ITRB ); \ -if (start <= node->ITSUBTREE) \ -continue ; \ - } \ + node =rb_entry (node->ITRB.rb_right,ITSTRUCT ,ITRB ); \ +continue ; \ } \return NULL ;/* No match */ \ } \
tools/include/linux/objtool_types.h +2 -0
@@ -67,4 +67,6 @@ struct unwind_hint {#define ANNOTYPE_REACHABLE 8#define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 +#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/include/linux/static_call_types.h +0 -6
@@ -34,12 +34,6 @@ struct static_call_site {s32 key; }; -/* For finding the key associated with a trampoline */ -struct static_call_tramp_key { -s32 tramp; -s32 key; -}; -#define DECLARE_STATIC_CALL (name, func) \ extern struct static_call_key STATIC_CALL_KEY(name); \ extern typeof(func) STATIC_CALL_TRAMP(name);
tools/objtool/arch/loongarch/orc.c +0 -1
@@ -5,7 +5,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry (struct orc_entry *orc,struct cfi_state *cfi,struct instruction *insn) {
tools/objtool/arch/powerpc/decode.c +0 -1
@@ -7,7 +7,6 @@#include <objtool/arch.h> #include <objtool/warn.h> #include <objtool/builtin.h> -#include <objtool/endianness.h> int arch_ftrace_match (const char *name) {
tools/objtool/arch/x86/decode.c +0 -1
@@ -19,7 +19,6 @@#include <objtool/elf.h> #include <objtool/arch.h> #include <objtool/warn.h> -#include <objtool/endianness.h> #include <objtool/builtin.h> #include <arch/elf.h>
tools/objtool/arch/x86/orc.c +0 -1
@@ -5,7 +5,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry (struct orc_entry *orc,struct cfi_state *cfi,struct instruction *insn) {
tools/objtool/builtin-check.c +1 -2
@@ -74,7 +74,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)static const struct option check_options[] = {OPT_GROUP ("Actions:" ),OPT_BOOLEAN (0 ,"checksum" , &opts.checksum,"generate per-function checksums" ), -OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ), +OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ),OPT_CALLBACK_OPTARG ('h' ,"hacks" ,NULL ,NULL ,"jump_label,noinstr,skylake" ,"patch toolchain bugs/limitations" , parse_hacks),OPT_BOOLEAN ('i' ,"ibt" , &opts.ibt,"validate and annotate IBT" ),OPT_BOOLEAN ('m' ,"mcount" , &opts.mcount,"annotate mcount/fentry calls for ftrace" ),
@@ -162,7 +162,6 @@ static bool opts_valid(void)return false; } -#ifndef BUILD_KLP if (opts.checksum) {ERROR ("--checksum not supported; install xxhash-devel and recompile" );
tools/objtool/check.c +60 -41
178 lines not on this page · raw message
tools/objtool/elf.c +29 -34
90 lines not on this page · raw message
tools/objtool/include/objtool/builtin.h +1 -1
@@ -10,6 +10,7 @@struct opts {/* actions: */ bool cfi; +bool checksum;bool dump_orc;bool hack_jump_label;bool hack_noinstr;
@@ -25,7 +26,6 @@ struct opts {bool sls;bool stackval;bool static_call; -bool checksum;bool uaccess;int prefix;
tools/objtool/include/objtool/elf.h +17 -6
@@ -14,12 +14,15 @@#include <linux/rbtree.h> #include <linux/jhash.h> +#include <objtool/endianness.h> #include <objtool/checksum_types.h> #include <arch/elf.h> #define SEC_NAME_LEN 1024#define SYM_NAME_LEN 512 +#define bswap_if_needed (elf, val) __bswap_if_needed(&elf->ehdr, val) +#ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum# define elf_getshdrstrndx elf_getshstrndx
@@ -146,8 +149,6 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name, unsigned int type, unsigned long offset, size_t size);struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec); -struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig, -size_t size);void *elf_add_data (struct elf *elf,struct section *sec,const void *data,size_t size);
@@ -274,7 +275,7 @@ static inline bool is_local_sym(struct symbol *sym)static inline bool is_prefix_func (struct symbol *sym) { -return is_func_sym (sym) && sym->prefix; +return sym->prefix; }static inline bool is_reloc_sec (struct section *sec)
@@ -414,6 +415,15 @@ static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsignedmark_sec_changed (elf, reloc->sec, true); } +static inline unsigned int annotype (struct elf *elf,struct section *sec, +struct reloc *reloc) +{ +unsigned int type; + + type = *(u32 *)(sec->data->d_buf + (reloc_idx (reloc) *8 ) +4 ); +return bswap_if_needed (elf, type); +} +#define RELOC_JUMP_TABLE_BIT 1UL/* Does reloc mark the beginning of a jump table? */
@@ -445,9 +455,6 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)#define sec_for_each_sym (sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) -#define sec_for_each_sym_continue_reverse (sec, sym) \ - list_for_each_entry_continue_reverse(sym, &sec->symbol_list, list) -#define sec_prev_sym (sym) \ sym->sec && sym->list.prev != &sym->sec->symbol_list ? \ list_prev_entry(sym, list) : NULL
@@ -467,6 +474,10 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)#define for_each_reloc_from (rsec, reloc) \ for (; reloc; reloc = rsec_next_reloc(rsec, reloc)) +#define for_each_reloc_continue (rsec, reloc) \ + for (reloc = rsec_next_reloc(rsec, reloc); reloc; \ + reloc = rsec_next_reloc(rsec, reloc)) +#define sym_for_each_reloc (elf, sym, reloc) \ for (reloc = find_reloc_by_dest_range(elf, sym->sec, \ sym->offset, sym->len); \
tools/objtool/include/objtool/endianness.h +4 -5
@@ -4,7 +4,6 @@#include <linux/kernel.h> #include <endian.h> -#include <objtool/elf.h> /* * Does a byte swap if target file endianness doesn't match the host, i.e. cross
@@ -12,16 +11,16 @@* To be used for multi-byte values conversion, which are read from / about * to be written to a target native endianness ELF file. */ -static inline bool need_bswap (struct elf *elf) +static inline bool need_bswap (GElf_Ehdr *ehdr) {return (__BYTE_ORDER == __LITTLE_ENDIAN) ^ - (elf->ehdr.e_ident[EI_DATA ] ==ELFDATA2LSB ); + (ehdr->e_ident[EI_DATA ] ==ELFDATA2LSB ); } -#define bswap_if_needed (elf, val) \ +#define __bswap_if_needed (ehdr, val) \ ({ \ __typeof__(val) __ret; \ - bool __need_bswap = need_bswap(elf); \ + bool __need_bswap = need_bswap(ehdr); \ switch (sizeof(val)) { \ case 8: \ __ret = __need_bswap ? bswap_64(val) : (val); break; \
tools/objtool/include/objtool/objtool.h +0 -2
@@ -14,8 +14,6 @@#define __weak __attribute__((weak)) -#define SYM_CHECKSUM_SEC ".discard.sym_checksum" -struct pv_state {bool clean;struct list_head targets;
tools/objtool/klp-diff.c +138 -92
277 lines not on this page · raw message
tools/objtool/orc_dump.c +0 -1
@@ -8,7 +8,6 @@#include <objtool/objtool.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int orc_dump (const char *filename) {
tools/objtool/orc_gen.c +0 -1
@@ -12,7 +12,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct orc_list_entry {struct list_head list;
tools/objtool/special.c +0 -1
@@ -15,7 +15,6 @@#include <objtool/builtin.h> #include <objtool/special.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct special_entry {const char *sec;
tools/objtool/sync-check.sh +1 -0
@@ -16,6 +16,7 @@ arch/x86/include/asm/orc_types.h arch/x86/include/asm/emulate_prefix.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk +include/linux/interval_tree_generic.h include/linux/livepatch_external.h include/linux/static_call_types.h "
Josh Poimboeuf
maintainerPATCH v4 1/63 s390/vmlinux.lds.S: Prevent thunk functions from getting placed with normal text
The s390 indirect thunks are placed in the .text.__s390_indirect_jump_* sections.
Certain config options which enable -ffunction-sections have a custom version of the TEXT_TEXT macro:
.text.[0-9a-zA-Z_]*
That unintentionally matches the thunk sections, causing them to get grouped with normal text rather than being handled by their intended rule later in the script:
*(.text.*_indirect_*)
Fix that by adding another period to the thunk section names, following the kernel's general convention for distinguishing code-generated text sections from compiler-generated ones.
--- arch/s390/include/asm/nospec-insn.h | 2 +- arch/s390/kernel/vmlinux.lds.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
arch/s390/include/asm/nospec-insn.h +1 -1
@@ -19,7 +19,7 @@#ifdef CONFIG_EXPOLINE_EXTERN SYM_CODE_START(\name) #else - .pushsection .text.\name,"axG",@progbits,\name,comdat + .pushsection .text..\name,"axG",@progbits,\name,comdat .globl \name .hidden \name .type \name,@function
arch/s390/kernel/vmlinux.lds.S +1 -1
@@ -51,7 +51,7 @@ SECTIONS IRQENTRY_TEXT SOFTIRQENTRY_TEXT FTRACE_HOTPATCH_TRAMPOLINES_TEXT - *(.text.*_indirect_*) + *(.text..*_indirect_*) *(.gnu.warning) . = ALIGN(PAGE_SIZE); _etext = .; /* End of text section */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 2/63 vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
In reply to Josh PoimboeufTEXT_MAIN, DATA_MAIN and friends are defined differently depending on whether certain config options enable -ffunction-sections and/or -fdata-sections.
There's no technical reason for that beyond voodoo coding. Keeping the separate implementations adds unnecessary complexity, fragments the logic, and increases the risk of subtle bugs.
Unify the macros by using the same input section patterns across all configs.
This is a prerequisite for the upcoming livepatch klp-build tooling which will manually enable -ffunction-sections and -fdata-sections via KCFLAGS.
--- include/asm-generic/vmlinux.lds.h | 40 ++++++++++--------------------- scripts/module.lds.S | 12 ++++------ 2 files changed, 17 insertions(+), 35 deletions(-)
include/asm-generic/vmlinux.lds.h +12 -28
@@ -87,39 +87,24 @@#define ALIGN_FUNCTION () . = ALIGN(CONFIG_FUNCTION_ALIGNMENT)/* -* LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which -* generates .data.identifier sections, which need to be pulled in with -* .data. We don't want to pull in .data..other sections, which Linux -* has defined. Same for text and bss. +* Support -ffunction-sections by matching .text and .text.*, +* but exclude '.text..*'. * -* With LTO_CLANG, the linker also splits sections by default, so we need -* these macros to combine the sections during the final link. -* -* With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits -* text sections and regroups functions into subsections. -* -* RODATA_MAIN is not used because existing code already defines .rodata.x -* sections to be brought in with rodata. +* Special .text.* sections that are typically grouped separately, such as +* .text.unlikely or .text.hot, must be matched explicitly before using +* TEXT_MAIN. */ -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ) || defined(CONFIG_LTO_CLANG ) || \ -defined(CONFIG_AUTOFDO_CLANG ) || defined(CONFIG_PROPELLER_CLANG )#define TEXT_MAIN .text .text.[0-9a-zA-Z_]* -#else -#define TEXT_MAIN .text -#endif -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ) || defined(CONFIG_LTO_CLANG ) + +/* +* Support -fdata-sections by matching .data, .data.*, and others, +* but exclude '.data..*'. +*/ #define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data.rel.* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral*#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]* -#else -#define DATA_MAIN .data .data.rel .data.rel.local -#define SDATA_MAIN .sdata -#define RODATA_MAIN .rodata -#define BSS_MAIN .bss -#define SBSS_MAIN .sbss -#endif /* * GCC 4.5 and later have a 32 bytes section alignment for structures.
@@ -580,9 +565,8 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)* during second ld run in second ld pass when generating System.map * * TEXT_MAIN here will match symbols with a fixed pattern (for example, -* .text.hot or .text.unlikely) if dead code elimination or -* function-section is enabled. Match these symbols first before -* TEXT_MAIN to ensure they are grouped together. +* .text.hot or .text.unlikely). Match those before TEXT_MAIN to ensure +* they get grouped together. * * Also placing .text.hot section at the beginning of a page, this * would help the TLB performance.
scripts/module.lds.S +5 -7
@@ -38,12 +38,10 @@ SECTIONS { __kcfi_traps : { KEEP(*(.kcfi_traps)) } #endif -#ifdef CONFIG_LTO_CLANG - /* - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and - * -ffunction-sections, which increases the size of the final module. - * Merge the split sections in the final binary. - */ + .text : { + *(.text .text.[0-9a-zA-Z_]*) + } + .bss : { *(.bss .bss.[0-9a-zA-Z_]*) *(.bss..L*)
@@ -58,7 +56,7 @@ SECTIONS { *(.rodata .rodata.[0-9a-zA-Z_]*) *(.rodata..L*) } -#endif + MOD_SEPARATE_CODETAG_SECTIONS() }
Signature · 1 line
2.50.0
Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
Quoted 98 lines · Josh Poimboeuf
TEXT_MAIN,DATA_MAINand friends are defined differently depending on whether certain config options enable -ffunction-sections and/or -fdata-sections.There's no technical reason for that beyond voodoo coding. Keeping the separate implementations adds unnecessary complexity, fragments the logic, and increases the risk of subtle bugs.
Unify the macros by using the same input section patterns across all configs.
This is a prerequisite for the upcoming livepatch klp-build tooling which will manually enable -ffunction-sections and -fdata-sections via KCFLAGS.
Cc Heiko Carstens <[email protected]>Cc Vasily Gorbik <[email protected]>Cc Alexander Gordeev <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>--- include/asm-generic/vmlinux.lds.h | 40 ++++++++++--------------------- scripts/module.lds.S | 12 ++++------ 2 files changed, 17 insertions(+), 35 deletions(-)include/asm-generic/vmlinux.lds.h +12
-28@@ -87,39 +87,24 @@#define ALIGN_FUNCTION () . = ALIGN(CONFIG_FUNCTION_ALIGNMENT)/* -* LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which -* generates .data.identifier sections, which need to be pulled in with -* .data. We don't want to pull in .data..other sections, which Linux -* has defined. Same for text and bss. +* Support -ffunction-sections by matching .text and .text.*, +* but exclude '.text..*'. * -* With LTO_CLANG, the linker also splits sections by default, so we need -* these macros to combine the sections during the final link. -* -* With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits -* text sections and regroups functions into subsections. -* -* RODATA_MAIN is not used because existing code already defines .rodata.x -* sections to be brought in with rodata. +* Special .text.* sections that are typically grouped separately, such as +* .text.unlikely or .text.hot, must be matched explicitly before using +* TEXT_MAIN. */ -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ) || defined(CONFIG_LTO_CLANG ) || \ -defined(CONFIG_AUTOFDO_CLANG ) || defined(CONFIG_PROPELLER_CLANG )#define TEXT_MAIN .text .text.[0-9a-zA-Z_]* -#else -#define TEXT_MAIN .text -#endif -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION ) || defined(CONFIG_LTO_CLANG ) + +/* +* Support -fdata-sections by matching .data, .data.*, and others, +* but exclude '.data..*'. +*/ #define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data.rel.* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral*#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]* -#else -#define DATA_MAIN .data .data.rel .data.rel.local -#define SDATA_MAIN .sdata -#define RODATA_MAIN .rodata -#define BSS_MAIN .bss -#define SBSS_MAIN .sbss -#endif /* * GCC 4.5 and later have a 32 bytes section alignment for structures. @@ -580,9 +565,8 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)* during second ld run in second ld pass when generating System.map * * TEXT_MAIN here will match symbols with a fixed pattern (for example, -* .text.hot or .text.unlikely) if dead code elimination or -* function-section is enabled. Match these symbols first before -* TEXT_MAIN to ensure they are grouped together. +* .text.hot or .text.unlikely). Match those before TEXT_MAIN to ensure +* they get grouped together. * * Also placing .text.hot section at the beginning of a page, this * would help the TLB performance. scripts/module.lds.S +0
-0@@ -38,12 +38,10 @@ SECTIONS { __kcfi_traps : { KEEP(*(.kcfi_traps)) } #endif
scripts/module.lds.S SECTIONS { · line 44
Quoted 10 lines
scripts/module.lds.S +4
-6-#ifdef CONFIG_LTO_CLANG - /* - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and - * -ffunction-sections, which increases the size of the final module. - * Merge the split sections in the final binary. - */ + .text : { + *(.text .text.[0-9a-zA-Z_]*) + } +
I'm seeing some KP when trying to load modules after this change. I believe there is some sort of incompatibility with the SCS (Shadow Call Stack) code in arm64? The panic is always on __pi_scs_handle_fde_frame:
init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
Unable to handle kernel paging request at virtual address ffffffe6468f0ffc [...] pc : __pi_scs_handle_fde_frame+0xd8/0x15c lr : __pi_$x+0x74/0x138 sp : ffffffc08005bb10 x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000 x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000 x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4 x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000 x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000 x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000 x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001 x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000 x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004 Call trace: __pi_scs_handle_fde_frame+0xd8/0x15c (P) module_finalize+0xfc/0x164 post_relocation+0xbc/0xd8 load_module+0xfd4/0x11a8 __arm64_sys_finit_module+0x23c/0x328 invoke_syscall+0x58/0xe4 el0_svc_common+0x80/0xdc do_el0_svc+0x1c/0x28 el0_svc+0x54/0x1c4 el0t_64_sync_handler+0x68/0xdc el0t_64_sync+0x1c4/0x1c8 Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)
This is not a problem if I disable UNWIND_PATCH_PAC_INTO_SCS but I have no idea why. Looking around it seems like this might related:
$ cat arch/arm64/include/asm/module.lds.h
SECTIONS {
[...]
#ifdef CONFIG_UNWIND_TABLES
/*
* Currently, we only use unwind info at module load time, so we can
* put it into the .init allocation.
*/
.init.eh_frame : { *(.eh_frame) }
#endifI must note that I've only seen this in Android kernels and I have not tried to reproduce the issue elsewhere. However, the incompatibility seems like it could be applicable upstream too and I'm hoping that the issue is evident to others (I can't understand any of this).
Thanks,
--
Carlos Llamas
Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
Quoted 24 lines · Carlos Llamas
Quoted 23 lines · Josh Poimboeuf
TEXT_MAIN,DATA_MAINand friends are defined differently depending on whether certain config options enable -ffunction-sections and/or -fdata-sections.There's no technical reason for that beyond voodoo coding. Keeping the separate implementations adds unnecessary complexity, fragments the logic, and increases the risk of subtle bugs.
Unify the macros by using the same input section patterns across all configs.
This is a prerequisite for the upcoming livepatch klp-build tooling which will manually enable -ffunction-sections and -fdata-sections via KCFLAGS.
Cc Heiko Carstens <[email protected]>Cc Vasily Gorbik <[email protected]>Cc Alexander Gordeev <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>--- include/asm-generic/vmlinux.lds.h | 40 ++++++++++--------------------- scripts/module.lds.S | 12 ++++------ 2 files changed, 17 insertions(+), 35 deletions(-)
[...]
Quoted 7 lines
I'm seeing some KP when trying to load modules after this change. I believe there is some sort of incompatibility with the SCS (Shadow Call Stack) code in arm64? The panic is always on
__pi_scs_handle_fde_frame:init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
Unable to handle kernel paging request at virtual address ffffffe6468f0ffc [...]
nit: please don't trim the useful stuff when reporting a crash!
Quoted 18 lines
pc : __pi_scs_handle_fde_frame+0xd8/0x15c lr : __pi_$x+0x74/0x138 sp : ffffffc08005bb10 x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000 x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000 x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4 x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000 x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000 x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000 x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001 x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000 x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004 Call trace: __pi_scs_handle_fde_frame+0xd8/0x15c (P) module_finalize+0xfc/0x164 post_relocation+0xbc/0xd8 load_module+0xfd4/0x11a8
Quoted 8 lines
__arm64_sys_finit_module+0x23c/0x328 invoke_syscall+0x58/0xe4 el0_svc_common+0x80/0xdc do_el0_svc+0x1c/0x28 el0_svc+0x54/0x1c4 el0t_64_sync_handler+0x68/0xdc el0t_64_sync+0x1c4/0x1c8 Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)
Hmm, looks like a translation fault from the load buried here:
u32 insn = le32_to_cpup((void *)loc);
in scs_patch_loc(), called from the 'DW_CFA_negate_ra_state' case in scs_handle_fde_frame(). So presumably 'loc' is bogus.
Since you replied to this patch, does reverting it fix the problem for you?
Quoted 2 lines
This is not a problem if I disable
UNWIND_PATCH_PAC_INTO_SCSbut I have no idea why.
Well, that avoids compiling the code that's crashing :p
Quoted 12 lines
Looking around it seems like this might related:
$ cat arch/arm64/include/asm/module.lds.h SECTIONS { [...] #ifdef CONFIG_UNWIND_TABLES /* * Currently, we only use unwind info at module load time, so we can * put it into the .init allocation. */ .init.eh_frame : { *(.eh_frame) } #endif
This patch doesn't seem to change that though?
Ard, do you have any ideas here? I wonder whether the addition of support for 64-bit offsets in 60de7a647fc5 ("arm64/scs: Deal with 64-bit relative offsets in FDE frames") has introduced padding/alignment requirements into 'struct eh_frame' and we end up off-by-4 for 'loc' or something like that? The faulting address looks like an underflow.
Will
Re: [PATCH v4 02/63] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros
Quoted 67 lines · Will Deacon
Quoted 24 lines · Carlos Llamas
Quoted 23 lines · Josh Poimboeuf
TEXT_MAIN,DATA_MAINand friends are defined differently depending on whether certain config options enable -ffunction-sections and/or -fdata-sections.There's no technical reason for that beyond voodoo coding. Keeping the separate implementations adds unnecessary complexity, fragments the logic, and increases the risk of subtle bugs.
Unify the macros by using the same input section patterns across all configs.
This is a prerequisite for the upcoming livepatch klp-build tooling which will manually enable -ffunction-sections and -fdata-sections via KCFLAGS.
Cc Heiko Carstens <[email protected]>Cc Vasily Gorbik <[email protected]>Cc Alexander Gordeev <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>--- include/asm-generic/vmlinux.lds.h | 40 ++++++++++--------------------- scripts/module.lds.S | 12 ++++------ 2 files changed, 17 insertions(+), 35 deletions(-)[...]
Quoted 7 lines
I'm seeing some KP when trying to load modules after this change. I believe there is some sort of incompatibility with the SCS (Shadow Call Stack) code in arm64? The panic is always on
__pi_scs_handle_fde_frame:init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko
Unable to handle kernel paging request at virtual address ffffffe6468f0ffc [...]nit: please don't trim the useful stuff when reporting a crash!
Quoted 18 lines
pc : __pi_scs_handle_fde_frame+0xd8/0x15c lr : __pi_$x+0x74/0x138 sp : ffffffc08005bb10 x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000 x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000 x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4 x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000 x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000 x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000 x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001 x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000 x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004 Call trace: __pi_scs_handle_fde_frame+0xd8/0x15c (P) module_finalize+0xfc/0x164 post_relocation+0xbc/0xd8 load_module+0xfd4/0x11a8Quoted 8 lines
__arm64_sys_finit_module+0x23c/0x328 invoke_syscall+0x58/0xe4 el0_svc_common+0x80/0xdc do_el0_svc+0x1c/0x28 el0_svc+0x54/0x1c4 el0t_64_sync_handler+0x68/0xdc el0t_64_sync+0x1c4/0x1c8 Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0)Hmm, looks like a translation fault from the load buried here:
Quoted 7 lines
u32 insn = le32_to_cpup((void *)loc);in
scs_patch_loc(), called from the 'DW_CFA_negate_ra_state' case inscs_handle_fde_frame(). So presumably 'loc' is bogus.Since you replied to this patch, does reverting it fix the problem for you?
Yes, but it is only coincidental. The real issue seems to be with our toolchain. I'll start looking there instead. Sorry for the noise.
--
Carlos Llamas
Josh Poimboeuf
maintainerPATCH v4 3/63 x86/module: Improve relocation error messages
In reply to Josh PoimboeufAdd the section number and reloc index to relocation error messages to help find the faulty relocation.
--- arch/x86/kernel/module.c | 15 +++++++++------ kernel/livepatch/core.c | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-)
arch/x86/kernel/module.c +9 -6
@@ -97,6 +97,7 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs,DEBUGP ("%s relocate section %u to %u\n" , apply ?"Applying" :"Clearing" , relsec, sechdrs[relsec].sh_info); +for (i =0 ; i < sechdrs[relsec].sh_size /sizeof (*rel); i++) {size_t size;
@@ -162,15 +163,17 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs,if (apply) {if (memcmp (loc, &zero, size)) { -pr_err ("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n" , - (int )ELF64_R_TYPE (rel[i].r_info), loc, val); +pr_err ("x86/modules: Invalid relocation target, existing value is nonzero for sec %u, idx %u, type %d, loc %lx, val %llx\n" , + relsec, i, (int )ELF64_R_TYPE (rel[i].r_info), + (unsigned long )loc, val);return -ENOEXEC ; }write (loc, &val, size); }else {if (memcmp (loc, &val, size)) { -pr_warn ("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n" , - (int )ELF64_R_TYPE (rel[i].r_info), loc, val); +pr_warn ("x86/modules: Invalid relocation target, existing value does not match expected value for sec %u, idx %u, type %d, loc %lx, val %llx\n" , + relsec, i, (int )ELF64_R_TYPE (rel[i].r_info), + (unsigned long )loc, val);return -ENOEXEC ; }write (loc, &zero, size);
@@ -179,8 +182,8 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs,return 0 ; overflow: -pr_err ("overflow in relocation type %d val %Lx\n" , - (int )ELF64_R_TYPE (rel[i].r_info), val); +pr_err ("overflow in relocation type %d val %llx sec %u idx %d\n" , + (int )ELF64_R_TYPE (rel[i].r_info), val, relsec, i);pr_err ("`%s' likely not compiled with -mcmodel=kernel\n" , me->name);return -ENOEXEC ;
kernel/livepatch/core.c +2 -2
@@ -217,8 +217,8 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab,for (i =0 ; i < relasec->sh_size /sizeof (Elf_Rela); i++) { sym = (Elf_Sym *)sechdrs[symndx].sh_addr +ELF_R_SYM (relas[i].r_info);if (sym->st_shndx !=SHN_LIVEPATCH ) { -pr_err ("symbol %s is not marked as a livepatch symbol\n" , - strtab + sym->st_name); +pr_err ("symbol %s at rela sec %u idx %d is not marked as a livepatch symbol\n" , + strtab + sym->st_name, symndx, i);return -EINVAL ; }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 4/63 x86/kprobes: Remove STACK_FRAME_NON_STANDARD annotation
In reply to Josh PoimboeufSince commit 877b145f0f47 ("x86/kprobes: Move trampoline code into RODATA"), the optprobe template code is no longer analyzed by objtool so it doesn't need to be ignored.
--- arch/x86/kernel/kprobes/opt.c | 4 ---- 1 file changed, 4 deletions(-)
arch/x86/kernel/kprobes/opt.c +0 -4
@@ -103,7 +103,6 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) asm ( ".pushsection .rodata\n" - "optprobe_template_func:\n" ".global optprobe_template_entry\n" "optprobe_template_entry:\n"#ifdef CONFIG_X86_64
@@ -160,9 +159,6 @@ asm ("optprobe_template_end:\n" ".popsection\n"); -void optprobe_template_func (void ); -STACK_FRAME_NON_STANDARD (optprobe_template_func); -#define TMPL_CLAC_IDX \ ((long)optprobe_template_clac - (long)optprobe_template_entry)#define TMPL_MOVE_IDX \
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 5/63 compiler: Tweak __UNIQUE_ID() naming
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, add an underscore between the name and the counter. This will make it possible for objtool to distinguish between the non-unique and unique parts of the symbol name so it can properly correlate the symbols.
--- include/linux/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
include/linux/compiler.h +5 -1
@@ -163,7 +163,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, __asm__ ("" : "=r" (var) : "0" (var))#endif -#define __UNIQUE_ID (prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) +/* Format: __UNIQUE_ID_<name>_<__COUNTER__> */ +#define __UNIQUE_ID (name) \ + __PASTE(__UNIQUE_ID_, \ + __PASTE(name, \ + __PASTE(_, __COUNTER__)))/** * data_race - mark an expression as containing intentional data races
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 6/63 compiler.h: Make addressable symbols less of an eyesore
In reply to Josh PoimboeufAvoid underscore overload by changing:
__UNIQUE_ID___addressable_loops_per_jiffy_868
to the following:
__UNIQUE_ID_addressable_loops_per_jiffy_868
This matches the format used by other __UNIQUE_ID()-generated symbols and improves readability for those who stare at ELF symbol table dumps.
--- include/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/compiler.h +1 -1
@@ -287,7 +287,7 @@ static inline void *offset_to_ptr(const int *off)*/ #define ___ADDRESSABLE (sym, __attrs) \ static void * __used __attrs \ - __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)(uintptr_t)&sym; + __UNIQUE_ID(__PASTE(addressable_, sym)) = (void *)(uintptr_t)&sym;#define __ADDRESSABLE (sym) \ ___ADDRESSABLE(sym, __section(".discard.addressable"))
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 7/63 elfnote: Change ELFNOTE() to use __UNIQUE_ID()
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, replace the custom unique symbol name generation in ELFNOTE() with __UNIQUE_ID().
This standardizes the naming format for all "unique" symbols, which will allow objtool to properly correlate them. Note this also removes the "one ELF note per line" limitation.
--- include/linux/elfnote.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
include/linux/elfnote.h +5 -8
@@ -60,23 +60,21 @@#else /* !__ASSEMBLER__ */ #include <uapi/linux/elf.h> +#include <linux/compiler.h> /* * Use an anonymous structure which matches the shape of * Elf{32,64}_Nhdr, but includes the name and desc data. The size and * type of name and desc depend on the macro arguments. "name" must -* be a literal string, and "desc" must be passed by value. You may -* only define one note per line, since __LINE__ is used to generate -* unique symbols. +* be a literal string, and "desc" must be passed by value. */ -#define _ELFNOTE_PASTE (a,b) a##b -#define _ELFNOTE (size, name, unique, type, desc) \ +#define ELFNOTE (size, name, type, desc) \ static const struct { \ struct elf##size##_note _nhdr; \ unsigned char _name[sizeof(name)] \ __attribute__((aligned(sizeof(Elf##size##_Word)))); \ typeof(desc) _desc \ __attribute__((aligned(sizeof(Elf##size##_Word)))); \ - } _ELFNOTE_PASTE(_note_, unique) \ + } __UNIQUE_ID(note) \ __used \ __attribute__((section(".note." name), \ aligned(sizeof(Elf##size##_Word)), \
@@ -89,11 +87,10 @@ name, \ desc \ } -#define ELFNOTE (size, name, type, desc) \ - _ELFNOTE(size, name, __LINE__, type, desc)#define ELFNOTE32 (name, type, desc) ELFNOTE(32, name, type, desc)#define ELFNOTE64 (name, type, desc) ELFNOTE(64, name, type, desc) +#endif /* __ASSEMBLER__ */ #endif /* _LINUX_ELFNOTE_H */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 8/63 kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, remove the arbitrary 'kmod_' prefix from __KBUILD_MODNAME and instead add it explicitly in the __initcall_id() macro.
This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
--- include/linux/init.h | 3 ++- scripts/Makefile.lib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
include/linux/init.h +2 -1
@@ -200,12 +200,13 @@ extern struct module __this_module;/* Format: <modname>__<counter>_<line>_<fn> */ #define __initcall_id (fn) \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(__COUNTER__, \ __PASTE(_, \ __PASTE(__LINE__, \ - __PASTE(_, fn)))))) + __PASTE(_, fn)))))))/* Format: __<prefix>__<iid><id> */ #define __initcall_name (prefix, __iid, id) \
scripts/Makefile.lib +1 -1
@@ -20,7 +20,7 @@ name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) name-fix = $(call stringify,$(call name-fix-token,$1)) basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname)) \ - -D__KBUILD_MODNAME=kmod_$(call name-fix-token,$(modname)) + -D__KBUILD_MODNAME=$(call name-fix-token,$(modname)) modfile_flags = -DKBUILD_MODFILE=$(call stringify,$(modfile)) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
Signature · 1 line
2.50.0
Re: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
Hi,
Am Mittwoch, 17. September 2025, 18:03:16 CEST schrieb Josh Poimboeuf:
Quoted 11 lines
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
Cc Masahiro Yamada <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>
Starting with this commit 6717e8f91db71 ("kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME") in next-20251020 I don't get any module aliases anymore.
modinfo spi-fsl-dspi.ko returns:
Quoted 8 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver depends: intree: Y name: spi_fsl_dspi vermagic: 6.18.0-rc1+ SMP preempt mod_unload modversions aarch64
but it should be like this:
Quoted 20 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver alias: of:N*T*Cnxp,s32g2-dspiC* alias: of:N*T*Cnxp,s32g2-dspi alias: of:N*T*Cfsl,lx2160a-dspiC* alias: of:N*T*Cfsl,lx2160a-dspi alias: of:N*T*Cfsl,ls2085a-dspiC* alias: of:N*T*Cfsl,ls2085a-dspi alias: of:N*T*Cfsl,ls2080a-dspiC* alias: of:N*T*Cfsl,ls2080a-dspi alias: of:N*T*Cfsl,ls1046a-dspiC* alias: of:N*T*Cfsl,ls1046a-dspi alias: of:N*T*Cfsl,ls1043a-dspiC* alias: of:N*T*Cfsl,ls1043a-dspi alias: of:N*T*Cfsl,ls1028a-dspiC* alias: of:N*T*Cfsl,ls1028a-dspi alias: of:N*T*Cfsl,ls1012a-dspiC* alias: of:N*T*Cfsl,ls1012a-dspi
Quoted 8 lines
alias: of:N*T*Cfsl,ls1021a-v1.0-dspiC* alias: of:N*T*Cfsl,ls1021a-v1.0-dspi alias: of:N*T*Cfsl,vf610-dspiC* alias: of:N*T*Cfsl,vf610-dspi depends: intree: Y name: spi_fsl_dspi vermagic: 6.18.0-rc1+ SMP preempt mod_unload modversions aarch64
Reverting does not work on all building platforms, it works on one but fails on another one.
Best regards
Alexander
Quoted 38 lines
--- include/linux/init.h | 3 ++- scripts/Makefile.lib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)include/linux/init.h +2
-1@@ -200,12 +200,13 @@ extern struct module __this_module;/* Format: <modname>__<counter>_<line>_<fn> */ #define __initcall_id (fn) \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(__COUNTER__, \ __PASTE(_, \ __PASTE(__LINE__, \ - __PASTE(_, fn)))))) + __PASTE(_, fn)))))))/* Format: __<prefix>__<iid><id> */ #define __initcall_name (prefix, __iid, id) \scripts/Makefile.lib +1
-1@@ -20,7 +20,7 @@ name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) name-fix = $(call stringify,$(call name-fix-token,$1)) basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname)) \ - -D__KBUILD_MODNAME=kmod_$(call name-fix-token,$(modname)) + -D__KBUILD_MODNAME=$(call name-fix-token,$(modname)) modfile_flags = -DKBUILD_MODFILE=$(call stringify,$(modfile)) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
Signature · 4 lines
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany Amtsgericht München, HRB 105018 Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider http://www.tq-group.com/
Josh Poimboeuf
maintainerRe: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
Quoted 28 lines · Alexander Stein
Hi,
Am Mittwoch, 17. September 2025, 18:03:16 CEST schrieb Josh Poimboeuf:
Quoted 11 lines
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
Cc Masahiro Yamada <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>Starting with this commit
6717e8f91db71("kbuild: Remove 'kmod_' prefix from__KBUILD_MODNAME") in next-20251020 I don't get any module aliases anymore.
modinfo spi-fsl-dspi.ko returns:Quoted 8 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver depends: intree: Y name: spi_fsl_dspi vermagic: 6.18.0-rc1+ SMP preempt mod_unload modversions aarch64
Quoted 6 lines
but it should be like this:
Quoted 5 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver alias: of:N*T*Cnxp,s32g2-dspiC*
Thanks, this patch broke the MODULE_DEVICE_TABLE() macro, as it no longer produces the format expected by scripts/mod/file2alias.c.
I didn't see this in x86 testing since it doesn't have device tree.
I will post the following fix shortly:
include/linux/module.h +2 -1
@@ -251,10 +251,11 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name);*/ #define __mod_device_table (type, name) \ __PASTE(__mod_device_table__, \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(type, \ - __PASTE(__, name))))) + __PASTE(__, name))))))/* Creates an alias so file2alias.c can find device table. */ #define MODULE_DEVICE_TABLE (type, name) \
Anders Roxell
Tested-byRe: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
Quoted 36 lines · Josh Poimboeuf
Quoted 28 lines · Alexander Stein
Hi,
Am Mittwoch, 17. September 2025, 18:03:16 CEST schrieb Josh Poimboeuf:
Quoted 11 lines
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
Cc Masahiro Yamada <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>Starting with this commit
6717e8f91db71("kbuild: Remove 'kmod_' prefix from__KBUILD_MODNAME") in next-20251020 I don't get any module aliases anymore.
modinfo spi-fsl-dspi.ko returns:Quoted 8 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver depends: intree: Y name: spi_fsl_dspi vermagic: 6.18.0-rc1+ SMP preempt mod_unload modversions aarch64Quoted 6 lines
but it should be like this:
Quoted 5 lines
filename: /work/repo/linux/build_arm64/drivers/spi/spi-fsl-dspi.ko alias: platform:fsl-dspi license: GPL description: Freescale DSPI Controller Driver alias: of:N*T*Cnxp,s32g2-dspiC*
Quoted 6 lines
Thanks, this patch broke the
MODULE_DEVICE_TABLE()macro, as it no longer produces the format expected byscripts/mod/file2alias.c.I didn't see this in x86 testing since it doesn't have device tree.
I will post the following fix shortly:
When can we expect it?
Cheers,
Anders
Quoted 18 lines
include/linux/module.h +2
-1@@ -251,10 +251,11 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name);*/ #define __mod_device_table (type, name) \ __PASTE(__mod_device_table__, \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(type, \ - __PASTE(__, name))))) + __PASTE(__, name))))))/* Creates an alias so file2alias.c can find device table. */ #define MODULE_DEVICE_TABLE (type, name) \
Re: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
In reply to Josh PoimboeufQuoted 11 lines · Josh Poimboeuf
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
Cc Masahiro Yamada <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>
This patch landed recently in linux-next as commit 6717e8f91db7 ("kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME"). In my tests I found that it completely breaks automatic modules loading on all tested boards (ARM 32bit, ARM 64bit and RiscV64 based), what looks like some kind of a generic issue. Reverting it on top of current linux-next fixes this issue.
Quoted 29 lines
--- include/linux/init.h | 3 ++- scripts/Makefile.lib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)include/linux/init.h +2
-1@@ -200,12 +200,13 @@ extern struct module __this_module;/* Format: <modname>__<counter>_<line>_<fn> */ #define __initcall_id (fn) \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(__COUNTER__, \ __PASTE(_, \ __PASTE(__LINE__, \ - __PASTE(_, fn)))))) + __PASTE(_, fn)))))))/* Format: __<prefix>__<iid><id> */ #define __initcall_name (prefix, __iid, id) \scripts/Makefile.lib +0
-0
scripts/Makefile.lib name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) · line 26
Quoted 8 lines
scripts/Makefile.lib +1
-1@@ -20,7 +20,7 @@ name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) name-fix = $(call stringify,$(call name-fix-token,$1)) basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname)) \ - -D__KBUILD_MODNAME=kmod_$(call name-fix-token,$(modname)) + -D__KBUILD_MODNAME=$(call name-fix-token,$(modname)) modfile_flags = -DKBUILD_MODFILE=$(call stringify,$(modfile)) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
In reply to Josh PoimboeufQuoted 3 lines · Josh Poimboeuf
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.
I'll add my name to the list of people reporting that this is causing extensive breakage in -next, anything that tries to load modules has a bad time which takes out a lot of tests.
Sample bisect log:
# bad: [606da5bb165594c052ee11de79bf05bc38bc1aa6] Add linux-next specific files for 20251020
# good: [4d7f6adc7b72e14c0f2646a4abb79bb6cc676ada] Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git
# good: [211ddde0823f1442e4ad052a2f30f050145ccada] Linux 6.18-rc2
# good: [0cdb2b1b7edaefb54773d790c7b5c2e4ac7db60d] spi: airoha: driver fixes & improvements
# good: [0743acf746a81e0460a56fd5ff847d97fa7eb370] spi: airoha: buffer must be 0xff-ed before writing
# good: [661856ca131c8bf6724905966e02149805660abe] spi: airoha: remove unnecessary restriction length
# good: [70eec454f2d6cdfab547c262781acd38328e11a1] spi: airoha: avoid setting of page/oob sizes in REG_SPI_NFI_PAGEFMT
# good: [d1ff30df1d9a4eb4c067795abb5e2a66910fd108] spi: airoha: reduce the number of modification of REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers
# good: [fb81b5cecb8553e3ca2b45288cf340d43c9c2991] spi: airoha: set custom sector size equal to flash page size
# good: [902c0ea18a97b1a6eeee5799cb1fd9a79ef9208e] spi: airoha: avoid reading flash page settings from SNFI registers during driver startup
# good: [80b09137aeab27e59004383058f8cc696a9ee048] spi: airoha: support of dualio/quadio flash reading commands
# good: [0cc08c8130ac8f74419f99fe707dc193b7f79d86] spi: aspeed: Fix an IS_ERR() vs NULL bug in probe()
# good: [93b2838c6e79bc263e6129d88c5ab043dd793d28] Add Audio Support for Kaanapali MTP Boards
# good: [233a22687411ea053a4b169c07324ee6aa33bf38] spi: airoha: unify dirmap read/write code
# good: [7350f8dc15bfbb7abf1ce4babea6fcace1c574c5] spi: airoha: remove unnecessary switch to non-dma mode
# good: [5263cd81578f99a00b2dd7de1da2b570b96a1b7c] rpmh-regulators: Update rpmh-regulator driver and
# good: [281c97376cfcfc8cef4f5ed5dd961a1b39f5a25e] ASoC: codecs: va-macro: Rework version checking
# good: [d77daa49085b067137d0adbe3263f75a7ee13a1b] spi: aspeed: fix spelling mistake "triming" -> "trimming"
# good: [4673dbe9837e3eb2fecdd12f0953006c31636aac] ASoC: qcom: sc8280xp: Add support for Kaanapali
# good: [367ca0688e4218e51c3d4dfdf3ef5657a62cf88d] ASoC: dt-bindings: qcom,sm8250: Add kaanapali sound card
# good: [15afe57a874eaf104bfbb61ec598fa31627f7b19] ASoC: dt-bindings: qcom: Add Kaanapali LPASS macro codecs
# good: [1e570e77392f43a3cdab2849d1f81535f8a033e2] ASoC: mxs-saif: support usage with simple-audio-card
# good: [1356c98ef911e14ccfaf374800840ce5bdcb3bbd] regulator: dt-bindings: rpmh-regulator: Update pmic-id DT prop info for new CMD-DB
# good: [fb25114cd760c13cf177d9ac37837fafcc9657b5] regulator: sy7636a: add gpios and input regulator
# good: [835dfb12fc389f36eb007657f163bd1c539dcd45] regulator: dt-bindings: rpmh-regulator : Add compatibles for PMH01XX & PMCX0102
# good: [65efe5404d151767653c7b7dd39bd2e7ad532c2d] regulator: rpmh-regulator: Add RPMH regulator support for Glymur
# good: [6621b0f118d500092f5f3d72ddddb22aeeb3c3a0] ASoC: codecs: rt5670: use SOC_VALUE_ENUM_SINGLE_DECL for DAC2 L/R MX-1B
# good: [6a8cdef7dc2a4c0dbde3f7d7100b3d99712a766b] regulator: rpmh-regulator: Add support for new resource name format
# good: [cee2c8396d9c8e834fe28929bc1d8153d7e9897f] ASoC: use sof_sdw as default Intel SOF SDW machine
# good: [7d9c2924f61dcabcbc5868bec6054ab4f4de01d1] spi: aspeed: Improve clock, timing and address
# good: [79c36ecfc8994011ab0a973d3b4148aa5d9e0c91] ASoC: use sof_sdw as default Intel SOF SDW machine
# good: [433e294c3c5b5d2020085a0e36c1cb47b694690a] regulator: core: forward undervoltage events downstream by default
# good: [0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4] ASoC: replace use of system_wq with system_dfl_wq
# good: [92a42edd347c3b5a9045bb137a33204c6ddc0803] Add target mode support for the DesignWare SPI
# good: [c1afb0350069c3be137b5692923ad13d69648970] Add tegra264 audio device tree support
# good: [a758314f71ba90cca2a5813bbf96c4954a15b613] spi: offload: Add offset parameter
# good: [506cbe36a2ac7b504a2362476dc53cd548b7a29e] ASoC: soc_sdw_utils: export asoc_sdw_get_dai_type
# good: [225d70b8074502acee3943bf0c2e839e867cd38c] ASoC: SOF: don't check the existence of dummy topology
# good: [55f8b5a96597a7b88c323a7de7228f9eae8c9943] ASoC: Intel: export sof_sdw_get_tplg_files
# good: [7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd] ASoC: sof-function-topology-lib: escalate the log when missing function topoplogy
# good: [bb940b13998c40d55e186f0cf5d65c592ea1677a] ASoC: SOF: Don't print the monolithic topology name if function topology may be used
# good: [aa1ee85ce3576defd29f2a389d7508d2036af977] ASoC: soc_sdw_utils: add name_prefix to asoc_sdw_codec_info struct
# good: [7f47685b150dbc20f881d029a7366a81b1d66322] ASoC: SOF: Intel: use sof_sdw as default SDW machine driver
# good: [3180c7b1575d635851f0ceab6bdb176bb15e69dd] ASoC: soc-acpi: make some variables of acpi adr and link adr non-const
# good: [0d202ae0256e8e7dcea862ead5904fa27cf4ce6a] ASoC: SOF: add platform name into sof_intel_dsp_desc
# good: [2b92b98cc4765fbb0748742e7e0dd94d15d6f178] ASoC: SOF: Don't print the monolithic topology name if function topology may be used
# good: [6277a486a7faaa6c87f4bf1d59a2de233a093248] regulator: dt-bindings: Convert Dialog DA9211 Regulators to DT schema
# good: [454cd43a283f7697297c52981c7a499a16725656] spi: dt-bindings: spi-qpic-snand: Add IPQ5424 compatible
# good: [6937ff42f28a13ffdbe2d1f5b9a51a35f626e93a] ASoC: SOF: add platform name into sof_intel_dsp_desc
# good: [b926b15547d29a88932de3c24a05c12826fc1dbc] spi: dw: rename the spi controller to ctlr
# good: [7196fc4e482928a276da853e2687f31cd8ea2611] ASoC: Intel: export sof_sdw_get_tplg_files
# good: [d25de16477657f9eddd4be9abd409515edcc3b9e] ASoC: soc-acpi: make some variables of acpi adr and link adr non-const
# good: [630a185fd06109193574d10f38b29812986c21de] spi: aspeed: Force default address decoding range assignment for each CS
# good: [5226d19d4cae5398caeb93a6052bfb614e0099c7] ASoC: SOF: Intel: use sof_sdw as default SDW machine driver
# good: [31dcc7e1f8a9377d8fd9f967f84c121c5ba8f89c] spi: aspeed: Update clock selection strategy
# good: [9797329220a2c6622411eb9ecf6a35b24ce09d04] ASoC: sof-function-topology-lib: escalate the log when missing function topoplogy
# good: [ea97713903784286ef1ce45456f404ed288f19b1] ASoC: soc_sdw_utils: add name_prefix to asoc_sdw_codec_info struct
# good: [4ebe64f507ca921c5109eb37eae6058b77413d93] ASoC: tas2781: Add TAS5802, TAS5815, and TAS5828
# good: [5ed60e45c59d66e61586a10433e2b5527d4d72b5] ASoC: soc_sdw_utils: export asoc_sdw_get_dai_type
# good: [b83fb1b14c06bdd765903ac852ba20a14e24f227] spi: offload: Add offset parameter
# good: [4d410ba9aa275e7990a270f63ce436990ace1bea] dt-bindings: sound: Update ADMAIF bindings for tegra264
# good: [29fa213c6ab00c6749db47b47e384cab760c109e] ASoC: dt-bindings: ti,tas2781: Add TAS5802, TAS5815, and TAS5828
# good: [99c159279c6dfa2c4867c7f76875f58263f8f43b] ASoC: SOF: don't check the existence of dummy topology
# good: [0586b53d4a0c7c5a132629f99da934cc674ea4cd] spi: aspeed: Add per-platform adjust_window callback for decoding range
# good: [3c89238ca35bfe176ba34bc688541f90f6fa7bdb] ASoc: tas2783A: Remove unneeded variable assignment
# good: [5e537031f322d55315cd384398b726a9a0748d47] ASoC: codecs: Fix the error of excessive semicolons
# good: [4412ab501677606436e5c49e41151a1e6eac7ac0] spi: dt-bindings: spi-qpic-snand: Add IPQ5332 compatible
# good: [efb79de36e947d136517bac14c139d494fcc72fa] spi: aspeed: Improve timing calibration algorithm for AST2600 platform
# good: [fe8cc44dd173cde5788ab4e3730ac61f3d316d9c] spi: dw: add target mode support
# good: [64d87ccfae3326a9561fe41dc6073064a083e0df] spi: aspeed: Only map necessary address window region
# good: [be2ba2fef1676861b295053c2a567b057e9031b9] bugs/sh: Concatenate 'cond_str' with '__FILE__' in __WARN_FLAGS(), to extend WARN_ON/BUG_ON output
# good: [6c177775dcc5e70a64ddf4ee842c66af498f2c7c] Merge branch 'next/drivers' into for-next
# good: [da15636d84a812275f785057451c0e7b15b39012] Merge branch 'v6.18/arm64-dt' into for-next
# good: [06dd3eda0e958cdae48ca755eb5047484f678d78] Merge branch 'vfs-6.18.rust' into vfs.all
# good: [6dde339a3df80a57ac3d780d8cfc14d9262e2acd] landlock: Minor comments improvements
# good: [447c98c1ca4a4b0d43be99f76c558c09956484f3] tools/power turbostat: Add idle governor statistics reporting
# good: [3778dcb2dcc1ce03a2b25e5d951fe9912e843d1e] random: use offstack cpumask when necessary
# good: [6684aba0780da9f505c202f27e68ee6d18c0aa66] XArray: Add extra debugging check to xas_lock and friends
git bisect start '606da5bb165594c052ee11de79bf05bc38bc1aa6' '4d7f6adc7b72e14c0f2646a4abb79bb6cc676ada' '211ddde0823f1442e4ad052a2f30f050145ccada' '0cdb2b1b7edaefb54773d790c7b5c2e4ac7db60d' '0743acf746a81e0460a56fd5ff847d97fa7eb370' '661856ca131c8bf6724905966e02149805660abe' '70eec454f2d6cdfab547c262781acd38328e11a1' 'd1ff30df1d9a4eb4c067795abb5e2a66910fd108' 'fb81b5cecb8553e3ca2b45288cf340d43c9c2991' '902c0ea18a97b1a6eeee5799cb1fd9a79ef9208e' '80b09137aeab27e59004383058f8cc696a9ee048' '0cc08c8130ac8f74419f99fe707dc193b7f79d86' '93b2838c6e79bc263e6129d88c5ab043dd793d28' '233a22687411ea053a4b169c07324ee6aa33bf38' '7350f8dc15bfbb7abf1ce4babea6fcace1c574c5' '5263cd81578f99a00b2dd7de1da2b570b96a1b7c' '281c97376cfcfc8cef4f5ed5dd961a1b39f5a25e' 'd77daa49085b067137d0adbe3263f75a7ee13a1b' '4673dbe9837e3eb2fecdd12f0953006c31636aac' '367ca0688e4218e51c3d4dfdf3ef5657a62cf88d' '15afe57a874eaf104bfbb61ec598fa31627f7b19' '1e570e77392f43a3cdab2849d1f81535f8a033e2' '1356c98ef911e14ccfaf374800840ce5bdcb3bbd' 'fb25114cd760c13cf177d9ac37837fafcc9657b5' '835dfb12fc389f36eb007657f163bd1c539dcd45' '65efe5404d151767653c7b7dd39bd2e7ad532c2d' '6621b0f118d500092f5f3d72ddddb22aeeb3c3a0' '6a8cdef7dc2a4c0dbde3f7d7100b3d99712a766b' 'cee2c8396d9c8e834fe28929bc1d8153d7e9897f' '7d9c2924f61dcabcbc5868bec6054ab4f4de01d1' '79c36ecfc8994011ab0a973d3b4148aa5d9e0c91' '433e294c3c5b5d2020085a0e36c1cb47b694690a' '0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4' '92a42edd347c3b5a9045bb137a33204c6ddc0803' 'c1afb0350069c3be137b5692923ad13d69648970' 'a758314f71ba90cca2a5813bbf96c4954a15b613' '506cbe36a2ac7b504a2362476dc53cd548b7a29e' '225d70b8074502acee3943bf0c2e839e867cd38c' '55f8b5a96597a7b88c323a7de7228f9eae8c9943' '7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd' 'bb940b13998c40d55e186f0cf5d65c592ea1677a' 'aa1ee85ce3576defd29f2a389d7508d2036af977' '7f47685b150dbc20f881d029a7366a81b1d66322' '3180c7b1575d635851f0ceab6bdb176bb15e69dd' '0d202ae0256e8e7dcea862ead5904fa27cf4ce6a' '2b92b98cc4765fbb0748742e7e0dd94d15d6f178' '6277a486a7faaa6c87f4bf1d59a2de233a093248' '454cd43a283f7697297c52981c7a499a16725656' '6937ff42f28a13ffdbe2d1f5b9a51a35f626e93a' 'b926b15547d29a88932de3c24a05c12826fc1dbc' '7196fc4e482928a276da853e2687f31cd8ea2611' 'd25de16477657f9eddd4be9abd409515edcc3b9e' '630a185fd06109193574d10f38b29812986c21de' '5226d19d4cae5398caeb93a6052bfb614e0099c7' '31dcc7e1f8a9377d8fd9f967f84c121c5ba8f89c' '9797329220a2c6622411eb9ecf6a35b24ce09d04' 'ea97713903784286ef1ce45456f404ed288f19b1' '4ebe64f507ca921c5109eb37eae6058b77413d93' '5ed60e45c59d66e61586a10433e2b5527d4d72b5' 'b83fb1b14c06bdd765903ac852ba20a14e24f227' '4d410ba9aa275e7990a270f63ce436990ace1bea' '29fa213c6ab00c6749db47b47e384cab760c109e' '99c159279c6dfa2c4867c7f76875f58263f8f43b' '0586b53d4a0c7c5a132629f99da934cc674ea4cd' '3c89238ca35bfe176ba34bc688541f90f6fa7bdb' '5e537031f322d55315cd384398b726a9a0748d47' '4412ab501677606436e5c49e41151a1e6eac7ac0' 'efb79de36e947d136517bac14c139d494fcc72fa' 'fe8cc44dd173cde5788ab4e3730ac61f3d316d9c' '64d87ccfae3326a9561fe41dc6073064a083e0df' 'be2ba2fef1676861b295053c2a567b057e9031b9' '6c177775dcc5e70a64ddf4ee842c66af498f2c7c' 'da15636d84a812275f785057451c0e7b15b39012' '06dd3eda0e958cdae48ca755eb5047484f678d78' '6dde339a3df80a57ac3d780d8cfc14d9262e2acd' '447c98c1ca4a4b0d43be99f76c558c09956484f3' '3778dcb2dcc1ce03a2b25e5d951fe9912e843d1e' '6684aba0780da9f505c202f27e68ee6d18c0aa66'
# test job: [211ddde0823f1442e4ad052a2f30f050145ccada] https://lava.sirena.org.uk/scheduler/job/1976562 # test job: [0cdb2b1b7edaefb54773d790c7b5c2e4ac7db60d] https://lava.sirena.org.uk/scheduler/job/1965930 # test job: [0743acf746a81e0460a56fd5ff847d97fa7eb370] https://lava.sirena.org.uk/scheduler/job/1964854 # test job: [661856ca131c8bf6724905966e02149805660abe] https://lava.sirena.org.uk/scheduler/job/1965121 # test job: [70eec454f2d6cdfab547c262781acd38328e11a1] https://lava.sirena.org.uk/scheduler/job/1964899 # test job: [d1ff30df1d9a4eb4c067795abb5e2a66910fd108] https://lava.sirena.org.uk/scheduler/job/1965054 # test job: [fb81b5cecb8553e3ca2b45288cf340d43c9c2991] https://lava.sirena.org.uk/scheduler/job/1965035 # test job: [902c0ea18a97b1a6eeee5799cb1fd9a79ef9208e] https://lava.sirena.org.uk/scheduler/job/1964990 # test job: [80b09137aeab27e59004383058f8cc696a9ee048] https://lava.sirena.org.uk/scheduler/job/1965075 # test job: [0cc08c8130ac8f74419f99fe707dc193b7f79d86] https://lava.sirena.org.uk/scheduler/job/1965700 # test job: [93b2838c6e79bc263e6129d88c5ab043dd793d28] https://lava.sirena.org.uk/scheduler/job/1964758 # test job: [233a22687411ea053a4b169c07324ee6aa33bf38] https://lava.sirena.org.uk/scheduler/job/1965101 # test job: [7350f8dc15bfbb7abf1ce4babea6fcace1c574c5] https://lava.sirena.org.uk/scheduler/job/1965137 # test job: [5263cd81578f99a00b2dd7de1da2b570b96a1b7c] https://lava.sirena.org.uk/scheduler/job/1964744 # test job: [281c97376cfcfc8cef4f5ed5dd961a1b39f5a25e] https://lava.sirena.org.uk/scheduler/job/1962783 # test job: [d77daa49085b067137d0adbe3263f75a7ee13a1b] https://lava.sirena.org.uk/scheduler/job/1962822 # test job: [4673dbe9837e3eb2fecdd12f0953006c31636aac] https://lava.sirena.org.uk/scheduler/job/1962868 # test job: [367ca0688e4218e51c3d4dfdf3ef5657a62cf88d] https://lava.sirena.org.uk/scheduler/job/1962854 # test job: [15afe57a874eaf104bfbb61ec598fa31627f7b19] https://lava.sirena.org.uk/scheduler/job/1962908 # test job: [1e570e77392f43a3cdab2849d1f81535f8a033e2] https://lava.sirena.org.uk/scheduler/job/1962270 # test job: [1356c98ef911e14ccfaf374800840ce5bdcb3bbd] https://lava.sirena.org.uk/scheduler/job/1959898 # test job: [fb25114cd760c13cf177d9ac37837fafcc9657b5] https://lava.sirena.org.uk/scheduler/job/1960171 # test job: [835dfb12fc389f36eb007657f163bd1c539dcd45] https://lava.sirena.org.uk/scheduler/job/1959997 # test job: [65efe5404d151767653c7b7dd39bd2e7ad532c2d] https://lava.sirena.org.uk/scheduler/job/1959947 # test job: [6621b0f118d500092f5f3d72ddddb22aeeb3c3a0] https://lava.sirena.org.uk/scheduler/job/1959730 # test job: [6a8cdef7dc2a4c0dbde3f7d7100b3d99712a766b] https://lava.sirena.org.uk/scheduler/job/1959863 # test job: [cee2c8396d9c8e834fe28929bc1d8153d7e9897f] https://lava.sirena.org.uk/scheduler/job/1959137 # test job: [7d9c2924f61dcabcbc5868bec6054ab4f4de01d1] https://lava.sirena.org.uk/scheduler/job/1957764 # test job: [79c36ecfc8994011ab0a973d3b4148aa5d9e0c91] https://lava.sirena.org.uk/scheduler/job/1959155 # test job: [433e294c3c5b5d2020085a0e36c1cb47b694690a] https://lava.sirena.org.uk/scheduler/job/1957349 # test job: [0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4] https://lava.sirena.org.uk/scheduler/job/1957419 # test job: [92a42edd347c3b5a9045bb137a33204c6ddc0803] https://lava.sirena.org.uk/scheduler/job/1957776 # test job: [c1afb0350069c3be137b5692923ad13d69648970] https://lava.sirena.org.uk/scheduler/job/1959166 # test job: [a758314f71ba90cca2a5813bbf96c4954a15b613] https://lava.sirena.org.uk/scheduler/job/1957731 # test job: [506cbe36a2ac7b504a2362476dc53cd548b7a29e] https://lava.sirena.org.uk/scheduler/job/1954111 # test job: [225d70b8074502acee3943bf0c2e839e867cd38c] https://lava.sirena.org.uk/scheduler/job/1954369 # test job: [55f8b5a96597a7b88c323a7de7228f9eae8c9943] https://lava.sirena.org.uk/scheduler/job/1954364 # test job: [7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd] https://lava.sirena.org.uk/scheduler/job/1954346 # test job: [bb940b13998c40d55e186f0cf5d65c592ea1677a] https://lava.sirena.org.uk/scheduler/job/1954225 # test job: [aa1ee85ce3576defd29f2a389d7508d2036af977] https://lava.sirena.org.uk/scheduler/job/1954318 # test job: [7f47685b150dbc20f881d029a7366a81b1d66322] https://lava.sirena.org.uk/scheduler/job/1954198 # test job: [3180c7b1575d635851f0ceab6bdb176bb15e69dd] https://lava.sirena.org.uk/scheduler/job/1954125 # test job: [0d202ae0256e8e7dcea862ead5904fa27cf4ce6a] https://lava.sirena.org.uk/scheduler/job/1954349 # test job: [2b92b98cc4765fbb0748742e7e0dd94d15d6f178] https://lava.sirena.org.uk/scheduler/job/1947182 # test job: [6277a486a7faaa6c87f4bf1d59a2de233a093248] https://lava.sirena.org.uk/scheduler/job/1947002 # test job: [454cd43a283f7697297c52981c7a499a16725656] https://lava.sirena.org.uk/scheduler/job/1946525 # test job: [6937ff42f28a13ffdbe2d1f5b9a51a35f626e93a] https://lava.sirena.org.uk/scheduler/job/1947463 # test job: [b926b15547d29a88932de3c24a05c12826fc1dbc] https://lava.sirena.org.uk/scheduler/job/1947155 # test job: [7196fc4e482928a276da853e2687f31cd8ea2611] https://lava.sirena.org.uk/scheduler/job/1947424 # test job: [d25de16477657f9eddd4be9abd409515edcc3b9e] https://lava.sirena.org.uk/scheduler/job/1947441 # test job: [630a185fd06109193574d10f38b29812986c21de] https://lava.sirena.org.uk/scheduler/job/1947408 # test job: [5226d19d4cae5398caeb93a6052bfb614e0099c7] https://lava.sirena.org.uk/scheduler/job/1947447 # test job: [31dcc7e1f8a9377d8fd9f967f84c121c5ba8f89c] https://lava.sirena.org.uk/scheduler/job/1947173 # test job: [9797329220a2c6622411eb9ecf6a35b24ce09d04] https://lava.sirena.org.uk/scheduler/job/1947403 # test job: [ea97713903784286ef1ce45456f404ed288f19b1] https://lava.sirena.org.uk/scheduler/job/1947261 # test job: [4ebe64f507ca921c5109eb37eae6058b77413d93] https://lava.sirena.org.uk/scheduler/job/1946707 # test job: [5ed60e45c59d66e61586a10433e2b5527d4d72b5] https://lava.sirena.org.uk/scheduler/job/1947418 # test job: [b83fb1b14c06bdd765903ac852ba20a14e24f227] https://lava.sirena.org.uk/scheduler/job/1946831 # test job: [4d410ba9aa275e7990a270f63ce436990ace1bea] https://lava.sirena.org.uk/scheduler/job/1947842 # test job: [29fa213c6ab00c6749db47b47e384cab760c109e] https://lava.sirena.org.uk/scheduler/job/1946529 # test job: [99c159279c6dfa2c4867c7f76875f58263f8f43b] https://lava.sirena.org.uk/scheduler/job/1947475 # test job: [0586b53d4a0c7c5a132629f99da934cc674ea4cd] https://lava.sirena.org.uk/scheduler/job/1947341 # test job: [3c89238ca35bfe176ba34bc688541f90f6fa7bdb] https://lava.sirena.org.uk/scheduler/job/1946592 # test job: [5e537031f322d55315cd384398b726a9a0748d47] https://lava.sirena.org.uk/scheduler/job/1946678 # test job: [4412ab501677606436e5c49e41151a1e6eac7ac0] https://lava.sirena.org.uk/scheduler/job/1946586 # test job: [efb79de36e947d136517bac14c139d494fcc72fa] https://lava.sirena.org.uk/scheduler/job/1947142 # test job: [fe8cc44dd173cde5788ab4e3730ac61f3d316d9c] https://lava.sirena.org.uk/scheduler/job/1947055 # test job: [64d87ccfae3326a9561fe41dc6073064a083e0df] https://lava.sirena.org.uk/scheduler/job/1947243 # test job: [be2ba2fef1676861b295053c2a567b057e9031b9] https://lava.sirena.org.uk/scheduler/job/1738858 # test job: [6c177775dcc5e70a64ddf4ee842c66af498f2c7c] https://lava.sirena.org.uk/scheduler/job/1774070 # test job: [da15636d84a812275f785057451c0e7b15b39012] https://lava.sirena.org.uk/scheduler/job/1855168 # test job: [06dd3eda0e958cdae48ca755eb5047484f678d78] https://lava.sirena.org.uk/scheduler/job/1831740 # test job: [6dde339a3df80a57ac3d780d8cfc14d9262e2acd] https://lava.sirena.org.uk/scheduler/job/1647204 # test job: [447c98c1ca4a4b0d43be99f76c558c09956484f3] https://lava.sirena.org.uk/scheduler/job/1647256 # test job: [3778dcb2dcc1ce03a2b25e5d951fe9912e843d1e] https://lava.sirena.org.uk/scheduler/job/1676804 # test job: [6684aba0780da9f505c202f27e68ee6d18c0aa66] https://lava.sirena.org.uk/scheduler/job/1738724 # test job: [606da5bb165594c052ee11de79bf05bc38bc1aa6] https://lava.sirena.org.uk/scheduler/job/1976482 # bad: [606da5bb165594c052ee11de79bf05bc38bc1aa6] Add linux-next specific files for 20251020 git bisect bad 606da5bb165594c052ee11de79bf05bc38bc1aa6 # skip: [9a8ae3ba7a0d4467067d039a3eba8c0b0bd1c153] Merge branch 'libcrypto-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git git bisect skip 9a8ae3ba7a0d4467067d039a3eba8c0b0bd1c153 # test job: [9a4bbd20a879b66dddb563698345b0ae24d810a6] https://lava.sirena.org.uk/scheduler/job/1978205 # good: [9a4bbd20a879b66dddb563698345b0ae24d810a6] hwmon: (tmp108) Drop mutex.h include git bisect good 9a4bbd20a879b66dddb563698345b0ae24d810a6 # test job: [42277a1f86a14172c673a249bdc9e757065ca5a1] https://lava.sirena.org.uk/scheduler/job/1978413 # good: [42277a1f86a14172c673a249bdc9e757065ca5a1] Merge branch 'for-6.19' into for-next git bisect good 42277a1f86a14172c673a249bdc9e757065ca5a1 # test job: [dd590d4d57ebeeb826823c288741f2ed20f452af] https://lava.sirena.org.uk/scheduler/job/1978495 # bad: [dd590d4d57ebeeb826823c288741f2ed20f452af] objtool/klp: Introduce klp diff subcommand for diffing object files git bisect bad dd590d4d57ebeeb826823c288741f2ed20f452af # test job: [3e4b5f66cf1a7879a081f5044ff1796aa33cb999] https://lava.sirena.org.uk/scheduler/job/1978783 # bad: [3e4b5f66cf1a7879a081f5044ff1796aa33cb999] objtool: Check for missing annotation entries in read_annotate() git bisect bad 3e4b5f66cf1a7879a081f5044ff1796aa33cb999 # test job: [4109043bff31f95d3da9ace33eb3c1925fd62cbd] https://lava.sirena.org.uk/scheduler/job/1978959 # bad: [4109043bff31f95d3da9ace33eb3c1925fd62cbd] modpost: Ignore unresolved section bounds symbols git bisect bad 4109043bff31f95d3da9ace33eb3c1925fd62cbd # test job: [1ba9f8979426590367406c70c1c821f5b943f993] https://lava.sirena.org.uk/scheduler/job/1979168 # good: [1ba9f8979426590367406c70c1c821f5b943f993] vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros git bisect good 1ba9f8979426590367406c70c1c821f5b943f993 # test job: [9f14f1f91883aa2bfd6663161d2002c8ce937c43] https://lava.sirena.org.uk/scheduler/job/1979231 # good: [9f14f1f91883aa2bfd6663161d2002c8ce937c43] compiler.h: Make addressable symbols less of an eyesore git bisect good 9f14f1f91883aa2bfd6663161d2002c8ce937c43 # test job: [6717e8f91db71641cb52855ed14c7900972ed0bc] https://lava.sirena.org.uk/scheduler/job/1979182 # bad: [6717e8f91db71641cb52855ed14c7900972ed0bc] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME git bisect bad 6717e8f91db71641cb52855ed14c7900972ed0bc # test job: [c2d420796a427dda71a2400909864e7f8e037fd4] https://lava.sirena.org.uk/scheduler/job/1979307 # good: [c2d420796a427dda71a2400909864e7f8e037fd4] elfnote: Change ELFNOTE() to use __UNIQUE_ID() git bisect good c2d420796a427dda71a2400909864e7f8e037fd4 # first bad commit: [6717e8f91db71641cb52855ed14c7900972ed0bc] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
Re: [PATCH v4 08/63] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
In reply to Josh PoimboeufQuoted 40 lines · Josh Poimboeuf
In preparation for the objtool klp diff subcommand, remove the arbitrary '
kmod_' prefix from__KBUILD_MODNAMEand instead add it explicitly in the__initcall_id()macro.This change supports the standardization of "unique" symbol naming by ensuring the non-unique portion of the name comes before the unique part. That will enable objtool to properly correlate symbols across builds.
Cc Masahiro Yamada <[email protected]>Signed-off-by Josh Poimboeuf <[email protected]>--- include/linux/init.h | 3 ++- scripts/Makefile.lib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)include/linux/init.h +2
-1@@ -200,12 +200,13 @@ extern struct module __this_module;/* Format: <modname>__<counter>_<line>_<fn> */ #define __initcall_id (fn) \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(__COUNTER__, \ __PASTE(_, \ __PASTE(__LINE__, \ - __PASTE(_, fn)))))) + __PASTE(_, fn)))))))/* Format: __<prefix>__<iid><id> */ #define __initcall_name (prefix, __iid, id) \scripts/Makefile.lib +0
-0
scripts/Makefile.lib name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) · line 23
Quoted 5 lines
scripts/Makefile.lib +1
-1@@ -20,7 +20,7 @@ name-fix-token = $(subst $(comma),_,$(subst -,_,$1)) name-fix = $(call stringify,$(call name-fix-token,$1)) basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname)) \ - -D__KBUILD_MODNAME=kmod_$(call name-fix-token,$(modname)) + -D__KBUILD_MODNAME=$(call name-fix-token,$(modname))
As others have mentioned, this breaks modules.alias generation.
The following diff seems to fix it, although in introduces a slight functional change if symbols do not actually follow the naming scheme.
scripts/mod/file2alias.c +2 -5
@@ -1489,14 +1489,11 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,if (ELF_ST_TYPE (sym->st_info) !=STT_OBJECT )return ; -/* All our symbols are of form __mod_device_table__kmod_<modname>__<type>__<name>. */ +/* All our symbols are of form __mod_device_table__<modname>__<type>__<name>. */ if (!strstarts (symname, prefix))return ; - modname =strstr (symname,"__kmod_" ); -if (!modname) -return ; - modname +=strlen ("__kmod_" ); + modname = symname +strlen (prefix); type =strstr (modname,"__" );if (!type)
It would seem like rust generated symbols don't follow it exactly?
See module_device_table macro in rust/kernel/device_id.rs.
Quoted 3 lines
scripts/Makefile.lib +0
-0modfile_flags = -DKBUILD_MODFILE=$(call stringify,$(modfile)) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
Josh Poimboeuf
maintainerPATCH v4 9/63 modpost: Ignore unresolved section bounds symbols
In reply to Josh PoimboeufIn preparation for klp-build livepatch module creation tooling, suppress warnings for unresolved references to linker-generated __start_* and __stop_* section bounds symbols.
These symbols are expected to be undefined when modpost runs, as they're created later by the linker.
--- scripts/mod/modpost.c | 5 +++++ 1 file changed, 5 insertions(+)
scripts/mod/modpost.c +5 -0
@@ -606,6 +606,11 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) strstarts(symname, "_savevr_") || strcmp(symname, ".TOC.") == 0)return 1 ; + +/* ignore linker-created section bounds variables */ +if (strstarts (symname,"__start_" ) ||strstarts (symname,"__stop_" )) +return 1 ; +/* Do not ignore this symbol */ return 0 ; }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 10/63 x86/alternative: Refactor INT3 call emulation selftest
In reply to Josh PoimboeufThe INT3 call emulation selftest is a bit fragile as it relies on the compiler not inserting any extra instructions before the int3_selftest_ip() definition.
Also, the int3_selftest_ip() symbol overlaps with the int3_selftest symbol(), which can confuse objtool.
Fix those issues by slightly reworking the functionality and moving int3_selftest_ip() to a separate asm function. While at it, improve the naming.
--- arch/x86/kernel/alternative.c | 51 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-)
arch/x86/kernel/alternative.c +28 -23
@@ -2244,21 +2244,34 @@ int alternatives_text_reserved(void *start, void *end)* See entry_{32,64}.S for more details. */ -/* -* We define the int3_magic() function in assembly to control the calling -* convention such that we can 'call' it from assembly. -*/ - -extern void int3_magic (unsigned int *ptr);/* defined in asm */ +extern void int3_selftest_asm (unsigned int *ptr); asm (" .pushsection .init.text, \"ax\", @progbits\n" -" .type int3_magic, @function\n" -"int3_magic:\n" +" .type int3_selftest_asm, @function\n" +"int3_selftest_asm:\n" ANNOTATE_NOENDBR -" movl $1, (%" _ASM_ARG1")\n" +/* +* INT3 padded with NOP to CALL_INSN_SIZE. The INT3 triggers an +* exception, then the int3_exception_nb notifier emulates a call to +* int3_selftest_callee(). +*/ +" int3; nop; nop; nop; nop\n" ASM_RET -" .size int3_magic, .-int3_magic\n" +" .size int3_selftest_asm, . - int3_selftest_asm\n" +" .popsection\n" +); + +extern void int3_selftest_callee (unsigned int *ptr); + +asm ( +" .pushsection .init.text, \"ax\", @progbits\n" +" .type int3_selftest_callee, @function\n" +"int3_selftest_callee:\n" +ANNOTATE_NOENDBR +" movl $0x1234, (%" _ASM_ARG1")\n" +ASM_RET +" .size int3_selftest_callee, . - int3_selftest_callee\n" " .popsection\n" );
@@ -2267,7 +2280,7 @@ extern void int3_selftest_ip(void); /* defined in asm below */static int __init int3_exception_notify (struct notifier_block *self,unsigned long val,void *data) { -unsigned long selftest = (unsigned long )&int3_selftest_ip; +unsigned long selftest = (unsigned long )&int3_selftest_asm;struct die_args *args = data;struct pt_regs *regs = args->regs;
@@ -2282,7 +2295,7 @@ int3_exception_notify(struct notifier_block *self, unsigned long val, void *dataif (regs->ip -INT3_INSN_SIZE != selftest)return NOTIFY_DONE ; -int3_emulate_call (regs, (unsigned long )&int3_magic); +int3_emulate_call (regs, (unsigned long )&int3_selftest_callee);return NOTIFY_STOP ; }
@@ -2298,19 +2311,11 @@ static noinline void __init int3_selftest(void)BUG_ON (register_die_notifier (&int3_exception_nb));/* -* Basically: int3_magic(&val); but really complicated :-) -* -* INT3 padded with NOP to CALL_INSN_SIZE. The int3_exception_nb -* notifier above will emulate CALL for us. +* Basically: int3_selftest_callee(&val); but really complicated :-) */ - asmvolatile ("int3_selftest_ip:\n\t" -ANNOTATE_NOENDBR -" int3; nop; nop; nop; nop\n\t" - : ASM_CALL_CONSTRAINT - : __ASM_SEL_RAW(a, D) (&val) - : "memory"); +int3_selftest_asm (&val); -BUG_ON (val !=1 ); +BUG_ON (val !=0x1234 );unregister_die_notifier (&int3_exception_nb); }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 11/63 interval_tree: Sync interval_tree_generic.h with tools
In reply to Josh PoimboeufThe following commit made an improvement to interval_tree_generic.h, but didn't sync it to the tools copy:
19811285784f ("lib/interval_tree: skip the check before go to the right subtree")
Sync it, and add it to objtool's sync-check.sh so they are more likely to stay in sync going forward.
--- tools/include/linux/interval_tree_generic.h | 8 ++------ tools/objtool/sync-check.sh | 1 + 2 files changed, 3 insertions(+), 6 deletions(-)
tools/include/linux/interval_tree_generic.h +2 -6
@@ -104,12 +104,8 @@ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \if (ITSTART (node) <= last) {/* Cond1 */ \if (start <=ITLAST (node))/* Cond2 */ \return node;/* node is leftmost match */ \ -if (node->ITRB.rb_right) { \ - node =rb_entry (node->ITRB.rb_right, \ -ITSTRUCT ,ITRB ); \ -if (start <= node->ITSUBTREE) \ -continue ; \ - } \ + node =rb_entry (node->ITRB.rb_right,ITSTRUCT ,ITRB ); \ +continue ; \ } \return NULL ;/* No match */ \ } \
tools/objtool/sync-check.sh +1 -0
@@ -16,6 +16,7 @@ arch/x86/include/asm/orc_types.h arch/x86/include/asm/emulate_prefix.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk +include/linux/interval_tree_generic.h include/linux/static_call_types.h "
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 12/63 interval_tree: Fix ITSTATIC usage for *_subtree_search()
In reply to Josh PoimboeufFor consistency with the other function templates, change _subtree_search_*() to use the user-supplied ITSTATIC rather than the hard-coded 'static'.
--- include/linux/interval_tree.h | 4 ++++ include/linux/interval_tree_generic.h | 2 +- include/linux/mm.h | 2 ++ tools/include/linux/interval_tree_generic.h | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-)
include/linux/interval_tree.h +4 -0
@@ -19,6 +19,10 @@ extern void interval_tree_remove(struct interval_tree_node *node, struct rb_root_cached *root); +extern struct interval_tree_node * +interval_tree_subtree_search (struct interval_tree_node *node, +unsigned long start,unsigned long last); +extern struct interval_tree_node *interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last);
include/linux/interval_tree_generic.h +1 -1
@@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \* Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \while (true) { \
include/linux/mm.h +2 -0
@@ -3265,6 +3265,8 @@ void vma_interval_tree_insert_after(struct vm_area_struct *node, struct rb_root_cached *root);void vma_interval_tree_remove (struct vm_area_struct *node,struct rb_root_cached *root); +struct vm_area_struct *vma_interval_tree_subtree_search (struct vm_area_struct *node, +unsigned long start,unsigned long last);struct vm_area_struct *vma_interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last); struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node,
tools/include/linux/interval_tree_generic.h +1 -1
@@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \* Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \while (true) { \
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 12/63 interval_tree: Fix ITSTATIC usage for *_subtree_search()
For consistency with the other function templates, change _subtree_search_*() to use the user-supplied ITSTATIC rather than the hard-coded 'static'.
---
v4.1: Fixed a couple more INTERVAL_TREE_DEFINE usages.
drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.h | 4 ++++ include/linux/interval_tree.h | 4 ++++ include/linux/interval_tree_generic.h | 2 +- include/linux/mm.h | 2 ++ lib/interval_tree.c | 1 + tools/include/linux/interval_tree_generic.h | 2 +- 6 files changed, 13 insertions(+), 2 deletions(-)
drivers/infiniband/hw/usnic/usnic_uiom_interval_tree.h +4 -0
@@ -53,6 +53,10 @@ extern void usnic_uiom_interval_tree_remove(struct usnic_uiom_interval_node *node, struct rb_root_cached *root);extern struct usnic_uiom_interval_node * +usnic_uiom_interval_tree_subtree_search (struct usnic_uiom_interval_node *node, +unsigned long start, +unsigned long last); +extern struct usnic_uiom_interval_node *usnic_uiom_interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last);
include/linux/interval_tree.h +4 -0
@@ -19,6 +19,10 @@ extern void interval_tree_remove(struct interval_tree_node *node, struct rb_root_cached *root); +extern struct interval_tree_node * +interval_tree_subtree_search (struct interval_tree_node *node, +unsigned long start,unsigned long last); +extern struct interval_tree_node *interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last);
include/linux/interval_tree_generic.h +1 -1
@@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \* Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \while (true) { \
include/linux/mm.h +2 -0
@@ -3265,6 +3265,8 @@ void vma_interval_tree_insert_after(struct vm_area_struct *node, struct rb_root_cached *root);void vma_interval_tree_remove (struct vm_area_struct *node,struct rb_root_cached *root); +struct vm_area_struct *vma_interval_tree_subtree_search (struct vm_area_struct *node, +unsigned long start,unsigned long last);struct vm_area_struct *vma_interval_tree_iter_first (struct rb_root_cached *root,unsigned long start,unsigned long last); struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node,
lib/interval_tree.c +1 -0
@@ -13,6 +13,7 @@ INTERVAL_TREE_DEFINE(struct interval_tree_node, rb,EXPORT_SYMBOL_GPL (interval_tree_insert);EXPORT_SYMBOL_GPL (interval_tree_remove); +EXPORT_SYMBOL_GPL (interval_tree_subtree_search);EXPORT_SYMBOL_GPL (interval_tree_iter_first);EXPORT_SYMBOL_GPL (interval_tree_iter_next);
tools/include/linux/interval_tree_generic.h +1 -1
@@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \* Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \while (true) { \
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 13/63 objtool: Make find_symbol_containing() less arbitrary
In reply to Josh PoimboeufIn the rare case of overlapping symbols, find_symbol_containing() just returns the first one it finds. Make it slightly less arbitrary by returning the smallest symbol with size > 0.
--- tools/objtool/elf.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
tools/objtool/elf.c +20 -5
@@ -193,14 +193,29 @@ struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)struct symbol *find_symbol_containing (const struct section *sec,unsigned long offset) {struct rb_root_cached *tree = (struct rb_root_cached *)&sec->symbol_tree; -struct symbol *iter; +struct symbol *sym =NULL , *tmp; -__sym_for_each (iter, tree, offset, offset) { -if (iter->type !=STT_SECTION ) -return iter; +__sym_for_each (tmp, tree, offset, offset) { +if (tmp->len) { +if (!sym) { + sym = tmp; +continue ; + } + +if (sym->offset != tmp->offset || sym->len != tmp->len) { +/* +* In the rare case of overlapping symbols, +* pick the smaller one. +* +* TODO: outlaw overlapping symbols +*/ +if (tmp->len < sym->len) + sym = tmp; + } + } } -return NULL ; +return sym; }/*
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 14/63 objtool: Fix broken error handling in read_symbols()
In reply to Josh PoimboeufThe free(sym) call in the read_symbols() error path is fundamentally
broken: 'sym' doesn't point to any allocated block. If triggered, things would go from bad to worse.
Remove the free() and simplify the error paths. Freeing memory isn't necessary here anyway, these are fatal errors which lead to an immediate exit().
--- tools/objtool/elf.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
tools/objtool/elf.c +3 -7
@@ -492,14 +492,14 @@ static int read_symbols(struct elf *elf)if (!gelf_getsymshndx (symtab->data, shndx_data, i, &sym->sym, &shndx)) {ERROR_ELF ("gelf_getsymshndx" ); - goto err; +return -1 ; } sym->name =elf_strptr (elf->elf, symtab->sh.sh_link, sym->sym.st_name);if (!sym->name) {ERROR_ELF ("elf_strptr" ); - goto err; +return -1 ; } if ((sym->sym.st_shndx > SHN_UNDEF &&
@@ -511,7 +511,7 @@ static int read_symbols(struct elf *elf) sym->sec =find_section_by_index (elf, shndx);if (!sym->sec) {ERROR ("couldn't find section for symbol %s" , sym->name); - goto err; +return -1 ; }if (GELF_ST_TYPE (sym->sym.st_info) ==STT_SECTION ) { sym->name = sym->sec->name;
@@ -581,10 +581,6 @@ static int read_symbols(struct elf *elf) }return 0 ; - -err: -free (sym); -return -1 ; }static int mark_group_syms (struct elf *elf)
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 15/63 objtool: Propagate elf_truncate_section() error in elf_write()
In reply to Josh PoimboeufProperly check and propagate the return value of elf_truncate_section() to avoid silent failures.
--- tools/objtool/elf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
tools/objtool/elf.c +2 -3
@@ -1307,7 +1307,6 @@ static int elf_truncate_section(struct elf *elf, struct section *sec)for (;;) {/* get next data descriptor for the relevant section */ data =elf_getdata (s, data); -if (!data) {if (size) {ERROR ("end of section data but non-zero size left\n" );
@@ -1343,8 +1342,8 @@ int elf_write(struct elf *elf)/* Update changed relocation sections and section headers: */ list_for_each_entry (sec, &elf->sections, list) { -if (sec->truncate) -elf_truncate_section (elf, sec); +if (sec->truncate &&elf_truncate_section (elf, sec)) +return -1 ;if (sec_changed (sec)) { s =elf_getscn (elf->elf, sec->idx);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 16/63 objtool: Remove error handling boilerplate
In reply to Josh PoimboeufUp to a certain point in objtool's execution, all errors are fatal and return -1. When propagating such errors, just return -1 directly instead of trying to propagate the original return code. This helps make the code more compact and the behavior more explicit.
--- tools/objtool/check.c | 151 +++++++++++++++------------------------- tools/objtool/special.c | 9 +-- 2 files changed, 59 insertions(+), 101 deletions(-)
tools/objtool/check.c +56 -95
@@ -430,7 +430,6 @@ static int decode_instructions(struct objtool_file *file)struct symbol *func;unsigned long offset;struct instruction *insn; -int ret;for_each_sec (file, sec) {struct instruction *insns =NULL ;
@@ -479,11 +478,8 @@ static int decode_instructions(struct objtool_file *file) insn->offset = offset; insn->prev_len = prev_len; - ret =arch_decode_instruction (file, sec, offset, - sec->sh.sh_size - offset, - insn); -if (ret) -return ret; +if (arch_decode_instruction (file, sec, offset, sec->sh.sh_size - offset, insn)) +return -1 ; prev_len = insn->len;
@@ -599,7 +595,7 @@ static int init_pv_ops(struct objtool_file *file) };const char *pv_ops;struct symbol *sym; -int idx, nr, ret; +int idx, nr;if (!opts.noinstr)return 0 ;
@@ -621,9 +617,8 @@ static int init_pv_ops(struct objtool_file *file)INIT_LIST_HEAD (&file->pv_ops[idx].targets);for (idx =0 ; (pv_ops = pv_ops_tables[idx]); idx++) { - ret =add_pv_ops (file, pv_ops); -if (ret) -return ret; +if (add_pv_ops (file, pv_ops)) +return -1 ; }return 0 ;
@@ -1484,7 +1479,6 @@ static int add_jump_destinations(struct objtool_file *file)struct reloc *reloc;struct section *dest_sec;unsigned long dest_off; -int ret;for_each_insn (file, insn) {struct symbol *func =insn_func (insn);
@@ -1507,9 +1501,8 @@ static int add_jump_destinations(struct objtool_file *file) dest_sec = reloc->sym->sec; dest_off =arch_dest_reloc_offset (reloc_addend (reloc)); }else if (reloc->sym->retpoline_thunk) { - ret =add_retpoline_call (file, insn); -if (ret) -return ret; +if (add_retpoline_call (file, insn)) +return -1 ;continue ; }else if (reloc->sym->return_thunk) {add_return_call (file, insn, true);
@@ -1519,9 +1512,8 @@ static int add_jump_destinations(struct objtool_file *file)* External sibling call or internal sibling call with * STT_FUNC reloc. */ - ret =add_call_dest (file, insn, reloc->sym, true); -if (ret) -return ret; +if (add_call_dest (file, insn, reloc->sym, true)) +return -1 ;continue ; }else if (reloc->sym->sec->idx) { dest_sec = reloc->sym->sec;
@@ -1570,9 +1562,8 @@ static int add_jump_destinations(struct objtool_file *file)*/ if (jump_dest->sym && jump_dest->offset == jump_dest->sym->offset) {if (jump_dest->sym->retpoline_thunk) { - ret =add_retpoline_call (file, insn); -if (ret) -return ret; +if (add_retpoline_call (file, insn)) +return -1 ;continue ; }if (jump_dest->sym->return_thunk) {
@@ -1613,9 +1604,8 @@ static int add_jump_destinations(struct objtool_file *file)* Internal sibling call without reloc or with * STT_SECTION reloc. */ - ret =add_call_dest (file, insn,insn_func (jump_dest), true); -if (ret) -return ret; +if (add_call_dest (file, insn,insn_func (jump_dest), true)) +return -1 ;continue ; }
@@ -1645,7 +1635,6 @@ static int add_call_destinations(struct objtool_file *file)unsigned long dest_off;struct symbol *dest;struct reloc *reloc; -int ret;for_each_insn (file, insn) {struct symbol *func =insn_func (insn);
@@ -1657,9 +1646,8 @@ static int add_call_destinations(struct objtool_file *file) dest_off =arch_jump_destination (insn); dest =find_call_destination (insn->sec, dest_off); - ret =add_call_dest (file, insn, dest, false); -if (ret) -return ret; +if (add_call_dest (file, insn, dest, false)) +return -1 ;if (func && func->ignore)continue ;
@@ -1683,19 +1671,16 @@ static int add_call_destinations(struct objtool_file *file)return -1 ; } - ret =add_call_dest (file, insn, dest, false); -if (ret) -return ret; +if (add_call_dest (file, insn, dest, false)) +return -1 ; }else if (reloc->sym->retpoline_thunk) { - ret =add_retpoline_call (file, insn); -if (ret) -return ret; +if (add_retpoline_call (file, insn)) +return -1 ; }else { - ret =add_call_dest (file, insn, reloc->sym, false); -if (ret) -return ret; +if (add_call_dest (file, insn, reloc->sym, false)) +return -1 ; } }
@@ -1912,7 +1897,6 @@ static int add_special_section_alts(struct objtool_file *file)struct instruction *orig_insn, *new_insn;struct special_alt *special_alt, *tmp;struct alternative *alt; -int ret;if (special_get_alts (file->elf, &special_alts))return -1 ;
@@ -1944,16 +1928,12 @@ static int add_special_section_alts(struct objtool_file *file)continue ; } - ret =handle_group_alt (file, special_alt, orig_insn, - &new_insn); -if (ret) -return ret; +if (handle_group_alt (file, special_alt, orig_insn, &new_insn)) +return -1 ; }else if (special_alt->jump_or_nop) { - ret =handle_jump_alt (file, special_alt, orig_insn, - &new_insn); -if (ret) -return ret; +if (handle_jump_alt (file, special_alt, orig_insn, &new_insn)) +return -1 ; } alt =calloc (1 ,sizeof (*alt));
@@ -2141,15 +2121,13 @@ static int add_func_jump_tables(struct objtool_file *file, struct symbol *func) {struct instruction *insn; -int ret;func_for_each_insn (file, func, insn) {if (!insn_jump_table (insn))continue ; - ret =add_jump_table (file, insn); -if (ret) -return ret; +if (add_jump_table (file, insn)) +return -1 ; }return 0 ;
@@ -2163,7 +2141,6 @@ static int add_func_jump_tables(struct objtool_file *file,static int add_jump_table_alts (struct objtool_file *file) {struct symbol *func; -int ret;if (!file->rodata)return 0 ;
@@ -2173,9 +2150,8 @@ static int add_jump_table_alts(struct objtool_file *file)continue ;mark_func_jump_tables (file, func); - ret =add_func_jump_tables (file, func); -if (ret) -return ret; +if (add_func_jump_tables (file, func)) +return -1 ; }return 0 ;
@@ -2299,7 +2275,7 @@ static int read_annotate(struct objtool_file *file,struct instruction *insn;struct reloc *reloc;uint64_t offset; -int type, ret; +int type; sec =find_section_by_name (file->elf,".discard.annotate_insn" );if (!sec)
@@ -2329,9 +2305,8 @@ static int read_annotate(struct objtool_file *file,return -1 ; } - ret =func (file, type, insn); -if (ret <0 ) -return ret; +if (func (file, type, insn)) +return -1 ; }return 0 ;
@@ -2540,76 +2515,62 @@ static void mark_rodata(struct objtool_file *file)static int decode_sections (struct objtool_file *file) { -int ret; -mark_rodata (file); - ret =init_pv_ops (file); -if (ret) -return ret; +if (init_pv_ops (file)) +return -1 ;/* * Must be before add_{jump_call}_destination. */ - ret =classify_symbols (file); -if (ret) -return ret; +if (classify_symbols (file)) +return -1 ; - ret =decode_instructions (file); -if (ret) -return ret; +if (decode_instructions (file)) +return -1 ; - ret =add_ignores (file); -if (ret) -return ret; +if (add_ignores (file)) +return -1 ;add_uaccess_safe (file); - ret =read_annotate (file, __annotate_early); -if (ret) -return ret; +if (read_annotate (file, __annotate_early)) +return -1 ;/* * Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr) { - ret =add_special_section_alts (file); -if (ret) -return ret; +if (add_special_section_alts (file)) +return -1 ; } - ret =add_jump_destinations (file); -if (ret) -return ret; +if (add_jump_destinations (file)) +return -1 ;/* * Must be before add_call_destination(); it changes INSN_CALL to * INSN_JUMP. */ - ret =read_annotate (file, __annotate_ifc); -if (ret) -return ret; +if (read_annotate (file, __annotate_ifc)) +return -1 ; - ret =add_call_destinations (file); -if (ret) -return ret; +if (add_call_destinations (file)) +return -1 ; - ret =add_jump_table_alts (file); -if (ret) -return ret; +if (add_jump_table_alts (file)) +return -1 ; - ret =read_unwind_hints (file); -if (ret) -return ret; +if (read_unwind_hints (file)) +return -1 ;/* * Must be after add_call_destinations() such that it can override * dead_end_function() marks. */ - ret =read_annotate (file, __annotate_late); -if (ret) -return ret; +if (read_annotate (file, __annotate_late)) +return -1 ;return 0 ; }
tools/objtool/special.c +3 -6
@@ -133,7 +133,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)struct section *sec;unsigned int nr_entries;struct special_alt *alt; -int idx, ret; +int idx;INIT_LIST_HEAD (alts);
@@ -157,11 +157,8 @@ int special_get_alts(struct elf *elf, struct list_head *alts) }memset (alt,0 ,sizeof (*alt)); - ret =get_alt_entry (elf, entry, sec, idx, alt); -if (ret >0 ) -continue ; -if (ret <0 ) -return ret; +if (get_alt_entry (elf, entry, sec, idx, alt)) +return -1 ;list_add_tail (&alt->list, alts); }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 17/63 objtool: Add empty symbols to the symbol tree again
In reply to Josh PoimboeufThe following commit
5da6aea375cd ("objtool: Fix find_{symbol,func}_containing()")
fixed the issue where overlapping symbols weren't getting sorted properly in the symbol tree. Therefore the workaround to skip adding empty symbols from the following commit
a2e38dffcd93 ("objtool: Don't add empty symbols to the rbtree")
is no longer needed.
--- tools/objtool/elf.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
tools/objtool/elf.c +2 -8
@@ -96,7 +96,8 @@ static inline unsigned long __sym_last(struct symbol *s) } INTERVAL_TREE_DEFINE(struct symbol, node, unsigned long, __subtree_last, - __sym_start, __sym_last, static, __sym) + __sym_start, __sym_last, static inline __maybe_unused, + __sym)#define __sym_for_each (_iter, _tree, _start, _end) \ for (_iter = __sym_iter_first((_tree), (_start), (_end)); \
@@ -440,13 +441,6 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)list_add (&sym->list, entry);elf_hash_add (symbol, &sym->hash, sym->idx);elf_hash_add (symbol_name, &sym->name_hash,str_hash (sym->name)); - -/* -* Don't store empty STT_NOTYPE symbols in the rbtree. They -* can exist within a function, confusing the sorting. -*/ -if (!sym->len) -__sym_remove (sym, &sym->sec->symbol_tree); }static int read_symbols (struct elf *elf)
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 18/63 objtool: Fix interval tree insertion for zero-length symbols
In reply to Josh PoimboeufZero-length symbols get inserted in the wrong spot. Fix that.
--- tools/objtool/elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/elf.c +1 -1
@@ -92,7 +92,7 @@ static inline unsigned long __sym_start(struct symbol *s)static inline unsigned long __sym_last (struct symbol *s) { -return s->offset + s->len -1 ; +return s->offset + (s->len ? s->len -1 :0 ); } INTERVAL_TREE_DEFINE(struct symbol, node, unsigned long, __subtree_last,
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 19/63 objtool: Fix weak symbol detection
In reply to Josh Poimboeuffind_symbol_hole_containing() fails to find a symbol hole (aka stripped weak symbol) if its section has no symbols before the hole. This breaks weak symbol detection if -ffunction-sections is enabled.
Fix that by allowing the interval tree to contain section symbols, which are always at offset zero for a given section.
Fixes a bunch of (-ffunction-sections) warnings like:
vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x10: unreachable instruction
--- tools/objtool/elf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/objtool/elf.c +4 -4
@@ -109,7 +109,7 @@ struct symbol_hole { };/* -* Find !section symbol where @offset is after it. +* Find the last symbol before @offset. */ static int symbol_hole_by_offset (const void *key,const struct rb_node *node) {
@@ -120,8 +120,7 @@ static int symbol_hole_by_offset(const void *key, const struct rb_node *node)return -1 ;if (sh->key >= s->offset + s->len) { -if (s->type !=STT_SECTION ) - sh->sym = s; + sh->sym = s;return 1 ; }
@@ -428,7 +427,8 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym) sym->len = sym->sym.st_size;__sym_for_each (iter, &sym->sec->symbol_tree, sym->offset, sym->offset) { -if (iter->offset == sym->offset && iter->type == sym->type) +if (iter->offset == sym->offset && iter->type == sym->type && + iter->len == sym->len) iter->alias = sym; }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 20/63 objtool: Fix x86 addend calculation
In reply to Josh PoimboeufOn x86, arch_dest_reloc_offset() hardcodes the addend adjustment to four, but the actual adjustment depends on the relocation type. Fix that.
--- tools/objtool/arch/loongarch/decode.c | 4 ++-- tools/objtool/arch/powerpc/decode.c | 4 ++-- tools/objtool/arch/x86/decode.c | 9 +++++++-- tools/objtool/check.c | 15 +++++---------- tools/objtool/include/objtool/arch.h | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-)
tools/objtool/arch/loongarch/decode.c +2 -2
@@ -17,9 +17,9 @@ unsigned long arch_jump_destination(struct instruction *insn)return insn->offset + (insn->immediate <<2 ); } -unsigned long arch_dest_reloc_offset (int addend) +s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc) { -return addend; +return reloc_addend (reloc); }bool arch_pc_relative_reloc (struct reloc *reloc)
tools/objtool/arch/powerpc/decode.c +2 -2
@@ -14,9 +14,9 @@ int arch_ftrace_match(char *name)return !strcmp (name,"_mcount" ); } -unsigned long arch_dest_reloc_offset (int addend) +s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc) { -return addend; +return reloc_addend (reloc); }bool arch_callee_saved_reg (unsigned char reg)
tools/objtool/arch/x86/decode.c +7 -2
@@ -68,9 +68,14 @@ bool arch_callee_saved_reg(unsigned char reg) } } -unsigned long arch_dest_reloc_offset (int addend) +s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc) { -return addend +4 ; +s64 addend =reloc_addend (reloc); + +if (arch_pc_relative_reloc (reloc)) + addend += insn->offset + insn->len -reloc_offset (reloc); + +return addend; }unsigned long arch_jump_destination (struct instruction *insn)
tools/objtool/check.c +5 -10
@@ -1499,7 +1499,7 @@ static int add_jump_destinations(struct objtool_file *file) dest_off =arch_jump_destination (insn); }else if (reloc->sym->type ==STT_SECTION ) { dest_sec = reloc->sym->sec; - dest_off =arch_dest_reloc_offset (reloc_addend (reloc)); + dest_off =arch_insn_adjusted_addend (insn, reloc); }else if (reloc->sym->retpoline_thunk) {if (add_retpoline_call (file, insn))return -1 ;
@@ -1518,7 +1518,7 @@ static int add_jump_destinations(struct objtool_file *file) }else if (reloc->sym->sec->idx) { dest_sec = reloc->sym->sec; dest_off = reloc->sym->sym.st_value + -arch_dest_reloc_offset (reloc_addend (reloc)); +arch_insn_adjusted_addend (insn, reloc); }else {/* non-func asm code jumping to another file */ continue ;
@@ -1663,7 +1663,7 @@ static int add_call_destinations(struct objtool_file *file) } }else if (reloc->sym->type ==STT_SECTION ) { - dest_off =arch_dest_reloc_offset (reloc_addend (reloc)); + dest_off =arch_insn_adjusted_addend (insn, reloc); dest =find_call_destination (reloc->sym->sec, dest_off);if (!dest) { ERROR_INSN(insn, "can't find call dest symbol at %s+0x%lx",
@@ -3324,7 +3324,7 @@ static bool pv_call_dest(struct objtool_file *file, struct instruction *insn)if (!reloc ||strcmp (reloc->sym->name,"pv_ops" ))return false; - idx = (arch_dest_reloc_offset (reloc_addend (reloc)) /sizeof (void *)); + idx =arch_insn_adjusted_addend (insn, reloc) /sizeof (void *);if (file->pv_ops[idx].clean)return true;
@@ -4405,12 +4405,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn reloc_offset(reloc) + 1, (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { - off = reloc->sym->offset; -if (reloc_type (reloc) ==R_X86_64_PC32 || -reloc_type (reloc) ==R_X86_64_PLT32 ) - off +=arch_dest_reloc_offset (reloc_addend (reloc)); -else - off +=reloc_addend (reloc); + off = reloc->sym->offset +arch_insn_adjusted_addend (insn, reloc); dest =find_insn (file, reloc->sym->sec, off);if (!dest)
tools/objtool/include/objtool/arch.h +1 -1
@@ -83,7 +83,7 @@ bool arch_callee_saved_reg(unsigned char reg);unsigned long arch_jump_destination (struct instruction *insn); -unsigned long arch_dest_reloc_offset (int addend); +s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc);const char *arch_nop_insn (int len);const char *arch_ret_insn (int len);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 21/63 objtool: Fix __pa_symbol() relocation handling
In reply to Josh Poimboeuf__pa_symbol() generates a relocation which refers to a physical address. Convert it to back its virtual form before calculating the addend.
--- tools/objtool/arch/x86/decode.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
tools/objtool/arch/x86/decode.c +12 -1
@@ -68,6 +68,17 @@ bool arch_callee_saved_reg(unsigned char reg) } } +/* Undo the effects of __pa_symbol() if necessary */ +static unsigned long phys_to_virt (unsigned long pa) +{ +s64 va = pa; + +if (va >0 ) + va &= ~(0x80000000 ); + +return va; +} +s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc) {s64 addend =reloc_addend (reloc);
@@ -75,7 +86,7 @@ s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc)if (arch_pc_relative_reloc (reloc)) addend += insn->offset + insn->len -reloc_offset (reloc); -return addend; +return phys_to_virt (addend); }unsigned long arch_jump_destination (struct instruction *insn)
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 22/63 objtool: Fix "unexpected end of section" warning for alternatives
In reply to Josh PoimboeufDue to the short circuiting logic in next_insn_to_validate(), control flow may silently transition from .altinstr_replacement to .text without a corresponding nested call to validate_branch().
As a result the validate_branch() 'sec' variable doesn't get reinitialized, which can trigger a confusing "unexpected end of section" warning which blames .altinstr_replacement rather than the offending fallthrough function.
Fix that by not caching the section. There's no point in doing that anyway.
--- tools/objtool/check.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
tools/objtool/check.c +1 -4
@@ -3521,15 +3521,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, {struct alternative *alt;struct instruction *next_insn, *prev_insn =NULL ; -struct section *sec;u8 visited;int ret;if (func && func->ignore)return 0 ; - sec = insn->sec; -while (1 ) { next_insn =next_insn_to_validate (file, insn);
@@ -3769,7 +3766,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,WARN ("%s%sunexpected end of section %s" , func ? func->name :"" , func ?"(): " :"" , - sec->name); + insn->sec->name);return 1 ; }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 23/63 objtool: Check for missing annotation entries in read_annotate()
In reply to Josh PoimboeufAdd a sanity check to make sure none of the relocations for the .discard.annotate_insn section have gone missing.
--- tools/objtool/check.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/objtool/check.c +5 -0
@@ -2293,6 +2293,11 @@ static int read_annotate(struct objtool_file *file, sec->sh.sh_entsize =8 ; } +if (sec_num_entries (sec) !=sec_num_entries (sec->rsec)) { +ERROR ("bad .discard.annotate_insn section: missing relocs" ); +return -1 ; + } +for_each_reloc (sec->rsec, reloc) { type = *(u32 *)(sec->data->d_buf + (reloc_idx (reloc) * sec->sh.sh_entsize) +4 ); type =bswap_if_needed (file->elf, type);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 24/63 objtool: Const string cleanup
In reply to Josh PoimboeufUse 'const char *' where applicable.
--- tools/objtool/arch/loongarch/decode.c | 2 +- tools/objtool/arch/powerpc/decode.c | 2 +- tools/objtool/arch/x86/decode.c | 2 +- tools/objtool/elf.c | 6 +++--- tools/objtool/include/objtool/arch.h | 2 +- tools/objtool/include/objtool/elf.h | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-)
tools/objtool/arch/loongarch/decode.c +1 -1
@@ -7,7 +7,7 @@#include <linux/objtool_types.h> #include <arch/elf.h> -int arch_ftrace_match (char *name) +int arch_ftrace_match (const char *name) {return !strcmp (name,"_mcount" ); }
tools/objtool/arch/powerpc/decode.c +1 -1
@@ -9,7 +9,7 @@#include <objtool/builtin.h> #include <objtool/endianness.h> -int arch_ftrace_match (char *name) +int arch_ftrace_match (const char *name) {return !strcmp (name,"_mcount" ); }
tools/objtool/arch/x86/decode.c +1 -1
@@ -23,7 +23,7 @@#include <objtool/builtin.h> #include <arch/elf.h> -int arch_ftrace_match (char *name) +int arch_ftrace_match (const char *name) {return !strcmp (name,"__fentry__" ); }
tools/objtool/elf.c +3 -3
@@ -853,7 +853,7 @@ elf_create_section_symbol(struct elf *elf, struct section *sec)return sym; } -static int elf_add_string (struct elf *elf,struct section *strtab,char *str); +static int elf_add_string (struct elf *elf,struct section *strtab,const char *str);struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,long size)
@@ -1086,7 +1086,7 @@ struct elf *elf_open_read(const char *name, int flags)return NULL ; } -static int elf_add_string (struct elf *elf,struct section *strtab,char *str) +static int elf_add_string (struct elf *elf,struct section *strtab,const char *str) {Elf_Data *data;Elf_Scn *s;
@@ -1111,7 +1111,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)return -1 ; } - data->d_buf = str; + data->d_buf =strdup (str); data->d_size =strlen (str) +1 ; data->d_align =1 ;
tools/objtool/include/objtool/arch.h +1 -1
@@ -71,7 +71,7 @@ struct stack_op {struct instruction ; -int arch_ftrace_match (char *name); +int arch_ftrace_match (const char *name);void arch_initial_func_cfi_state (struct cfi_init_state *state);
tools/objtool/include/objtool/elf.h +3 -3
@@ -40,7 +40,7 @@ struct section {struct section *base, *rsec;struct symbol *sym;Elf_Data *data; -char *name; +const char *name;int idx;bool _changed, text, rodata, noinstr, init, truncate;struct reloc *relocs;
@@ -53,7 +53,7 @@ struct symbol {struct elf_hash_node name_hash;GElf_Sym sym;struct section *sec; -char *name; +const char *name;unsigned int idx, len;unsigned long offset;unsigned long __subtree_last;
@@ -88,7 +88,7 @@ struct elf {GElf_Ehdr ehdr;int fd;bool changed; -char *name; +const char *name;unsigned int num_files;struct list_head sections;unsigned long num_relocs;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 25/63 objtool: Clean up compiler flag usage
In reply to Josh PoimboeufKBUILD_HOSTCFLAGS and KBUILD_HOSTLDFLAGS aren't defined when objtool is built standalone. Also, the EXTRA_WARNINGS flags are rather arbitrary.
Make things simpler and more consistent by specifying compiler flags explicitly and tweaking the warnings. Also make a few code tweaks to make the new warnings happy.
--- tools/objtool/Makefile | 15 ++++++++++----- tools/objtool/check.c | 4 ++-- tools/objtool/elf.c | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-)
tools/objtool/Makefile +10 -5
@@ -23,6 +23,11 @@ LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lel all: $(OBJTOOL) +WARNINGS := -Werror -Wall -Wextra -Wmissing-prototypes \ + -Wmissing-declarations -Wwrite-strings \ + -Wno-implicit-fallthrough -Wno-sign-compare \ + -Wno-unused-parameter + INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/include/uapi \ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
@@ -30,11 +35,11 @@ INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/objtool/include \ -I$(srctree)/tools/objtool/arch/$(SRCARCH)/include \ -I$(LIBSUBCMD_OUTPUT)/include -# Note, EXTRA_WARNINGS here was determined for CC and not HOSTCC, it -# is passed here to match a legacy behavior. -WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -Wno-nested-externs -OBJTOOL_CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS) -OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) + +OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g \ + $(WARNINGS) $(INCLUDES) $(LIBELF_FLAGS) $(HOSTCFLAGS) + +OBJTOOL_LDFLAGS := $(LIBSUBCMD) $(LIBELF_LIBS) $(HOSTLDFLAGS) # Allow old libelf to be used: elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - 2>/dev/null | grep elf_getshdr)
tools/objtool/check.c +2 -2
@@ -461,7 +461,7 @@ static int decode_instructions(struct objtool_file *file)for (offset =0 ; offset < sec->sh.sh_size; offset += insn->len) {if (!insns || idx ==INSN_CHUNK_MAX ) { - insns =calloc (sizeof (*insn),INSN_CHUNK_SIZE ); + insns =calloc (INSN_CHUNK_SIZE ,sizeof (*insn));if (!insns) {ERROR_GLIBC ("calloc" );return -1 ;
@@ -607,7 +607,7 @@ static int init_pv_ops(struct objtool_file *file)return 0 ; nr = sym->len /sizeof (unsigned long ); - file->pv_ops =calloc (sizeof (struct pv_state ), nr); + file->pv_ops =calloc (nr,sizeof (struct pv_state ));if (!file->pv_ops) {ERROR_GLIBC ("calloc" );return -1 ;
tools/objtool/elf.c +1 -1
@@ -736,7 +736,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab, }/* setup extended section index magic and write the symbol */ -if ((shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) || is_special_shndx) { +if (shndx <SHN_LORESERVE || is_special_shndx) { sym->sym.st_shndx = shndx;if (!shndx_data) shndx =0 ;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 26/63 objtool: Remove .parainstructions reference
In reply to Josh PoimboeufThe .parainstructions section no longer exists since the following commit:
60bc276b129e ("x86/paravirt: Switch mixed paravirt/alternative calls to alternatives").
Remove the reference to it.
--- tools/objtool/check.c | 1 - 1 file changed, 1 deletion(-)
tools/objtool/check.c +0 -1
@@ -4477,7 +4477,6 @@ static int validate_ibt(struct objtool_file *file) !strcmp (sec->name,".altinstructions" ) || !strcmp (sec->name,".ibt_endbr_seal" ) || !strcmp (sec->name,".orc_unwind_ip" ) || - !strcmp (sec->name,".parainstructions" ) || !strcmp (sec->name,".retpoline_sites" ) || !strcmp (sec->name,".smp_locks" ) || !strcmp(sec->name, ".static_call_sites") ||
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 27/63 objtool: Convert elf iterator macros to use 'struct elf'
In reply to Josh Poimboeuf'struct objtool_file' is specific to the check code and doesn't belong in the elf code which is supposed to be objtool_file-agnostic. Convert the elf iterator macros to use 'struct elf' instead.
--- tools/objtool/check.c | 24 ++++++++++++------------ tools/objtool/include/objtool/elf.h | 8 ++++---- tools/objtool/orc_gen.c | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-)
tools/objtool/check.c +12 -12
@@ -106,7 +106,7 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,#define for_each_insn (file, insn) \ for (struct section *__sec, *__fake = (struct section *)1; \ __fake; __fake = NULL) \ - for_each_sec(file, __sec) \ + for_each_sec(file->elf, __sec) \ sec_for_each_insn(file, __sec, insn)#define func_for_each_insn (file, func, insn) \
@@ -431,7 +431,7 @@ static int decode_instructions(struct objtool_file *file)unsigned long offset;struct instruction *insn; -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {struct instruction *insns =NULL ;u8 prev_len =0 ;u8 idx =0 ;
@@ -857,7 +857,7 @@ static int create_cfi_sections(struct objtool_file *file) } idx =0 ; -for_each_sym (file, sym) { +for_each_sym (file->elf, sym) {if (sym->type !=STT_FUNC )continue ;
@@ -873,7 +873,7 @@ static int create_cfi_sections(struct objtool_file *file)return -1 ; idx =0 ; -for_each_sym (file, sym) { +for_each_sym (file->elf, sym) {if (sym->type !=STT_FUNC )continue ;
@@ -2145,7 +2145,7 @@ static int add_jump_table_alts(struct objtool_file *file)if (!file->rodata)return 0 ; -for_each_sym (file, func) { +for_each_sym (file->elf, func) {if (func->type !=STT_FUNC )continue ;
@@ -2461,7 +2461,7 @@ static int classify_symbols(struct objtool_file *file) {struct symbol *func; -for_each_sym (file, func) { +for_each_sym (file->elf, func) {if (func->type ==STT_NOTYPE &&strstarts (func->name,".L" )) func->local_label = true;
@@ -2506,7 +2506,7 @@ static void mark_rodata(struct objtool_file *file)* * .rodata.str1.* sections are ignored; they don't contain jump tables. */ -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {if ((!strncmp (sec->name,".rodata" ,7 ) && !strstr (sec->name,".str1." )) || !strncmp (sec->name,".data.rel.ro" ,12 )) {
@@ -4187,7 +4187,7 @@ static int add_prefix_symbols(struct objtool_file *file)struct section *sec;struct symbol *func; -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {if (!(sec->sh.sh_flags &SHF_EXECINSTR ))continue ;
@@ -4279,7 +4279,7 @@ static int validate_functions(struct objtool_file *file)struct section *sec;int warnings =0 ; -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {if (!(sec->sh.sh_flags &SHF_EXECINSTR ))continue ;
@@ -4458,7 +4458,7 @@ static int validate_ibt(struct objtool_file *file)for_each_insn (file, insn) warnings +=validate_ibt_insn (file, insn); -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {/* Already done by validate_ibt_insn() */ if (sec->sh.sh_flags &SHF_EXECINSTR )
@@ -4619,7 +4619,7 @@ static void disas_warned_funcs(struct objtool_file *file)struct symbol *sym;char *funcs =NULL , *tmp; -for_each_sym (file, sym) { +for_each_sym (file->elf, sym) {if (sym->warned) {if (!funcs) { funcs =malloc (strlen (sym->name) +1 );
@@ -4659,7 +4659,7 @@ static int check_abs_references(struct objtool_file *file)struct reloc *reloc;int ret =0 ; -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {/* absolute references in non-loadable sections are fine */ if (!(sec->sh.sh_flags &SHF_ALLOC ))continue ;
tools/objtool/include/objtool/elf.h +4 -4
@@ -325,16 +325,16 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next) reloc->_sym_next_reloc = (unsigned long )next | bit; } -#define for_each_sec (file, sec) \ - list_for_each_entry(sec, &file->elf->sections, list) +#define for_each_sec (elf, sec) \ + list_for_each_entry(sec, &elf->sections, list)#define sec_for_each_sym (sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) -#define for_each_sym (file, sym) \ +#define for_each_sym (elf, sym) \ for (struct section *__sec, *__fake = (struct section *)1; \ __fake; __fake = NULL) \ - for_each_sec(file, __sec) \ + for_each_sec(elf, __sec) \ sec_for_each_sym(__sec, sym)#define for_each_reloc (rsec, reloc) \
tools/objtool/orc_gen.c +1 -1
@@ -57,7 +57,7 @@ int orc_create(struct objtool_file *file)/* Build a deduplicated list of ORC entries: */ INIT_LIST_HEAD (&orc_list); -for_each_sec (file, sec) { +for_each_sec (file->elf, sec) {struct orc_entry orc, prev_orc = {0 };struct instruction *insn;bool empty = true;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 28/63 objtool: Add section/symbol type helpers
In reply to Josh PoimboeufAdd some helper macros to improve readability.
--- tools/objtool/arch/x86/special.c | 2 +- tools/objtool/check.c | 58 ++++++++++++------------- tools/objtool/elf.c | 20 ++++----- tools/objtool/include/objtool/elf.h | 66 +++++++++++++++++++++++++++++ tools/objtool/special.c | 4 +- 5 files changed, 108 insertions(+), 42 deletions(-)
tools/objtool/arch/x86/special.c +1 -1
@@ -89,7 +89,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,/* look for a relocation which references .rodata */ text_reloc =find_reloc_by_dest_range (file->elf, insn->sec, insn->offset, insn->len); -if (!text_reloc || text_reloc->sym->type !=STT_SECTION || +if (!text_reloc || !is_sec_sym (text_reloc->sym) || !text_reloc->sym->sec->rodata)return NULL ;
tools/objtool/check.c +29 -29
214 lines not on this page · raw message
tools/objtool/elf.c +10 -10
@@ -170,7 +170,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)struct symbol *iter;__sym_for_each (iter, tree, offset, offset) { -if (iter->offset == offset && iter->type !=STT_SECTION ) +if (iter->offset == offset && !is_sec_sym (iter))return iter; }
@@ -183,7 +183,7 @@ struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)struct symbol *iter;__sym_for_each (iter, tree, offset, offset) { -if (iter->offset == offset && iter->type ==STT_FUNC ) +if (iter->offset == offset &&is_func_sym (iter))return iter; }
@@ -264,7 +264,7 @@ struct symbol *find_func_containing(struct section *sec, unsigned long offset)struct symbol *iter;__sym_for_each (iter, tree, offset, offset) { -if (iter->type ==STT_FUNC ) +if (is_func_sym (iter))return iter; }
@@ -373,14 +373,14 @@ static int read_sections(struct elf *elf)return -1 ; } -if (sec->sh.sh_size !=0 && !is_dwarf_section (sec)) { +if (sec_size (sec) !=0 && !is_dwarf_section (sec)) { sec->data =elf_getdata (s,NULL );if (!sec->data) {ERROR_ELF ("elf_getdata" );return -1 ; }if (sec->data->d_off !=0 || - sec->data->d_size != sec->sh.sh_size) { + sec->data->d_size !=sec_size (sec)) {ERROR ("unexpected data attributes for %s" , sec->name);return -1 ; }
@@ -420,7 +420,7 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym) sym->type =GELF_ST_TYPE (sym->sym.st_info); sym->bind =GELF_ST_BIND (sym->sym.st_info); -if (sym->type ==STT_FILE ) +if (is_file_sym (sym)) elf->num_files++; sym->offset = sym->sym.st_value;
@@ -527,7 +527,7 @@ static int read_symbols(struct elf *elf)sec_for_each_sym (sec, sym) {char *pname;size_t pnamelen; -if (sym->type !=STT_FUNC ) +if (!is_func_sym (sym))continue ;if (sym->pfunc ==NULL )
@@ -929,7 +929,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,struct symbol *sym = insn_sec->sym;int addend = insn_off; -if (!(insn_sec->sh.sh_flags &SHF_EXECINSTR )) { +if (!is_text_sec (insn_sec)) {ERROR ("bad call to %s() for data symbol %s" , __func__, sym->name);return NULL ; }
@@ -958,7 +958,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, struct symbol *sym, s64 addend) { -if (sym->sec && (sec->sh.sh_flags &SHF_EXECINSTR )) { + if (is_text_sec(sec)) {ERROR ("bad call to %s() for text symbol %s" , __func__, sym->name);return NULL ; }
@@ -1287,7 +1287,7 @@ int elf_write_insn(struct elf *elf, struct section *sec,*/ static int elf_truncate_section (struct elf *elf,struct section *sec) { -u64 size = sec->sh.sh_size; +u64 size =sec_size (sec);bool truncated = false;Elf_Data *data =NULL ;Elf_Scn *s;
tools/objtool/include/objtool/elf.h +66 -0
89 lines not on this page · raw message
tools/objtool/special.c +2 -2
@@ -142,12 +142,12 @@ int special_get_alts(struct elf *elf, struct list_head *alts)if (!sec)continue ; -if (sec->sh.sh_size % entry->size !=0 ) { +if (sec_size (sec) % entry->size !=0 ) {ERROR ("%s size not a multiple of %d" , sec->name, entry->size);return -1 ; } - nr_entries = sec->sh.sh_size / entry->size; + nr_entries =sec_size (sec) / entry->size;for (idx =0 ; idx < nr_entries; idx++) { alt =malloc (sizeof (*alt));
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 29/63 objtool: Mark .cold subfunctions
In reply to Josh PoimboeufIntroduce a flag to identify .cold subfunctions so they can be detected easier and faster.
--- tools/objtool/check.c | 14 ++++++-------- tools/objtool/elf.c | 19 ++++++++++--------- tools/objtool/include/objtool/elf.h | 1 + 3 files changed, 17 insertions(+), 17 deletions(-)
tools/objtool/check.c +6 -8
@@ -1575,7 +1575,9 @@ static int add_jump_destinations(struct objtool_file *file)/* * Cross-function jump. */ -if (func &&insn_func (jump_dest) && func !=insn_func (jump_dest)) { + +if (func &&insn_func (jump_dest) && !func->cold && +insn_func (jump_dest)->cold) {/* * For GCC 8+, create parent/child links for any cold
@@ -1592,11 +1594,8 @@ static int add_jump_destinations(struct objtool_file *file)* case where the parent function's only reference to a * subfunction is through a jump table. */ -if (!strstr (func->name,".cold" ) && -strstr (insn_func (jump_dest)->name,".cold" )) { - func->cfunc =insn_func (jump_dest); -insn_func (jump_dest)->pfunc = func; - } + func->cfunc =insn_func (jump_dest); +insn_func (jump_dest)->pfunc = func; }if (jump_is_sibling_call (file, insn, jump_dest)) {
@@ -4075,9 +4074,8 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio* If this hole jumps to a .cold function, mark it ignore too. */ if (insn->jump_dest &&insn_func (insn->jump_dest) && -strstr (insn_func (insn->jump_dest)->name,".cold" )) { +insn_func (insn->jump_dest)->cold)insn_func (insn->jump_dest)->ignore = true; - } }return false;
tools/objtool/elf.c +10 -9
@@ -441,6 +441,10 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)list_add (&sym->list, entry);elf_hash_add (symbol, &sym->hash, sym->idx);elf_hash_add (symbol_name, &sym->name_hash,str_hash (sym->name)); + +if (is_func_sym (sym) &&strstr (sym->name,".cold" )) + sym->cold =1 ; + sym->pfunc = sym->cfunc = sym; }static int read_symbols (struct elf *elf)
@@ -527,18 +531,15 @@ static int read_symbols(struct elf *elf)sec_for_each_sym (sec, sym) {char *pname;size_t pnamelen; -if (!is_func_sym (sym)) + +if (!sym->cold)continue ; -if (sym->pfunc ==NULL ) - sym->pfunc = sym; - -if (sym->cfunc ==NULL ) - sym->cfunc = sym; - coldstr =strstr (sym->name,".cold" ); -if (!coldstr) -continue ; +if (!coldstr) { +ERROR ("%s(): cold subfunction without \".cold\"?" , sym->name); +return -1 ; + } pnamelen = coldstr - sym->name; pname =strndup (sym->name, pnamelen);
tools/objtool/include/objtool/elf.h +1 -0
@@ -72,6 +72,7 @@ struct symbol { u8 frame_pointer : 1; u8 ignore : 1; u8 nocfi : 1; + u8 cold : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 30/63 objtool: Fix weak symbol hole detection for .cold functions
In reply to Josh PoimboeufWhen ignore_unreachable_insn() looks for weak function holes which jump to their .cold functions, it assumes the parent function comes before the corresponding .cold function in the symbol table. That's not necessarily the case with -ffunction-sections.
Mark all the holes beforehand (including .cold functions) so the ordering of the discovery doesn't matter.
--- tools/objtool/check.c | 84 ++++++++++++++------------- tools/objtool/include/objtool/check.h | 3 +- 2 files changed, 45 insertions(+), 42 deletions(-)
tools/objtool/check.c +43 -41
@@ -2517,6 +2517,44 @@ static void mark_rodata(struct objtool_file *file) file->rodata = found; } +static void mark_holes (struct objtool_file *file) +{ +struct instruction *insn; +bool in_hole = false; + +if (!opts.link) +return ; + +/* +* Whole archive runs might encounter dead code from weak symbols. +* This is where the linker will have dropped the weak symbol in +* favour of a regular symbol, but leaves the code in place. +*/ +for_each_insn (file, insn) { +if (insn->sym || !find_symbol_hole_containing (insn->sec, insn->offset)) { + in_hole = false; +continue ; + } + +/* Skip function padding and pfx code */ +if (!in_hole && insn->type ==INSN_NOP ) +continue ; + + in_hole = true; + insn->hole =1 ; + +/* +* If this hole jumps to a .cold function, mark it ignore. +*/ +if (insn->jump_dest) { +struct symbol *dest_func =insn_func (insn->jump_dest); + +if (dest_func && dest_func->cold) + dest_func->ignore = true; + } + } +} +static int decode_sections (struct objtool_file *file) {mark_rodata (file);
@@ -2569,6 +2607,9 @@ static int decode_sections(struct objtool_file *file)if (read_unwind_hints (file))return -1 ; +/* Must be after add_jump_destinations() */ +mark_holes (file); +/* * Must be after add_call_destinations() such that it can override * dead_end_function() marks.
@@ -4030,7 +4071,8 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructiostruct instruction *prev_insn;int i; -if (insn->type ==INSN_NOP || insn->type ==INSN_TRAP || (func && func->ignore)) +if (insn->type ==INSN_NOP || insn->type ==INSN_TRAP || + insn->hole || (func && func->ignore))return true;/*
@@ -4041,46 +4083,6 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio !strcmp(insn->sec->name, ".altinstr_aux"))return true; -/* -* Whole archive runs might encounter dead code from weak symbols. -* This is where the linker will have dropped the weak symbol in -* favour of a regular symbol, but leaves the code in place. -* -* In this case we'll find a piece of code (whole function) that is not -* covered by a !section symbol. Ignore them. -*/ -if (opts.link && !func) { -int size =find_symbol_hole_containing (insn->sec, insn->offset); -unsigned long end = insn->offset + size; - -if (!size)/* not a hole */ -return false; - -if (size <0 )/* hole until the end */ -return true; - -sec_for_each_insn_continue (file, insn) { -/* -* If we reach a visited instruction at or before the -* end of the hole, ignore the unreachable. -*/ -if (insn->visited) -return true; - -if (insn->offset >= end) -break ; - -/* -* If this hole jumps to a .cold function, mark it ignore too. -*/ -if (insn->jump_dest &&insn_func (insn->jump_dest) && -insn_func (insn->jump_dest)->cold) -insn_func (insn->jump_dest)->ignore = true; - } - -return false; - } -if (!func)return false;
tools/objtool/include/objtool/check.h +2 -1
@@ -64,7 +64,8 @@ struct instruction { noendbr : 1, unret : 1, visited : 4, - no_reloc : 1; + no_reloc : 1, + hole : 1;/* 10 bit hole */ struct alt_group *alt_group;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 31/63 objtool: Mark prefix functions
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, introduce a flag to identify __pfx_*() and __cfi_*() functions in advance so they don't need to be manually identified every time a check is needed.
--- tools/objtool/check.c | 5 +---- tools/objtool/elf.c | 7 +++++++ tools/objtool/include/objtool/elf.h | 6 ++++++ 3 files changed, 14 insertions(+), 4 deletions(-)
tools/objtool/check.c +1 -4
@@ -3577,10 +3577,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,if (func &&insn_func (insn) && func !=insn_func (insn)->pfunc) {/* Ignore KCFI type preambles, which always fall through */ -if (!strncmp (func->name,"__cfi_" ,6 ) || - !strncmp (func->name,"__pfx_" ,6 ) || - !strncmp (func->name,"__pi___cfi_" ,11 ) || - !strncmp (func->name,"__pi___pfx_" ,11 )) +if (is_prefix_func (func))return 0 ;if (file->ignore_unreachables)
tools/objtool/elf.c +7 -0
@@ -442,6 +442,13 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)elf_hash_add (symbol, &sym->hash, sym->idx);elf_hash_add (symbol_name, &sym->name_hash,str_hash (sym->name)); +if (is_func_sym (sym) && + (strstarts (sym->name,"__pfx_" ) || +strstarts (sym->name,"__cfi_" ) || +strstarts (sym->name,"__pi___pfx_" ) || +strstarts (sym->name,"__pi___cfi_" ))) + sym->prefix =1 ; +if (is_func_sym (sym) &&strstr (sym->name,".cold" )) sym->cold =1 ; sym->pfunc = sym->cfunc = sym;
tools/objtool/include/objtool/elf.h +6 -0
@@ -73,6 +73,7 @@ struct symbol { u8 ignore : 1; u8 nocfi : 1; u8 cold : 1; + u8 prefix : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
@@ -230,6 +231,11 @@ static inline bool is_local_sym(struct symbol *sym)return sym->bind ==STB_LOCAL ; } +static inline bool is_prefix_func (struct symbol *sym) +{ +return sym->prefix; +} +static inline bool is_reloc_sec (struct section *sec) {return sec->sh.sh_type ==SHT_RELA || sec->sh.sh_type ==SHT_REL ;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 32/63 objtool: Simplify reloc offset calculation in unwind_read_hints()
In reply to Josh PoimboeufSimplify the relocation offset calculation in unwind_read_hints(), similar to other conversions which have already been done.
--- tools/objtool/check.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
tools/objtool/check.c +1 -8
@@ -2200,14 +2200,7 @@ static int read_unwind_hints(struct objtool_file *file)return -1 ; } -if (is_sec_sym (reloc->sym)) { - offset =reloc_addend (reloc); - }else if (reloc->sym->local_label) { - offset = reloc->sym->offset; - }else { -ERROR ("unexpected relocation symbol type in %s" , sec->rsec->name); -return -1 ; - } + offset = reloc->sym->offset +reloc_addend (reloc); insn =find_insn (file, reloc->sym->sec, offset);if (!insn) {
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 33/63 objtool: Avoid emptying lists for duplicate sections
In reply to Josh PoimboeufWhen a to-be-created section already exists, there's no point in emptying the various lists if their respective sections already exist. In fact it's better to leave them intact as they might get used later.
--- tools/objtool/check.c | 4 ---- 1 file changed, 4 deletions(-)
tools/objtool/check.c +0 -4
@@ -635,7 +635,6 @@ static int create_static_call_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,".static_call_sites" );if (sec) { -INIT_LIST_HEAD (&file->static_call_list);WARN ("file already has .static_call_sites section, skipping" );return 0 ; }
@@ -851,7 +850,6 @@ static int create_cfi_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,".cfi_sites" );if (sec) { -INIT_LIST_HEAD (&file->call_list);WARN ("file already has .cfi_sites section, skipping" );return 0 ; }
@@ -900,7 +898,6 @@ static int create_mcount_loc_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,"__mcount_loc" );if (sec) { -INIT_LIST_HEAD (&file->mcount_loc_list);WARN ("file already has __mcount_loc section, skipping" );return 0 ; }
@@ -945,7 +942,6 @@ static int create_direct_call_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,".call_sites" );if (sec) { -INIT_LIST_HEAD (&file->call_list);WARN ("file already has .call_sites section, skipping" );return 0 ; }
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 34/63 objtool: Rename --Werror to --werror
In reply to Josh PoimboeufThe objtool --Werror option name is stylistically inconsistent: halfway between GCC's single-dash capitalized -Werror and objtool's double-dash --lowercase convention, making it unnecessarily hard to remember.
Make the 'W' lower case (--werror) for consistency with objtool's other options.
--- scripts/Makefile.lib | 2 +- scripts/Makefile.vmlinux_o | 2 +- tools/objtool/builtin-check.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
scripts/Makefile.lib +1 -1
@@ -191,7 +191,7 @@ objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) += --no-unreachable objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES) -objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror +objtool-args-$(CONFIG_OBJTOOL_WERROR) += --werror objtool-args = $(objtool-args-y) \ $(if $(delay-objtool), --link) \
scripts/Makefile.vmlinux_o +1 -1
@@ -41,7 +41,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION)) ifeq ($(delay-objtool),y) vmlinux-objtool-args-y += $(objtool-args-y) else -vmlinux-objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror +vmlinux-objtool-args-$(CONFIG_OBJTOOL_WERROR) += --werror endif vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) += --noinstr \
tools/objtool/builtin-check.c +1 -1
@@ -101,7 +101,7 @@ static const struct option check_options[] = {OPT_BOOLEAN (0 ,"sec-address" , &opts.sec_address,"print section addresses in warnings" ),OPT_BOOLEAN (0 ,"stats" , &opts.stats,"print statistics" ),OPT_BOOLEAN ('v' ,"verbose" , &opts.verbose,"verbose warnings" ), -OPT_BOOLEAN (0 ,"Werror" , &opts.werror,"return error on warnings" ), +OPT_BOOLEAN (0 ,"werror" , &opts.werror,"return error on warnings" ), OPT_END(), };
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 35/63 objtool: Resurrect --backup option
In reply to Josh PoimboeufThe --backup option was removed with the following commit:
aa8b3e64fd39 ("objtool: Create backup on error and print args")
... which tied the backup functionality to --verbose, and only for warnings/errors.
It's a bit inelegant and out of scope to tie that to --verbose.
Bring back the old --backup option, but with the new behavior: only on warnings/errors, and print the args to make it easier to recreate.
--- tools/objtool/builtin-check.c | 25 +++++++++++-------------- tools/objtool/check.c | 4 +++- tools/objtool/include/objtool/builtin.h | 3 ++- 3 files changed, 16 insertions(+), 16 deletions(-)
tools/objtool/builtin-check.c +11 -14
@@ -92,6 +92,7 @@ static const struct option check_options[] = {OPT_GROUP ("Options:" ),OPT_BOOLEAN (0 ,"backtrace" , &opts.backtrace,"unwind on error" ), +OPT_BOOLEAN (0 ,"backup" , &opts.backup,"create backup (.orig) file on warning/error" ),OPT_BOOLEAN (0 ,"dry-run" , &opts.dryrun,"don't write modifications" ),OPT_BOOLEAN (0 ,"link" , &opts.link,"object is a linked object" ), OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
@@ -246,12 +247,9 @@ static void save_argv(int argc, const char **argv) }; } -void print_args (void ) +int make_backup (void ) { -char *backup =NULL ; - -if (opts.output || opts.dryrun) - goto print; +char *backup;/* * Make a backup before kbuild deletes the file so the error
@@ -260,33 +258,32 @@ void print_args(void) backup =malloc (strlen (objname) +strlen (ORIG_SUFFIX ) +1 );if (!backup) {ERROR_GLIBC ("malloc" ); - goto print; +return 1 ; }strcpy (backup, objname);strcat (backup,ORIG_SUFFIX ); -if (copy_file (objname, backup)) { - backup =NULL ; - goto print; - } +if (copy_file (objname, backup)) +return 1 ; -print:/* -* Print the cmdline args to make it easier to recreate. If '--output' -* wasn't used, add it to the printed args with the backup as input. +* Print the cmdline args to make it easier to recreate. */ +fprintf (stderr,"%s" , orig_argv[0 ]);for (int i =1 ; i < orig_argc; i++) {char *arg = orig_argv[i]; -if (backup && !strcmp (arg, objname)) +/* Modify the printed args to use the backup */ +if (!opts.output && !strcmp (arg, objname))fprintf (stderr," %s -o %s" , backup, objname);else fprintf (stderr," %s" , arg); }fprintf (stderr,"\n" ); +return 0 ; }int objtool_run (int argc,const char **argv)
tools/objtool/check.c +3 -1
@@ -4833,9 +4833,11 @@ int check(struct objtool_file *file)if (opts.verbose) {if (opts.werror && warnings)WARN ("%d warning(s) upgraded to errors" , warnings); -print_args ();disas_warned_funcs (file); } +if (opts.backup &&make_backup ()) +return 1 ; +return ret; }
tools/objtool/include/objtool/builtin.h +2 -1
@@ -30,6 +30,7 @@ struct opts {/* options: */ bool backtrace; +bool backup;bool dryrun;bool link;bool mnop;
@@ -48,6 +49,6 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[]);int objtool_run (int argc,const char **argv); -void print_args (void ); +int make_backup (void );#endif /* _BUILTIN_H */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 36/63 objtool: Reindent check_options[]
In reply to Josh PoimboeufBring the cmdline check_options[] array back into vertical alignment for better readability.
--- tools/objtool/builtin-check.c | 54 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-)
tools/objtool/builtin-check.c +27 -27
@@ -73,36 +73,36 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)static const struct option check_options[] = {OPT_GROUP ("Actions:" ), +OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ),OPT_CALLBACK_OPTARG ('h' ,"hacks" ,NULL ,NULL ,"jump_label,noinstr,skylake" ,"patch toolchain bugs/limitations" , parse_hacks), -OPT_BOOLEAN ('i' ,"ibt" , &opts.ibt,"validate and annotate IBT" ), -OPT_BOOLEAN ('m' ,"mcount" , &opts.mcount,"annotate mcount/fentry calls for ftrace" ), -OPT_BOOLEAN ('n' ,"noinstr" , &opts.noinstr,"validate noinstr rules" ), -OPT_BOOLEAN (0 ,"orc" , &opts.orc,"generate ORC metadata" ), -OPT_BOOLEAN ('r' ,"retpoline" , &opts.retpoline,"validate and annotate retpoline usage" ), -OPT_BOOLEAN (0 ,"rethunk" , &opts.rethunk,"validate and annotate rethunk usage" ), -OPT_BOOLEAN (0 ,"unret" , &opts.unret,"validate entry unret placement" ), -OPT_INTEGER (0 ,"prefix" , &opts.prefix,"generate prefix symbols" ), -OPT_BOOLEAN ('l' ,"sls" , &opts.sls,"validate straight-line-speculation mitigations" ), -OPT_BOOLEAN ('s' ,"stackval" , &opts.stackval,"validate frame pointer rules" ), -OPT_BOOLEAN ('t' ,"static-call" , &opts.static_call,"annotate static calls" ), -OPT_BOOLEAN ('u' ,"uaccess" , &opts.uaccess,"validate uaccess rules for SMAP" ), -OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ), -OPT_BOOLEAN (0 ,"noabs" , &opts.noabs,"reject absolute references in allocatable sections" ), -OPT_CALLBACK_OPTARG (0 ,"dump" ,NULL ,NULL ,"orc" ,"dump metadata" , parse_dump), +OPT_BOOLEAN ('i' ,"ibt" , &opts.ibt,"validate and annotate IBT" ), +OPT_BOOLEAN ('m' ,"mcount" , &opts.mcount,"annotate mcount/fentry calls for ftrace" ), +OPT_BOOLEAN (0 ,"noabs" , &opts.noabs,"reject absolute references in allocatable sections" ), +OPT_BOOLEAN ('n' ,"noinstr" , &opts.noinstr,"validate noinstr rules" ), +OPT_BOOLEAN (0 ,"orc" , &opts.orc,"generate ORC metadata" ), +OPT_BOOLEAN ('r' ,"retpoline" , &opts.retpoline,"validate and annotate retpoline usage" ), +OPT_BOOLEAN (0 ,"rethunk" , &opts.rethunk,"validate and annotate rethunk usage" ), +OPT_BOOLEAN (0 ,"unret" , &opts.unret,"validate entry unret placement" ), +OPT_INTEGER (0 ,"prefix" , &opts.prefix,"generate prefix symbols" ), +OPT_BOOLEAN ('l' ,"sls" , &opts.sls,"validate straight-line-speculation mitigations" ), +OPT_BOOLEAN ('s' ,"stackval" , &opts.stackval,"validate frame pointer rules" ), +OPT_BOOLEAN ('t' ,"static-call" , &opts.static_call,"annotate static calls" ), +OPT_BOOLEAN ('u' ,"uaccess" , &opts.uaccess,"validate uaccess rules for SMAP" ), +OPT_CALLBACK_OPTARG (0 ,"dump" ,NULL ,NULL ,"orc" ,"dump metadata" , parse_dump),OPT_GROUP ("Options:" ), -OPT_BOOLEAN (0 ,"backtrace" , &opts.backtrace,"unwind on error" ), -OPT_BOOLEAN (0 ,"backup" , &opts.backup,"create backup (.orig) file on warning/error" ), -OPT_BOOLEAN (0 ,"dry-run" , &opts.dryrun,"don't write modifications" ), -OPT_BOOLEAN (0 ,"link" , &opts.link,"object is a linked object" ), -OPT_BOOLEAN (0 ,"module" , &opts.module,"object is part of a kernel module" ), -OPT_BOOLEAN (0 ,"mnop" , &opts.mnop,"nop out mcount call sites" ), -OPT_BOOLEAN (0 ,"no-unreachable" , &opts.no_unreachable,"skip 'unreachable instruction' warnings" ), -OPT_STRING ('o' ,"output" , &opts.output,"file" ,"output file name" ), -OPT_BOOLEAN (0 ,"sec-address" , &opts.sec_address,"print section addresses in warnings" ), -OPT_BOOLEAN (0 ,"stats" , &opts.stats,"print statistics" ), -OPT_BOOLEAN ('v' ,"verbose" , &opts.verbose,"verbose warnings" ), -OPT_BOOLEAN (0 ,"werror" , &opts.werror,"return error on warnings" ), +OPT_BOOLEAN (0 ,"backtrace" , &opts.backtrace,"unwind on error" ), +OPT_BOOLEAN (0 ,"backup" , &opts.backup,"create backup (.orig) file on warning/error" ), +OPT_BOOLEAN (0 ,"dry-run" , &opts.dryrun,"don't write modifications" ), +OPT_BOOLEAN (0 ,"link" , &opts.link,"object is a linked object" ), +OPT_BOOLEAN (0 ,"module" , &opts.module,"object is part of a kernel module" ), +OPT_BOOLEAN (0 ,"mnop" , &opts.mnop,"nop out mcount call sites" ), +OPT_BOOLEAN (0 ,"no-unreachable" , &opts.no_unreachable,"skip 'unreachable instruction' warnings" ), +OPT_STRING ('o' ,"output" , &opts.output,"file" ,"output file name" ), +OPT_BOOLEAN (0 ,"sec-address" , &opts.sec_address,"print section addresses in warnings" ), +OPT_BOOLEAN (0 ,"stats" , &opts.stats,"print statistics" ), +OPT_BOOLEAN ('v' ,"verbose" , &opts.verbose,"verbose warnings" ), +OPT_BOOLEAN (0 ,"werror" , &opts.werror,"return error on warnings" ),OPT_END (), };
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 37/63 objtool: Refactor add_jump_destinations()
In reply to Josh PoimboeufThe add_jump_destinations() logic is a bit weird and convoluted after being incrementally tweaked over the years. Refactor it to hopefully be more logical and straightforward.
--- tools/objtool/check.c | 222 +++++++++++++--------------- tools/objtool/include/objtool/elf.h | 4 +- 2 files changed, 106 insertions(+), 120 deletions(-)
tools/objtool/check.c +104 -118
@@ -1423,9 +1423,14 @@ static void add_return_call(struct objtool_file *file, struct instruction *insn, }static bool is_first_func_insn (struct objtool_file *file, -struct instruction *insn,struct symbol *sym) +struct instruction *insn) { -if (insn->offset == sym->offset) +struct symbol *func =insn_func (insn); + +if (!func) +return false; + +if (insn->offset == func->offset)return true;/* Allow direct CALL/JMP past ENDBR */
@@ -1433,51 +1438,30 @@ static bool is_first_func_insn(struct objtool_file *file,struct instruction *prev =prev_insn_same_sym (file, insn);if (prev && prev->type ==INSN_ENDBR && - insn->offset == sym->offset + prev->len) + insn->offset == func->offset + prev->len)return true; }return false; } -/* -* A sibling call is a tail-call to another symbol -- to differentiate from a -* recursive tail-call which is to the same symbol. -*/ -static bool jump_is_sibling_call (struct objtool_file *file, -struct instruction *from,struct instruction *to) -{ -struct symbol *fs = from->sym; -struct symbol *ts = to->sym; - -/* Not a sibling call if from/to a symbol hole */ -if (!fs || !ts) -return false; - -/* Not a sibling call if not targeting the start of a symbol. */ -if (!is_first_func_insn (file, to, ts)) -return false; - -/* Disallow sibling calls into STT_NOTYPE */ -if (is_notype_sym (ts)) -return false; - -/* Must not be self to be a sibling */ -return fs->pfunc != ts->pfunc; -} -/* * Find the destination instructions for all jumps. */ static int add_jump_destinations (struct objtool_file *file) { -struct instruction *insn, *jump_dest; +struct instruction *insn;struct reloc *reloc; -struct section *dest_sec; -unsigned long dest_off;for_each_insn (file, insn) {struct symbol *func =insn_func (insn); +struct instruction *dest_insn; +struct section *dest_sec; +struct symbol *dest_sym; +unsigned long dest_off; + +if (!is_static_jump (insn)) +continue ;if (insn->jump_dest) {/*
@@ -1486,51 +1470,53 @@ static int add_jump_destinations(struct objtool_file *file)*/ continue ; } -if (!is_static_jump (insn)) -continue ; reloc =insn_reloc (file, insn);if (!reloc) { dest_sec = insn->sec; dest_off =arch_jump_destination (insn); - }else if (is_sec_sym (reloc->sym)) { - dest_sec = reloc->sym->sec; - dest_off =arch_insn_adjusted_addend (insn, reloc); - }else if (reloc->sym->retpoline_thunk) { -if (add_retpoline_call (file, insn)) -return -1 ; -continue ; - }else if (reloc->sym->return_thunk) { -add_return_call (file, insn, true); -continue ; - }else if (func) { -/* -* External sibling call or internal sibling call with -* STT_FUNC reloc. -*/ -if (add_call_dest (file, insn, reloc->sym, true)) -return -1 ; -continue ; - }else if (reloc->sym->sec->idx) { - dest_sec = reloc->sym->sec; - dest_off = reloc->sym->sym.st_value + -arch_insn_adjusted_addend (insn, reloc); + dest_sym = dest_sec->sym; }else { -/* non-func asm code jumping to another file */ -continue ; + dest_sym = reloc->sym; +if (is_undef_sym (dest_sym)) { +if (dest_sym->retpoline_thunk) { +if (add_retpoline_call (file, insn)) +return -1 ; +continue ; + } + +if (dest_sym->return_thunk) { +add_return_call (file, insn, true); +continue ; + } + +/* External symbol */ +if (func) { +/* External sibling call */ +if (add_call_dest (file, insn, dest_sym, true)) +return -1 ; +continue ; + } + +/* Non-func asm code jumping to external symbol */ +continue ; + } + + dest_sec = dest_sym->sec; + dest_off = dest_sym->offset +arch_insn_adjusted_addend (insn, reloc); } - jump_dest =find_insn (file, dest_sec, dest_off); -if (!jump_dest) { + dest_insn =find_insn (file, dest_sec, dest_off); +if (!dest_insn) {struct symbol *sym =find_symbol_by_offset (dest_sec, dest_off);/* -* This is a special case for retbleed_untrain_ret(). -* It jumps to __x86_return_thunk(), but objtool -* can't find the thunk's starting RET -* instruction, because the RET is also in the -* middle of another instruction. Objtool only -* knows about the outer instruction. +* retbleed_untrain_ret() jumps to +* __x86_return_thunk(), but objtool can't find +* the thunk's starting RET instruction, +* because the RET is also in the middle of +* another instruction. Objtool only knows +* about the outer instruction. */ if (sym && sym->embedded_insn) {add_return_call (file, insn, false);
@@ -1538,73 +1524,73 @@ static int add_jump_destinations(struct objtool_file *file) }/* -* GCOV/KCOV dead code can jump to the end of the -* function/section. +* GCOV/KCOV dead code can jump to the end of +* the function/section. */ if (file->ignore_unreachables && func && dest_sec == insn->sec && dest_off == func->offset + func->len)continue ; -ERROR_INSN (insn,"can't find jump dest instruction at %s+0x%lx" , - dest_sec->name, dest_off); +ERROR_INSN (insn,"can't find jump dest instruction at %s" , +offstr (dest_sec, dest_off));return -1 ; } -/* -* An intra-TU jump in retpoline.o might not have a relocation -* for its jump dest, in which case the above -* add_{retpoline,return}_call() didn't happen. -*/ -if (jump_dest->sym && jump_dest->offset == jump_dest->sym->offset) { -if (jump_dest->sym->retpoline_thunk) { -if (add_retpoline_call (file, insn)) -return -1 ; -continue ; - } -if (jump_dest->sym->return_thunk) { -add_return_call (file, insn, true); -continue ; - } +if (!dest_sym ||is_sec_sym (dest_sym)) { + dest_sym = dest_insn->sym; +if (!dest_sym) + goto set_jump_dest; } -/* -* Cross-function jump. -*/ - -if (func &&insn_func (jump_dest) && !func->cold && -insn_func (jump_dest)->cold) { - -/* -* For GCC 8+, create parent/child links for any cold -* subfunctions. This is _mostly_ redundant with a -* similar initialization in read_symbols(). -* -* If a function has aliases, we want the *first* such -* function in the symbol table to be the subfunction's -* parent. In that case we overwrite the -* initialization done in read_symbols(). -* -* However this code can't completely replace the -* read_symbols() code because this doesn't detect the -* case where the parent function's only reference to a -* subfunction is through a jump table. -*/ - func->cfunc =insn_func (jump_dest); -insn_func (jump_dest)->pfunc = func; - } - -if (jump_is_sibling_call (file, insn, jump_dest)) { -/* -* Internal sibling call without reloc or with -* STT_SECTION reloc. -*/ -if (add_call_dest (file, insn,insn_func (jump_dest), true)) +if (dest_sym->retpoline_thunk && dest_insn->offset == dest_sym->offset) { +if (add_retpoline_call (file, insn))return -1 ;continue ; } - insn->jump_dest = jump_dest; +if (dest_sym->return_thunk && dest_insn->offset == dest_sym->offset) { +add_return_call (file, insn, true); +continue ; + } + +if (!insn->sym || insn->sym == dest_insn->sym) + goto set_jump_dest; + +/* +* Internal cross-function jump. +*/ + +/* +* For GCC 8+, create parent/child links for any cold +* subfunctions. This is _mostly_ redundant with a +* similar initialization in read_symbols(). +* +* If a function has aliases, we want the *first* such +* function in the symbol table to be the subfunction's +* parent. In that case we overwrite the +* initialization done in read_symbols(). +* +* However this code can't completely replace the +* read_symbols() code because this doesn't detect the +* case where the parent function's only reference to a +* subfunction is through a jump table. +*/ +if (func && dest_sym->cold) { + func->cfunc = dest_sym; + dest_sym->pfunc = func; + goto set_jump_dest; + } + +if (is_first_func_insn (file, dest_insn)) { +/* Internal sibling call */ +if (add_call_dest (file, insn, dest_sym, true)) +return -1 ; +continue ; + } + +set_jump_dest: + insn->jump_dest = dest_insn; }return 0 ;
tools/objtool/include/objtool/elf.h +2 -2
@@ -181,9 +181,9 @@ static inline unsigned int elf_text_rela_type(struct elf *elf)return elf_addr_size (elf) ==4 ?R_TEXT32 :R_TEXT64 ; } -static inline bool sym_has_sec (struct symbol *sym) +static inline bool is_undef_sym (struct symbol *sym) { -return sym->sec->idx; +return !sym->sec->idx; }static inline bool is_null_sym (struct symbol *sym)
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 38/63 objtool: Simplify special symbol handling in elf_update_symbol()
In reply to Josh Poimboeuf!sym->sec isn't actually a thing: even STT_UNDEF and other special symbol types belong to NULL section 0.
Simplify the initialization of 'shndx' accordingly.
--- tools/objtool/elf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
tools/objtool/elf.c +2 -3
@@ -637,7 +637,7 @@ static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym)static int elf_update_symbol (struct elf *elf,struct section *symtab,struct section *symtab_shndx,struct symbol *sym) { -Elf32_Word shndx = sym->sec ? sym->sec->idx :SHN_UNDEF ; +Elf32_Word shndx;Elf_Data *symtab_data =NULL , *shndx_data =NULL ;Elf64_Xword entsize = symtab->sh.sh_entsize;int max_idx, idx = sym->idx;
@@ -645,8 +645,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,bool is_special_shndx = sym->sym.st_shndx >=SHN_LORESERVE && sym->sym.st_shndx !=SHN_XINDEX ; -if (is_special_shndx) - shndx = sym->sym.st_shndx; + shndx = is_special_shndx ? sym->sym.st_shndx : sym->sec->idx; s =elf_getscn (elf->elf, symtab->idx);if (!s) {
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 39/63 objtool: Generalize elf_create_symbol()
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, broaden the elf_create_symbol() interface to give callers more control and reduce duplication of some subtle setup logic.
While at it, make elf_create_symbol() and elf_create_section_symbol() global so sections can be created by the upcoming klp diff code.
--- tools/objtool/elf.c | 111 +++++++++++++++------------- tools/objtool/include/objtool/elf.h | 11 ++- 2 files changed, 69 insertions(+), 53 deletions(-)
tools/objtool/elf.c +59 -52
@@ -763,24 +763,60 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,return 0 ; } -static struct symbol * -__elf_create_symbol (struct elf *elf,struct symbol *sym) +static int elf_add_string (struct elf *elf,struct section *strtab,const char *str); + +struct symbol *elf_create_symbol (struct elf *elf,const char *name, +struct section *sec,unsigned int bind, +unsigned int type,unsigned long offset, +size_t size) {struct section *symtab, *symtab_shndx;Elf32_Word first_non_local, new_idx; -struct symbol *old; +struct symbol *old, *sym; + + sym =calloc (1 ,sizeof (*sym)); +if (!sym) { +ERROR_GLIBC ("calloc" ); +return NULL ; + } + + sym->name =strdup (name); +if (!sym->name) { +ERROR_GLIBC ("strdup" ); +return NULL ; + } + +if (type !=STT_SECTION ) { + sym->sym.st_name =elf_add_string (elf,NULL , sym->name); +if (sym->sym.st_name ==-1 ) +return NULL ; + } + +if (sec) { + sym->sec = sec; + }else { + sym->sec =find_section_by_index (elf,0 ); +if (!sym->sec) { +ERROR ("no NULL section" ); +return NULL ; + } + } + + sym->sym.st_info =GELF_ST_INFO (bind, type); + sym->sym.st_value = offset; + sym->sym.st_size = size; symtab =find_section_by_name (elf,".symtab" ); -if (symtab) { - symtab_shndx =find_section_by_name (elf,".symtab_shndx" ); - }else { +if (!symtab) {ERROR ("no .symtab" );return NULL ; } + symtab_shndx =find_section_by_name (elf,".symtab_shndx" ); + new_idx =sec_num_entries (symtab); -if (GELF_ST_BIND (sym->sym.st_info) !=STB_LOCAL ) +if (bind !=STB_LOCAL ) goto non_local;/*
@@ -818,10 +854,8 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym) non_local: sym->idx = new_idx; -if (elf_update_symbol (elf, symtab, symtab_shndx, sym)) { -ERROR ("elf_update_symbol" ); +if (sym->idx &&elf_update_symbol (elf, symtab, symtab_shndx, sym))return NULL ; - } symtab->sh.sh_size += symtab->sh.sh_entsize;mark_sec_changed (elf, symtab, true);
@@ -831,64 +865,39 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)mark_sec_changed (elf, symtab_shndx, true); } +elf_add_symbol (elf, sym); +return sym; } -static struct symbol * -elf_create_section_symbol (struct elf *elf,struct section *sec) +struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec) {struct symbol *sym =calloc (1 ,sizeof (*sym)); -if (!sym) { -ERROR_GLIBC ("malloc" ); + sym =elf_create_symbol (elf, sec->name, sec,STB_LOCAL ,STT_SECTION ,0 ,0 ); +if (!sym)return NULL ; - } - sym->name = sec->name; - sym->sec = sec; - -// st_name 0 - sym->sym.st_info =GELF_ST_INFO (STB_LOCAL ,STT_SECTION ); -// st_other 0 -// st_value 0 -// st_size 0 - - sym =__elf_create_symbol (elf, sym); -if (sym) -elf_add_symbol (elf, sym); + sec->sym = sym;return sym; } -static int elf_add_string (struct elf *elf,struct section *strtab,const char *str); -struct symbol * -elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,long size) +elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,size_t size) { -struct symbol *sym =calloc (1 ,sizeof (*sym));size_t namelen =strlen (orig->name) +sizeof ("__pfx_" ); -char *name =malloc (namelen); - -if (!sym || !name) { -ERROR_GLIBC ("malloc" ); -return NULL ; - } +char name[SYM_NAME_LEN ]; +unsigned long offset;snprintf (name, namelen,"__pfx_%s" , orig->name); - sym->name = name; - sym->sec = orig->sec; + offset = orig->sym.st_value - size; - sym->sym.st_name =elf_add_string (elf,NULL , name); - sym->sym.st_info = orig->sym.st_info; - sym->sym.st_value = orig->sym.st_value - size; - sym->sym.st_size = size; - - sym =__elf_create_symbol (elf, sym); -if (sym) -elf_add_symbol (elf, sym); - -return sym; +return elf_create_symbol (elf, name, orig->sec, +GELF_ST_BIND (orig->sym.st_info), +GELF_ST_TYPE (orig->sym.st_info), + offset, size); } static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
@@ -934,7 +943,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long insn_off) {struct symbol *sym = insn_sec->sym; -int addend = insn_off; +s64 addend = insn_off;if (!is_text_sec (insn_sec)) {ERROR ("bad call to %s() for data symbol %s" , __func__, sym->name);
@@ -951,8 +960,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, sym =elf_create_section_symbol (elf, insn_sec);if (!sym)return NULL ; - - insn_sec->sym = sym; } return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
tools/objtool/include/objtool/elf.h +10 -1
@@ -15,6 +15,8 @@#include <linux/jhash.h> #include <arch/elf.h> +#define SYM_NAME_LEN 512 +#ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum# define elf_getshdrstrndx elf_getshstrndx
@@ -120,7 +122,14 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name, size_t entsize, unsigned int nr, unsigned int reloc_nr); -struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,long size); +struct symbol *elf_create_symbol (struct elf *elf,const char *name, +struct section *sec,unsigned int bind, +unsigned int type,unsigned long offset, +size_t size); +struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec); +struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig, +size_t size); + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset,
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 40/63 objtool: Generalize elf_create_section()
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, broaden the elf_create_section() interface to give callers more control and reduce duplication of some subtle setup logic.
While at it, make elf_create_rela_section() global so sections can be created by the upcoming klp diff code.
--- tools/objtool/elf.c | 118 ++++++++++++++++------------ tools/objtool/include/objtool/elf.h | 7 +- tools/objtool/orc_gen.c | 6 +- 3 files changed, 77 insertions(+), 54 deletions(-)
tools/objtool/elf.c +66 -52
@@ -1138,51 +1138,53 @@ static int elf_add_string(struct elf *elf, struct section *strtab, const char *s }struct section *elf_create_section (struct elf *elf,const char *name, -size_t entsize,unsigned int nr) +size_t size,size_t entsize, +unsigned int type,unsigned int align, +unsigned int flags) {struct section *sec, *shstrtab; -size_t size = entsize * nr;Elf_Scn *s; - sec =malloc (sizeof (*sec)); -if (!sec) { -ERROR_GLIBC ("malloc" ); +if (name &&find_section_by_name (elf, name)) { +ERROR ("section '%s' already exists" , name); +return NULL ; + } + + sec =calloc (1 ,sizeof (*sec)); +if (!sec) { +ERROR_GLIBC ("calloc" );return NULL ; } -memset (sec,0 ,sizeof (*sec));INIT_LIST_HEAD (&sec->symbol_list); +/* don't actually create the section, just the data structures */ +if (type ==SHT_NULL ) + goto add; + s =elf_newscn (elf->elf);if (!s) {ERROR_ELF ("elf_newscn" );return NULL ; } - sec->name =strdup (name); -if (!sec->name) { -ERROR_GLIBC ("strdup" ); -return NULL ; - } - sec->idx =elf_ndxscn (s); - sec->data =elf_newdata (s); -if (!sec->data) { -ERROR_ELF ("elf_newdata" ); -return NULL ; - } - - sec->data->d_size = size; - sec->data->d_align =1 ; -if (size) { - sec->data->d_buf =malloc (size); -if (!sec->data->d_buf) { -ERROR_GLIBC ("malloc" ); + sec->data =elf_newdata (s); +if (!sec->data) { +ERROR_ELF ("elf_newdata" ); +return NULL ; + } + + sec->data->d_size = size; + sec->data->d_align =1 ; + + sec->data->d_buf =calloc (1 , size); +if (!sec->data->d_buf) { +ERROR_GLIBC ("calloc" );return NULL ; } -memset (sec->data->d_buf,0 , size); }if (!gelf_getshdr (s, &sec->sh)) {
@@ -1192,34 +1194,44 @@ struct section *elf_create_section(struct elf *elf, const char *name, sec->sh.sh_size = size; sec->sh.sh_entsize = entsize; - sec->sh.sh_type =SHT_PROGBITS ; - sec->sh.sh_addralign =1 ; - sec->sh.sh_flags =SHF_ALLOC ; + sec->sh.sh_type = type; + sec->sh.sh_addralign = align; + sec->sh.sh_flags = flags; -/* Add section name to .shstrtab (or .strtab for Clang) */ - shstrtab =find_section_by_name (elf,".shstrtab" ); -if (!shstrtab) - shstrtab =find_section_by_name (elf,".strtab" ); -if (!shstrtab) { -ERROR ("can't find .shstrtab or .strtab section" ); -return NULL ; +if (name) { + sec->name =strdup (name); +if (!sec->name) { +ERROR ("strdup" ); +return NULL ; + } + +/* Add section name to .shstrtab (or .strtab for Clang) */ + shstrtab =find_section_by_name (elf,".shstrtab" ); +if (!shstrtab) { + shstrtab =find_section_by_name (elf,".strtab" ); +if (!shstrtab) { +ERROR ("can't find .shstrtab or .strtab" ); +return NULL ; + } + } + sec->sh.sh_name =elf_add_string (elf, shstrtab, sec->name); +if (sec->sh.sh_name ==-1 ) +return NULL ; + +elf_hash_add (section_name, &sec->name_hash,str_hash (sec->name)); } - sec->sh.sh_name =elf_add_string (elf, shstrtab, sec->name); -if (sec->sh.sh_name ==-1 ) -return NULL ; +add:list_add_tail (&sec->list, &elf->sections);elf_hash_add (section, &sec->hash, sec->idx); -elf_hash_add (section_name, &sec->name_hash,str_hash (sec->name));mark_sec_changed (elf, sec, true);return sec; } -static struct section *elf_create_rela_section (struct elf *elf, -struct section *sec, -unsigned int reloc_nr) +struct section *elf_create_rela_section (struct elf *elf,struct section *sec, +unsigned int reloc_nr) {struct section *rsec;char *rsec_name;
@@ -1232,22 +1244,23 @@ static struct section *elf_create_rela_section(struct elf *elf,strcpy (rsec_name,".rela" );strcat (rsec_name, sec->name); - rsec =elf_create_section (elf, rsec_name,elf_rela_size (elf), reloc_nr); + rsec =elf_create_section (elf, rsec_name, reloc_nr *elf_rela_size (elf), +elf_rela_size (elf),SHT_RELA ,elf_addr_size (elf), +SHF_INFO_LINK );free (rsec_name);if (!rsec)return NULL ; - rsec->data->d_type =ELF_T_RELA ; - rsec->sh.sh_type =SHT_RELA ; - rsec->sh.sh_addralign =elf_addr_size (elf); rsec->sh.sh_link =find_section_by_name (elf,".symtab" )->idx; rsec->sh.sh_info = sec->idx; - rsec->sh.sh_flags =SHF_INFO_LINK ; - rsec->relocs =calloc (sec_num_entries (rsec),sizeof (struct reloc )); -if (!rsec->relocs) { -ERROR_GLIBC ("calloc" ); -return NULL ; +if (reloc_nr) { + rsec->data->d_type =ELF_T_RELA ; + rsec->relocs =calloc (sec_num_entries (rsec),sizeof (struct reloc )); +if (!rsec->relocs) { +ERROR_GLIBC ("calloc" ); +return NULL ; + } } sec->rsec = rsec;
@@ -1262,7 +1275,8 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name, {struct section *sec; - sec =elf_create_section (elf, name, entsize, nr); + sec =elf_create_section (elf, name, nr * entsize, entsize, +SHT_PROGBITS ,1 ,SHF_ALLOC );if (!sec)return NULL ;
tools/objtool/include/objtool/elf.h +6 -1
@@ -117,11 +117,16 @@ struct elf {struct elf *elf_open_read (const char *name,int flags);struct section *elf_create_section (struct elf *elf,const char *name, -size_t entsize,unsigned int nr); +size_t size,size_t entsize, +unsigned int type,unsigned int align, +unsigned int flags);struct section *elf_create_section_pair (struct elf *elf,const char *name,size_t entsize,unsigned int nr,unsigned int reloc_nr); +struct section *elf_create_rela_section (struct elf *elf,struct section *sec, +unsigned int reloc_nr); + struct symbol *elf_create_symbol(struct elf *elf, const char *name, struct section *sec, unsigned int bind, unsigned int type, unsigned long offset,
tools/objtool/orc_gen.c +5 -1
@@ -127,7 +127,11 @@ int orc_create(struct objtool_file *file)return -1 ; } orc_sec =elf_create_section (file->elf,".orc_unwind" , -sizeof (struct orc_entry ), nr); + nr *sizeof (struct orc_entry ), +sizeof (struct orc_entry ), +SHT_PROGBITS , +1 , +SHF_ALLOC );if (!orc_sec)return -1 ;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 41/63 objtool: Add elf_create_data()
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, refactor elf_add_string() by adding a new elf_add_data() helper which allows the adding of arbitrary data to a section.
Make both interfaces global so they can be used by the upcoming klp diff code.
--- tools/objtool/elf.c | 66 ++++++++++++++++++++--------- tools/objtool/include/objtool/elf.h | 10 +++-- 2 files changed, 54 insertions(+), 22 deletions(-)
tools/objtool/elf.c +47 -19
@@ -18,10 +18,11 @@#include <errno.h> #include <linux/interval_tree_generic.h> #include <objtool/builtin.h> -#include <objtool/elf.h> #include <objtool/warn.h> +#define ALIGN_UP (x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1)) +static inline u32 str_hash (const char *str) {return jhash (str,strlen (str),0 );
@@ -763,8 +764,6 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,return 0 ; } -static int elf_add_string (struct elf *elf,struct section *strtab,const char *str); - struct symbol *elf_create_symbol(struct elf *elf, const char *name, struct section *sec, unsigned int bind, unsigned int type, unsigned long offset,
@@ -1100,11 +1099,9 @@ struct elf *elf_open_read(const char *name, int flags)return NULL ; } -static int elf_add_string (struct elf *elf,struct section *strtab,const char *str) +unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str) { -Elf_Data *data; -Elf_Scn *s; -int len; +unsigned int offset;if (!strtab) strtab =find_section_by_name (elf,".strtab" );
@@ -1113,28 +1110,59 @@ static int elf_add_string(struct elf *elf, struct section *strtab, const char *sreturn -1 ; } - s =elf_getscn (elf->elf, strtab->idx); +if (!strtab->sh.sh_addralign) { +ERROR ("'%s': invalid sh_addralign" , strtab->name); +return -1 ; + } + + offset =ALIGN_UP (strtab->sh.sh_size, strtab->sh.sh_addralign); + +if (!elf_add_data (elf, strtab, str,strlen (str) +1 )) +return -1 ; + +return offset; +} + +void *elf_add_data (struct elf *elf,struct section *sec,const void *data,size_t size) +{ +unsigned long offset; +Elf_Scn *s; + +if (!sec->sh.sh_addralign) { +ERROR ("'%s': invalid sh_addralign" , sec->name); +return NULL ; + } + + s =elf_getscn (elf->elf, sec->idx);if (!s) {ERROR_ELF ("elf_getscn" ); -return -1 ; +return NULL ; } - data =elf_newdata (s); -if (!data) { + sec->data =elf_newdata (s); +if (!sec->data) {ERROR_ELF ("elf_newdata" ); -return -1 ; +return NULL ; } - data->d_buf =strdup (str); - data->d_size =strlen (str) +1 ; - data->d_align =1 ; + sec->data->d_buf =calloc (1 , size); +if (!sec->data->d_buf) { +ERROR_GLIBC ("calloc" ); +return NULL ; + } - len = strtab->sh.sh_size; - strtab->sh.sh_size += data->d_size; +if (data) +memcpy (sec->data->d_buf, data, size); -mark_sec_changed (elf, strtab, true); + sec->data->d_size = size; + sec->data->d_align =1 ; -return len; + offset =ALIGN_UP (sec->sh.sh_size, sec->sh.sh_addralign); + sec->sh.sh_size = offset + size; + +mark_sec_changed (elf, sec, true); + +return sec->data->d_buf; } struct section *elf_create_section(struct elf *elf, const char *name,
tools/objtool/include/objtool/elf.h +7 -3
@@ -135,6 +135,10 @@ struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec);struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,size_t size); +void *elf_add_data (struct elf *elf,struct section *sec,const void *data, +size_t size); + +unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str); struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset,
@@ -148,9 +152,9 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,struct symbol *sym, s64 addend); -int elf_write_insn (struct elf *elf,struct section *sec, -unsigned long offset,unsigned int len, -const char *insn); +int elf_write_insn (struct elf *elf,struct section *sec,unsigned long offset, +unsigned int len,const char *insn); +int elf_write (struct elf *elf);void elf_close (struct elf *elf);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 42/63 objtool: Add elf_create_reloc() and elf_init_reloc()
In reply to Josh Poimboeufelf_create_rela_section() is quite limited in that it requires the caller to know how many relocations need to be allocated up front.
In preparation for the objtool klp diff subcommand, allow an arbitrary number of relocations to be created and initialized on demand after section creation.
--- tools/objtool/elf.c | 170 +++++++++++++++++++++++++--- tools/objtool/include/objtool/elf.h | 9 ++ 2 files changed, 165 insertions(+), 14 deletions(-)
tools/objtool/elf.c +156 -14
@@ -22,6 +22,8 @@#include <objtool/warn.h> #define ALIGN_UP (x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1)) +#define ALIGN_UP_POW2 (x) (1U << ((8 * sizeof(x)) - __builtin_clz((x) - 1U))) +#define MAX (a, b) ((a) > (b) ? (a) : (b))static inline u32 str_hash (const char *str) {
@@ -899,10 +901,9 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, size_t size) offset, size); } -static struct reloc *elf_init_reloc (struct elf *elf,struct section *rsec, -unsigned int reloc_idx, -unsigned long offset,struct symbol *sym, -s64 addend,unsigned int type) +struct reloc *elf_init_reloc (struct elf *elf,struct section *rsec, +unsigned int reloc_idx,unsigned long offset, +struct symbol *sym,s64 addend,unsigned int type) {struct reloc *reloc, empty = {0 };
@@ -1004,12 +1005,16 @@ static int read_relocs(struct elf *elf) rsec->base->rsec = rsec; - nr_reloc =0 ; +/* nr_alloc_relocs=0: libelf owns d_buf */ + rsec->nr_alloc_relocs =0 ; + rsec->relocs =calloc (sec_num_entries (rsec),sizeof (*reloc));if (!rsec->relocs) {ERROR_GLIBC ("calloc" );return -1 ; } + + nr_reloc =0 ;for (i =0 ; i <sec_num_entries (rsec); i++) { reloc = &rsec->relocs[i];
@@ -1258,8 +1263,116 @@ struct section *elf_create_section(struct elf *elf, const char *name,return sec; } +static int elf_alloc_reloc (struct elf *elf,struct section *rsec) +{ +struct reloc *old_relocs, *old_relocs_end, *new_relocs; +unsigned int nr_relocs_old =sec_num_entries (rsec); +unsigned int nr_relocs_new = nr_relocs_old +1 ; +unsigned long nr_alloc; +struct symbol *sym; + +if (!rsec->data) { + rsec->data =elf_newdata (elf_getscn (elf->elf, rsec->idx)); +if (!rsec->data) { +ERROR_ELF ("elf_newdata" ); +return -1 ; + } + + rsec->data->d_align =1 ; + rsec->data->d_type =ELF_T_RELA ; + rsec->data->d_buf =NULL ; + } + + rsec->data->d_size = nr_relocs_new *elf_rela_size (elf); + rsec->sh.sh_size = rsec->data->d_size; + + nr_alloc =MAX (64 ,ALIGN_UP_POW2 (nr_relocs_new)); +if (nr_alloc <= rsec->nr_alloc_relocs) +return 0 ; + +if (rsec->data->d_buf && !rsec->nr_alloc_relocs) { +void *orig_buf = rsec->data->d_buf; + +/* +* The original d_buf is owned by libelf so it can't be +* realloced. +*/ + rsec->data->d_buf =malloc (nr_alloc *elf_rela_size (elf)); +if (!rsec->data->d_buf) { +ERROR_GLIBC ("malloc" ); +return -1 ; + } +memcpy (rsec->data->d_buf, orig_buf, + nr_relocs_old *elf_rela_size (elf)); + }else { + rsec->data->d_buf =realloc (rsec->data->d_buf, + nr_alloc *elf_rela_size (elf)); +if (!rsec->data->d_buf) { +ERROR_GLIBC ("realloc" ); +return -1 ; + } + } + + rsec->nr_alloc_relocs = nr_alloc; + + old_relocs = rsec->relocs; + new_relocs =calloc (nr_alloc,sizeof (struct reloc )); +if (!new_relocs) { +ERROR_GLIBC ("calloc" ); +return -1 ; + } + +if (!old_relocs) + goto done; + +/* +* The struct reloc's address has changed. Update all the symbols and +* relocs which reference it. +*/ + + old_relocs_end = &old_relocs[nr_relocs_old]; +for_each_sym (elf, sym) { +struct reloc *reloc; + + reloc = sym->relocs; +if (!reloc) +continue ; + +if (reloc >= old_relocs && reloc < old_relocs_end) + sym->relocs = &new_relocs[reloc - old_relocs]; + +while (1 ) { +struct reloc *next_reloc =sym_next_reloc (reloc); + +if (!next_reloc) +break ; + +if (next_reloc >= old_relocs && next_reloc < old_relocs_end) +set_sym_next_reloc (reloc, &new_relocs[next_reloc - old_relocs]); + + reloc = next_reloc; + } + } + +memcpy (new_relocs, old_relocs, nr_relocs_old *sizeof (struct reloc )); + +for (int i =0 ; i < nr_relocs_old; i++) { +struct reloc *old = &old_relocs[i]; +struct reloc *new = &new_relocs[i]; +u32 key =reloc_hash (old); + +elf_hash_del (reloc, &old->hash, key); +elf_hash_add (reloc, &new->hash, key); + } + +free (old_relocs); +done: + rsec->relocs = new_relocs; +return 0 ; +} +struct section *elf_create_rela_section (struct elf *elf,struct section *sec, -unsigned int reloc_nr) +unsigned int nr_relocs) {struct section *rsec;char *rsec_name;
@@ -1272,34 +1385,63 @@ struct section *elf_create_rela_section(struct elf *elf, struct section *sec,strcpy (rsec_name,".rela" );strcat (rsec_name, sec->name); - rsec =elf_create_section (elf, rsec_name, reloc_nr *elf_rela_size (elf), + rsec =elf_create_section (elf, rsec_name, nr_relocs *elf_rela_size (elf),elf_rela_size (elf),SHT_RELA ,elf_addr_size (elf),SHF_INFO_LINK );free (rsec_name);if (!rsec)return NULL ; - rsec->sh.sh_link =find_section_by_name (elf,".symtab" )->idx; - rsec->sh.sh_info = sec->idx; - -if (reloc_nr) { +if (nr_relocs) { rsec->data->d_type =ELF_T_RELA ; - rsec->relocs =calloc (sec_num_entries (rsec),sizeof (struct reloc )); + + rsec->nr_alloc_relocs = nr_relocs; + rsec->relocs =calloc (nr_relocs,sizeof (struct reloc ));if (!rsec->relocs) {ERROR_GLIBC ("calloc" );return NULL ; } } + rsec->sh.sh_link =find_section_by_name (elf,".symtab" )->idx; + rsec->sh.sh_info = sec->idx; + sec->rsec = rsec; rsec->base = sec;return rsec; } +struct reloc *elf_create_reloc (struct elf *elf,struct section *sec, +unsigned long offset, +struct symbol *sym,s64 addend, +unsigned int type) +{ +struct section *rsec = sec->rsec; + +if (!rsec) { + rsec =elf_create_rela_section (elf, sec,0 ); +if (!rsec) +return NULL ; + } + +if (find_reloc_by_dest (elf, sec, offset)) { +ERROR_FUNC (sec, offset,"duplicate reloc" ); +return NULL ; + } + +if (elf_alloc_reloc (elf, rsec)) +return NULL ; + +mark_sec_changed (elf, rsec, true); + +return elf_init_reloc (elf, rsec,sec_num_entries (rsec) -1 , offset, sym, + addend, type); +} +struct section *elf_create_section_pair (struct elf *elf,const char *name,size_t entsize,unsigned int nr, -unsigned int reloc_nr) +unsigned int nr_relocs) {struct section *sec;
@@ -1308,7 +1450,7 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name,if (!sec)return NULL ; -if (!elf_create_rela_section (elf, sec, reloc_nr)) +if (!elf_create_rela_section (elf, sec, nr_relocs))return NULL ;return sec;
tools/objtool/include/objtool/elf.h +9 -0
@@ -47,6 +47,7 @@ struct section {int idx;bool _changed, text, rodata, noinstr, init, truncate;struct reloc *relocs; +unsigned long nr_alloc_relocs; };struct symbol {
@@ -140,6 +141,14 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data,unsigned int elf_add_string (struct elf *elf,struct section *strtab,const char *str); +struct reloc *elf_create_reloc (struct elf *elf,struct section *sec, +unsigned long offset,struct symbol *sym, +s64 addend,unsigned int type); + +struct reloc *elf_init_reloc (struct elf *elf,struct section *rsec, +unsigned int reloc_idx,unsigned long offset, +struct symbol *sym,s64 addend,unsigned int type); + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset, unsigned int reloc_idx,
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 43/63 objtool: Add elf_create_file()
In reply to Josh PoimboeufAdd interface to enable the creation of a new ELF file.
--- tools/objtool/builtin-check.c | 2 +- tools/objtool/elf.c | 144 +++++++++++++++++++++++++++- tools/objtool/include/objtool/elf.h | 5 +- 3 files changed, 147 insertions(+), 4 deletions(-)
tools/objtool/builtin-check.c +1 -1
@@ -329,5 +329,5 @@ int objtool_run(int argc, const char **argv)if (!opts.dryrun && file->elf->changed &&elf_write (file->elf))return 1 ; -return 0 ; +return elf_close (file->elf); }
tools/objtool/elf.c +143 -1
176 lines not on this page · raw message
tools/objtool/include/objtool/elf.h +3 -2
@@ -94,7 +94,7 @@ struct elf {GElf_Ehdr ehdr;int fd;bool changed; -const char *name; +const char *name, *tmp_name;unsigned int num_files;struct list_head sections;unsigned long num_relocs;
@@ -116,6 +116,7 @@ struct elf { };struct elf *elf_open_read (const char *name,int flags); +struct elf *elf_create_file (GElf_Ehdr *ehdr,const char *name); struct section *elf_create_section(struct elf *elf, const char *name, size_t size, size_t entsize,
@@ -165,7 +166,7 @@ int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, const char *insn);int elf_write (struct elf *elf); -void elf_close (struct elf *elf); +int elf_close (struct elf *elf);struct section *find_section_by_name (const struct elf *elf,const char *name);struct symbol *find_func_by_offset (struct section *sec,unsigned long offset);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 44/63 objtool: Add annotype() helper
In reply to Josh Poimboeuf... for reading annotation types.
--- tools/objtool/arch/loongarch/orc.c | 1 - tools/objtool/arch/powerpc/decode.c | 1 - tools/objtool/arch/x86/decode.c | 1 - tools/objtool/arch/x86/orc.c | 1 - tools/objtool/check.c | 5 +---- tools/objtool/include/objtool/elf.h | 13 +++++++++++++ tools/objtool/include/objtool/endianness.h | 9 ++++----- tools/objtool/orc_dump.c | 1 - tools/objtool/orc_gen.c | 1 - tools/objtool/special.c | 1 - 10 files changed, 18 insertions(+), 16 deletions(-)
tools/objtool/arch/loongarch/orc.c +0 -1
@@ -5,7 +5,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry (struct orc_entry *orc,struct cfi_state *cfi,struct instruction *insn) {
tools/objtool/arch/powerpc/decode.c +0 -1
@@ -7,7 +7,6 @@#include <objtool/arch.h> #include <objtool/warn.h> #include <objtool/builtin.h> -#include <objtool/endianness.h> int arch_ftrace_match (const char *name) {
tools/objtool/arch/x86/decode.c +0 -1
@@ -19,7 +19,6 @@#include <objtool/elf.h> #include <objtool/arch.h> #include <objtool/warn.h> -#include <objtool/endianness.h> #include <objtool/builtin.h> #include <arch/elf.h>
tools/objtool/arch/x86/orc.c +0 -1
@@ -5,7 +5,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry (struct orc_entry *orc,struct cfi_state *cfi,struct instruction *insn) {
tools/objtool/check.c +1 -4
@@ -14,7 +14,6 @@#include <objtool/check.h> #include <objtool/special.h> #include <objtool/warn.h> -#include <objtool/endianness.h> #include <linux/objtool_types.h> #include <linux/hashtable.h>
@@ -2273,9 +2272,7 @@ static int read_annotate(struct objtool_file *file, }for_each_reloc (sec->rsec, reloc) { - type = *(u32 *)(sec->data->d_buf + (reloc_idx (reloc) * sec->sh.sh_entsize) +4 ); - type =bswap_if_needed (file->elf, type); - + type =annotype (file->elf, sec, reloc); offset = reloc->sym->offset +reloc_addend (reloc); insn =find_insn (file, reloc->sym->sec, offset);
tools/objtool/include/objtool/elf.h +13 -0
@@ -13,10 +13,14 @@#include <linux/hashtable.h> #include <linux/rbtree.h> #include <linux/jhash.h> + +#include <objtool/endianness.h> #include <arch/elf.h> #define SYM_NAME_LEN 512 +#define bswap_if_needed (elf, val) __bswap_if_needed(&elf->ehdr, val) +#ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum# define elf_getshdrstrndx elf_getshstrndx
@@ -401,6 +405,15 @@ static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsignedmark_sec_changed (elf, reloc->sec, true); } +static inline unsigned int annotype (struct elf *elf,struct section *sec, +struct reloc *reloc) +{ +unsigned int type; + + type = *(u32 *)(sec->data->d_buf + (reloc_idx (reloc) *8 ) +4 ); +return bswap_if_needed (elf, type); +} +#define RELOC_JUMP_TABLE_BIT 1UL/* Does reloc mark the beginning of a jump table? */
tools/objtool/include/objtool/endianness.h +4 -5
@@ -4,7 +4,6 @@#include <linux/kernel.h> #include <endian.h> -#include <objtool/elf.h> /* * Does a byte swap if target file endianness doesn't match the host, i.e. cross
@@ -12,16 +11,16 @@* To be used for multi-byte values conversion, which are read from / about * to be written to a target native endianness ELF file. */ -static inline bool need_bswap (struct elf *elf) +static inline bool need_bswap (GElf_Ehdr *ehdr) {return (__BYTE_ORDER == __LITTLE_ENDIAN) ^ - (elf->ehdr.e_ident[EI_DATA ] ==ELFDATA2LSB ); + (ehdr->e_ident[EI_DATA ] ==ELFDATA2LSB ); } -#define bswap_if_needed (elf, val) \ +#define __bswap_if_needed (ehdr, val) \ ({ \ __typeof__(val) __ret; \ - bool __need_bswap = need_bswap(elf); \ + bool __need_bswap = need_bswap(ehdr); \ switch (sizeof(val)) { \ case 8: \ __ret = __need_bswap ? bswap_64(val) : (val); break; \
tools/objtool/orc_dump.c +0 -1
@@ -8,7 +8,6 @@#include <objtool/objtool.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int orc_dump (const char *filename) {
tools/objtool/orc_gen.c +0 -1
@@ -12,7 +12,6 @@#include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct orc_list_entry {struct list_head list;
tools/objtool/special.c +0 -1
@@ -15,7 +15,6 @@#include <objtool/builtin.h> #include <objtool/special.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct special_entry {const char *sec;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 45/63 objtool: Move ANNOTATE* macros to annotate.h
In reply to Josh PoimboeufIn preparation for using the objtool annotation macros in higher-level objtool.h macros like UNWIND_HINT, move them to their own file.
--- include/linux/annotate.h | 109 +++++++++++++++++++++++++++++++++++++++ include/linux/objtool.h | 90 +------------------------------- 2 files changed, 110 insertions(+), 89 deletions(-) create mode 100644 include/linux/annotate.h
include/linux/annotate.h new file +109 -0
@@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_ANNOTATE_H +#define _LINUX_ANNOTATE_H + +#include <linux/objtool_types.h> + +#ifdef CONFIG_OBJTOOL + +#ifndef __ASSEMBLY__ + +#define __ASM_ANNOTATE (label, type) \ + ".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \ + ".long " __stringify(label) " - .\n\t" \ + ".long " __stringify(type) "\n\t" \ + ".popsection\n\t" + +#define ASM_ANNOTATE (type) \ + "911:\n\t" \ + __ASM_ANNOTATE(911b, type) + +#else /* __ASSEMBLY__ */ + +.macro ANNOTATE type:req +.Lhere_\@: + .pushsection .discard.annotate_insn,"M",@progbits,8 + .long .Lhere_\@ - . + .long \type + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_OBJTOOL */ +#ifndef __ASSEMBLY__ +#define __ASM_ANNOTATE (label, type) "" +#define ASM_ANNOTATE (type) +#else /* __ASSEMBLY__ */ +.macro ANNOTATE type:req +.endm +#endif /* __ASSEMBLY__ */ +#endif /* !CONFIG_OBJTOOL */ + +#ifndef __ASSEMBLY__ + +/* +* Annotate away the various 'relocation to !ENDBR` complaints; knowing that +* these relocations will never be used for indirect calls. +*/ +#define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR) +#define ANNOTATE_NOENDBR_SYM (sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOENDBR)) + +/* +* This should be used immediately before an indirect jump/call. It tells +* objtool the subsequent indirect jump/call is vouched safe for retpoline +* builds. +*/ +#define ANNOTATE_RETPOLINE_SAFE ASM_ANNOTATE(ANNOTYPE_RETPOLINE_SAFE) +/* +* See linux/instrumentation.h +*/ +#define ANNOTATE_INSTR_BEGIN (label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_BEGIN) +#define ANNOTATE_INSTR_END (label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_END) +/* +* objtool annotation to ignore the alternatives and only consider the original +* instruction(s). +*/ +#define ANNOTATE_IGNORE_ALTERNATIVE ASM_ANNOTATE(ANNOTYPE_IGNORE_ALTS) +/* +* This macro indicates that the following intra-function call is valid. +* Any non-annotated intra-function call will cause objtool to issue a warning. +*/ +#define ANNOTATE_INTRA_FUNCTION_CALL ASM_ANNOTATE(ANNOTYPE_INTRA_FUNCTION_CALL) +/* +* Use objtool to validate the entry requirement that all code paths do +* VALIDATE_UNRET_END before RET. +* +* NOTE: The macro must be used at the beginning of a global symbol, otherwise +* it will be ignored. +*/ +#define ANNOTATE_UNRET_BEGIN ASM_ANNOTATE(ANNOTYPE_UNRET_BEGIN) +/* +* This should be used to refer to an instruction that is considered +* terminating, like a noreturn CALL or UD2 when we know they are not -- eg +* WARN using UD2. +*/ +#define ANNOTATE_REACHABLE (label) __ASM_ANNOTATE(label, ANNOTYPE_REACHABLE) +/* +* This should not be used; it annotates away CFI violations. There are a few +* valid use cases like kexec handover to the next kernel image, and there is +* no security concern there. +* +* There are also a few real issues annotated away, like EFI because we can't +* control the EFI code. +*/ +#define ANNOTATE_NOCFI_SYM (sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOCFI)) + +#else /* __ASSEMBLY__ */ +#define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR +#define ANNOTATE_RETPOLINE_SAFE ANNOTATE type=ANNOTYPE_RETPOLINE_SAFE +/* ANNOTATE_INSTR_BEGIN ANNOTATE type=ANNOTYPE_INSTR_BEGIN */ +/* ANNOTATE_INSTR_END ANNOTATE type=ANNOTYPE_INSTR_END */ +#define ANNOTATE_IGNORE_ALTERNATIVE ANNOTATE type=ANNOTYPE_IGNORE_ALTS +#define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL +#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN +#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE +#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI +#endif /* __ASSEMBLY__ */ + +#endif /* _LINUX_ANNOTATE_H */
include/linux/objtool.h +1 -89
126 lines not on this page · raw message
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 46/63 objtool: Add ANNOTATE_DATA_SPECIAL
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, add an ANNOTATE_DATA_SPECIAL macro which annotates special section entries so that objtool can determine their size and location and extract them when needed.
--- include/linux/annotate.h | 49 ++++++++++++++++++++++------- include/linux/objtool_types.h | 2 ++ tools/include/linux/objtool_types.h | 2 ++ 3 files changed, 41 insertions(+), 12 deletions(-)
include/linux/annotate.h +37 -12
@@ -8,34 +8,52 @@#ifndef __ASSEMBLY__ -#define __ASM_ANNOTATE (label, type) \ - ".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \ +#define __ASM_ANNOTATE (section, label, type) \ + ".pushsection " section ",\"M\", @progbits, 8\n\t" \ ".long " __stringify(label) " - .\n\t" \ ".long " __stringify(type) "\n\t" \ ".popsection\n\t" +#define ASM_ANNOTATE_LABEL (label, type) \ + __ASM_ANNOTATE(".discard.annotate_insn", label, type) +#define ASM_ANNOTATE (type) \ "911:\n\t" \ - __ASM_ANNOTATE(911b, type) + ASM_ANNOTATE_LABEL(911b, type) + +#define ASM_ANNOTATE_DATA (type) \ + "912:\n\t" \ + __ASM_ANNOTATE(".discard.annotate_data", 912b, type)#else /* __ASSEMBLY__ */ -.macro ANNOTATE type:req +.macro __ANNOTATE section, type .Lhere_\@: - .pushsection .discard.annotate_insn,"M",@progbits,8 + .pushsection \section, "M", @progbits, 8 .long .Lhere_\@ - . .long \type .popsection .endm +.macro ANNOTATE type + __ANNOTATE ".discard.annotate_insn", \type +.endm + +.macro ANNOTATE_DATA type + __ANNOTATE ".discard.annotate_data", \type +.endm +#endif /* __ASSEMBLY__ */ #else /* !CONFIG_OBJTOOL */ #ifndef __ASSEMBLY__ -#define __ASM_ANNOTATE (label, type) "" +#define ASM_ANNOTATE_LABEL (label, type) ""#define ASM_ANNOTATE (type) +#define ASM_ANNOTATE_DATA (type)#else /* __ASSEMBLY__ */ -.macro ANNOTATE type:req +.macro ANNOTATE type +.endm +.macro ANNOTATE_DATA type .endm#endif /* __ASSEMBLY__ */ #endif /* !CONFIG_OBJTOOL */
@@ -47,7 +65,7 @@* these relocations will never be used for indirect calls. */ #define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR) -#define ANNOTATE_NOENDBR_SYM (sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOENDBR)) +#define ANNOTATE_NOENDBR_SYM (sym) asm(ASM_ANNOTATE_LABEL(sym, ANNOTYPE_NOENDBR))/* * This should be used immediately before an indirect jump/call. It tells
@@ -58,8 +76,8 @@/* * See linux/instrumentation.h */ -#define ANNOTATE_INSTR_BEGIN (label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_BEGIN) -#define ANNOTATE_INSTR_END (label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_END) +#define ANNOTATE_INSTR_BEGIN (label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_INSTR_BEGIN) +#define ANNOTATE_INSTR_END (label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_INSTR_END)/* * objtool annotation to ignore the alternatives and only consider the original * instruction(s).
@@ -83,7 +101,7 @@* terminating, like a noreturn CALL or UD2 when we know they are not -- eg * WARN using UD2. */ -#define ANNOTATE_REACHABLE (label) __ASM_ANNOTATE(label, ANNOTYPE_REACHABLE) +#define ANNOTATE_REACHABLE (label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_REACHABLE)/* * This should not be used; it annotates away CFI violations. There are a few * valid use cases like kexec handover to the next kernel image, and there is
@@ -92,7 +110,13 @@* There are also a few real issues annotated away, like EFI because we can't * control the EFI code. */ -#define ANNOTATE_NOCFI_SYM (sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOCFI)) +#define ANNOTATE_NOCFI_SYM (sym) asm(ASM_ANNOTATE_LABEL(sym, ANNOTYPE_NOCFI)) + +/* +* Annotate a special section entry. This emables livepatch module generation +* to find and extract individual special section entries as needed. +*/ +#define ANNOTATE_DATA_SPECIAL ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL)#else /* __ASSEMBLY__ */ #define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR
@@ -104,6 +128,7 @@#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI +#define ANNOTATE_DATA_SPECIAL ANNOTATE_DATA type=ANNOTYPE_DATA_SPECIAL#endif /* __ASSEMBLY__ */ #endif /* _LINUX_ANNOTATE_H */
include/linux/objtool_types.h +2 -0
@@ -67,4 +67,6 @@ struct unwind_hint {#define ANNOTYPE_REACHABLE 8#define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 +#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/include/linux/objtool_types.h +2 -0
@@ -67,4 +67,6 @@ struct unwind_hint {#define ANNOTYPE_REACHABLE 8#define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 +#endif /* _LINUX_OBJTOOL_TYPES_H */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 47/63 x86/asm: Annotate special section entries
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, add annotations for special section entries. This will enable objtool to determine the size and location of the entries and to extract them when needed.
--- arch/x86/include/asm/alternative.h | 4 ++++ arch/x86/include/asm/asm.h | 5 +++++ arch/x86/include/asm/bug.h | 1 + arch/x86/include/asm/cpufeature.h | 1 + arch/x86/include/asm/jump_label.h | 1 + include/linux/objtool.h | 4 +++- 6 files changed, 15 insertions(+), 1 deletion(-)
arch/x86/include/asm/alternative.h +4 -0
@@ -198,6 +198,7 @@ static inline int alternatives_text_reserved(void *start, void *end)#define ALTINSTR_ENTRY (ft_flags) \ ".pushsection .altinstructions,\"a\"\n" \ + ANNOTATE_DATA_SPECIAL \ " .long 771b - .\n"/* label */ \" .long 774f - .\n" /* new instruction */ \ " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
@@ -207,6 +208,7 @@ static inline int alternatives_text_reserved(void *start, void *end)#define ALTINSTR_REPLACEMENT (newinstr)/* replacement */ \ ".pushsection .altinstr_replacement, \"ax\"\n" \ + ANNOTATE_DATA_SPECIAL \ "# ALT: replacement\n" \ "774:\n\t" newinstr "\n775:\n" \ ".popsection\n"
@@ -337,6 +339,7 @@ void nop_func(void);* instruction. See apply_alternatives(). */ .macro altinstr_entry orig alt ft_flags orig_len alt_len + ANNOTATE_DATA_SPECIAL .long \orig - . .long \alt - . .4byte \ft_flags
@@ -365,6 +368,7 @@ void nop_func(void); .popsection ; \ .pushsection .altinstr_replacement,"ax" ; \ 743: \ +ANNOTATE_DATA_SPECIAL ; \ newinst ; \ 744: \ .popsection ;
arch/x86/include/asm/asm.h +5 -0
@@ -2,6 +2,8 @@#ifndef _ASM_X86_ASM_H#define _ASM_X86_ASM_H +#include <linux/annotate.h> +#ifdef __ASSEMBLER__# define __ASM_FORM (x, ...) x,## __VA_ARGS__# define __ASM_FORM_RAW (x, ...) x,## __VA_ARGS__
@@ -132,6 +134,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)# define _ASM_EXTABLE_TYPE (from, to, type) \ .pushsection "__ex_table","a" ; \ .balign 4 ; \ + ANNOTATE_DATA_SPECIAL ; \ .long (from) - . ; \ .long (to) - . ; \ .long type ; \
@@ -179,6 +182,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)# define _ASM_EXTABLE_TYPE (from, to, type) \ " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ " .long " __stringify(type) " \n" \
@@ -187,6 +191,7 @@ static __always_inline __pure void *rip_rel_ptr(void *p)# define _ASM_EXTABLE_TYPE_REG (from, to, type, reg) \ " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ DEFINE_EXTABLE_TYPE_REG \
arch/x86/include/asm/bug.h +1 -0
@@ -57,6 +57,7 @@#define _BUG_FLAGS_ASM (ins, file, line, flags, size, extra) \ "1:\t" ins "\n" \ ".pushsection __bug_table,\"aw\"\n" \ + ANNOTATE_DATA_SPECIAL \ __BUG_ENTRY(file, line, flags) \ "\t.org 2b + " size "\n" \ ".popsection\n" \
arch/x86/include/asm/cpufeature.h +1 -0
@@ -101,6 +101,7 @@ static __always_inline bool _static_cpu_has(u16 bit) asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]")".pushsection .altinstr_aux,\"ax\"\n" "6:\n" +ANNOTATE_DATA_SPECIAL " testb %[bitnum], %a[cap_byte]\n" " jnz %l[t_yes]\n" " jmp %l[t_no]\n"
arch/x86/include/asm/jump_label.h +1 -0
@@ -15,6 +15,7 @@#define JUMP_TABLE_ENTRY (key, label) \ ".pushsection __jump_table, \"aw\" \n\t" \ _ASM_ALIGN "\n\t" \ + ANNOTATE_DATA_SPECIAL \ ".long 1b - . \n\t" \ ".long " label " - . \n\t" \ _ASM_PTR " " key " - . \n\t" \
include/linux/objtool.h +3 -1
@@ -9,9 +9,10 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (type, sp_reg, sp_offset, signal) \ +#define UNWIND_HINT (type, sp_reg, sp_offset, signal) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \ + ANNOTATE_DATA_SPECIAL \/* struct unwind_hint */ \".long 987b - .\n\t" \ ".short " __stringify(sp_offset) "\n\t" \
@@ -78,6 +79,7 @@ .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .Lhere_\@: .pushsection .discard.unwind_hints + ANNOTATE_DATA_SPECIAL /* struct unwind_hint */ .long .Lhere_\@ - . .short \sp_offset
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 48/63 objtool: Unify STACK_FRAME_NON_STANDARD entry sizes
In reply to Josh PoimboeufThe C implementation of STACK_FRAME_NON_STANDARD emits 8-byte entries, whereas the asm version's entries are only 4 bytes.
Make them consistent by converting the asm version to 8-byte entries.
This is much easier than converting the C version to 4-bytes, which would require awkwardly putting inline asm in a dummy function in order to pass the 'func' pointer to the asm.
--- include/linux/objtool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/objtool.h +1 -1
@@ -92,7 +92,7 @@ .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard,"aw" - .long \func - . + .quad \func .popsection .endm
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 49/63 objtool/klp: Add --checksum option to generate per-function checksums
In reply to Josh PoimboeufIn preparation for the objtool klp diff subcommand, add a command-line option to generate a unique checksum for each function. This will enable detection of functions which have changed between two versions of an object file.
--- tools/objtool/Makefile | 38 +++-- tools/objtool/builtin-check.c | 11 +- tools/objtool/check.c | 140 +++++++++++++++++- tools/objtool/elf.c | 46 +++++- tools/objtool/include/objtool/builtin.h | 5 +- tools/objtool/include/objtool/check.h | 5 +- tools/objtool/include/objtool/checksum.h | 42 ++++++ .../objtool/include/objtool/checksum_types.h | 25 ++++ tools/objtool/include/objtool/elf.h | 4 +- 9 files changed, 289 insertions(+), 27 deletions(-) create mode 100644 tools/objtool/include/objtool/checksum.h create mode 100644 tools/objtool/include/objtool/checksum_types.h
tools/objtool/Makefile +24 -14
@@ -2,6 +2,27 @@ include ../scripts/Makefile.include include ../scripts/Makefile.arch +ifeq ($(SRCARCH),x86) + BUILD_ORC := y + ARCH_HAS_KLP := y +endif + +ifeq ($(SRCARCH),loongarch) + BUILD_ORC := y +endif + +ifeq ($(ARCH_HAS_KLP),y) + HAVE_XXHASH = $(shell echo "int main() {}" | \ + $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) + ifeq ($(HAVE_XXHASH),y) + LIBXXHASH_CFLAGS := $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/null) \ + -DBUILD_KLP + LIBXXHASH_LIBS := $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/null || echo -lxxhash) + endif +endif + +export BUILD_ORC + ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree)))
@@ -36,10 +57,10 @@ INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/objtool/arch/$(SRCARCH)/include \ -I$(LIBSUBCMD_OUTPUT)/include -OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g \ - $(WARNINGS) $(INCLUDES) $(LIBELF_FLAGS) $(HOSTCFLAGS) +OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g $(WARNINGS) \ + $(INCLUDES) $(LIBELF_FLAGS) $(LIBXXHASH_CFLAGS) $(HOSTCFLAGS) -OBJTOOL_LDFLAGS := $(LIBSUBCMD) $(LIBELF_LIBS) $(HOSTLDFLAGS) +OBJTOOL_LDFLAGS := $(LIBSUBCMD) $(LIBELF_LIBS) $(LIBXXHASH_LIBS) $(HOSTLDFLAGS) # Allow old libelf to be used: elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - 2>/dev/null | grep elf_getshdr)
@@ -51,17 +72,6 @@ HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" AWK = awk MKDIR = mkdir -BUILD_ORC := n - -ifeq ($(SRCARCH),x86) - BUILD_ORC := y -endif - -ifeq ($(SRCARCH),loongarch) - BUILD_ORC := y -endif - -export BUILD_ORC export srctree OUTPUT CFLAGS SRCARCH AWK include $(srctree)/tools/build/Makefile.include
tools/objtool/builtin-check.c +10 -1
@@ -73,6 +73,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)static const struct option check_options[] = {OPT_GROUP ("Actions:" ), +OPT_BOOLEAN (0 ,"checksum" , &opts.checksum,"generate per-function checksums" ),OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ),OPT_CALLBACK_OPTARG ('h' ,"hacks" ,NULL ,NULL ,"jump_label,noinstr,skylake" ,"patch toolchain bugs/limitations" , parse_hacks),OPT_BOOLEAN ('i' ,"ibt" , &opts.ibt,"validate and annotate IBT" ),
@@ -160,7 +161,15 @@ static bool opts_valid(void)return false; } - if (opts.hack_jump_label || +#ifndef BUILD_KLP +if (opts.checksum) { +ERROR ("--checksum not supported; install xxhash-devel and recompile" ); +return false; + } +#endif + + if (opts.checksum || + opts.hack_jump_label || opts.hack_noinstr || opts.ibt || opts.mcount ||
tools/objtool/check.c +136 -4
214 lines not on this page · raw message
tools/objtool/elf.c +43 -3
76 lines not on this page · raw message
tools/objtool/include/objtool/builtin.h +3 -2
@@ -9,12 +9,15 @@struct opts {/* actions: */ +bool cfi; +bool checksum;bool dump_orc;bool hack_jump_label;bool hack_noinstr;bool hack_skylake;bool ibt;bool mcount; +bool noabs;bool noinstr;bool orc;bool retpoline;
@@ -25,8 +28,6 @@ struct opts {bool static_call;bool uaccess;int prefix; -bool cfi; -bool noabs;/* options: */ bool backtrace;
tools/objtool/include/objtool/check.h +3 -2
@@ -65,8 +65,9 @@ struct instruction { unret : 1, visited : 4, no_reloc : 1, - hole : 1; -/* 10 bit hole */ + hole : 1, + fake : 1; +/* 9 bit hole */ struct alt_group *alt_group;struct instruction *jump_dest;
tools/objtool/include/objtool/checksum.h new file +42 -0
42 lines not on this page · raw message
tools/objtool/include/objtool/checksum_types.h new file +25 -0
@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _OBJTOOL_CHECKSUM_TYPES_H +#define _OBJTOOL_CHECKSUM_TYPES_H + +struct sym_checksum { +u64 addr; +u64 checksum; +}; + +#ifdef BUILD_KLP + +#include <xxhash.h> + +struct checksum { +XXH3_state_t *state; +XXH64_hash_t checksum; +}; + +#else /* !BUILD_KLP */ + +struct checksum {}; + +#endif /* !BUILD_KLP */ + +#endif /* _OBJTOOL_CHECKSUM_TYPES_H */
tools/objtool/include/objtool/elf.h +3 -1
@@ -15,6 +15,7 @@#include <linux/jhash.h> #include <objtool/endianness.h> +#include <objtool/checksum_types.h> #include <arch/elf.h> #define SYM_NAME_LEN 512
@@ -61,7 +62,7 @@ struct symbol {struct elf_hash_node name_hash;GElf_Sym sym;struct section *sec; -const char *name; +const char *name, *demangled_name;unsigned int idx, len;unsigned long offset;unsigned long __subtree_last;
@@ -84,6 +85,7 @@ struct symbol {struct list_head pv_target;struct reloc *relocs;struct section *group_sec; +struct checksum csum; };struct reloc {
Signature · 1 line
2.50.0
RE: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
From: Josh Poimboeuf <[email protected]> Sent: Wednesday, September 17, 2025 9:04 AM
Quoted 37 lines
In preparation for the objtool klp diff subcommand, add a command-line option to generate a unique checksum for each function. This will enable detection of functions which have changed between two versions of an object file.
Signed-off-by Josh Poimboeuf <[email protected]>--- tools/objtool/Makefile | 38 +++-- tools/objtool/builtin-check.c | 11 +- tools/objtool/check.c | 140 +++++++++++++++++- tools/objtool/elf.c | 46 +++++- tools/objtool/include/objtool/builtin.h | 5 +- tools/objtool/include/objtool/check.h | 5 +- tools/objtool/include/objtool/checksum.h | 42 ++++++ .../objtool/include/objtool/checksum_types.h | 25 ++++ tools/objtool/include/objtool/elf.h | 4 +- 9 files changed, 289 insertions(+), 27 deletions(-) create mode 100644 tools/objtool/include/objtool/checksum.h create mode 100644 tools/objtool/include/objtool/checksum_types.htools/objtool/Makefile +8
-0@@ -2,6 +2,27 @@ include ../scripts/Makefile.include include ../scripts/Makefile.arch +ifeq ($(SRCARCH),x86) + BUILD_ORC := y + ARCH_HAS_KLP := y +endif + +ifeq ($(SRCARCH),loongarch) + BUILD_ORC := y +endif
tools/objtool/Makefile line 22
Quoted 10 lines
tools/objtool/Makefile +10
-0+ +ifeq ($(ARCH_HAS_KLP),y) + HAVE_XXHASH = $(shell echo "int main() {}" | \ + $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) + ifeq ($(HAVE_XXHASH),y) + LIBXXHASH_CFLAGS := $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/null) \ + -DBUILD_KLP + LIBXXHASH_LIBS := $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/null || echo -lxxhash) + endif +endif
I ran into an interesting issue with xxhash when building the linux-next20251024 kernel on Ubuntu 20.04 for x86/x64. My first result was the new error that this patch adds (as modified by Boris Petkov's follow-up patch):
error: objtool: --checksum not supported; install xxhash-devel/libxxhash-dev and recompile
OK, not a big deal. I installed libxxhash-dev using:
# apt install libxxhash-dev
Then objtool got a compile error when building:
CC /data/linux-next20251024/tools/objtool/libsubcmd/exec-cmd.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/help.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/pager.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/parse-options.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/run-command.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/sigchain.o
CC /data/linux-next20251024/tools/objtool/libsubcmd/subcmd-config.o
LD /data/linux-next20251024/tools/objtool/libsubcmd/libsubcmd-in.o
AR /data/linux-next20251024/tools/objtool/libsubcmd/libsubcmd.a
INSTALL libsubcmd_headers
CC /data/linux-next20251024/tools/objtool/arch/x86/special.o
In file included from /data/linux-next20251024/tools/objtool/include/objtool/elf.h:18,
from /data/linux-next20251024/tools/objtool/include/objtool/objtool.h:13,
from /data/linux-next20251024/tools/objtool/include/objtool/arch.h:11,
from /data/linux-next20251024/tools/objtool/include/objtool/check.h:11,
from /data/linux-next20251024/tools/objtool/include/objtool/special.h:10,
from arch/x86/special.c:4:
/data/linux-next20251024/tools/objtool/include/objtool/checksum_types.h:15:9: error: unknown type name 'XXH3_state_t'
15 | XXH3_state_t *state;
| ^~~~~~~~~~~~It turns out that Ubuntu 20.04 installed the 0.7.3-1 version of libxxhash. But from a quick look at the README on the xxhash github site, XXH3 is first supported by the 0.8.0 version, so the compile error probably makes sense. I found a PPA that offers the 0.8.3 version of xxhash for Ubuntu 20.04, and that solved the problem.
So the Makefile steps above that figure out if xxhash is present probably aren't sufficient, as the version of xxhash matters. And the "--checksum not supported" error message should be more specific about the required version.
I reproduced the behavior on two different Ubuntu 20.04 systems, but someone who knows this xxhash stuff better than I do should confirm my conclusions. Maybe the way to fix the check for the presence of xxhash is to augment the inline test program to include a reference to XXH3_state, but I haven't tried to put together a patch to do that, pending any further discussion or ideas.
Michael
Quoted 553 lines
tools/objtool/Makefile +6
-3+ +export BUILD_ORC + ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree)))@@ -36,10 +57,10 @@ INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/objtool/arch/$(SRCARCH)/include \ -I$(LIBSUBCMD_OUTPUT)/include -OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g \ - $(WARNINGS) $(INCLUDES) $(LIBELF_FLAGS) $(HOSTCFLAGS) +OBJTOOL_CFLAGS := -std=gnu11 -fomit-frame-pointer -O2 -g $(WARNINGS) \ + $(INCLUDES) $(LIBELF_FLAGS) $(LIBXXHASH_CFLAGS) $(HOSTCFLAGS) -OBJTOOL_LDFLAGS := $(LIBSUBCMD) $(LIBELF_LIBS) $(HOSTLDFLAGS) +OBJTOOL_LDFLAGS := $(LIBSUBCMD) $(LIBELF_LIBS) $(LIBXXHASH_LIBS) $(HOSTLDFLAGS)# Allow old libelf to be used:
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x
c -E - 2>/dev/null | grepelf_getshdr)tools/objtool/Makefile +0
-0@@ -51,17 +72,6 @@ HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)"AR="$(HOSTAR)"
AWK = awk
MKDIR = mkdirtools/objtool/Makefile +0
-11-BUILD_ORC := n - -ifeq ($(SRCARCH),x86) - BUILD_ORC := y -endif - -ifeq ($(SRCARCH),loongarch) - BUILD_ORC := y -endif - -export BUILD_ORC export srctree OUTPUT CFLAGS SRCARCH AWK include $(srctree)/tools/build/Makefile.includetools/objtool/builtin-check.c +10
-1@@ -73,6 +73,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)static const struct option check_options[] = {OPT_GROUP ("Actions:" ), +OPT_BOOLEAN (0 ,"checksum" , &opts.checksum,"generate per-function checksums" ),OPT_BOOLEAN (0 ,"cfi" , &opts.cfi,"annotate kernel control flow integrity (kCFI) function preambles" ),OPT_CALLBACK_OPTARG ('h' ,"hacks" ,NULL ,NULL ,"jump_label,noinstr,skylake" ,"patch toolchain bugs/limitations" , parse_hacks),OPT_BOOLEAN ('i' ,"ibt" , &opts.ibt,"validate and annotate IBT" ),@@ -160,7 +161,15 @@ static bool opts_valid(void)return false; } - if (opts.hack_jump_label || +#ifndef BUILD_KLP +if (opts.checksum) { +ERROR ("--checksum not supported; install xxhash-devel and recompile" ); +return false; + } +#endif + + if (opts.checksum || + opts.hack_jump_label || opts.hack_noinstr || opts.ibt || opts.mcount ||tools/objtool/check.c +54
-0@@ -14,6 +14,7 @@#include <objtool/check.h> #include <objtool/special.h> #include <objtool/warn.h> +#include <objtool/checksum.h> #include <linux/objtool_types.h> #include <linux/hashtable.h> @@ -971,6 +972,59 @@ static int create_direct_call_sections(struct objtool_file *file)return 0 ; } +#ifdef BUILD_KLP +static int create_sym_checksum_section (struct objtool_file *file) +{ +struct section *sec; +struct symbol *sym; +unsigned int idx =0 ; +struct sym_checksum *checksum; +size_t entsize =sizeof (struct sym_checksum ); + + sec =find_section_by_name (file->elf,".discard.sym_checksum" ); +if (sec) { +if (!opts.dryrun) +WARN ("file already has .discard.sym_checksum section, skipping"); + +return 0 ; + } + +for_each_sym (file->elf, sym) +if (sym->csum.checksum) + idx++; + +if (!idx) +return 0 ; + + sec =elf_create_section_pair (file->elf,".discard.sym_checksum" , entsize, + idx, idx); +if (!sec) +return -1 ; + + idx =0 ; +for_each_sym (file->elf, sym) { +if (!sym->csum.checksum) +continue ; + +if (!elf_init_reloc (file->elf, sec->rsec, idx, idx * entsize, + sym,0 ,R_TEXT64 )) +return -1 ; + + checksum = (struct sym_checksum *)sec->data->d_buf + idx; + checksum->addr =0 ;/* reloc */ + checksum->checksum = sym->csum.checksum; + +mark_sec_changed (file->elf, sec, true); + + idx++; + } + +return 0 ; +} +#else +static int create_sym_checksum_section (struct objtool_file *file) {return -EINVAL ; } +#endif +/* * Warnings shouldn't be reported for ignored functions. */
tools/objtool/check.c +54
-1@@ -1748,6 +1802,7 @@ static int handle_group_alt(struct objtool_file *file, nop->type =INSN_NOP ; nop->sym = orig_insn->sym; nop->alt_group = new_alt_group; + nop->fake =1 ; }if (!special_alt->new_len) {@@ -2527,6 +2582,14 @@ static void mark_holes(struct objtool_file *file) } } +static bool validate_branch_enabled (void ) +{ +return opts.stackval || + opts.orc || + opts.uaccess || + opts.checksum; +} +static int decode_sections (struct objtool_file *file) {mark_rodata (file);@@ -2555,7 +2618,7 @@ static int decode_sections(struct objtool_file *file)* Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ -if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr) { +if (validate_branch_enabled () || opts.noinstr) {if (add_special_section_alts (file))return -1 ; }@@ -3527,6 +3590,50 @@ static bool skip_alt_group(struct instruction *insn)return alt_insn->type ==INSN_CLAC || alt_insn->type ==INSN_STAC ; } +static void checksum_update_insn (struct objtool_file *file,struct symbol *func, +struct instruction *insn) +{ +struct reloc *reloc =insn_reloc (file, insn); +unsigned long offset; +struct symbol *sym; + +if (insn->fake) +return ; + +checksum_update (func, insn, insn->sec->data->d_buf + insn->offset, insn- >len); + +if (!reloc) { +struct symbol *call_dest =insn_call_dest (insn); + +if (call_dest) +checksum_update (func, insn, call_dest->demangled_name, +strlen (call_dest->demangled_name)); +return ; + } + + sym = reloc->sym; + offset =arch_insn_adjusted_addend (insn, reloc); + +if (is_string_sec (sym->sec)) { +char *str; + + str = sym->sec->data->d_buf + sym->offset + offset; +checksum_update (func, insn, str,strlen (str)); +return ; + } + +if (is_sec_sym (sym)) { + sym =find_symbol_containing (reloc->sym->sec, offset); +if (!sym) +return ; + + offset -= sym->offset; + } + +checksum_update (func, insn, sym->demangled_name,strlen (sym- >demangled_name)); +checksum_update (func, insn, &offset,sizeof (offset)); +} +/* * Follow the branch starting at the given instruction, and recursively follow
* any other branches (jumps). Meanwhile, track the frame pointer state attools/objtool/check.c +3
-0@@ -3547,6 +3654,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, while (1) { next_insn =next_insn_to_validate (file, insn); +if (opts.checksum && func && insn->sec) +checksum_update_insn (file, func, insn); +if (func &&insn_func (insn) && func !=insn_func (insn)->pfunc) {/* Ignore KCFI type preambles, which always fall through */ tools/objtool/check.c +8
-1if (is_prefix_func (func))@@ -3796,7 +3906,13 @@ static int validate_unwind_hint(struct objtool_file *file, struct insn_state *state) {if (insn->hint && !insn->visited) { -int ret =validate_branch (file,insn_func (insn), insn, *state); +struct symbol *func =insn_func (insn); +int ret; + +if (opts.checksum) +checksum_init (func); + + ret =validate_branch (file, func, insn, *state);if (ret)BT_INSN (insn,"<=== (hint)" );return ret;@@ -4175,6 +4291,7 @@ static int validate_symbol(struct objtool_file *file, structsection *sec, struct symbol *sym, struct insn_state *state) { struct instruction *insn; +struct symbol *func;int ret;tools/objtool/check.c +17
-2if (!sym->len) {@@ -4192,9 +4309,18 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, if (opts.uaccess) state->uaccess = sym->uaccess_safe; - ret =validate_branch (file,insn_func (insn), insn, *state); + func =insn_func (insn); + +if (opts.checksum) +checksum_init (func); + + ret =validate_branch (file, func, insn, *state);if (ret)BT_INSN (insn,"<=== (sym)" ); + +if (opts.checksum) +checksum_finish (func); +return ret; }@@ -4712,7 +4838,7 @@ int check(struct objtool_file *file)if (opts.retpoline) warnings +=validate_retpoline (file); -if (opts.stackval || opts.orc || opts.uaccess) { +if (validate_branch_enabled ()) {int w =0 ; w +=validate_functions (file);@@ -4791,6 +4917,12 @@ int check(struct objtool_file *file)if (opts.noabs) warnings +=check_abs_references (file); +if (opts.checksum) { + ret =create_sym_checksum_section (file); +if (ret) + goto out; + } +if (opts.orc && nr_insns) { ret =orc_create (file);if (ret)tools/objtool/elf.c +43
-3@@ -17,6 +17,7 @@#include <unistd.h> #include <errno.h> #include <libgen.h> +#include <ctype.h> #include <linux/interval_tree_generic.h> #include <objtool/builtin.h> #include <objtool/elf.h> @@ -412,7 +413,38 @@ static int read_sections(struct elf *elf)return 0 ; } -static void elf_add_symbol (struct elf *elf,struct symbol *sym) +static const char *demangle_name (struct symbol *sym) +{ +char *str; + +if (!is_local_sym (sym)) +return sym->name; + +if (!is_func_sym (sym) && !is_object_sym (sym)) +return sym->name; + +if (!strstarts (sym->name,"__UNIQUE_ID_" ) && !strchr (sym->name,'.' )) +return sym->name; + + str =strdup (sym->name); +if (!str) { +ERROR_GLIBC ("strdup" ); +return NULL ; + } + +for (int i =strlen (str) -1 ; i >=0 ; i--) { +char c = str[i]; + +if (!isdigit (c) && c !='.' ) { + str[i +1 ] ='\0' ; +break ; + } + }; + +return str; +} + +static int elf_add_symbol (struct elf *elf,struct symbol *sym) {struct list_head *entry;struct rb_node *pnode;@@ -456,6 +488,12 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)if (is_func_sym (sym) &&strstr (sym->name,".cold" )) sym->cold =1 ; sym->pfunc = sym->cfunc = sym; + + sym->demangled_name =demangle_name (sym); +if (!sym->demangled_name) +return -1 ; + +return 0 ; }static int read_symbols (struct elf *elf)@@ -529,7 +567,8 @@ static int read_symbols(struct elf *elf) }else sym->sec =find_section_by_index (elf,0 ); -elf_add_symbol (elf, sym); +if (elf_add_symbol (elf, sym)) +return -1 ; }if (opts.stats) {@@ -867,7 +906,8 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name,mark_sec_changed (elf, symtab_shndx, true); } -elf_add_symbol (elf, sym); +if (elf_add_symbol (elf, sym)) +return NULL ;return sym;}
tools/objtool/include/objtool/builtin.h +3
-2@@ -9,12 +9,15 @@struct opts {/* actions: */ +bool cfi; +bool checksum;bool dump_orc;bool hack_jump_label;bool hack_noinstr;bool hack_skylake;bool ibt;bool mcount; +bool noabs;bool noinstr;bool orc;bool retpoline;@@ -25,8 +28,6 @@ struct opts {bool static_call;bool uaccess;int prefix; -bool cfi; -bool noabs;/* options: */ bool backtrace;tools/objtool/include/objtool/check.h +3
-2@@ -65,8 +65,9 @@ struct instruction { unret : 1, visited : 4, no_reloc : 1, - hole : 1; -/* 10 bit hole */ + hole : 1, + fake : 1; +/* 9 bit hole */ struct alt_group *alt_group;struct instruction *jump_dest;tools/objtool/include/objtool/checksum.h new file +42
-0@@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_CHECKSUM_H +#define _OBJTOOL_CHECKSUM_H + +#include <objtool/elf.h> + +#ifdef BUILD_KLP + +static inline void checksum_init (struct symbol *func) +{ +if (func && !func->csum.state) { + func->csum.state =XXH3_createState (); +XXH3_64bits_reset (func->csum.state); + } +} + +static inline void checksum_update (struct symbol *func, +struct instruction *insn, +const void *data,size_t size) +{ +XXH3_64bits_update (func->csum.state, data, size); +} + +static inline void checksum_finish (struct symbol *func) +{ +if (func && func->csum.state) { + func->csum.checksum =XXH3_64bits_digest (func->csum.state); + func->csum.state =NULL ; + } +} + +#else /* !BUILD_KLP */ + +static inline void checksum_init (struct symbol *func) {} +static inline void checksum_update (struct symbol *func, +struct instruction *insn, +const void *data,size_t size) {} +static inline void checksum_finish (struct symbol *func) {} + +#endif /* !BUILD_KLP */ + +#endif /* _OBJTOOL_CHECKSUM_H */ tools/objtool/include/objtool/checksum_types.h new file +25
-0@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _OBJTOOL_CHECKSUM_TYPES_H +#define _OBJTOOL_CHECKSUM_TYPES_H + +struct sym_checksum { +u64 addr; +u64 checksum; +}; + +#ifdef BUILD_KLP + +#include <xxhash.h> + +struct checksum { +XXH3_state_t *state; +XXH64_hash_t checksum; +}; + +#else /* !BUILD_KLP */ + +struct checksum {}; + +#endif /* !BUILD_KLP */ + +#endif /* _OBJTOOL_CHECKSUM_TYPES_H */ tools/objtool/include/objtool/elf.h +3
-2@@ -15,6 +15,7 @@#include <linux/jhash.h> #include <objtool/endianness.h> +#include <objtool/checksum_types.h> #include <arch/elf.h> #define SYM_NAME_LEN 512@@ -61,7 +62,7 @@ struct symbol {struct elf_hash_node name_hash;GElf_Sym sym;struct section *sec; -const char *name; +const char *name, *demangled_name;unsigned int idx, len;unsigned long offset;unsigned long __subtree_last;@@ -84,6 +85,7 @@ struct symbol {struct list_head pv_target;struct reloc *relocs;struct section *group_sec; +struct checksum csum; };struct reloc { --2.50.0
Josh Poimboeuf
maintainerRe: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 9 lines · Michael Kelley
It turns out that Ubuntu 20.04 installed the 0.7.3-1 version of libxxhash. But from a quick look at the README on the xxhash github site, XXH3 is first supported by the 0.8.0 version, so the compile error probably makes sense. I found a PPA that offers the 0.8.3 version of xxhash for Ubuntu 20.04, and that solved the problem.
So the
Makefilesteps above that figure out if xxhash is present probably aren't sufficient, as the version of xxhash matters. And the "--checksum not supported" error message should be more specific about the required version.
Quoted 6 lines
I reproduced the behavior on two different Ubuntu 20.04 systems, but someone who knows this xxhash stuff better than I do should confirm my conclusions. Maybe the way to fix the check for the presence of xxhash is to augment the inline test program to include a reference to
XXH3_state, but I haven't tried to put together a patch to do that, pending any further discussion or ideas.
Thanks for reporting that. I suppose something like the below would work?
Though, maybe the missing xxhash shouldn't fail the build at all. It's really only needed for people who are actually trying to run klp-build. I may look at improving that.
tools/objtool/Makefile +1 -1
@@ -12,7 +12,7 @@ ifeq ($(SRCARCH),loongarch) endif ifeq ($(ARCH_HAS_KLP),y) - HAVE_XXHASH = $(shell echo "int main() {}" | \ + HAVE_XXHASH = $(shell echo -e "#include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) ifeq ($(HAVE_XXHASH),y) BUILD_KLP := y
tools/objtool/builtin-check.c +1 -1
@@ -164,7 +164,7 @@ static bool opts_valid(void)#ifndef BUILD_KLP if (opts.checksum) { -ERROR ("--checksum not supported; install xxhash-devel/libxxhash-dev and recompile" ); +ERROR ("--checksum not supported; install xxhash-devel/libxxhash-dev (version >= 0.8) and recompile" );return false; }#endif
RE: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
From: Josh Poimboeuf <[email protected]> Sent: Monday, October 27, 2025 3:22 PM
Quoted 1 line
Sorry for the delay in my follow-up. I've been travelling the past 10 days.
Quoted 17 lines · Michael Kelley
Quoted 9 lines
It turns out that Ubuntu 20.04 installed the 0.7.3-1 version of libxxhash. But from a quick look at the README on the xxhash github site, XXH3 is first supported by the 0.8.0 version, so the compile error probably makes sense. I found a PPA that offers the 0.8.3 version of xxhash for Ubuntu 20.04, and that solved the problem.
So the
Makefilesteps above that figure out if xxhash is present probably aren't sufficient, as the version of xxhash matters. And the "--checksum not supported" error message should be more specific about the required version.Quoted 6 lines
I reproduced the behavior on two different Ubuntu 20.04 systems, but someone who knows this xxhash stuff better than I do should confirm my conclusions. Maybe the way to fix the check for the presence of xxhash is to augment the inline test program to include a reference to
XXH3_state, but I haven't tried to put together a patch to do that, pending any further discussion or ideas.
Quoted 5 lines
Thanks for reporting that. I suppose something like the below would work?
Though, maybe the missing xxhash shouldn't fail the build at all. It's really only needed for people who are actually trying to run klp-build. I may look at improving that.
Yes, that would probably be better.
Quoted 6 lines
tools/objtool/Makefile +0
-0
tools/objtool/Makefile ifeq ($(SRCARCH),loongarch) · line 18
Quoted 8 lines
tools/objtool/Makefile +1
-1@@ -12,7 +12,7 @@ ifeq ($(SRCARCH),loongarch) endif ifeq ($(ARCH_HAS_KLP),y) - HAVE_XXHASH = $(shell echo "int main() {}" | \ + HAVE_XXHASH = $(shell echo -e "#include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) ifeq ($(HAVE_XXHASH),y) BUILD_KLP := y
Indeed this is what I had in mind for the enhanced check. But the above gets a syntax error:
Makefile:15: *** unterminated call to function 'shell': missing ')'. Stop. make[4]: *** [Makefile:73: objtool] Error 2
As a debugging experiment, adding only the -e option to the existing code like this shouldn't affect anything,
HAVE_XXHASH = $(shell echo -e "int main() {}" | \but it causes HAVE_XXHASH to always be 'n' even if the xxhash library is present. So the -e option is somehow fouling things up.
Running the equivalent interactively at a 'bash' prompt works as expected. And your proposed patch works correctly in an interactive bash. So something weird is happening in the context of make's shell function, and I haven't been able to figure out what it is.
Do you get the same failures? Or is this some kind of problem with my environment? I've got GNU make version 4.2.1.
Michael
Quoted 13 lines
tools/objtool/builtin-check.c +1
-1@@ -164,7 +164,7 @@ static bool opts_valid(void)#ifndef BUILD_KLP if (opts.checksum) { -ERROR ("--checksum not supported; install xxhash-devel/libxxhash-dev and recompile" ); +ERROR ("--checksum not supported; install xxhash-devel/libxxhash-dev (version >= 0.8) and recompile" );return false; }#endif
Josh Poimboeuf
maintainerRe: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 37 lines · Michael Kelley
Quoted 5 lines
Thanks for reporting that. I suppose something like the below would work?
Though, maybe the missing xxhash shouldn't fail the build at all. It's really only needed for people who are actually trying to run klp-build. I may look at improving that.
Yes, that would probably be better.
Quoted 6 lines
tools/objtool/Makefile +0
-0tools/objtool/Makefile ifeq ($(SRCARCH),loongarch) · line 18
Quoted 8 lines
tools/objtool/Makefile +1
-1@@ -12,7 +12,7 @@ ifeq ($(SRCARCH),loongarch) endif ifeq ($(ARCH_HAS_KLP),y) - HAVE_XXHASH = $(shell echo "int main() {}" | \ + HAVE_XXHASH = $(shell echo -e "#include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) ifeq ($(HAVE_XXHASH),y) BUILD_KLP := yIndeed this is what I had in mind for the enhanced check. But the above gets a syntax error:
Makefile:15: *** unterminated call to function 'shell': missing ')'. Stop. make[4]: *** [Makefile:73: objtool] Error 2
As a debugging experiment, adding only the -e option to the existing code like this shouldn't affect anything,
HAVE_XXHASH = $(shell echo -e "int main() {}" | \but it causes
HAVE_XXHASHto always be 'n' even if the xxhash library is present. So the -e option is somehow fouling things up.
Quoted 7 lines
Running the equivalent interactively at a 'bash' prompt works as expected. And your proposed patch works correctly in an interactive bash. So something weird is happening in the context of make's shell function, and I haven't been able to figure out what it is.
Do you get the same failures? Or is this some kind of problem with my environment? I've got GNU make version 4.2.1.
That's weird, it builds fine for me. I have GNU make 4.4.1.
Signature · 1 line
Josh
RE: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 12:09 PM
Quoted 44 lines · Michael Kelley
Quoted 42 lines
Quoted 5 lines
Thanks for reporting that. I suppose something like the below would work?
Though, maybe the missing xxhash shouldn't fail the build at all. It's really only needed for people who are actually trying to run klp-build. I may look at improving that.
Yes, that would probably be better.
Quoted 6 lines
tools/objtool/Makefile +0
-0tools/objtool/Makefile ifeq ($(SRCARCH),loongarch) · line 18
Quoted 8 lines
tools/objtool/Makefile +1
-1@@ -12,7 +12,7 @@ ifeq ($(SRCARCH),loongarch) endif ifeq ($(ARCH_HAS_KLP),y) - HAVE_XXHASH = $(shell echo "int main() {}" | \ + HAVE_XXHASH = $(shell echo -e "#include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) ifeq ($(HAVE_XXHASH),y) BUILD_KLP := yIndeed this is what I had in mind for the enhanced check. But the above gets a syntax error:
Makefile:15: *** unterminated call to function 'shell': missing ')'. Stop. make[4]: *** [Makefile:73: objtool] Error 2
As a debugging experiment, adding only the -e option to the existing code like this shouldn't affect anything,
HAVE_XXHASH = $(shell echo -e "int main() {}" | \but it causes
HAVE_XXHASHto always be 'n' even if the xxhash library is present. So the -e option is somehow fouling things up.Running the equivalent interactively at a 'bash' prompt works as expected. And your proposed patch works correctly in an interactive bash. So something weird is happening in the context of make's shell function, and I haven't been able to figure out what it is.
Quoted 4 lines
Quoted 2 lines
Do you get the same failures? Or is this some kind of problem with my environment? I've got GNU make version 4.2.1.
That's weird, it builds fine for me. I have GNU make 4.4.1.
I've been able to debug this. Two problems:
1) On Ubuntu (both 20.04 and 24.04), /bin/sh and /usr/bin/sh are symlinks to "dash" (not "bash"). So the "shell" command in "make" invokes dash. The man page for dash shows that the built-in echo command accepts only -n as an option. The -e behavior of processing "\n" and similar sequences is always enabled. So on my Ubuntu systems, the "-e" is ignored by echo and becomes part of the C source code sent to gcc, and of course it barfs. Dropping the -e makes it work for me (and the \n is handled correctly), but that might not work with other shells. Using "/bin/echo" with the -e solves the problem in a more compatible way across different shells.
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
What a mess.
Michael
RE: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
From: Michael Kelley <[email protected]> Sent: Tuesday, November 11, 2025 5:39 PM
Quoted 63 lines
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 12:09 PM
Quoted 44 lines · Michael Kelley
Quoted 42 lines
Quoted 5 lines
Thanks for reporting that. I suppose something like the below would work?
Though, maybe the missing xxhash shouldn't fail the build at all. It's really only needed for people who are actually trying to run klp-build. I may look at improving that.
Yes, that would probably be better.
Quoted 6 lines
tools/objtool/Makefile +0
-0tools/objtool/Makefile ifeq ($(SRCARCH),loongarch) · line 18
Quoted 8 lines
tools/objtool/Makefile +1
-1@@ -12,7 +12,7 @@ ifeq ($(SRCARCH),loongarch) endif ifeq ($(ARCH_HAS_KLP),y) - HAVE_XXHASH = $(shell echo "int main() {}" | \ + HAVE_XXHASH = $(shell echo -e "#include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo > n) ifeq ($(HAVE_XXHASH),y) BUILD_KLP := yIndeed this is what I had in mind for the enhanced check. But the above gets a syntax error:
Makefile:15: *** unterminated call to function 'shell': missing ')'. Stop. make[4]: *** [Makefile:73: objtool] Error 2
As a debugging experiment, adding only the -e option to the existing code like this shouldn't affect anything,
HAVE_XXHASH = $(shell echo -e "int main() {}" | \but it causes
HAVE_XXHASHto always be 'n' even if the xxhash library is present. So the -e option is somehow fouling things up.Running the equivalent interactively at a 'bash' prompt works as expected. And your proposed patch works correctly in an interactive bash. So something weird is happening in the context of make's shell function, and I haven't been able to figure out what it is.
Quoted 4 lines
Quoted 2 lines
Do you get the same failures? Or is this some kind of problem with my environment? I've got GNU make version 4.2.1.
That's weird, it builds fine for me. I have GNU make 4.4.1.
I've been able to debug this. Two problems:
1) On Ubuntu (both 20.04 and 24.04),
/bin/shand/usr/bin/share symlinks to "dash" (not "bash"). So the "shell" command in "make" invokes dash. The man page for dash shows that the built-in echo command accepts only -n as an option. The -e behavior of processing "\n" and similar sequences is always enabled. So on my Ubuntu systems, the "-e" is ignored by echo and becomes part of the C source code sent to gcc, and of course it barfs. Dropping the -e makes it work for me (and the \n is handled correctly), but that might not work with other shells. Using "/bin/echo" with the -e solves the problem in a more compatible way across different shells.
Quoted 12 lines
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
Using "\043" instead of the "#" is a compatible solution that works in make v4.2.1 and v4.3 and presumably all other versions as well.
Michael
Josh Poimboeuf
maintainerRe: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 11 lines · Michael Kelley
Quoted 11 lines
I've been able to debug this. Two problems:
1) On Ubuntu (both 20.04 and 24.04),
/bin/shand/usr/bin/share symlinks to "dash" (not "bash"). So the "shell" command in "make" invokes dash. The man page for dash shows that the built-in echo command accepts only -n as an option. The -e behavior of processing "\n" and similar sequences is always enabled. So on my Ubuntu systems, the "-e" is ignored by echo and becomes part of the C source code sent to gcc, and of course it barfs. Dropping the -e makes it work for me (and the \n is handled correctly), but that might not work with other shells. Using "/bin/echo" with the -e solves the problem in a more compatible way across different shells.
Ah. I think we can use "printf" here.
Quoted 13 lines
Quoted 4 lines
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell
Quoted 8 lines
command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
Quoted 2 lines
Using "\043" instead of the "#" is a compatible solution that works in make v4.2.1 and v4.3 and presumably all other versions as well.
Hm... I've seen similar portability issues with "," for which we had to change it to "$(comma)" which magically worked for some reason that I am forgetting.
Does "$(pound)" work? This seems to work here:
HAVE_XXHASH = $(shell printf "$(pound)include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \Signature · 1 line
Josh
RE: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 8:04 PM
Quoted 32 lines · Michael Kelley
Quoted 11 lines
Quoted 11 lines
I've been able to debug this. Two problems:
1) On Ubuntu (both 20.04 and 24.04),
/bin/shand/usr/bin/share symlinks to "dash" (not "bash"). So the "shell" command in "make" invokes dash. The man page for dash shows that the built-in echo command accepts only -n as an option. The -e behavior of processing "\n" and similar sequences is always enabled. So on my Ubuntu systems, the "-e" is ignored by echo and becomes part of the C source code sent to gcc, and of course it barfs. Dropping the -e makes it work for me (and the \n is handled correctly), but that might not work with other shells. Using "/bin/echo" with the -e solves the problem in a more compatible way across different shells.Ah. I think we can use "printf" here.
Quoted 13 lines
Quoted 4 lines
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell
Quoted 8 lines
command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
Quoted 2 lines
Using "\043" instead of the "#" is a compatible solution that works in make v4.2.1 and v4.3 and presumably all other versions as well.
Quoted 8 lines
Hm... I've seen similar portability issues with "," for which we had to change it to "$(comma)" which magically worked for some reason that I am forgetting.
Does "$(pound)" work? This seems to work here:
HAVE_XXHASH = $(shell printf "$(pound)include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \
Yes, the above line works in my Ubuntu 20.04 and 24.04 environments. It properly detects the presence and absence of xxhash 0.8. Seems like a good solution to me.
Michael
Re: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 16 lines · On Wed, 12 Nov 2025 04:32:02 +0000 Michael Kelley <[email protected]> wrote:
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 8:04 PM
Quoted 15 lines · Michael Kelley
Quoted 11 lines
Quoted 11 lines
I've been able to debug this. Two problems:
1) On Ubuntu (both 20.04 and 24.04),
/bin/shand/usr/bin/share symlinks to "dash" (not "bash"). So the "shell" command in "make" invokes dash. The man page for dash shows that the built-in echo command accepts only -n as an option. The -e behavior of processing "\n" and similar sequences is always enabled. So on my Ubuntu systems, the "-e" is ignored by echo and becomes part of the C source code sent to gcc, and of course it barfs. Dropping the -e makes it work for me (and the \n is handled correctly), but that might not work with other shells. Using "/bin/echo" with the -e solves the problem in a more compatible way across different shells.Ah. I think we can use "printf" here.
Much better than echo - and a bultin on most shells.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Using "\043" instead of the "#" is a compatible solution that works in make v4.2.1 and v4.3 and presumably all other versions as well.
Hm... I've seen similar portability issues with "," for which we had to change it to "$(comma)" which magically worked for some reason that I am forgetting.
Does "$(pound)" work? This seems to work here:
Please not 'pound' - that is the uk currency symbol (not what US greengrocers scrawl for lb).
David
Quoted 9 lines
Quoted 3 lines
HAVE_XXHASH = $(shell printf "$(pound)include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \Yes, the above line works in my Ubuntu 20.04 and 24.04 environments. It properly detects the presence and absence of xxhash 0.8. Seems like a good solution to me.
Michael
Josh Poimboeuf
maintainerRe: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 19 lines · David Laight
Quoted 18 lines · On Wed, 12 Nov 2025 04:32:02 +0000 Michael Kelley <[email protected]> wrote:
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 8:04 PM
Quoted 17 lines · Michael Kelley
Quoted 15 lines
Quoted 4 lines
2) With make v4.2.1 on my Ubuntu 20.04 system, the "#" character in the "#include" added to the echo command is problematic. "make" seems to be treating it as a comment character, though I'm not 100% sure of that interpretation. Regardless, the "#" causes a syntax error in the "make" shell
Quoted 8 lines
command. Adding a backslash before the "#" solves that problem. On an Ubuntu 24.04 system with make v4.3, the "#" does not cause any problems. (I tried to put make 4.3 on my Ubuntu 20.04 system, but ran into library compatibility problems so I wasn’t able to definitively confirm that it is the make version that changes the handling of the "#"). Unfortunately, adding the backslash before the # does *not* work with make v4.3. The backslash becomes part of the C source code sent to gcc, which barfs. I don't immediately have a suggestion on how to resolve this in a way that is compatible across make versions.
Using "\043" instead of the "#" is a compatible solution that works in make v4.2.1 and v4.3 and presumably all other versions as well.
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
Hm... I've seen similar portability issues with "," for which we had to change it to "$(comma)" which magically worked for some reason that I am forgetting.
Does "$(pound)" work? This seems to work here:
Please not 'pound' - that is the uk currency symbol (not what US greengrocers scrawl for lb).
While I do call it the "pound sign", I can't take the credit/blame for that name it as the variable already exists.
It's better than "hashtag" which is what my kids call it :-/
Signature · 1 line
Josh
Re: [PATCH v4 49/63] objtool/klp: Add --checksum option to generate per-function checksums
Quoted 4 lines · On Wed, 12 Nov 2025 08:16:59 -0800 Josh Poimboeuf <[email protected]> wrote:
Quoted 3 lines · David Laight
Quoted 2 lines · On Wed, 12 Nov 2025 04:32:02 +0000 Michael Kelley <[email protected]> wrote:
From: Josh Poimboeuf <[email protected]> Sent: Tuesday, November 11, 2025 8:04 PM
Quoted 1 line · Michael Kelley
..
Quoted 9 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Does "$(pound)" work? This seems to work here:
Please not 'pound' - that is the uk currency symbol (not what US greengrocers scrawl for lb).
While I do call it the "pound sign", I can't take the credit/blame for that name it as the variable already exists.
It's better than "hashtag" which is what my kids call it :-/
'£' is a "pound sign", '#' is a "hash".
David
Josh Poimboeuf
maintainerPATCH v4 50/63 objtool/klp: Add --debug-checksum=<funcs> to show per-instruction checksums
In reply to Josh PoimboeufAdd a --debug-checksum=<funcs> option to the check subcommand to print the calculated checksum of each instruction in the given functions.
This is useful for determining where two versions of a function begin to diverge.
--- tools/objtool/builtin-check.c | 6 ++++ tools/objtool/check.c | 42 ++++++++++++++++++++++++ tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/checksum.h | 1 + tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/warn.h | 19 +++++++++++ 6 files changed, 70 insertions(+)
tools/objtool/builtin-check.c +6 -0
@@ -94,6 +94,7 @@ static const struct option check_options[] = {OPT_GROUP ("Options:" ),OPT_BOOLEAN (0 ,"backtrace" , &opts.backtrace,"unwind on error" ),OPT_BOOLEAN (0 ,"backup" , &opts.backup,"create backup (.orig) file on warning/error" ), +OPT_STRING (0 ,"debug-checksum" , &opts.debug_checksum,"funcs" ,"enable checksum debug output" ),OPT_BOOLEAN (0 ,"dry-run" , &opts.dryrun,"don't write modifications" ),OPT_BOOLEAN (0 ,"link" , &opts.link,"object is a linked object" ), OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
@@ -168,6 +169,11 @@ static bool opts_valid(void) }#endif +if (opts.debug_checksum && !opts.checksum) { +ERROR ("--debug-checksum requires --checksum" ); +return false; + } + if (opts.checksum || opts.hack_jump_label || opts.hack_noinstr ||
tools/objtool/check.c +42 -0
54 lines not on this page · raw message
tools/objtool/include/objtool/builtin.h +1 -0
@@ -32,6 +32,7 @@ struct opts {/* options: */ bool backtrace;bool backup; +const char *debug_checksum;bool dryrun;bool link;bool mnop;
tools/objtool/include/objtool/checksum.h +1 -0
@@ -19,6 +19,7 @@ static inline void checksum_update(struct symbol *func, const void *data, size_t size) { XXH3_64bits_update(func->csum.state, data, size); +dbg_checksum (func, insn,XXH3_64bits_digest (func->csum.state)); }static inline void checksum_finish (struct symbol *func)
tools/objtool/include/objtool/elf.h +1 -0
@@ -82,6 +82,7 @@ struct symbol { u8 nocfi : 1; u8 cold : 1; u8 prefix : 1; + u8 debug_checksum : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
tools/objtool/include/objtool/warn.h +19 -0
@@ -102,4 +102,23 @@ static inline char *offstr(struct section *sec, unsigned long offset)#define ERROR_FUNC (sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__)#define ERROR_INSN (insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) + +#define __dbg (format, ...) \ + fprintf(stderr, \ + "DEBUG: %s%s" format "\n", \ + objname ?: "", \ + objname ? ": " : "", \ + ##__VA_ARGS__) + +#define dbg_checksum (func, insn, checksum) \ +({ \ + if (unlikely(insn->sym && insn->sym->pfunc && \ + insn->sym->pfunc->debug_checksum)) { \ + char *insn_off = offstr(insn->sec, insn->offset); \ + __dbg("checksum: %s %s %016lx", \ + func->name, insn_off, checksum); \ + free(insn_off); \ + } \ +}) +#endif /* _WARN_H */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 51/63 objtool/klp: Introduce klp diff subcommand for diffing object files
In reply to Josh PoimboeufAdd a new klp diff subcommand which performs a binary diff between two object files and extracts changed functions into a new object which can then be linked into a livepatch module.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
Key improvements compared to kpatch-build:
- Integrated with objtool: Leverages objtool's existing control-flow graph analysis to help detect changed functions.
- Works on vmlinux.o: Supports late-linked objects, making it compatible with LTO, IBT, and similar.
- Simplified code base: ~3k fewer lines of code.
- Upstream: No more out-of-tree #ifdef hacks, far less cruft.
- Cleaner internals: Vastly simplified logic for symbol/section/reloc inclusion and special section extraction.
- Robust __LINE__ macro handling: Avoids false positive binary diffs caused by the __LINE__ macro by introducing a fix-patch-lines script (coming in a later patch) which injects #line directives into the source .patch to preserve the original line numbers at compile time.
Note the end result of this subcommand is not yet functionally complete. Livepatch needs some ELF magic which linkers don't like:
- Two relocation sections (.rela*, .klp.rela*) for the same text section.
- Use of SHN_LIVEPATCH to mark livepatch symbols.
Unfortunately linkers tend to mangle such things. To work around that, klp diff generates a linker-compliant intermediate binary which encodes the relevant KLP section/reloc/symbol metadata.
After module linking, a klp post-link step (coming soon) will clean up the mess and convert the linked .ko into a fully compliant livepatch module.
Note this subcommand requires the diffed binaries to have been compiled with -ffunction-sections and -fdata-sections, and processed with 'objtool --checksum'. Those constraints will be handled by a klp-build script introduced in a later patch.
Without '-ffunction-sections -fdata-sections', reliable object diffing would be infeasible due to toolchain limitations:
- For intra-file+intra-section references, the compiler might occasionally generated hard-coded instruction offsets instead of relocations.
- Section-symbol-based references can be ambiguous:
- Overlapping or zero-length symbols create ambiguity as to which symbol is being referenced.
- A reference to the end of a symbol (e.g., checking array bounds) can be misinterpreted as a reference to the next symbol, or vice versa.
A potential future alternative to '-ffunction-sections -fdata-sections' would be to introduce a toolchain option that forces symbol-based (non-section) relocations.
--- MAINTAINERS | 2 +- include/linux/livepatch.h | 25 +- include/linux/livepatch_external.h | 76 + kernel/livepatch/core.c | 4 +- scripts/module.lds.S | 10 +- tools/include/linux/livepatch_external.h | 76 + tools/include/linux/string.h | 14 + tools/objtool/Build | 4 +- tools/objtool/Makefile | 3 +- tools/objtool/arch/x86/decode.c | 40 + tools/objtool/builtin-klp.c | 52 + tools/objtool/check.c | 14 - tools/objtool/elf.c | 21 +- tools/objtool/include/objtool/arch.h | 1 + tools/objtool/include/objtool/builtin.h | 2 + tools/objtool/include/objtool/elf.h | 56 +- tools/objtool/include/objtool/klp.h | 31 + tools/objtool/include/objtool/objtool.h | 2 + tools/objtool/include/objtool/util.h | 19 + tools/objtool/klp-diff.c | 1646 ++++++++++++++++++++++ tools/objtool/objtool.c | 41 +- tools/objtool/sync-check.sh | 1 + tools/objtool/weak.c | 7 + 23 files changed, 2088 insertions(+), 59 deletions(-) create mode 100644 include/linux/livepatch_external.h create mode 100644 tools/include/linux/livepatch_external.h create mode 100644 tools/objtool/builtin-klp.c create mode 100644 tools/objtool/include/objtool/klp.h create mode 100644 tools/objtool/include/objtool/util.h create mode 100644 tools/objtool/klp-diff.c
MAINTAINERS +1 -1
@@ -14221,7 +14221,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.g F: Documentation/ABI/testing/sysfs-kernel-livepatch F: Documentation/livepatch/ F: arch/powerpc/include/asm/livepatch.h -F: include/linux/livepatch.h +F: include/linux/livepatch*.h F: kernel/livepatch/ F: kernel/module/livepatch.c F: samples/livepatch/
include/linux/livepatch.h +1 -24
@@ -13,6 +13,7 @@#include <linux/ftrace.h> #include <linux/completion.h> #include <linux/list.h> +#include <linux/livepatch_external.h> #include <linux/livepatch_sched.h> #if IS_ENABLED (CONFIG_LIVEPATCH )
@@ -77,30 +78,6 @@ struct klp_func {bool transition; }; -struct klp_object ; - -/** -* struct klp_callbacks - pre/post live-(un)patch callback structure -* @pre_patch: executed before code patching -* @post_patch: executed after code patching -* @pre_unpatch: executed before code unpatching -* @post_unpatch: executed after code unpatching -* @post_unpatch_enabled: flag indicating if post-unpatch callback -* should run -* -* All callbacks are optional. Only the pre-patch callback, if provided, -* will be unconditionally executed. If the parent klp_object fails to -* patch for any reason, including a non-zero error status returned from -* the pre-patch callback, no further callbacks will be executed. -*/ -struct klp_callbacks { -int (*pre_patch)(struct klp_object *obj); -void (*post_patch)(struct klp_object *obj); -void (*pre_unpatch)(struct klp_object *obj); -void (*post_unpatch)(struct klp_object *obj); -bool post_unpatch_enabled; -}; -/** * struct klp_object - kernel object structure for live patching * @name: module name (or NULL for vmlinux)
include/linux/livepatch_external.h new file +76 -0
76 lines not on this page · raw message
kernel/livepatch/core.c +2 -2
@@ -224,7 +224,7 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab,/* Format: .klp.sym.sym_objname.sym_name,sympos */ cnt =sscanf (strtab + sym->st_name, -".klp.sym.%55[^.].%511[^,],%lu" , +KLP_SYM_PREFIX "%55[^.].%511[^,],%lu" , sym_objname, sym_name, &sympos);if (cnt !=3 ) { pr_err("symbol %s has an incorrectly formatted name\n",
@@ -303,7 +303,7 @@ static int klp_write_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,* See comment in klp_resolve_symbols() for an explanation * of the selected field width value. */ - cnt =sscanf (shstrtab + sec->sh_name,".klp.rela.%55[^.]" , + cnt =sscanf (shstrtab + sec->sh_name,KLP_RELOC_SEC_PREFIX "%55[^.]" , sec_objname);if (cnt !=1 ) { pr_err("section %s has an incorrectly formatted name\n",
scripts/module.lds.S +9 -1
@@ -34,8 +34,16 @@ SECTIONS { __patchable_function_entries : { *(__patchable_function_entries) } + __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) } + + __klp_objects 0: ALIGN(8) { + __start_klp_objects = .; + KEEP(*(__klp_objects)) + __stop_klp_objects = .; + } + #ifdef CONFIG_ARCH_USES_CFI_TRAPS - __kcfi_traps : { KEEP(*(.kcfi_traps)) } + __kcfi_traps : { KEEP(*(.kcfi_traps)) } #endif .text : {
tools/include/linux/livepatch_external.h new file +76 -0
76 lines not on this page · raw message
tools/include/linux/string.h +14 -0
@@ -44,6 +44,20 @@ static inline bool strstarts(const char *str, const char *prefix)return strncmp (str, prefix,strlen (prefix)) ==0 ; } +/* +* Checks if a string ends with another. +*/ +static inline bool str_ends_with (const char *str,const char *substr) +{ +size_t len =strlen (str); +size_t sublen =strlen (substr); + +if (sublen > len) +return false; + +return !strcmp (str + len - sublen, substr); +} +extern char *__must_check skip_spaces (const char *);extern char *strim (char *);
tools/objtool/Build +2 -2
@@ -8,8 +8,8 @@ objtool-y += builtin-check.o objtool-y += elf.o objtool-y += objtool.o -objtool-$(BUILD_ORC) += orc_gen.o -objtool-$(BUILD_ORC) += orc_dump.o +objtool-$(BUILD_ORC) += orc_gen.o orc_dump.o +objtool-$(BUILD_KLP) += builtin-klp.o klp-diff.o objtool-y += libstring.o objtool-y += libctype.o
tools/objtool/Makefile +2 -1
@@ -15,13 +15,14 @@ ifeq ($(ARCH_HAS_KLP),y) HAVE_XXHASH = $(shell echo "int main() {}" | \ $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) ifeq ($(HAVE_XXHASH),y) + BUILD_KLP := y LIBXXHASH_CFLAGS := $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/null) \ -DBUILD_KLP LIBXXHASH_LIBS := $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/null || echo -lxxhash) endif endif -export BUILD_ORC +export BUILD_ORC BUILD_KLP ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(CURDIR)))
tools/objtool/arch/x86/decode.c +40 -0
@@ -88,6 +88,46 @@ s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc)return phys_to_virt (addend); } +static void scan_for_insn (struct section *sec,unsigned long offset, +unsigned long *insn_off,unsigned int *insn_len) +{ +unsigned long o =0 ; +struct insn insn; + +while (1 ) { + +insn_decode (&insn, sec->data->d_buf + o,sec_size (sec) - o, +INSN_MODE_64 ); + +if (o + insn.length > offset) { + *insn_off = o; + *insn_len = insn.length; +return ; + } + + o += insn.length; + } +} + +u64 arch_adjusted_addend (struct reloc *reloc) +{ +unsigned int type =reloc_type (reloc); +s64 addend =reloc_addend (reloc); +unsigned long insn_off; +unsigned int insn_len; + +if (type ==R_X86_64_PLT32 ) +return addend +4 ; + +if (type !=R_X86_64_PC32 || !is_text_sec (reloc->sec->base)) +return addend; + +scan_for_insn (reloc->sec->base,reloc_offset (reloc), + &insn_off, &insn_len); + +return addend + insn_off + insn_len -reloc_offset (reloc); +} +unsigned long arch_jump_destination (struct instruction *insn) {return insn->offset + insn->len + insn->immediate;
tools/objtool/builtin-klp.c new file +52 -0
52 lines not on this page · raw message
tools/objtool/check.c +0 -14
@@ -185,20 +185,6 @@ static bool is_sibling_call(struct instruction *insn)return (is_static_jump (insn) &&insn_call_dest (insn)); } -/* -* Checks if a string ends with another. -*/ -static bool str_ends_with (const char *s,const char *sub) -{ -const int slen =strlen (s); -const int sublen =strlen (sub); - -if (sublen > slen) -return 0 ; - -return !memcmp (s + slen - sublen, sub, sublen); -} -/* * Checks if a function is a Rust "noreturn" one. */
tools/objtool/elf.c +20 -1
@@ -288,6 +288,18 @@ struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)return NULL ; } +struct symbol *find_global_symbol_by_name (const struct elf *elf,const char *name) +{ +struct symbol *sym; + +elf_hash_for_each_possible (symbol_name, sym, name_hash,str_hash (name)) { +if (!strcmp (sym->name, name) && !is_local_sym (sym)) +return sym; + } + +return NULL ; +} +struct reloc *find_reloc_by_dest_range (const struct elf *elf,struct section *sec,unsigned long offset,unsigned int len) {
@@ -475,6 +487,8 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)else entry = &sym->sec->symbol_list;list_add (&sym->list, entry); + +list_add_tail (&sym->global_list, &elf->symbols);elf_hash_add (symbol, &sym->hash, sym->idx);elf_hash_add (symbol_name, &sym->name_hash,str_hash (sym->name));
@@ -531,6 +545,9 @@ static int read_symbols(struct elf *elf)ERROR_GLIBC ("calloc" );return -1 ; } + +INIT_LIST_HEAD (&elf->symbols); +for (i =0 ; i < symbols_nr; i++) { sym = &elf->symbol_data[i];
@@ -639,7 +656,7 @@ static int mark_group_syms(struct elf *elf)return -1 ; } -list_for_each_entry (sec, &elf->sections, list) { +for_each_sec (elf, sec) {if (sec->sh.sh_type ==SHT_GROUP && sec->sh.sh_link == symtab->idx) { sym =find_symbol_by_index (elf, sec->sh.sh_info);
@@ -1224,6 +1241,8 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name)return NULL ; } +INIT_LIST_HEAD (&elf->symbols); + if (!elf_alloc_hash(section, 1000) || !elf_alloc_hash(section_name, 1000) || !elf_alloc_hash(symbol, 10000) ||
tools/objtool/include/objtool/arch.h +1 -0
@@ -84,6 +84,7 @@ bool arch_callee_saved_reg(unsigned char reg);unsigned long arch_jump_destination (struct instruction *insn);s64 arch_insn_adjusted_addend (struct instruction *insn,struct reloc *reloc); +u64 arch_adjusted_addend (struct reloc *reloc);const char *arch_nop_insn (int len);const char *arch_ret_insn (int len);
tools/objtool/include/objtool/builtin.h +2 -0
@@ -53,4 +53,6 @@ int objtool_run(int argc, const char **argv);int make_backup (void ); +int cmd_klp (int argc,const char **argv); +#endif /* _BUILTIN_H */
tools/objtool/include/objtool/elf.h +45 -11
105 lines not on this page · raw message
tools/objtool/include/objtool/klp.h new file +31 -0
@@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_KLP_H +#define _OBJTOOL_KLP_H + +/* +* __klp_objects and __klp_funcs are created by klp diff and used by the patch +* module init code to build the klp_patch, klp_object and klp_func structs +* needed by the livepatch API. +*/ +#define KLP_OBJECTS_SEC "__klp_objects" +#define KLP_FUNCS_SEC "__klp_funcs" + +/* +* __klp_relocs is an intermediate section which are created by klp diff and +* converted into KLP symbols/relas by "objtool klp post-link". This is needed +* to work around the linker, which doesn't preserve SHN_LIVEPATCH or +* SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a +* single PROGBITS section. +*/ +#define KLP_RELOCS_SEC "__klp_relocs" +#define KLP_STRINGS_SEC ".rodata.klp.str1.1" + +struct klp_reloc { +void *offset; +void *sym; +u32 type; +}; + +int cmd_klp_diff (int argc,const char **argv); + +#endif /* _OBJTOOL_KLP_H */
tools/objtool/include/objtool/objtool.h +2 -0
@@ -39,6 +39,8 @@ struct objtool_file {struct pv_state *pv_ops; }; +char *top_level_dir (const char *file); +struct objtool_file *objtool_open_read (const char *_objname);int objtool_pv_add (struct objtool_file *file,int idx,struct symbol *func);
tools/objtool/include/objtool/util.h new file +19 -0
@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _UTIL_H +#define _UTIL_H + +#include <objtool/warn.h> + +#define snprintf_check(str, size, format, args...) \ +({ \ + int __ret = snprintf(str, size, format, args); \ + if (__ret < 0) \ + ERROR_GLIBC("snprintf"); \ + else if (__ret >= size) \ + ERROR("snprintf() failed for '" format "'", args); \ + else \ + __ret = 0; \ + __ret; \ +}) + +#endif /* _UTIL_H */
tools/objtool/klp-diff.c new file +1646 -0
1,646 lines not on this page · raw message
tools/objtool/objtool.c +39 -2
58 lines not on this page · raw message
tools/objtool/sync-check.sh +1 -0
@@ -17,6 +17,7 @@ arch/x86/include/asm/emulate_prefix.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk include/linux/interval_tree_generic.h +include/linux/livepatch_external.h include/linux/static_call_types.h "
tools/objtool/weak.c +7 -0
@@ -8,6 +8,8 @@#include <stdbool.h> #include <errno.h> #include <objtool/objtool.h> +#include <objtool/arch.h> +#include <objtool/builtin.h> #define UNSUPPORTED (name) \ ({ \
@@ -24,3 +26,8 @@ int __weak orc_create(struct objtool_file *file) {UNSUPPORTED ("ORC" ); } + +int __weak cmd_klp (int argc,const char **argv) +{ +UNSUPPORTED ("klp" ); +}
Signature · 1 line
2.50.0
Petr Mladek
maintainerRe: [PATCH v4 51/63] objtool/klp: Introduce klp diff subcommand for diffing object files
Quoted 25 lines · Josh Poimboeuf
Add a new klp diff subcommand which performs a binary diff between two object files and extracts changed functions into a new object which can then be linked into a livepatch module.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
tools/objtool/klp-diff.c new file +13
-0+static int read_exports (void ) +{ +const char *symvers ="Module.symvers" ; +char line[1024 ], *path =NULL ; +unsigned int line_num =1 ; +FILE *file; + + file =fopen (symvers,"r" ); +if (!file) { + path =top_level_dir (symvers); +if (!path) { +ERROR ("can't open '%s', \"objtool diff\" should be run from the kernel tree" , symvers); +return -1 ;
tools/objtool/klp-diff.c line 73
Quoted 10 lines
tools/objtool/klp-diff.c new file +10
-0+ } + + file =fopen (path,"r" ); +if (!file) { +ERROR_GLIBC ("fopen" ); +return -1 ; + } + } + +while (fgets (line,1024 , file)) {
Nit: It might be more safe to replace 1024 with sizeof(line).
It might be fixed later in a separate patch.
Quoted 9 lines
tools/objtool/klp-diff.c new file +9
-0+char *sym, *mod, *type; +struct export *export; + + sym =strchr (line,'\t' ); +if (!sym) { +ERROR ("malformed Module.symvers (sym) at line %d" , line_num); +return -1 ; + } +
[...]
Quoted 6 lines
+/*
+ * Klp relocations aren't allowed for__jump_tableand .static_call_sites if
+ * the referenced symbol lives in a kernel module, because such klp relocs may
+ * be applied after static branch/call init, resulting in code corruption.
+ *
+ * Validate a special section entry to avoid that. Note that an inert
Quoted 8 lines
+ * tracepoint is harmless enough, in that case just skip the entry and print a
+ * warning. Otherwise, return an error.
+ *
+ * This is only a temporary limitation which will be fixed when livepatch adds
+ * support for submodules: fully self-contained modules which are embedded in
+ * the top-level livepatch module's data and which can be loaded on demand when
+ * their corresponding to-be-patched module gets loaded. Then klp relocs can
+ * be retired.
I wonder how temporary this is ;-) The comment looks optimistic. I am just curious. Do you have any plans to implement the support for the submodules... ?
Quoted 7 lines
+ * Return:
+ * -1: error: validation failed
+ * 1: warning: tracepoint skipped
+ * 0: success
+ */tools/objtool/klp-diff.c new file +2
-0+static int validate_special_section_klp_reloc (struct elfs *e,struct symbol *sym) +{
tools/objtool/klp-diff.c line 1256
Quoted 10 lines
tools/objtool/klp-diff.c new file +10
-0+bool static_branch = !strcmp (sym->sec->name,"__jump_table" ); +bool static_call = !strcmp (sym->sec->name,".static_call_sites" ); +struct symbol *code_sym =NULL ; +unsigned long code_offset =0 ; +struct reloc *reloc; +int ret =0 ; + +if (!static_branch && !static_call) +return 0 ; +
Best Regards,
Petr
PS: To make some expectations. I am not doing a deep review.
I am just looking at the patchset to see how far and mature it is. And I just comment what catches my eye.
My first impression is that it is already in a pretty good state. And I do not see any big problem there. Well, some documentation would be fine ;-)
What are your plans, please?
Josh Poimboeuf
maintainerRe: [PATCH v4 51/63] objtool/klp: Introduce klp diff subcommand for diffing object files
Quoted 19 lines · Petr Mladek
Quoted 18 lines · Josh Poimboeuf
tools/objtool/klp-diff.c new file +18
-0+static int read_exports (void ) +{ +const char *symvers ="Module.symvers" ; +char line[1024 ], *path =NULL ; +unsigned int line_num =1 ; +FILE *file; + + file =fopen (symvers,"r" ); +if (!file) { + path =top_level_dir (symvers); +if (!path) { +ERROR ("can't open '%s', \"objtool diff\" should be run from the kernel tree" , symvers); +return -1 ; + } + + file =fopen (path,"r" ); +if (!file) { +ERROR_GLIBC ("fopen" );
Quoted 8 lines
tools/objtool/klp-diff.c line 73
Quoted 5 lines
tools/objtool/klp-diff.c new file +5
-0+return -1 ; + } + } + +while (fgets (line,1024 , file)) {Nit: It might be more safe to replace 1024 with sizeof(line).
It might be fixed later in a separate patch.
Indeed.
Quoted 15 lines
Quoted 6 lines
+/*
+ * Klp relocations aren't allowed for__jump_tableand .static_call_sites if
+ * the referenced symbol lives in a kernel module, because such klp relocs may
+ * be applied after static branch/call init, resulting in code corruption.
+ *
+ * Validate a special section entry to avoid that. Note that an inertQuoted 8 lines
+ * tracepoint is harmless enough, in that case just skip the entry and print a
+ * warning. Otherwise, return an error.
+ *
+ * This is only a temporary limitation which will be fixed when livepatch adds
+ * support for submodules: fully self-contained modules which are embedded in
+ * the top-level livepatch module's data and which can be loaded on demand when
+ * their corresponding to-be-patched module gets loaded. Then klp relocs can
+ * be retired.
Quoted 3 lines
I wonder how temporary this is ;-) The comment looks optimistic. I am just curious. Do you have any plans to implement the support for the submodules... ?
I actually already have a working POC for that, but didn't want to make the patch set even longer ;-)
It was surprisingly easy and straightforward to implement.
Quoted 9 lines
PS: To make some expectations. I am not doing a deep review.
I am just looking at the patchset to see how far and mature it is. And I just comment what catches my eye.My first impression is that it is already in a pretty good state. And I do not see any big problem there. Well, some documentation would be fine ;-)
What are your plans, please?
From my perspective, it's testing well and in a good enough state for merging soon (after the merge window?), if there aren't any objections to that.
There will be more patches to come, like the submodules and other arch support. And of course there will be bugs discovered by broader testing. But I think this is a good foundation to begin with.
And the sooner we can get people using this, the sooner we can start deprecating kpatch-build, which would be really nice.
Signature · 1 line
Josh
Petr Mladek
maintainerRe: [PATCH v4 51/63] objtool/klp: Introduce klp diff subcommand for diffing object files
Quoted 46 lines · Josh Poimboeuf
Quoted 19 lines · Petr Mladek
Quoted 18 lines · Josh Poimboeuf
tools/objtool/klp-diff.c new file +18
-0+static int read_exports (void ) +{ +const char *symvers ="Module.symvers" ; +char line[1024 ], *path =NULL ; +unsigned int line_num =1 ; +FILE *file; + + file =fopen (symvers,"r" ); +if (!file) { + path =top_level_dir (symvers); +if (!path) { +ERROR ("can't open '%s', \"objtool diff\" should be run from the kernel tree" , symvers); +return -1 ; + } + + file =fopen (path,"r" ); +if (!file) { +ERROR_GLIBC ("fopen" );Quoted 8 lines
tools/objtool/klp-diff.c line 73
Quoted 5 lines
tools/objtool/klp-diff.c new file +5
-0+return -1 ; + } + } + +while (fgets (line,1024 , file)) {Nit: It might be more safe to replace 1024 with sizeof(line).
It might be fixed later in a separate patch.Indeed.
Quoted 15 lines
Quoted 14 lines
+/*
+ * Klp relocations aren't allowed for__jump_tableand .static_call_sites if
+ * the referenced symbol lives in a kernel module, because such klp relocs may
+ * be applied after static branch/call init, resulting in code corruption.
+ *
+ * Validate a special section entry to avoid that. Note that an inert
+ * tracepoint is harmless enough, in that case just skip the entry and print a
+ * warning. Otherwise, return an error.
+ *
+ * This is only a temporary limitation which will be fixed when livepatch adds
+ * support for submodules: fully self-contained modules which are embedded in
+ * the top-level livepatch module's data and which can be loaded on demand when
+ * their corresponding to-be-patched module gets loaded. Then klp relocs can
+ * be retired.
Quoted 6 lines
Quoted 3 lines
I wonder how temporary this is ;-) The comment looks optimistic. I am just curious. Do you have any plans to implement the support for the submodules... ?
I actually already have a working POC for that, but didn't want to make the patch set even longer ;-)
Sure.
Quoted 1 line
It was surprisingly easy and straightforward to implement.
I am curious ;-)
Quoted 14 lines
Quoted 11 lines
PS: To make some expectations. I am not doing a deep review.
I am just looking at the patchset to see how far and mature it is. And I just comment what catches my eye.My first impression is that it is already in a pretty good state. And I do not see any big problem there. Well, some documentation would be fine ;-)
What are your plans, please?
From my perspective, it's testing well and in a good enough state for
merging soon (after the merge window?), if there aren't any objections to that.
Quoted 6 lines
There will be more patches to come, like the submodules and other arch support. And of course there will be bugs discovered by broader testing. But I think this is a good foundation to begin with.
And the sooner we can get people using this, the sooner we can start deprecating kpatch-build, which would be really nice.
Sounds reasonable and I am fine with it. I have one more question before I give my ack ;-)
I wonder about the patchset which better integrate callbacks with shadow variables and state API, see
https://lore.kernel.org/r/[email protected]
I think that it should not be that big problem to update it on top of this patchset. It would require:
+ moving declarations from livepatch.h to livepatch_external.h
+ updating the macros in livepatch_helpers.h
+ update callback-related code in create_klp_sections()
Or do you expect bigger problems, please?
Best Regards,
Petr
Josh Poimboeuf
maintainerRe: [PATCH v4 51/63] objtool/klp: Introduce klp diff subcommand for diffing object files
Quoted 7 lines · Petr Mladek
Sounds reasonable and I am fine with it. I have one more question before I give my ack ;-)
I wonder about the patchset which better integrate callbacks with shadow variables and state API, see
https://lore.kernel.org/r/[email protected]
Quoted 8 lines
I think that it should not be that big problem to update it on top of this patchset. It would require:
+ moving declarations from
livepatch.htolivepatch_external.h
+ updating the macros inlivepatch_helpers.h
+ update callback-related code increate_klp_sections()Or do you expect bigger problems, please?
Yeah, that should be pretty straightforward. I can help with that.
Right now there's not even a way to create a klp_state. (not sure if anybody's actually using that feature today?)
For your patch set we can add a macro to livepatch_helpers.h for adding a state (and its callbacks). And then corresponding code in create_klp_sections() as you mentioned, and a small change to scripts/livepatch/init.c to set the klp_patch.states pointer.
Signature · 1 line
Josh
Josh Poimboeuf
maintainerPATCH v4 52/63 objtool/klp: Add --debug option to show cloning decisions
In reply to Josh PoimboeufAdd a --debug option to klp diff which prints cloning decisions and an indented dependency tree for all cloned symbols and relocations. This helps visualize which symbols and relocations were included and why.
--- tools/objtool/include/objtool/warn.h | 21 ++++++++ tools/objtool/klp-diff.c | 75 ++++++++++++++++++++++++++++ tools/objtool/objtool.c | 3 ++ 3 files changed, 99 insertions(+)
tools/objtool/include/objtool/warn.h +21 -0
@@ -102,6 +102,10 @@ static inline char *offstr(struct section *sec, unsigned long offset)#define ERROR_FUNC (sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__)#define ERROR_INSN (insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) +extern bool debug; +extern int indent; + +static inline void unindent (int *unused) { indent--; }#define __dbg (format, ...) \ fprintf(stderr, \
@@ -110,6 +114,23 @@ static inline char *offstr(struct section *sec, unsigned long offset) objname ? ": " : "", \ ##__VA_ARGS__) +#define dbg(args...) \ +({ \ + if (unlikely(debug)) \ + __dbg(args); \ +}) + +#define __dbg_indent (format, ...) \ +({ \ + if (unlikely(debug)) \ + __dbg("%*s" format, indent * 8, "", ##__VA_ARGS__); \ +}) + +#define dbg_indent(args...) \ + int __attribute__((cleanup(unindent))) __dummy_##__COUNTER__; \ + __dbg_indent(args); \ + indent++ +#define dbg_checksum (func, insn, checksum) \ ({ \ if (unlikely(insn->sym && insn->sym->pfunc && \
tools/objtool/klp-diff.c +75 -0
123 lines not on this page · raw message
tools/objtool/objtool.c +3 -0
@@ -16,6 +16,9 @@#include <objtool/objtool.h> #include <objtool/warn.h> +bool debug; +int indent; +static struct objtool_file file;struct objtool_file *objtool_open_read (const char *filename)
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 53/63 objtool/klp: Add post-link subcommand to finalize livepatch modules
In reply to Josh PoimboeufLivepatch needs some ELF magic which linkers don't like:
- Two relocation sections (.rela*, .klp.rela*) for the same text section.
- Use of SHN_LIVEPATCH to mark livepatch symbols.
Unfortunately linkers tend to mangle such things. To work around that, klp diff generates a linker-compliant intermediate binary which encodes the relevant KLP section/reloc/symbol metadata.
After module linking, the .ko then needs to be converted to an actual livepatch module. Introduce a new klp post-link subcommand to do so.
--- tools/objtool/Build | 2 +- tools/objtool/builtin-klp.c | 1 + tools/objtool/include/objtool/klp.h | 4 + tools/objtool/klp-post-link.c | 168 ++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 tools/objtool/klp-post-link.c
tools/objtool/Build +1 -1
@@ -9,7 +9,7 @@ objtool-y += elf.o objtool-y += objtool.o objtool-$(BUILD_ORC) += orc_gen.o orc_dump.o -objtool-$(BUILD_KLP) += builtin-klp.o klp-diff.o +objtool-$(BUILD_KLP) += builtin-klp.o klp-diff.o klp-post-link.o objtool-y += libstring.o objtool-y += libctype.o
tools/objtool/builtin-klp.c +1 -0
@@ -14,6 +14,7 @@ struct subcmd {static struct subcmd subcmds[] = { {"diff" ,"Generate binary diff of two object files" , cmd_klp_diff, }, + {"post-link" ,"Finalize klp symbols/relocs after module linking" , cmd_klp_post_link, }, };static void cmd_klp_usage (void )
tools/objtool/include/objtool/klp.h +4 -0
@@ -2,6 +2,9 @@#ifndef _OBJTOOL_KLP_H#define _OBJTOOL_KLP_H +#define SHF_RELA_LIVEPATCH 0x00100000 +#define SHN_LIVEPATCH 0xff20 +/* * __klp_objects and __klp_funcs are created by klp diff and used by the patch * module init code to build the klp_patch, klp_object and klp_func structs
@@ -27,5 +30,6 @@ struct klp_reloc { };int cmd_klp_diff (int argc,const char **argv); +int cmd_klp_post_link (int argc,const char **argv);#endif /* _OBJTOOL_KLP_H */
tools/objtool/klp-post-link.c new file +168 -0
168 lines not on this page · raw message
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 54/63 objtool: Refactor prefix symbol creation code
In reply to Josh PoimboeufThe prefix symbol creation code currently ignores all errors, presumably because some functions don't have the leading NOPs.
Shuffle the code around a bit, improve the error handling and document why some errors are ignored.
--- tools/objtool/check.c | 59 ++++++++++++++++++++++------- tools/objtool/elf.c | 17 --------- tools/objtool/include/objtool/elf.h | 2 - 3 files changed, 46 insertions(+), 32 deletions(-)
tools/objtool/check.c +46 -13
@@ -15,6 +15,7 @@#include <objtool/special.h> #include <objtool/warn.h> #include <objtool/checksum.h> +#include <objtool/util.h> #include <linux/objtool_types.h> #include <linux/hashtable.h>
@@ -4243,37 +4244,71 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructioreturn false; } -static int add_prefix_symbol (struct objtool_file *file,struct symbol *func) +/* +* For FineIBT or kCFI, a certain number of bytes preceding the function may be +* NOPs. Those NOPs may be rewritten at runtime and executed, so give them a +* proper function name: __pfx_<func>. +* +* The NOPs may not exist for the following cases: +* +* - compiler cloned functions (*.cold, *.part0, etc) +* - asm functions created with inline asm or without SYM_FUNC_START() +* +* So return 0 if the NOPs are missing or the function already has a prefix +* symbol. +*/ +static int create_prefix_symbol (struct objtool_file *file,struct symbol *func) {struct instruction *insn, *prev; +char name[SYM_NAME_LEN ];struct cfi_state *cfi; - insn =find_insn (file, func->sec, func->offset); -if (!insn) +if (!is_func_sym (func) ||is_prefix_func (func) || + func->cold || func->static_call_tramp) +return 0 ; + +if ((strlen (func->name) +sizeof ("__pfx_" ) >SYM_NAME_LEN )) { +WARN ("%s: symbol name too long, can't create __pfx_ symbol" , + func->name); +return 0 ; + } + +if (snprintf_check (name,SYM_NAME_LEN ,"__pfx_%s" , func->name))return -1 ; + insn =find_insn (file, func->sec, func->offset); +if (!insn) { +WARN ("%s: can't find starting instruction" , func->name); +return -1 ; + } +for (prev =prev_insn_same_sec (file, insn); prev; prev =prev_insn_same_sec (file, prev)) {u64 offset;if (prev->type !=INSN_NOP ) -return -1 ; +return 0 ; offset = func->offset - prev->offset;if (offset > opts.prefix) -return -1 ; +return 0 ;if (offset < opts.prefix)continue ; -elf_create_prefix_symbol (file->elf, func, opts.prefix); +if (!elf_create_symbol (file->elf, name, func->sec, +GELF_ST_BIND (func->sym.st_info), +GELF_ST_TYPE (func->sym.st_info), + prev->offset, opts.prefix)) +return -1 ; +break ; }if (!prev) -return -1 ; +return 0 ;if (!insn->cfi) {/*
@@ -4291,7 +4326,7 @@ static int add_prefix_symbol(struct objtool_file *file, struct symbol *func)return 0 ; } -static int add_prefix_symbols (struct objtool_file *file) +static int create_prefix_symbols (struct objtool_file *file) {struct section *sec;struct symbol *func;
@@ -4301,10 +4336,8 @@ static int add_prefix_symbols(struct objtool_file *file)continue ;sec_for_each_sym (sec, func) { -if (!is_func_sym (func)) -continue ; - -add_prefix_symbol (file, func); +if (create_prefix_symbol (file, func)) +return -1 ; } }
@@ -4931,7 +4964,7 @@ int check(struct objtool_file *file) }if (opts.prefix) { - ret =add_prefix_symbols (file); + ret =create_prefix_symbols (file);if (ret) goto out; }
tools/objtool/elf.c +0 -17
@@ -942,23 +942,6 @@ struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)return sym; } -struct symbol * -elf_create_prefix_symbol (struct elf *elf,struct symbol *orig,size_t size) -{ -size_t namelen =strlen (orig->name) +sizeof ("__pfx_" ); -char name[SYM_NAME_LEN ]; -unsigned long offset; - -snprintf (name, namelen,"__pfx_%s" , orig->name); - - offset = orig->sym.st_value - size; - -return elf_create_symbol (elf, name, orig->sec, -GELF_ST_BIND (orig->sym.st_info), -GELF_ST_TYPE (orig->sym.st_info), - offset, size); -} -struct reloc *elf_init_reloc (struct elf *elf,struct section *rsec,unsigned int reloc_idx,unsigned long offset,struct symbol *sym,s64 addend,unsigned int type)
tools/objtool/include/objtool/elf.h +0 -2
@@ -148,8 +148,6 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name, unsigned int type, unsigned long offset, size_t size);struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec); -struct symbol *elf_create_prefix_symbol (struct elf *elf,struct symbol *orig, -size_t size);void *elf_add_data (struct elf *elf,struct section *sec,const void *data,size_t size);
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 55/63 objtool: Add base objtool support for livepatch modules
In reply to Josh PoimboeufIn preparation for klp-build, enable "classic" objtool to work on livepatch modules:
- Avoid duplicate symbol/section warnings for prefix symbols and the .static_call_sites and __mcount_loc sections which may have already been extracted by klp diff.
- Add __klp_funcs to the IBT function pointer section whitelist.
- Prevent KLP symbols from getting incorrectly classified as cold subfunctions.
--- tools/objtool/check.c | 52 ++++++++++++++++++++++--- tools/objtool/elf.c | 5 ++- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/objtool.h | 2 +- 4 files changed, 53 insertions(+), 7 deletions(-)
tools/objtool/check.c +47 -5
@@ -3,6 +3,7 @@* Copyright (C) 2015-2017 Josh Poimboeuf <[email protected]> */ +#define _GNU_SOURCE/* memmem() */ #include <string.h> #include <stdlib.h> #include <inttypes.h>
@@ -611,6 +612,20 @@ static int init_pv_ops(struct objtool_file *file)return 0 ; } +static bool is_livepatch_module (struct objtool_file *file) +{ +struct section *sec; + +if (!opts.module) +return false; + + sec =find_section_by_name (file->elf,".modinfo" ); +if (!sec) +return false; + +return memmem (sec->data->d_buf,sec_size (sec),"\0livepatch=Y" ,12 ); +} +static int create_static_call_sections (struct objtool_file *file) {struct static_call_site *site;
@@ -622,7 +637,14 @@ static int create_static_call_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,".static_call_sites" );if (sec) { -WARN ("file already has .static_call_sites section, skipping" ); +/* +* Livepatch modules may have already extracted the static call +* site entries to take advantage of vmlinux static call +* privileges. +*/ +if (!file->klp) +WARN ("file already has .static_call_sites section, skipping" ); +return 0 ; }
@@ -666,7 +688,7 @@ static int create_static_call_sections(struct objtool_file *file) key_sym =find_symbol_by_name (file->elf, tmp);if (!key_sym) { -if (!opts.module) { +if (!opts.module || file->klp) {ERROR ("static_call: can't find static_call_key symbol: %s" , tmp);return -1 ; }
@@ -885,7 +907,13 @@ static int create_mcount_loc_sections(struct objtool_file *file) sec =find_section_by_name (file->elf,"__mcount_loc" );if (sec) { -WARN ("file already has __mcount_loc section, skipping" ); +/* +* Livepatch modules have already extracted their __mcount_loc +* entries to cover the !CONFIG_FTRACE_MCOUNT_USE_OBJTOOL case. +*/ +if (!file->klp) +WARN ("file already has __mcount_loc section, skipping" ); +return 0 ; }
@@ -2579,6 +2607,8 @@ static bool validate_branch_enabled(void)static int decode_sections (struct objtool_file *file) { + file->klp =is_livepatch_module (file); +mark_rodata (file);if (init_pv_ops (file))
@@ -4254,6 +4284,9 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio* - compiler cloned functions (*.cold, *.part0, etc) * - asm functions created with inline asm or without SYM_FUNC_START() * +* Also, the function may already have a prefix from a previous objtool run +* (livepatch extracted functions, or manually running objtool multiple times). +* * So return 0 if the NOPs are missing or the function already has a prefix * symbol. */
@@ -4276,6 +4309,14 @@ static int create_prefix_symbol(struct objtool_file *file, struct symbol *func)if (snprintf_check (name,SYM_NAME_LEN ,"__pfx_%s" , func->name))return -1 ; +if (file->klp) { +struct symbol *pfx; + + pfx =find_symbol_by_offset (func->sec, func->offset - opts.prefix); +if (pfx &&is_prefix_func (pfx) && !strcmp (pfx->name, name)) +return 0 ; + } + insn =find_insn (file, func->sec, func->offset);if (!insn) {WARN ("%s: can't find starting instruction" , func->name);
@@ -4628,6 +4669,7 @@ static int validate_ibt(struct objtool_file *file) !strncmp (sec->name,".debug" ,6 ) || !strcmp (sec->name,".altinstructions" ) || !strcmp (sec->name,".ibt_endbr_seal" ) || + !strcmp (sec->name,".kcfi_traps" ) || !strcmp (sec->name,".orc_unwind_ip" ) || !strcmp (sec->name,".retpoline_sites" ) || !strcmp(sec->name, ".smp_locks") ||
@@ -4637,12 +4679,12 @@ static int validate_ibt(struct objtool_file *file) !strcmp (sec->name,"__bug_table" ) || !strcmp (sec->name,"__ex_table" ) || !strcmp (sec->name,"__jump_table" ) || + !strcmp (sec->name,"__klp_funcs" ) || !strcmp (sec->name,"__mcount_loc" ) || - !strcmp (sec->name,".kcfi_traps" ) || !strcmp (sec->name,".llvm.call-graph-profile" ) || !strcmp (sec->name,".llvm_bb_addr_map" ) || !strcmp (sec->name,"__tracepoints" ) || - strstr(sec->name, "__patchable_function_entries")) + !strcmp(sec->name, "__patchable_function_entries")) continue;for_each_reloc (sec->rsec, reloc)
tools/objtool/elf.c +4 -1
@@ -499,7 +499,10 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym) strstarts(sym->name, "__pi___cfi_"))) sym->prefix =1 ; -if (is_func_sym (sym) &&strstr (sym->name,".cold" )) +if (strstarts (sym->name,".klp.sym" )) + sym->klp =1 ; + +if (!sym->klp &&is_func_sym (sym) &&strstr (sym->name,".cold" )) sym->cold =1 ; sym->pfunc = sym->cfunc = sym;
tools/objtool/include/objtool/elf.h +1 -0
@@ -88,6 +88,7 @@ struct symbol { u8 debug_checksum : 1; u8 changed : 1; u8 included : 1; + u8 klp : 1;struct list_head pv_target;struct reloc *relocs;struct section *group_sec;
tools/objtool/include/objtool/objtool.h +1 -1
@@ -28,7 +28,7 @@ struct objtool_file {struct list_head mcount_loc_list;struct list_head endbr_list;struct list_head call_list; -bool ignore_unreachables, hints, rodata; +bool ignore_unreachables, hints, rodata, klp;unsigned int nr_endbr;unsigned int nr_endbr_int;
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 56/63 livepatch: Add CONFIG_KLP_BUILD
In reply to Josh PoimboeufIn preparation for introducing klp-build, add a new CONFIG_KLP_BUILD option. The initial version will only be supported on x86-64.
--- arch/x86/Kconfig | 1 + kernel/livepatch/Kconfig | 12 ++++++++++++ 2 files changed, 13 insertions(+)
arch/x86/Kconfig +1 -0
@@ -260,6 +260,7 @@ config X86 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_KRETPROBES select HAVE_RETHOOK + select HAVE_KLP_BUILD if X86_64 select HAVE_LIVEPATCH if X86_64 select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOD_ARCH_SPECIFIC
kernel/livepatch/Kconfig +12 -0
@@ -18,3 +18,15 @@ config LIVEPATCH module uses the interface provided by this option to register a patch, causing calls to patched functions to be redirected to new function code contained in the patch module. + +config HAVE_KLP_BUILD + bool + help + Arch supports klp-build + +config KLP_BUILD + def_bool y + depends on LIVEPATCH && HAVE_KLP_BUILD + select OBJTOOL + help + Enable klp-build support
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 57/63 kbuild,objtool: Defer objtool validation step for CONFIG_KLP_BUILD
In reply to Josh PoimboeufIn preparation for klp-build, defer objtool validation for CONFIG_KLP_BUILD kernels until the final pre-link archive (e.g., vmlinux.o, module-foo.o) is built. This will simplify the process of generating livepatch modules.
Delayed objtool is generally preferred anyway, and is already standard for IBT and LTO. Eventually the per-translation-unit mode will be phased out.
--- scripts/Makefile.lib | 2 +- scripts/link-vmlinux.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
scripts/Makefile.lib +1 -1
@@ -197,7 +197,7 @@ objtool-args = $(objtool-args-y) \ $(if $(delay-objtool), --link) \ $(if $(part-of-module), --module) -delay-objtool := $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT)) +delay-objtool := $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT),$(CONFIG_KLP_BUILD)) cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool-args) $@) cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)
scripts/link-vmlinux.sh +2 -1
@@ -60,7 +60,8 @@ vmlinux_link() # skip output file argument shift - if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then + if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT || + is_enabled CONFIG_KLP_BUILD; then # Use vmlinux.o instead of performing the slow LTO link again. objs=vmlinux.o libs=
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 58/63 livepatch/klp-build: Introduce fix-patch-lines script to avoid __LINE__ diff noise
In reply to Josh PoimboeufThe __LINE__ macro creates challenges for binary diffing. When a .patch file adds or removes lines, it shifts the line numbers for all code below it.
This can cause the code generation of functions using __LINE__ to change due to the line number constant being embedded in a MOV instruction, despite there being no semantic difference.
Avoid such false positives by adding a fix-patch-lines script which can be used to insert a #line directive in each patch hunk affecting the line numbering. This script will be used by klp-build, which will be introduced in a subsequent patch.
--- MAINTAINERS | 1 + scripts/livepatch/fix-patch-lines | 79 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100755 scripts/livepatch/fix-patch-lines
MAINTAINERS +1 -0
@@ -14225,6 +14225,7 @@ F: include/linux/livepatch*.h F: kernel/livepatch/ F: kernel/module/livepatch.c F: samples/livepatch/ +F: scripts/livepatch/ F: tools/testing/selftests/livepatch/ LLC (802.2)
scripts/livepatch/fix-patch-lines new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 59/63 livepatch/klp-build: Add stub init code for livepatch modules
In reply to Josh PoimboeufAdd a module initialization stub which can be linked with binary diff objects to produce a livepatch module.
--- scripts/livepatch/init.c | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 scripts/livepatch/init.c
scripts/livepatch/init.c new file +108 -0
@@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Init code for a livepatch kernel module +*/ + +#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/livepatch.h> + +extern struct klp_object_ext __start_klp_objects[]; +extern struct klp_object_ext __stop_klp_objects[]; + +static struct klp_patch *patch; + +static int __init livepatch_mod_init (void ) +{ +struct klp_object *objs; +unsigned int nr_objs; +int ret; + + nr_objs = __stop_klp_objects - __start_klp_objects; + +if (!nr_objs) { +pr_err ("nothing to patch!\n" ); + ret = -EINVAL ; + goto err; + } + + patch =kzalloc (sizeof (*patch),GFP_KERNEL ); +if (!patch) { + ret = -ENOMEM ; + goto err; + } + + objs =kzalloc (sizeof (struct klp_object ) * (nr_objs +1 ),GFP_KERNEL ); +if (!objs) { + ret = -ENOMEM ; + goto err_free_patch; + } + +for (int i =0 ; i < nr_objs; i++) { +struct klp_object_ext *obj_ext = __start_klp_objects + i; +struct klp_func_ext *funcs_ext = obj_ext->funcs; +unsigned int nr_funcs = obj_ext->nr_funcs; +struct klp_func *funcs = objs[i].funcs; +struct klp_object *obj = objs + i; + + funcs =kzalloc (sizeof (struct klp_func ) * (nr_funcs +1 ),GFP_KERNEL ); +if (!funcs) { + ret = -ENOMEM ; +for (int j =0 ; j < i; j++) +kfree (objs[i].funcs); + goto err_free_objs; + } + +for (int j =0 ; j < nr_funcs; j++) { + funcs[j].old_name = funcs_ext[j].old_name; + funcs[j].new_func = funcs_ext[j].new_func; + funcs[j].old_sympos = funcs_ext[j].sympos; + } + + obj->name = obj_ext->name; + obj->funcs = funcs; + +memcpy (&obj->callbacks, &obj_ext->callbacks,sizeof (struct klp_callbacks )); + } + + patch->mod =THIS_MODULE ; + patch->objs = objs; + +/* TODO patch->states */ + +#ifdef KLP_NO_REPLACE + patch->replace = false; +#else + patch->replace = true; +#endif + +return klp_enable_patch (patch); + +err_free_objs: +kfree (objs); +err_free_patch: +kfree (patch); +err: +return ret; +} + +static void __exit livepatch_mod_exit(void) +{ +unsigned int nr_objs; + + nr_objs = __stop_klp_objects - __start_klp_objects; + +for (int i =0 ; i < nr_objs; i++) +kfree (patch->objs[i].funcs); + +kfree (patch->objs); +kfree (patch); +} + +module_init (livepatch_mod_init); +module_exit (livepatch_mod_exit); +MODULE_LICENSE ("GPL" ); +MODULE_INFO (livepatch,"Y" ); +MODULE_DESCRIPTION ("Livepatch module" );
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 60/63 livepatch/klp-build: Introduce klp-build script for generating livepatch modules
In reply to Josh PoimboeufAdd a klp-build script which automates the generation of a livepatch module from a source .patch file by performing the following steps:
- Builds an original kernel with -function-sections and -fdata-sections, plus objtool function checksumming.
- Applies the .patch file and rebuilds the kernel using the same options.
- Runs 'objtool klp diff' to detect changed functions and generate intermediate binary diff objects.
- Builds a kernel module which links the diff objects with some livepatch module init code (scripts/livepatch/init.c).
- Finalizes the livepatch module (aka work around linker wreckage) using 'objtool klp post-link'.
--- scripts/Makefile.lib | 1 + scripts/livepatch/fix-patch-lines | 2 +- scripts/livepatch/klp-build | 743 ++++++++++++++++++++++++++++++ tools/objtool/klp-diff.c | 6 +- 4 files changed, 749 insertions(+), 3 deletions(-) create mode 100755 scripts/livepatch/klp-build
scripts/Makefile.lib +1 -0
@@ -173,6 +173,7 @@ ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool +objtool-args-$(CONFIG_KLP_BUILD) += --checksum objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) += --hacks=skylake
scripts/livepatch/fix-patch-lines +1 -1
@@ -23,7 +23,7 @@ BEGIN { in_hunk = 1 - # for @@ -1,3 +1,4 @@: + # @@ -1,3 +1,4 @@: # 1: line number in old file # 3: how many lines the hunk covers in old file # 1: line number in new file
scripts/livepatch/klp-build new file +743 -0
743 lines not on this page · raw message
tools/objtool/klp-diff.c +4 -2
@@ -241,10 +241,12 @@ static struct symbol *next_file_symbol(struct elf *elf, struct symbol *sym)static bool is_uncorrelated_static_local (struct symbol *sym) {static const char *const vars[] = { -"__key." , -"__warned." ,"__already_done." ,"__func__." , +"__key." , +"__warned." , +"_entry." , +"_entry_ptr." ,"_rs." ,"descriptor." ,"CSWTCH." ,
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 61/63 livepatch/klp-build: Add --debug option to show cloning decisions
In reply to Josh PoimboeufAdd a --debug option which gets passed to "objtool klp diff" to enable debug output related to cloning decisions.
--- scripts/livepatch/klp-build | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
scripts/livepatch/klp-build +13 -3
@@ -20,7 +20,7 @@ set -o nounset # This helps keep execution in pipes so pipefail+errexit can catch errors. shopt -s lastpipe -unset SKIP_CLEANUP XTRACE +unset DEBUG_CLONE SKIP_CLEANUP XTRACE REPLACE=1 SHORT_CIRCUIT=0
@@ -120,6 +120,7 @@ Options: -v, --verbose Pass V=1 to kernel/module builds Advanced Options: + -d, --debug Show symbol/reloc cloning decisions -S, --short-circuit=STEP Start at build step (requires prior --keep-tmp) 1|orig Build original kernel (default) 2|patched Build patched kernel
@@ -140,8 +141,8 @@ process_args() { local long local args - short="hj:o:vS:T" - long="help,jobs:,output:,no-replace,verbose,short-circuit:,keep-tmp" + short="hj:o:vdS:T" + long="help,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp" args=$(getopt --options "$short" --longoptions "$long" -- "$@") || { echo; usage; exit
@@ -174,6 +175,11 @@ process_args() { VERBOSE="V=1" shift ;; + -d | --debug) + DEBUG_CLONE=1 + keep_tmp=1 + shift + ;; -S | --short-circuit) [[ ! -d "$TMP_DIR" ]] && die "--short-circuit requires preserved klp-tmp dir" keep_tmp=1
@@ -596,6 +602,7 @@ copy_patched_objects() { diff_objects() { local log="$KLP_DIFF_LOG" local files=() + local opts=() rm -rf "$DIFF_DIR" mkdir -p "$DIFF_DIR"
@@ -603,6 +610,8 @@ diff_objects() { find "$PATCHED_DIR" -type f -name "*.o" | mapfile -t files [[ ${#files[@]} -eq 0 ]] && die "no changes detected" + [[ -v DEBUG_CLONE ]] && opts=("--debug") + # Diff all changed objects for file in "${files[@]}"; do local rel_file="${file#"$PATCHED_DIR"/}"
@@ -616,6 +625,7 @@ diff_objects() { cmd=("$SRC/tools/objtool/objtool") cmd+=("klp") cmd+=("diff") + (( ${#opts[@]} > 0 )) && cmd+=("${opts[@]}") cmd+=("$orig_file") cmd+=("$patched_file") cmd+=("$out_file")
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 62/63 livepatch/klp-build: Add --show-first-changed option to show function divergence
In reply to Josh PoimboeufAdd a --show-first-changed option to identify where changed functions begin to diverge:
- Parse 'objtool klp diff' output to find changed functions.
- Run objtool again on each object with --debug-checksum=<funcs>.
- Diff the per-instruction checksum debug output to locate the first differing instruction.
This can be useful for quickly determining where and why a function changed.
--- scripts/livepatch/klp-build | 82 +++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-)
scripts/livepatch/klp-build +78 -4
@@ -20,7 +20,7 @@ set -o nounset # This helps keep execution in pipes so pipefail+errexit can catch errors. shopt -s lastpipe -unset DEBUG_CLONE SKIP_CLEANUP XTRACE +unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE REPLACE=1 SHORT_CIRCUIT=0
@@ -114,6 +114,7 @@ Usage: $SCRIPT [OPTIONS] PATCH_FILE(s) Generate a livepatch module. Options: + -f, --show-first-changed Show address of first changed instruction -j, --jobs=<jobs> Build jobs to run simultaneously [default: $JOBS] -o, --output=<file.ko> Output file [default: livepatch-<patch-name>.ko] --no-replace Disable livepatch atomic replace
@@ -141,8 +142,8 @@ process_args() { local long local args - short="hj:o:vdS:T" - long="help,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp" + short="hfj:o:vdS:T" + long="help,show-first-changed,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp" args=$(getopt --options "$short" --longoptions "$long" -- "$@") || { echo; usage; exit
@@ -155,6 +156,10 @@ process_args() { usage exit 0 ;; + -f | --show-first-changed) + DIFF_CHECKSUM=1 + shift + ;; -j | --jobs) JOBS="$2" shift 2
@@ -618,6 +623,7 @@ diff_objects() { local orig_file="$rel_file" local patched_file="$PATCHED_DIR/$rel_file" local out_file="$DIFF_DIR/$rel_file" + local filter=() local cmd=() mkdir -p "$(dirname "$out_file")"
@@ -630,16 +636,80 @@ diff_objects() { cmd+=("$patched_file") cmd+=("$out_file") + if [[ -v DIFF_CHECKSUM ]]; then + filter=("grep0") + filter+=("-Ev") + filter+=("DEBUG: .*checksum: ") + else + filter=("cat") + fi + ( cd "$ORIG_DIR" "${cmd[@]}" \ 1> >(tee -a "$log") \ - 2> >(tee -a "$log" >&2) || \ + 2> >(tee -a "$log" | "${filter[@]}" >&2) || \ die "objtool klp diff failed" ) done } +# For each changed object, run objtool with --debug-checksum to get the +# per-instruction checksums, and then diff those to find the first changed +# instruction for each function. +diff_checksums() { + local orig_log="$ORIG_DIR/checksum.log" + local patched_log="$PATCHED_DIR/checksum.log" + local -A funcs + local cmd=() + local line + local file + local func + + gawk '/\.o: changed function: / { + sub(/:$/, "", $1) + print $1, $NF + }' "$KLP_DIFF_LOG" | mapfile -t lines + + for line in "${lines[@]}"; do + read -r file func <<< "$line" + if [[ ! -v funcs["$file"] ]]; then + funcs["$file"]="$func" + else + funcs["$file"]+=" $func" + fi + done + + cmd=("$SRC/tools/objtool/objtool") + cmd+=("--checksum") + cmd+=("--link") + cmd+=("--dry-run") + + for file in "${!funcs[@]}"; do + local opt="--debug-checksum=${funcs[$file]// /,}" + + ( + cd "$ORIG_DIR" + "${cmd[@]}" "$opt" "$file" &> "$orig_log" || \ + ( cat "$orig_log" >&2; die "objtool --debug-checksum failed" ) + + cd "$PATCHED_DIR" + "${cmd[@]}" "$opt" "$file" &> "$patched_log" || \ + ( cat "$patched_log" >&2; die "objtool --debug-checksum failed" ) + ) + + for func in ${funcs[$file]}; do + diff <( grep0 -E "^DEBUG: .*checksum: $func " "$orig_log" | sed "s|$ORIG_DIR/||") \ + <( grep0 -E "^DEBUG: .*checksum: $func " "$patched_log" | sed "s|$PATCHED_DIR/||") \ + | gawk '/^< DEBUG: / { + gsub(/:/, "") + printf "%s: %s: %s\n", $3, $5, $6 + exit + }' || true + done + done +} + # Build and post-process livepatch module in $KMOD_DIR build_patch_module() { local makefile="$KMOD_DIR/Kbuild"
@@ -743,6 +813,10 @@ fi if (( SHORT_CIRCUIT <= 3 )); then status "Diffing objects" diff_objects + if [[ -v DIFF_CHECKSUM ]]; then + status "Finding first changed instructions" + diff_checksums + fi fi if (( SHORT_CIRCUIT <= 4 )); then
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerPATCH v4 63/63 livepatch: Introduce source code helpers for livepatch modules
In reply to Josh PoimboeufAdd some helper macros which can be used by livepatch source .patch files to register callbacks, convert static calls to regular calls where needed, and patch syscalls.
--- include/linux/livepatch_helpers.h | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 include/linux/livepatch_helpers.h
include/linux/livepatch_helpers.h new file +77 -0
@@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_LIVEPATCH_HELPERS_H +#define _LINUX_LIVEPATCH_HELPERS_H + +/* +* Interfaces for use by livepatch patches +*/ + +#include <linux/syscalls.h> +#include <linux/livepatch.h> + +#ifdef MODULE +#define KLP_OBJNAME __KBUILD_MODNAME +#else +#define KLP_OBJNAME vmlinux +#endif + +/* Livepatch callback registration */ + +#define KLP_CALLBACK_PTRS ".discard.klp_callback_ptrs" + +#define KLP_PRE_PATCH_CALLBACK (func) \ + klp_pre_patch_t __used __section(KLP_CALLBACK_PTRS) \ + __PASTE(__KLP_PRE_PATCH_PREFIX, KLP_OBJNAME) = func + +#define KLP_POST_PATCH_CALLBACK (func) \ + klp_post_patch_t __used __section(KLP_CALLBACK_PTRS) \ + __PASTE(__KLP_POST_PATCH_PREFIX, KLP_OBJNAME) = func + +#define KLP_PRE_UNPATCH_CALLBACK (func) \ + klp_pre_unpatch_t __used __section(KLP_CALLBACK_PTRS) \ + __PASTE(__KLP_PRE_UNPATCH_PREFIX, KLP_OBJNAME) = func + +#define KLP_POST_UNPATCH_CALLBACK (func) \ + klp_post_unpatch_t __used __section(KLP_CALLBACK_PTRS) \ + __PASTE(__KLP_POST_UNPATCH_PREFIX, KLP_OBJNAME) = func + +/* +* Replace static_call() usage with this macro when create-diff-object +* recommends it due to the original static call key living in a module. +* +* This converts the static call to a regular indirect call. +*/ +#define KLP_STATIC_CALL (name) \ + ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) + +/* Syscall patching */ + +#define KLP_SYSCALL_DEFINE1 (name, ...) KLP_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) +#define KLP_SYSCALL_DEFINE2 (name, ...) KLP_SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) +#define KLP_SYSCALL_DEFINE3 (name, ...) KLP_SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) +#define KLP_SYSCALL_DEFINE4 (name, ...) KLP_SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) +#define KLP_SYSCALL_DEFINE5 (name, ...) KLP_SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) +#define KLP_SYSCALL_DEFINE6 (name, ...) KLP_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) + +#define KLP_SYSCALL_DEFINEx (x, sname, ...) \ + __KLP_SYSCALL_DEFINEx(x, sname, __VA_ARGS__) + +#ifdef CONFIG_X86_64 +// TODO move this to arch/x86/include/asm/syscall_wrapper.h and share code +#define __KLP_SYSCALL_DEFINEx (x, name, ...) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + __X64_SYS_STUBx(x, name, __VA_ARGS__) \ + __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __klp_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#endif + +#endif /* _LINUX_LIVEPATCH_HELPERS_H */
Signature · 1 line
2.50.0
Josh Poimboeuf
maintainerQuoted 10 lines · Josh Poimboeuf
Changes since v3 (https://lore.kernel.org/[email protected]):
- Get rid of the SHF_MERGE+SHF_WRITE toolchain shenanigans in favor of simple .discard.annotate_data annotations
- Fix potential double free inelf_create_reloc()
- Syncinterval_tree_generic.h(Peter)
- Refactor prefix symbol creation error handling
- Rebase on tip/master and fix new issue (--checksum getting added with --noabs)(v3..v4 diff below)
git branch:
git://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux.git klp-build-v4
Signature · 1 line
Josh
Joe Lawrence
maintainerQuoted 60 lines · Josh Poimboeuf
Changes since v3 (https://lore.kernel.org/[email protected]):
- Get rid of the SHF_MERGE+SHF_WRITE toolchain shenanigans in favor of simple .discard.annotate_data annotations
- Fix potential double free inelf_create_reloc()
- Syncinterval_tree_generic.h(Peter)
- Refactor prefix symbol creation error handling
- Rebase on tip/master and fix new issue (--checksum getting added with --noabs)(v3..v4 diff below)
----
This series introduces new objtool features and a klp-build script to generate livepatch modules using a source .patch as input.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
Key improvements compared to kpatch-build:
- Integrated with objtool: Leverages objtool's existing control-flow graph analysis to help detect changed functions.
- Works on vmlinux.o: Supports late-linked objects, making it compatible with LTO, IBT, and similar.
- Simplified code base: ~3k fewer lines of code.
- Upstream: No more out-of-tree #ifdef hacks, far less cruft.
- Cleaner internals: Vastly simplified logic for symbol/section/reloc inclusion and special section extraction.
- Robust
__LINE__macro handling: Avoids false positive binary diffs caused by the__LINE__macro by introducing a fix-patch-lines script which injects #line directives into the source .patch to preserve the original line numbers at compile time.The primary user interface is the klp-build script which does the following:
- Builds an original kernel with -function-sections and -fdata-sections, plus objtool function checksumming.
- Applies the .patch file and rebuilds the kernel using the same options.
- Runs 'objtool klp diff' to detect changed functions and generate intermediate binary diff objects.
- Builds a kernel module which links the diff objects with some livepatch module init code (
scripts/livepatch/init.c).- Finalizes the livepatch module (aka work around linker wreckage) using 'objtool klp post-link'.
Quoted 9 lines
I've tested with a variety of patches on defconfig and Fedora-config kernels with both GCC and Clang.
These patches can also be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux.gitklp-build-v3Please test!
For v4.1, with several dozen small, CVE input patches and gcc 14 + CentOS-Steam-10 config:
--
Joe
Quoted 8 lines · Josh Poimboeuf
This series introduces new objtool features and a klp-build script to generate livepatch modules using a source .patch as input.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
The series seems to be in a pretty good state, ready for linux-next, ...
Best Regards,
Petr
Josh Poimboeuf
maintainerQuoted 10 lines · Petr Mladek
Quoted 8 lines · Josh Poimboeuf
This series introduces new objtool features and a klp-build script to generate livepatch modules using a source .patch as input.
This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch.
Quoted 3 lines
The series seems to be in a pretty good state, ready for linux-next, ...
Acked-by Petr Mladek <[email protected]>
Thanks! I'll queue these up for -tip.
Signature · 1 line
Josh