From 41d24d78589705f85cbe90e5a8c1b55ea05557a2 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:28 -0700 Subject: objtool: Fix x86 addend calculation On x86, arch_dest_reloc_offset() hardcodes the addend adjustment to four, but the actual adjustment depends on the relocation type. Fix that. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h index be33c7b43180..68664625a467 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -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); -- cgit v1.2.3 From 34244f784c6d062af184944a25f40ab50dfdb67a Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:32 -0700 Subject: objtool: Const string cleanup Use 'const char *' where applicable. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/arch.h | 2 +- tools/objtool/include/objtool/elf.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h index 68664625a467..a4502947307a 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -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); diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index df8434d3b744..74ce454790f4 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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; -- cgit v1.2.3 From 96eceff331ea535b763b161df01300bbfd93b372 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:35 -0700 Subject: objtool: Convert elf iterator macros to use 'struct elf' '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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 74ce454790f4..4d5f27b49724 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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) \ -- cgit v1.2.3 From 25eac74b6bdbf6d15911b582e747e8ad12fcbf8f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:36 -0700 Subject: objtool: Add section/symbol type helpers Add some helper macros to improve readability. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 66 +++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 4d5f27b49724..f2dbcaa42a9c 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -178,11 +179,71 @@ 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) +{ + return sym->sec->idx; +} + +static inline bool is_null_sym(struct symbol *sym) +{ + return !sym->idx; +} + +static inline bool is_sec_sym(struct symbol *sym) +{ + return sym->type == STT_SECTION; +} + +static inline bool is_object_sym(struct symbol *sym) +{ + return sym->type == STT_OBJECT; +} + +static inline bool is_func_sym(struct symbol *sym) +{ + return sym->type == STT_FUNC; +} + +static inline bool is_file_sym(struct symbol *sym) +{ + return sym->type == STT_FILE; +} + +static inline bool is_notype_sym(struct symbol *sym) +{ + return sym->type == STT_NOTYPE; +} + +static inline bool is_global_sym(struct symbol *sym) +{ + return sym->bind == STB_GLOBAL; +} + +static inline bool is_weak_sym(struct symbol *sym) +{ + return sym->bind == STB_WEAK; +} + +static inline bool is_local_sym(struct symbol *sym) +{ + return sym->bind == STB_LOCAL; +} + static inline bool is_reloc_sec(struct section *sec) { return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL; } +static inline bool is_string_sec(struct section *sec) +{ + return sec->sh.sh_flags & SHF_STRINGS; +} + +static inline bool is_text_sec(struct section *sec) +{ + return sec->sh.sh_flags & SHF_EXECINSTR; +} + static inline bool sec_changed(struct section *sec) { return sec->_changed; @@ -223,6 +284,11 @@ static inline bool is_32bit_reloc(struct reloc *reloc) return reloc->sec->sh.sh_entsize < 16; } +static inline unsigned long sec_size(struct section *sec) +{ + return sec->sh.sh_size; +} + #define __get_reloc_field(reloc, field) \ ({ \ is_32bit_reloc(reloc) ? \ -- cgit v1.2.3 From 4ea029389bf0cc44da6d3a24a520200e060ce6bf Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:37 -0700 Subject: objtool: Mark .cold subfunctions Introduce a flag to identify .cold subfunctions so they can be detected easier and faster. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index f2dbcaa42a9c..dbadcc88a3b2 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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; -- cgit v1.2.3 From c9e9b85d41f9079d6a10faabf70a0b18d5c0f177 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:38 -0700 Subject: objtool: Fix weak symbol hole detection for .cold functions When 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/check.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h index 00fb745e7233..0f4e7ac929ef 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -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; -- cgit v1.2.3 From a1526bcfcb6cb7cb601b9ff8e24d08881ef9afb8 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:39 -0700 Subject: objtool: Mark prefix functions In 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index dbadcc88a3b2..79edf82e76dd 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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; -- cgit v1.2.3 From 2b91479776b66cd815e339d420abbf4ae047bfb2 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:43 -0700 Subject: objtool: Resurrect --backup option The --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. Suggested-by: Peter Zijlstra Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/builtin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index ab22673862e1..7d559a2c13b7 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -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 */ -- cgit v1.2.3 From a05de0a772ce423895a3b07504a9ed93ae75e912 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:45 -0700 Subject: objtool: Refactor add_jump_destinations() The 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 79edf82e76dd..07fc41f574b9 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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) -- cgit v1.2.3 From dd2c29aafde7653839791d3073515b62e5df1f4d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:47 -0700 Subject: objtool: Generalize elf_create_symbol() In 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 07fc41f574b9..c33b8fa0e3ce 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -15,6 +15,8 @@ #include #include +#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, -- cgit v1.2.3 From 243e96385368fc5e31da4e9927a201a27a2ae936 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:48 -0700 Subject: objtool: Generalize elf_create_section() In 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index c33b8fa0e3ce..badb10926d1e 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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, -- cgit v1.2.3 From 431dbabf2d9dd27cd597a9d1d4611e7ae64bf8bd Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:49 -0700 Subject: objtool: Add elf_create_data() In 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index badb10926d1e..0d9aeefb6d12 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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); -- cgit v1.2.3 From 2c05ca02621837af7cd8fab6ae7421b9cd5dff6e Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:50 -0700 Subject: objtool: Add elf_create_reloc() and elf_init_reloc() elf_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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 0d9aeefb6d12..999fd9369cf5 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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, -- cgit v1.2.3 From 03c19a99ee69f4680d7da11c164ac655b4946b99 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:51 -0700 Subject: objtool: Add elf_create_file() Add interface to enable the creation of a new ELF file. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 999fd9369cf5..9f135c262659 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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); -- cgit v1.2.3 From 3b92486fa1a905cf4be81c0b65961f547fcf7be3 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:52 -0700 Subject: objtool: Add annotype() helper ... for reading annotation types. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 13 +++++++++++++ tools/objtool/include/objtool/endianness.h | 9 ++++----- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 9f135c262659..814cfc0bbf16 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -13,10 +13,14 @@ #include #include #include + +#include #include #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, unsigned mark_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? */ diff --git a/tools/objtool/include/objtool/endianness.h b/tools/objtool/include/objtool/endianness.h index 4d2aa9b0fe2f..aebcd2338668 100644 --- a/tools/objtool/include/objtool/endianness.h +++ b/tools/objtool/include/objtool/endianness.h @@ -4,7 +4,6 @@ #include #include -#include /* * 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; \ -- cgit v1.2.3 From 0d83da43b1e1c8ce19f2bb10f54a0fdf795364f7 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:57 -0700 Subject: objtool/klp: Add --checksum option to generate per-function checksums 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/builtin.h | 5 +-- tools/objtool/include/objtool/check.h | 5 +-- tools/objtool/include/objtool/checksum.h | 42 ++++++++++++++++++++++++++ tools/objtool/include/objtool/checksum_types.h | 25 +++++++++++++++ tools/objtool/include/objtool/elf.h | 4 ++- 5 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 tools/objtool/include/objtool/checksum.h create mode 100644 tools/objtool/include/objtool/checksum_types.h (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 7d559a2c13b7..338bdab6b9ad 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -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; diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h index 0f4e7ac929ef..d73b0c3ae1ee 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -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; diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h new file mode 100644 index 000000000000..927ca74b5c39 --- /dev/null +++ b/tools/objtool/include/objtool/checksum.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _OBJTOOL_CHECKSUM_H +#define _OBJTOOL_CHECKSUM_H + +#include + +#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 */ diff --git a/tools/objtool/include/objtool/checksum_types.h b/tools/objtool/include/objtool/checksum_types.h new file mode 100644 index 000000000000..507efdd8ab5b --- /dev/null +++ b/tools/objtool/include/objtool/checksum_types.h @@ -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 + +struct checksum { + XXH3_state_t *state; + XXH64_hash_t checksum; +}; + +#else /* !BUILD_KLP */ + +struct checksum {}; + +#endif /* !BUILD_KLP */ + +#endif /* _OBJTOOL_CHECKSUM_TYPES_H */ diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 814cfc0bbf16..bc7d8a6167f8 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -15,6 +15,7 @@ #include #include +#include #include #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 { -- cgit v1.2.3 From a3493b33384a01a1f0e38b420d1a4766aec903a6 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:58 -0700 Subject: objtool/klp: Add --debug-checksum= to show per-instruction checksums Add a --debug-checksum= 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- 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 +++++++++++++++++++ 4 files changed, 22 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 338bdab6b9ad..cee9fc031877 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -32,6 +32,7 @@ struct opts { /* options: */ bool backtrace; bool backup; + const char *debug_checksum; bool dryrun; bool link; bool mnop; diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h index 927ca74b5c39..7fe21608722a 100644 --- a/tools/objtool/include/objtool/checksum.h +++ b/tools/objtool/include/objtool/checksum.h @@ -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) diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index bc7d8a6167f8..a1f1762f89c4 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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; diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index cb8fe846d9dd..29173a1368d7 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -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 */ -- cgit v1.2.3 From dd590d4d57ebeeb826823c288741f2ed20f452af Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:03:59 -0700 Subject: objtool/klp: Introduce klp diff subcommand for diffing object files 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. 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- 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 +++++++++++ 6 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 tools/objtool/include/objtool/klp.h create mode 100644 tools/objtool/include/objtool/util.h (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h index a4502947307a..d89f8b5ec14e 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -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); diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index cee9fc031877..bb0b25eb08ba 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -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 */ diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index a1f1762f89c4..e2cd817fca52 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -18,6 +18,7 @@ #include #include +#define SEC_NAME_LEN 1024 #define SYM_NAME_LEN 512 #define bswap_if_needed(elf, val) __bswap_if_needed(&elf->ehdr, val) @@ -53,10 +54,12 @@ struct section { bool _changed, text, rodata, noinstr, init, truncate; struct reloc *relocs; unsigned long nr_alloc_relocs; + struct section *twin; }; struct symbol { struct list_head list; + struct list_head global_list; struct rb_node node; struct elf_hash_node hash; struct elf_hash_node name_hash; @@ -83,10 +86,13 @@ struct symbol { u8 cold : 1; u8 prefix : 1; u8 debug_checksum : 1; + u8 changed : 1; + u8 included : 1; struct list_head pv_target; struct reloc *relocs; struct section *group_sec; struct checksum csum; + struct symbol *twin, *clone; }; struct reloc { @@ -104,6 +110,7 @@ struct elf { const char *name, *tmp_name; unsigned int num_files; struct list_head sections; + struct list_head symbols; unsigned long num_relocs; int symbol_bits; @@ -179,6 +186,7 @@ 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); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); +struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name); struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); int find_symbol_hole_containing(const struct section *sec, unsigned long offset); struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); @@ -448,22 +456,48 @@ 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_prev_sym(sym) \ + sym->sec && sym->list.prev != &sym->sec->symbol_list ? \ + list_prev_entry(sym, list) : NULL + #define for_each_sym(elf, sym) \ - for (struct section *__sec, *__fake = (struct section *)1; \ - __fake; __fake = NULL) \ - for_each_sec(elf, __sec) \ - sec_for_each_sym(__sec, sym) + list_for_each_entry(sym, &elf->symbols, global_list) + +#define for_each_sym_continue(elf, sym) \ + list_for_each_entry_continue(sym, &elf->symbols, global_list) + +#define rsec_next_reloc(rsec, reloc) \ + reloc_idx(reloc) < sec_num_entries(rsec) - 1 ? reloc + 1 : NULL #define for_each_reloc(rsec, reloc) \ - for (int __i = 0, __fake = 1; __fake; __fake = 0) \ - for (reloc = rsec->relocs; \ - __i < sec_num_entries(rsec); \ - __i++, reloc++) + for (reloc = rsec->relocs; reloc; reloc = rsec_next_reloc(rsec, reloc)) #define for_each_reloc_from(rsec, reloc) \ - for (int __i = reloc_idx(reloc); \ - __i < sec_num_entries(rsec); \ - __i++, 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); \ + reloc && reloc_offset(reloc) < sym->offset + sym->len; \ + reloc = rsec_next_reloc(sym->sec->rsec, reloc)) + +static inline struct symbol *get_func_prefix(struct symbol *func) +{ + struct symbol *prev; + + if (!is_func_sym(func)) + return NULL; + + prev = sec_prev_sym(func); + if (prev && is_prefix_func(prev)) + return prev; + + return NULL; +} #define OFFSET_STRIDE_BITS 4 #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS) diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h new file mode 100644 index 000000000000..07928fac059b --- /dev/null +++ b/tools/objtool/include/objtool/klp.h @@ -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 */ diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index c0dc86a78ff6..7f70b41d1b8d 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -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); diff --git a/tools/objtool/include/objtool/util.h b/tools/objtool/include/objtool/util.h new file mode 100644 index 000000000000..a0180b312f73 --- /dev/null +++ b/tools/objtool/include/objtool/util.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _UTIL_H +#define _UTIL_H + +#include + +#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 */ -- cgit v1.2.3 From 7c2575a6406fb85946b05d8dcc856686d3156354 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:04:00 -0700 Subject: objtool/klp: Add --debug option to show cloning decisions Add 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/warn.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index 29173a1368d7..e88322d97573 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -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 && \ -- cgit v1.2.3 From ebe864b55304f74c4e1a8b6c899e34446b2be424 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:04:01 -0700 Subject: objtool/klp: Add post-link subcommand to finalize livepatch modules 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, the .ko then needs to be converted to an actual livepatch module. Introduce a new klp post-link subcommand to do so. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/klp.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h index 07928fac059b..ad830a7ce55b 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -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 */ -- cgit v1.2.3 From 2058f6d1660edc4a9bda9bee627792b352121b10 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:04:02 -0700 Subject: objtool: Refactor prefix symbol creation code The 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index e2cd817fca52..60f844e43c5a 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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); -- cgit v1.2.3 From 164c9201e1dad8d5c0c38f583dba81e4b6da9cc7 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 17 Sep 2025 09:04:03 -0700 Subject: objtool: Add base objtool support for livepatch modules In 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. Acked-by: Petr Mladek Tested-by: Joe Lawrence Signed-off-by: Josh Poimboeuf --- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/objtool.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/objtool/include') diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 60f844e43c5a..21d8b825fd8f 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -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; diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index 7f70b41d1b8d..f7051bbe0bcb 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -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; -- cgit v1.2.3