* [PATCH 0/8] objtool/klp: klp-build LTO support and tests
@ 2026-02-12 19:21 Song Liu
2026-02-12 19:21 ` [PATCH 1/8] objtool/klp: Remove redundent strcmp in correlate_symbols Song Liu
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
Add support for LTO in klp-build toolchain. The key changes are to the
symbol correlation logic.Basically, we want to:
1. Match symbols with differerent .llvm.<hash> suffixes, e.g., foo.llvm.123
to foo.llvm.456.
2. Match local symbols with promoted global symbols, e.g., local foo
with global foo.llvm.123.
1/8 and 2/8 are small cleanup/fix for existing code.
3/8 through 7/8 contains the core logic changes to correlate_symbols().
8/8 contains tests for klp-build toolchain.
Song Liu (8):
objtool/klp: Remove redundent strcmp in correlate_symbols
objtool/klp: Remove trailing '_' in demangle_name()
objtool/klp: Use sym->demangled_name for symbol_name hash
objtool/klp: Also demangle global objects
objtool/klp: Remove .llvm suffix in demangle_name()
objtool/klp: Match symbols based on demangled_name for global
variables
objtool/klp: Correlate locals to globals
livepatch: Add tests for klp-build toolchain
kernel/livepatch/Kconfig | 20 +++
kernel/livepatch/Makefile | 2 +
kernel/livepatch/tests/Makefile | 6 +
kernel/livepatch/tests/klp_test_module.c | 111 ++++++++++++++
kernel/livepatch/tests/klp_test_module.h | 8 +
kernel/livepatch/tests/klp_test_vmlinux.c | 138 ++++++++++++++++++
kernel/livepatch/tests/klp_test_vmlinux.h | 16 ++
kernel/livepatch/tests/klp_test_vmlinux_aux.c | 59 ++++++++
scripts/setlocalversion | 9 ++
tools/objtool/elf.c | 95 +++++++++---
tools/objtool/include/objtool/elf.h | 2 +
tools/objtool/klp-diff.c | 59 +++++++-
.../selftests/livepatch/test_patches/README | 15 ++
.../test_patches/klp_test_hash_change.patch | 30 ++++
.../test_patches/klp_test_module.patch | 18 +++
.../klp_test_nonstatic_to_static.patch | 40 +++++
.../klp_test_static_to_nonstatic.patch | 39 +++++
.../test_patches/klp_test_vmlinux.patch | 18 +++
18 files changed, 663 insertions(+), 22 deletions(-)
create mode 100644 kernel/livepatch/tests/Makefile
create mode 100644 kernel/livepatch/tests/klp_test_module.c
create mode 100644 kernel/livepatch/tests/klp_test_module.h
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux.c
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux.h
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux_aux.c
create mode 100644 tools/testing/selftests/livepatch/test_patches/README
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_hash_change.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_module.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_nonstatic_to_static.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_static_to_nonstatic.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_vmlinux.patch
--
2.47.3
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/8] objtool/klp: Remove redundent strcmp in correlate_symbols
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:21 ` [PATCH 2/8] objtool/klp: Remove trailing '_' in demangle_name() Song Liu
` (7 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
find_global_symbol_by_name() already compares names of the two symbols,
so there is no need to compare them again.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/klp-diff.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index a3198a63c2f0..57606bc3390a 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -454,7 +454,7 @@ static int correlate_symbols(struct elfs *e)
sym2 = find_global_symbol_by_name(e->patched, sym1->name);
- if (sym2 && !sym2->twin && !strcmp(sym1->name, sym2->name)) {
+ if (sym2 && !sym2->twin) {
sym1->twin = sym2;
sym2->twin = sym1;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/8] objtool/klp: Remove trailing '_' in demangle_name()
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
2026-02-12 19:21 ` [PATCH 1/8] objtool/klp: Remove redundent strcmp in correlate_symbols Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:21 ` [PATCH 3/8] objtool/klp: Use sym->demangled_name for symbol_name hash Song Liu
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
With CONFIG_LTO_CLANG_THIN, it is possible to have nested __UNIQUE_ID_,
such as:
__UNIQUE_ID_addressable___UNIQUE_ID_pci_invalid_bar_694_695
To remove both trailing numbers, also remove trailing '_'.
Also add comments to demangle_name().
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/elf.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 2c02c7b49265..0d93e8496e8d 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -441,6 +441,19 @@ static int read_sections(struct elf *elf)
return 0;
}
+/*
+ * Remove number suffix of a symbol.
+ *
+ * Specifically, remove trailing numbers for "__UNIQUE_ID_" symbols and
+ * symbols with '.'.
+ *
+ * With CONFIG_LTO_CLANG_THIN, it is possible to have nested __UNIQUE_ID_,
+ * such as
+ *
+ * __UNIQUE_ID_addressable___UNIQUE_ID_pci_invalid_bar_694_695
+ *
+ * to remove both trailing numbers, also remove trailing '_'.
+ */
static const char *demangle_name(struct symbol *sym)
{
char *str;
@@ -463,7 +476,7 @@ static const char *demangle_name(struct symbol *sym)
for (int i = strlen(str) - 1; i >= 0; i--) {
char c = str[i];
- if (!isdigit(c) && c != '.') {
+ if (!isdigit(c) && c != '.' && c != '_') {
str[i + 1] = '\0';
break;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/8] objtool/klp: Use sym->demangled_name for symbol_name hash
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
2026-02-12 19:21 ` [PATCH 1/8] objtool/klp: Remove redundent strcmp in correlate_symbols Song Liu
2026-02-12 19:21 ` [PATCH 2/8] objtool/klp: Remove trailing '_' in demangle_name() Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:21 ` [PATCH 4/8] objtool/klp: Also demangle global objects Song Liu
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
For klp-build with LTO, it is necessary to correlate demangled symbols,
e.g., correlate foo.llvm.<num 1> and foo.llvm.<num 2>. However, these two
symbols do not have the same str_hash(name). To be able to correlate the
two symbols, calculate hash based on demanged_name, so that these two
symbols have the same hash.
No functional changes intended.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/elf.c | 58 +++++++++++++++++++++++++++++++--------------
1 file changed, 40 insertions(+), 18 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 0d93e8496e8d..c784a0484270 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -26,11 +26,18 @@
#include <objtool/elf.h>
#include <objtool/warn.h>
+static ssize_t demangled_name_len(const char *name);
+
static inline u32 str_hash(const char *str)
{
return jhash(str, strlen(str), 0);
}
+static inline u32 str_hash_demangled(const char *str)
+{
+ return jhash(str, demangled_name_len(str), 0);
+}
+
#define __elf_table(name) (elf->name##_hash)
#define __elf_bits(name) (elf->name##_bits)
@@ -294,7 +301,7 @@ static struct symbol *find_local_symbol_by_file_and_name(const struct elf *elf,
{
struct symbol *sym;
- elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) {
+ elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash_demangled(name)) {
if (sym->bind == STB_LOCAL && sym->file == file &&
!strcmp(sym->name, name)) {
return sym;
@@ -308,7 +315,7 @@ struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *nam
{
struct symbol *sym;
- elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) {
+ elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash_demangled(name)) {
if (!strcmp(sym->name, name) && !is_local_sym(sym))
return sym;
}
@@ -441,6 +448,28 @@ static int read_sections(struct elf *elf)
return 0;
}
+/*
+ * Returns desired length of the demangled name.
+ * If name doesn't need demangling, return strlen(name).
+ */
+static ssize_t demangled_name_len(const char *name)
+{
+ ssize_t len;
+
+ if (!strstarts(name, "__UNIQUE_ID_") && !strchr(name, '.'))
+ return strlen(name);
+
+ for (len = strlen(name) - 1; len >= 0; len--) {
+ char c = name[len];
+
+ if (!isdigit(c) && c != '.' && c != '_')
+ break;
+ }
+ if (len <= 0)
+ return strlen(name);
+ return len;
+}
+
/*
* Remove number suffix of a symbol.
*
@@ -457,6 +486,7 @@ static int read_sections(struct elf *elf)
static const char *demangle_name(struct symbol *sym)
{
char *str;
+ ssize_t len;
if (!is_local_sym(sym))
return sym->name;
@@ -464,24 +494,16 @@ static const char *demangle_name(struct symbol *sym)
if (!is_func_sym(sym) && !is_object_sym(sym))
return sym->name;
- if (!strstarts(sym->name, "__UNIQUE_ID_") && !strchr(sym->name, '.'))
+ len = demangled_name_len(sym->name);
+ if (len == strlen(sym->name))
return sym->name;
- str = strdup(sym->name);
+ str = strndup(sym->name, len);
if (!str) {
ERROR_GLIBC("strdup");
return NULL;
}
- for (int i = strlen(str) - 1; i >= 0; i--) {
- char c = str[i];
-
- if (!isdigit(c) && c != '.' && c != '_') {
- str[i + 1] = '\0';
- break;
- }
- }
-
return str;
}
@@ -517,9 +539,13 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)
entry = &sym->sec->symbol_list;
list_add(&sym->list, entry);
+ sym->demangled_name = demangle_name(sym);
+ if (!sym->demangled_name)
+ return -1;
+
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));
+ elf_hash_add(symbol_name, &sym->name_hash, str_hash(sym->demangled_name));
if (is_func_sym(sym) &&
(strstarts(sym->name, "__pfx_") ||
@@ -543,10 +569,6 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)
sym->pfunc = sym->cfunc = sym;
- sym->demangled_name = demangle_name(sym);
- if (!sym->demangled_name)
- return -1;
-
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/8] objtool/klp: Also demangle global objects
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (2 preceding siblings ...)
2026-02-12 19:21 ` [PATCH 3/8] objtool/klp: Use sym->demangled_name for symbol_name hash Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:21 ` [PATCH 5/8] objtool/klp: Remove .llvm suffix in demangle_name() Song Liu
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
With CONFIG_LTO_CLANG_THIN, it is possible to have global __UNIQUE_ID,
such as:
FUNC GLOBAL HIDDEN 19745 __UNIQUE_ID_quirk_amd_nb_node_458
Also demangle global objects.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/elf.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index c784a0484270..d66452d66fb4 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -488,9 +488,6 @@ static const char *demangle_name(struct symbol *sym)
char *str;
ssize_t len;
- if (!is_local_sym(sym))
- return sym->name;
-
if (!is_func_sym(sym) && !is_object_sym(sym))
return sym->name;
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/8] objtool/klp: Remove .llvm suffix in demangle_name()
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (3 preceding siblings ...)
2026-02-12 19:21 ` [PATCH 4/8] objtool/klp: Also demangle global objects Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:21 ` [PATCH 6/8] objtool/klp: Match symbols based on demangled_name for global variables Song Liu
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
Remove .llvm suffix, so that we can correlate foo.llvm.<hash 1> and
foo.llvm.<hash 2>.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/elf.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index d66452d66fb4..efb13ec0a89d 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -455,10 +455,15 @@ static int read_sections(struct elf *elf)
static ssize_t demangled_name_len(const char *name)
{
ssize_t len;
+ const char *p;
if (!strstarts(name, "__UNIQUE_ID_") && !strchr(name, '.'))
return strlen(name);
+ p = strstr(name, ".llvm.");
+ if (p)
+ return p - name;
+
for (len = strlen(name) - 1; len >= 0; len--) {
char c = name[len];
@@ -482,6 +487,9 @@ static ssize_t demangled_name_len(const char *name)
* __UNIQUE_ID_addressable___UNIQUE_ID_pci_invalid_bar_694_695
*
* to remove both trailing numbers, also remove trailing '_'.
+ *
+ * For symbols with llvm suffix, i.e., foo.llvm.<hash>, remove the
+ * .llvm.<hash> part.
*/
static const char *demangle_name(struct symbol *sym)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/8] objtool/klp: Match symbols based on demangled_name for global variables
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (4 preceding siblings ...)
2026-02-12 19:21 ` [PATCH 5/8] objtool/klp: Remove .llvm suffix in demangle_name() Song Liu
@ 2026-02-12 19:21 ` Song Liu
2026-02-12 19:22 ` [PATCH 7/8] objtool/klp: Correlate locals to globals Song Liu
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:21 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
correlate_symbols will always try to match full name first. If there is no
match, try match only demangled_name.
In very rare cases, it is possible to have multiple foo.llvm.<hash> in
the same kernel. So this match is not guaranteed to be correct. Show
a warning here so that the user can double check.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/elf.c | 13 +++++++++++++
tools/objtool/include/objtool/elf.h | 2 ++
tools/objtool/klp-diff.c | 23 +++++++++++++++++++++++
3 files changed, 38 insertions(+)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index efb13ec0a89d..d26ee877e613 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -323,6 +323,19 @@ struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *nam
return NULL;
}
+struct symbol *find_global_symbol_by_demangled_name(const struct elf *elf,
+ const char *demangled_name)
+{
+ struct symbol *sym;
+
+ elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(demangled_name)) {
+ if (!strcmp(sym->demangled_name, demangled_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)
{
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index e12c516bd320..f757850b8ff1 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -186,6 +186,8 @@ 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_global_symbol_by_demangled_name(const struct elf *elf,
+ const char *demangled_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);
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 57606bc3390a..cd82f674862a 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -453,6 +453,29 @@ static int correlate_symbols(struct elfs *e)
continue;
sym2 = find_global_symbol_by_name(e->patched, sym1->name);
+ if (!sym2) {
+ /*
+ * No full name match, try match demangled_name.
+ * This would match foo.llvm.123 and foo.llvm.456.
+ *
+ * Note that, in very rare cases, it is possible
+ * to have multiple foo.llvm.<hash> in the same
+ * kernel, e.g., foo.llvm.123 in the original
+ * kernel, and both foo.llvm.456 and foo.llvm.789
+ * in the patched kernel. The correlation is not
+ * guaranteed to be correct in such cases.
+ *
+ * Show a warning to remind the user to double
+ * check the correlation.
+ */
+
+ sym2 = find_global_symbol_by_demangled_name(e->patched,
+ sym1->demangled_name);
+ if (sym2) {
+ WARN("correlate %s (origial) to %s (patched)",
+ sym1->name, sym2->name);
+ }
+ }
if (sym2 && !sym2->twin) {
sym1->twin = sym2;
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/8] objtool/klp: Correlate locals to globals
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (5 preceding siblings ...)
2026-02-12 19:21 ` [PATCH 6/8] objtool/klp: Match symbols based on demangled_name for global variables Song Liu
@ 2026-02-12 19:22 ` Song Liu
2026-02-12 19:22 ` [PATCH 8/8] livepatch: Add tests for klp-build toolchain Song Liu
2026-02-18 23:00 ` [PATCH 0/8] objtool/klp: klp-build LTO support and tests Joe Lawrence
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:22 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
Allow correlating original locals to patched globals, and vice versa.
This is needed when:
1. User adds/removes "static" for a function.
2. CONFIG_LTO_CLANG_THIN promotes local functions and objects to global
and add .llvm.<hash> suffix.
Given this is a less common scenario, show warnings when this is needed.
Signed-off-by: Song Liu <song@kernel.org>
---
tools/objtool/klp-diff.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index cd82f674862a..f7a31ea2cbe7 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -483,6 +483,40 @@ static int correlate_symbols(struct elfs *e)
}
}
+ /* Correlate original locals with patched globals */
+ for_each_sym(e->orig, sym1) {
+ if (sym1->twin || dont_correlate(sym1) || !is_local_sym(sym1))
+ continue;
+ sym2 = find_global_symbol_by_name(e->patched, sym1->name);
+ if (!sym2) {
+ sym2 = find_global_symbol_by_demangled_name(e->patched,
+ sym1->demangled_name);
+ }
+ if (sym2 && !sym2->twin) {
+ sym1->twin = sym2;
+ sym2->twin = sym1;
+ WARN("correlate LOCAL %s (origial) to GLOBAL %s (patched)",
+ sym1->name, sym2->name);
+ }
+ }
+
+ /* Correlate original globals with patched locals */
+ for_each_sym(e->patched, sym2) {
+ if (sym2->twin || dont_correlate(sym2) || !is_local_sym(sym2))
+ continue;
+ sym1 = find_global_symbol_by_name(e->orig, sym2->name);
+ if (!sym1) {
+ sym1 = find_global_symbol_by_demangled_name(e->orig,
+ sym2->demangled_name);
+ }
+ if (sym1 && !sym1->twin) {
+ sym2->twin = sym1;
+ sym1->twin = sym2;
+ WARN("correlate GLOBAL %s (origial) to LOCAL %s (patched)",
+ sym1->name, sym2->name);
+ }
+ }
+
for_each_sym(e->orig, sym1) {
if (sym1->twin || dont_correlate(sym1))
continue;
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 8/8] livepatch: Add tests for klp-build toolchain
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (6 preceding siblings ...)
2026-02-12 19:22 ` [PATCH 7/8] objtool/klp: Correlate locals to globals Song Liu
@ 2026-02-12 19:22 ` Song Liu
2026-02-18 23:00 ` [PATCH 0/8] objtool/klp: klp-build LTO support and tests Joe Lawrence
8 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-12 19:22 UTC (permalink / raw)
To: live-patching
Cc: jpoimboe, jikos, mbenes, pmladek, joe.lawrence, kernel-team,
Song Liu
Add selftests for the klp-build toolchain. This includes kernel side test
code and .patch files. The tests cover both livepatch to vmlinux and kernel
modules.
Check tools/testing/selftests/livepatch/test_patches/README for
instructions to run these tests.
Signed-off-by: Song Liu <song@kernel.org>
---
AI was used to wrote the test code and .patch files in this.
---
kernel/livepatch/Kconfig | 20 +++
kernel/livepatch/Makefile | 2 +
kernel/livepatch/tests/Makefile | 6 +
kernel/livepatch/tests/klp_test_module.c | 111 ++++++++++++++
kernel/livepatch/tests/klp_test_module.h | 8 +
kernel/livepatch/tests/klp_test_vmlinux.c | 138 ++++++++++++++++++
kernel/livepatch/tests/klp_test_vmlinux.h | 16 ++
kernel/livepatch/tests/klp_test_vmlinux_aux.c | 59 ++++++++
scripts/setlocalversion | 9 ++
.../selftests/livepatch/test_patches/README | 15 ++
.../test_patches/klp_test_hash_change.patch | 30 ++++
.../test_patches/klp_test_module.patch | 18 +++
.../klp_test_nonstatic_to_static.patch | 40 +++++
.../klp_test_static_to_nonstatic.patch | 39 +++++
.../test_patches/klp_test_vmlinux.patch | 18 +++
15 files changed, 529 insertions(+)
create mode 100644 kernel/livepatch/tests/Makefile
create mode 100644 kernel/livepatch/tests/klp_test_module.c
create mode 100644 kernel/livepatch/tests/klp_test_module.h
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux.c
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux.h
create mode 100644 kernel/livepatch/tests/klp_test_vmlinux_aux.c
create mode 100644 tools/testing/selftests/livepatch/test_patches/README
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_hash_change.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_module.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_nonstatic_to_static.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_static_to_nonstatic.patch
create mode 100644 tools/testing/selftests/livepatch/test_patches/klp_test_vmlinux.patch
diff --git a/kernel/livepatch/Kconfig b/kernel/livepatch/Kconfig
index 4c0a9c18d0b2..852049601389 100644
--- a/kernel/livepatch/Kconfig
+++ b/kernel/livepatch/Kconfig
@@ -30,3 +30,23 @@ config KLP_BUILD
select OBJTOOL
help
Enable klp-build support
+
+config KLP_TEST
+ bool "Livepatch test code"
+ depends on LIVEPATCH
+ help
+ Dummy kernel code for testing the klp-build livepatch toolchain.
+ Provides built-in vmlinux functions with sysfs interfaces for
+ verifying livepatches.
+
+ If unsure, say N.
+
+config KLP_TEST_MODULE
+ tristate "Livepatch test module (klp_test_module)"
+ depends on KLP_TEST && m
+ help
+ Test module for livepatch testing. Dummy kernel module for
+ testing the klp-build toolchain. Provides sysfs interfaces for
+ verifying livepatches.
+
+ If unsure, say N.
diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile
index cf03d4bdfc66..751080a62cec 100644
--- a/kernel/livepatch/Makefile
+++ b/kernel/livepatch/Makefile
@@ -2,3 +2,5 @@
obj-$(CONFIG_LIVEPATCH) += livepatch.o
livepatch-objs := core.o patch.o shadow.o state.o transition.o
+
+obj-$(CONFIG_KLP_TEST) += tests/
diff --git a/kernel/livepatch/tests/Makefile b/kernel/livepatch/tests/Makefile
new file mode 100644
index 000000000000..82ae48f54abe
--- /dev/null
+++ b/kernel/livepatch/tests/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y += klp_test_vmlinux_all.o
+obj-$(CONFIG_KLP_TEST_MODULE) += klp_test_module.o
+
+klp_test_vmlinux_all-y := klp_test_vmlinux.o \
+ klp_test_vmlinux_aux.o
diff --git a/kernel/livepatch/tests/klp_test_module.c b/kernel/livepatch/tests/klp_test_module.c
new file mode 100644
index 000000000000..25cefbe36a2b
--- /dev/null
+++ b/kernel/livepatch/tests/klp_test_module.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * klp_test_module.c - Single-file test module for livepatch/klp-build testing
+ *
+ * Copyright (C) 2026 Meta Platforms, Inc. and affiliates.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/string.h>
+#include "klp_test_module.h"
+#include "klp_test_vmlinux.h"
+
+static int klp_test_module_var1;
+static int klp_test_module_var2;
+
+static noinline ssize_t __klp_test_module_func1(char *buf, int len)
+{
+ ssize_t ret = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ klp_test_module_var1 += i;
+
+ if (klp_test_module_var1 > 1000)
+ klp_test_module_var1 = 0;
+
+ ret = sysfs_emit(buf, "klp_test_module_func1 unpatched %d\n",
+ klp_test_module_var1);
+ return ret;
+}
+
+ssize_t klp_test_module_func1(char *buf, int len)
+{
+ return __klp_test_module_func1(buf, len);
+}
+EXPORT_SYMBOL_GPL(klp_test_module_func1);
+
+static noinline ssize_t __klp_test_module_func2(char *buf, int len)
+{
+ ssize_t ret = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ klp_test_module_var2 += i * 2;
+
+ if (klp_test_module_var2 > 1000)
+ klp_test_module_var2 = 0;
+
+ ret = sysfs_emit(buf, "klp_test_module_func2 unpatched %d\n",
+ klp_test_module_var2);
+ return ret;
+}
+
+ssize_t klp_test_module_func2(char *buf, int len)
+{
+ return __klp_test_module_func2(buf, len);
+}
+EXPORT_SYMBOL_GPL(klp_test_module_func2);
+
+static ssize_t func1_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return klp_test_module_func1(buf, 5);
+}
+
+static ssize_t func2_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return klp_test_module_func2(buf, 5);
+}
+
+static struct kobj_attribute func1_attr = __ATTR_RO(func1);
+static struct kobj_attribute func2_attr = __ATTR_RO(func2);
+
+static struct attribute *klp_test_module_attrs[] = {
+ &func1_attr.attr,
+ &func2_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group klp_test_module_attr_group = {
+ .attrs = klp_test_module_attrs,
+};
+
+static struct kobject *klp_test_module_kobj;
+
+static int __init klp_test_module_init(void)
+{
+ klp_test_module_kobj = kobject_create_and_add("module",
+ klp_test_kobj);
+ if (!klp_test_module_kobj)
+ return -ENOMEM;
+
+ return sysfs_create_group(klp_test_module_kobj,
+ &klp_test_module_attr_group);
+}
+
+static void __exit klp_test_module_exit(void)
+{
+ sysfs_remove_group(klp_test_module_kobj, &klp_test_module_attr_group);
+ kobject_put(klp_test_module_kobj);
+}
+
+module_init(klp_test_module_init);
+module_exit(klp_test_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Livepatch single-file test module");
diff --git a/kernel/livepatch/tests/klp_test_module.h b/kernel/livepatch/tests/klp_test_module.h
new file mode 100644
index 000000000000..56a766f4744b
--- /dev/null
+++ b/kernel/livepatch/tests/klp_test_module.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _KLP_TEST_MODULE_H
+#define _KLP_TEST_MODULE_H
+
+ssize_t klp_test_module_func1(char *buf, int len);
+ssize_t klp_test_module_func2(char *buf, int len);
+
+#endif /* _KLP_TEST_MODULE_H */
diff --git a/kernel/livepatch/tests/klp_test_vmlinux.c b/kernel/livepatch/tests/klp_test_vmlinux.c
new file mode 100644
index 000000000000..bd4157ea97c0
--- /dev/null
+++ b/kernel/livepatch/tests/klp_test_vmlinux.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * klp_test_vmlinux.c - Dummy built-in code for livepatch/klp-build testing
+ *
+ * Copyright (C) 2026 Meta Platforms, Inc. and affiliates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include "klp_test_vmlinux.h"
+
+static int klp_test_vmlinux_var1;
+static int klp_test_vmlinux_var2;
+
+static noinline int __helper(int x, int len)
+{
+ int i, sum = x;
+
+ for (i = 0; i < len; i++)
+ sum += i + 5;
+ if (sum > 1000)
+ sum = 0;
+ return sum;
+}
+
+static noinline ssize_t __klp_test_vmlinux_func1(char *buf, int len)
+{
+ ssize_t ret = 0;
+
+ klp_test_vmlinux_var1 = __helper(klp_test_vmlinux_var1, len);
+
+ ret = sysfs_emit(buf, "klp_test_vmlinux_func1 unpatched %d\n",
+ klp_test_vmlinux_var1);
+ return ret;
+}
+
+ssize_t klp_test_vmlinux_func1(char *buf, int len)
+{
+ return __klp_test_vmlinux_func1(buf, len);
+}
+EXPORT_SYMBOL_GPL(klp_test_vmlinux_func1);
+
+static noinline ssize_t __klp_test_vmlinux_func2(char *buf, int len)
+{
+ ssize_t ret = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ klp_test_vmlinux_var2 += i * 2;
+
+ if (klp_test_vmlinux_var2 > 1000)
+ klp_test_vmlinux_var2 = 0;
+
+ ret = sysfs_emit(buf, "klp_test_vmlinux_func2 unpatched %d\n",
+ klp_test_vmlinux_var2);
+ return ret;
+}
+
+ssize_t klp_test_vmlinux_func2(char *buf, int len)
+{
+ return __klp_test_vmlinux_func2(buf, len);
+}
+EXPORT_SYMBOL_GPL(klp_test_vmlinux_func2);
+
+static ssize_t vmlinux_func1_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return klp_test_vmlinux_func1(buf, 5);
+}
+
+static ssize_t vmlinux_func2_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return klp_test_vmlinux_func2(buf, 5);
+}
+
+static struct kobj_attribute vmlinux_func1_attr = __ATTR_RO(vmlinux_func1);
+static struct kobj_attribute vmlinux_func2_attr = __ATTR_RO(vmlinux_func2);
+
+static struct attribute *klp_test_attrs[] = {
+ &vmlinux_func1_attr.attr,
+ &vmlinux_func2_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group klp_test_attr_group = {
+ .attrs = klp_test_attrs,
+};
+
+static struct kobject *klp_test_vmlinux_kobj;
+struct kobject *klp_test_kobj;
+EXPORT_SYMBOL_GPL(klp_test_kobj);
+
+static int __init klp_test_vmlinux_init(void)
+{
+ int ret;
+
+ klp_test_kobj = kobject_create_and_add("klp_test", kernel_kobj);
+ if (!klp_test_kobj)
+ return -ENOMEM;
+
+ klp_test_vmlinux_kobj = kobject_create_and_add("vmlinux", klp_test_kobj);
+ if (!klp_test_vmlinux_kobj) {
+ kobject_put(klp_test_kobj);
+ return -ENOMEM;
+ }
+
+ ret = sysfs_create_group(klp_test_vmlinux_kobj, &klp_test_attr_group);
+ if (ret)
+ goto err_group;
+
+ ret = klp_test_vmlinux_aux_init(klp_test_vmlinux_kobj);
+ if (ret)
+ goto err_aux;
+
+ return 0;
+
+err_aux:
+ sysfs_remove_group(klp_test_vmlinux_kobj, &klp_test_attr_group);
+err_group:
+ kobject_put(klp_test_vmlinux_kobj);
+ kobject_put(klp_test_kobj);
+ return ret;
+}
+
+static void __exit klp_test_vmlinux_exit(void)
+{
+ klp_test_vmlinux_aux_exit(klp_test_vmlinux_kobj);
+ sysfs_remove_group(klp_test_vmlinux_kobj, &klp_test_attr_group);
+ kobject_put(klp_test_vmlinux_kobj);
+ kobject_put(klp_test_kobj);
+}
+
+late_initcall(klp_test_vmlinux_init);
diff --git a/kernel/livepatch/tests/klp_test_vmlinux.h b/kernel/livepatch/tests/klp_test_vmlinux.h
new file mode 100644
index 000000000000..56d9f7b6d350
--- /dev/null
+++ b/kernel/livepatch/tests/klp_test_vmlinux.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _KLP_TEST_VMLINUX_H
+#define _KLP_TEST_VMLINUX_H
+
+#include <linux/kobject.h>
+
+extern struct kobject *klp_test_kobj;
+
+ssize_t klp_test_vmlinux_func1(char *buf, int len);
+ssize_t klp_test_vmlinux_func2(char *buf, int len);
+ssize_t klp_test_vmlinux_func3(char *buf, int len);
+
+int klp_test_vmlinux_aux_init(struct kobject *parent);
+void klp_test_vmlinux_aux_exit(struct kobject *parent);
+
+#endif /* _KLP_TEST_VMLINUX_H */
diff --git a/kernel/livepatch/tests/klp_test_vmlinux_aux.c b/kernel/livepatch/tests/klp_test_vmlinux_aux.c
new file mode 100644
index 000000000000..1d76b0308a11
--- /dev/null
+++ b/kernel/livepatch/tests/klp_test_vmlinux_aux.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * klp_test_vmlinux_aux.c - Auxiliary built-in code for livepatch/klp-build
+ * testing. This file has its own static __helper()
+ * to test ThinLTO .llvm.<hash> suffix handling.
+ *
+ * Copyright (C) 2026 Meta Platforms, Inc. and affiliates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/string.h>
+#include "klp_test_vmlinux.h"
+
+static int klp_test_vmlinux_var3;
+
+static noinline int __helper(int x, int len)
+{
+ int i, sum = x;
+
+ for (i = 0; i < len; i++)
+ sum += i + 10;
+ if (sum > 1000)
+ sum = 0;
+ return sum;
+}
+
+static noinline ssize_t __klp_test_vmlinux_func3(char *buf, int len)
+{
+ klp_test_vmlinux_var3 = __helper(klp_test_vmlinux_var3, len);
+
+ return sysfs_emit(buf, "klp_test_vmlinux_func3 unpatched %d\n",
+ klp_test_vmlinux_var3);
+}
+
+ssize_t klp_test_vmlinux_func3(char *buf, int len)
+{
+ return __klp_test_vmlinux_func3(buf, len);
+}
+EXPORT_SYMBOL_GPL(klp_test_vmlinux_func3);
+
+static ssize_t vmlinux_func3_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return klp_test_vmlinux_func3(buf, 5);
+}
+
+static struct kobj_attribute vmlinux_func3_attr = __ATTR_RO(vmlinux_func3);
+
+int klp_test_vmlinux_aux_init(struct kobject *parent)
+{
+ return sysfs_create_file(parent, &vmlinux_func3_attr.attr);
+}
+
+void klp_test_vmlinux_aux_exit(struct kobject *parent)
+{
+ sysfs_remove_file(parent, &vmlinux_func3_attr.attr);
+}
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 28169d7e143b..6f28aedd253b 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -1,4 +1,13 @@
#!/bin/sh
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
+echo 6.19.0+; exit 0
# SPDX-License-Identifier: GPL-2.0
#
# This scripts adds local version information from the version
diff --git a/tools/testing/selftests/livepatch/test_patches/README b/tools/testing/selftests/livepatch/test_patches/README
new file mode 100644
index 000000000000..8266348aab57
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/README
@@ -0,0 +1,15 @@
+This is folder contains patches to test the klp-build toolchain.
+
+To run the test:
+
+1. Enable CONFIG_KLP_TEST and CONFIG_KLP_TEST_MODULE, and build the kernel.
+
+2. Build these patches with:
+
+ ./scripts/livepatch/klp-build tools/testing/selftests/livepatch/test_patches/*.patch
+
+3. Verify the correctness with:
+
+ modprobe klp_test_module
+ kpatch load livepatch-patch.ko
+ grep -q unpatched /sys/kernel/klp_test/*/* && echo FAIL || echo PASS
diff --git a/tools/testing/selftests/livepatch/test_patches/klp_test_hash_change.patch b/tools/testing/selftests/livepatch/test_patches/klp_test_hash_change.patch
new file mode 100644
index 000000000000..609d54d6d6f6
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/klp_test_hash_change.patch
@@ -0,0 +1,30 @@
+Test ThinLTO .llvm.<hash> suffix handling.
+
+Modify a static __helper() function whose body change causes its
+.llvm.<hash> suffix to change under ThinLTO. Both klp_test_vmlinux.c
+and klp_test_vmlinux_aux.c define static __helper() with different
+bodies, so ThinLTO promotes both to globals with different hashes.
+This patch changes the __helper() in the aux file, which changes its
+hash, and klp-build must correctly match the old and new symbols.
+
+diff --git i/kernel/livepatch/tests/klp_test_vmlinux_aux.c w/kernel/livepatch/tests/klp_test_vmlinux_aux.c
+--- i/kernel/livepatch/tests/klp_test_vmlinux_aux.c
++++ w/kernel/livepatch/tests/klp_test_vmlinux_aux.c
+@@ -20,7 +20,7 @@
+ int i, sum = x;
+
+ for (i = 0; i < len; i++)
+- sum += i + 10;
++ sum += i * 2 + 10;
+ if (sum > 1000)
+ sum = 0;
+ return sum;
+@@ -30,7 +30,7 @@
+ {
+ klp_test_vmlinux_var3 = __helper(klp_test_vmlinux_var3, len);
+
+- return sysfs_emit(buf, "klp_test_vmlinux_func3 unpatched %d\n",
++ return sysfs_emit(buf, "klp_test_vmlinux_func3 hash_patched %d\n",
+ klp_test_vmlinux_var3);
+ }
+
diff --git a/tools/testing/selftests/livepatch/test_patches/klp_test_module.patch b/tools/testing/selftests/livepatch/test_patches/klp_test_module.patch
new file mode 100644
index 000000000000..d86e75618136
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/klp_test_module.patch
@@ -0,0 +1,18 @@
+Test basic module patching.
+
+Patch a loadable module function to verify that klp-build can generate
+a livepatch for module code. Changes __klp_test_module_func1() output
+from "unpatched" to "patched".
+
+diff --git i/kernel/livepatch/tests/klp_test_module.c w/kernel/livepatch/tests/klp_test_module.c
+--- i/kernel/livepatch/tests/klp_test_module.c
++++ w/kernel/livepatch/tests/klp_test_module.c
+@@ -27,7 +27,7 @@
+ if (klp_test_module_var1 > 1000)
+ klp_test_module_var1 = 0;
+
+- ret = sysfs_emit(buf, "klp_test_module_func1 unpatched %d\n",
++ ret = sysfs_emit(buf, "klp_test_module_func1 patched %d\n",
+ klp_test_module_var1);
+ return ret;
+ }
diff --git a/tools/testing/selftests/livepatch/test_patches/klp_test_nonstatic_to_static.patch b/tools/testing/selftests/livepatch/test_patches/klp_test_nonstatic_to_static.patch
new file mode 100644
index 000000000000..f26711c6bfac
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/klp_test_nonstatic_to_static.patch
@@ -0,0 +1,40 @@
+Test nonstatic-to-static symbol change.
+
+Change klp_test_module_func2() from nonstatic (global) to static and
+remove its EXPORT_SYMBOL_GPL. Also remove its declaration from the
+header file. This tests klp-build's ability to handle symbol visibility
+changes where a function that was originally global becomes static in
+the patched kernel.
+
+diff --git i/kernel/livepatch/tests/klp_test_module.c w/kernel/livepatch/tests/klp_test_module.c
+--- i/kernel/livepatch/tests/klp_test_module.c
++++ w/kernel/livepatch/tests/klp_test_module.c
+@@ -49,16 +49,15 @@
+ if (klp_test_module_var2 > 1000)
+ klp_test_module_var2 = 0;
+
+- ret = sysfs_emit(buf, "klp_test_module_func2 unpatched %d\n",
++ ret = sysfs_emit(buf, "klp_test_module_func2 patched_nts %d\n",
+ klp_test_module_var2);
+ return ret;
+ }
+
+-ssize_t klp_test_module_func2(char *buf, int len)
++static noinline ssize_t klp_test_module_func2(char *buf, int len)
+ {
+ return __klp_test_module_func2(buf, len);
+ }
+-EXPORT_SYMBOL_GPL(klp_test_module_func2);
+
+ static ssize_t func1_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+diff --git i/kernel/livepatch/tests/klp_test_module.h w/kernel/livepatch/tests/klp_test_module.h
+--- i/kernel/livepatch/tests/klp_test_module.h
++++ w/kernel/livepatch/tests/klp_test_module.h
+@@ -3,6 +3,5 @@
+ #define _KLP_TEST_MODULE_H
+
+ ssize_t klp_test_module_func1(char *buf, int len);
+-ssize_t klp_test_module_func2(char *buf, int len);
+
+ #endif /* _KLP_TEST_MODULE_H */
diff --git a/tools/testing/selftests/livepatch/test_patches/klp_test_static_to_nonstatic.patch b/tools/testing/selftests/livepatch/test_patches/klp_test_static_to_nonstatic.patch
new file mode 100644
index 000000000000..673f6c42f698
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/klp_test_static_to_nonstatic.patch
@@ -0,0 +1,39 @@
+Test static-to-nonstatic symbol change.
+
+Change __klp_test_vmlinux_func2() from static to nonstatic (global).
+This tests klp-build's ability to handle symbol visibility changes
+where a function that was originally static becomes globally visible
+in the patched kernel.
+
+diff --git i/kernel/livepatch/tests/klp_test_vmlinux.c w/kernel/livepatch/tests/klp_test_vmlinux.c
+--- i/kernel/livepatch/tests/klp_test_vmlinux.c
++++ w/kernel/livepatch/tests/klp_test_vmlinux.c
+@@ -44,7 +44,7 @@
+ }
+ EXPORT_SYMBOL_GPL(klp_test_vmlinux_func1);
+
+-static noinline ssize_t __klp_test_vmlinux_func2(char *buf, int len)
++noinline ssize_t __klp_test_vmlinux_func2(char *buf, int len)
+ {
+ ssize_t ret = 0;
+ int i;
+@@ -55,7 +55,7 @@
+ if (klp_test_vmlinux_var2 > 1000)
+ klp_test_vmlinux_var2 = 0;
+
+- ret = sysfs_emit(buf, "klp_test_vmlinux_func2 unpatched %d\n",
++ ret = sysfs_emit(buf, "klp_test_vmlinux_func2 patched_stn %d\n",
+ klp_test_vmlinux_var2);
+ return ret;
+ }
+diff --git i/kernel/livepatch/tests/klp_test_vmlinux.h w/kernel/livepatch/tests/klp_test_vmlinux.h
+--- i/kernel/livepatch/tests/klp_test_vmlinux.h
++++ w/kernel/livepatch/tests/klp_test_vmlinux.h
+@@ -9,6 +9,7 @@
+ ssize_t klp_test_vmlinux_func1(char *buf, int len);
+ ssize_t klp_test_vmlinux_func2(char *buf, int len);
+ ssize_t klp_test_vmlinux_func3(char *buf, int len);
++ssize_t __klp_test_vmlinux_func2(char *buf, int len);
+
+ int klp_test_vmlinux_aux_init(struct kobject *parent);
+ void klp_test_vmlinux_aux_exit(struct kobject *parent);
diff --git a/tools/testing/selftests/livepatch/test_patches/klp_test_vmlinux.patch b/tools/testing/selftests/livepatch/test_patches/klp_test_vmlinux.patch
new file mode 100644
index 000000000000..8b1d91381728
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test_patches/klp_test_vmlinux.patch
@@ -0,0 +1,18 @@
+Test basic vmlinux patching.
+
+Patch a built-in vmlinux function to verify that klp-build can generate
+a livepatch for vmlinux code. Changes __klp_test_vmlinux_func1() output
+from "unpatched" to "patched".
+
+diff --git i/kernel/livepatch/tests/klp_test_vmlinux.c w/kernel/livepatch/tests/klp_test_vmlinux.c
+--- i/kernel/livepatch/tests/klp_test_vmlinux.c
++++ w/kernel/livepatch/tests/klp_test_vmlinux.c
+@@ -33,7 +33,7 @@
+
+ klp_test_vmlinux_var1 = __helper(klp_test_vmlinux_var1, len);
+
+- ret = sysfs_emit(buf, "klp_test_vmlinux_func1 unpatched %d\n",
++ ret = sysfs_emit(buf, "klp_test_vmlinux_func1 patched %d\n",
+ klp_test_vmlinux_var1);
+ return ret;
+ }
--
2.47.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 0/8] objtool/klp: klp-build LTO support and tests
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
` (7 preceding siblings ...)
2026-02-12 19:22 ` [PATCH 8/8] livepatch: Add tests for klp-build toolchain Song Liu
@ 2026-02-18 23:00 ` Joe Lawrence
2026-02-19 3:08 ` Song Liu
8 siblings, 1 reply; 14+ messages in thread
From: Joe Lawrence @ 2026-02-18 23:00 UTC (permalink / raw)
To: Song Liu; +Cc: live-patching, jpoimboe, jikos, mbenes, pmladek, kernel-team
On Thu, Feb 12, 2026 at 11:21:53AM -0800, Song Liu wrote:
> Add support for LTO in klp-build toolchain. The key changes are to the
> symbol correlation logic.Basically, we want to:
>
> 1. Match symbols with differerent .llvm.<hash> suffixes, e.g., foo.llvm.123
> to foo.llvm.456.
> 2. Match local symbols with promoted global symbols, e.g., local foo
> with global foo.llvm.123.
>
> 1/8 and 2/8 are small cleanup/fix for existing code.
> 3/8 through 7/8 contains the core logic changes to correlate_symbols().
> 8/8 contains tests for klp-build toolchain.
>
> Song Liu (8):
> objtool/klp: Remove redundent strcmp in correlate_symbols
> objtool/klp: Remove trailing '_' in demangle_name()
> objtool/klp: Use sym->demangled_name for symbol_name hash
> objtool/klp: Also demangle global objects
> objtool/klp: Remove .llvm suffix in demangle_name()
> objtool/klp: Match symbols based on demangled_name for global
> variables
> objtool/klp: Correlate locals to globals
> livepatch: Add tests for klp-build toolchain
>
Hi Song,
One of the tests that Josh had suggested running to validate "no
changes" and git apply --recount / recountdiff was to touch most of the
.c files in the tree like so:
$ find . -type f -name '*.c' ! -path "./lib/*" -print0 | xargs -0 sed -i '1iasm("nop");'
$ git checkout tools arch/x86/lib/inat.c arch/x86/lib/insn.c kernel/configs.c
$ git diff > /tmp/oneline.patch
which results in "klp-build: no changes detected" using gcc, but with
this patchset+llvm thin-LTO results in a few c_start/c_stop/c_next
uncorrelated variables.
Here is a minimal version of a reproducer:
$ grep LTO .config
CONFIG_LTO=y
CONFIG_LTO_CLANG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
CONFIG_HAS_LTO_CLANG=y
# CONFIG_LTO_NONE is not set
# CONFIG_LTO_CLANG_FULL is not set
CONFIG_LTO_CLANG_THIN=y
$ cat ~/min.patch
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 6571d432cbe3..96c6c8bb7228 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -1,3 +1,4 @@
+asm("nop");
// SPDX-License-Identifier: GPL-2.0
#include <linux/smp.h>
#include <linux/timex.h>
diff --git a/crypto/proc.c b/crypto/proc.c
index 82f15b967e85..1474800162bf 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -1,3 +1,4 @@
+asm("nop");
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Scatterlist Cryptographic API.
diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b7cab1ad990d..066e625ae14e 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -1,3 +1,4 @@
+asm("nop");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010 Werner Fink, Jiri Slaby
$ LLVM=1 ./scripts/livepatch/klp-build -T ~/min.patch
Validating patch(es)
Building original kernel
Copying original object files
Fixing patch(es)
Building patched kernel
Copying patched object files
Diffing objects
vmlinux.o: warning: objtool: correlate c_start.llvm.15251198824366928061 (origial) to c_start.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_stop.llvm.15251198824366928061 (origial) to c_stop.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_next.llvm.15251198824366928061 (origial) to c_next.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate show_cpuinfo.llvm.15251198824366928061 (origial) to show_cpuinfo.llvm.10047843810948474008 (patched)
vmlinux.o: warning: objtool: correlate .str.llvm.1768504738091882651 (origial) to .str.llvm.7814622528726587167 (patched)
vmlinux.o: warning: objtool: correlate crypto_seq_ops.llvm.1768504738091882651 (origial) to crypto_seq_ops.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_start.llvm.1768504738091882651 (origial) to c_start.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_stop.llvm.1768504738091882651 (origial) to c_stop.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_next.llvm.1768504738091882651 (origial) to c_next.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate c_show.llvm.1768504738091882651 (origial) to c_show.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.15251198824366928061 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.15251198824366928061 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.15251198824366928061 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_show_cpuinfo.llvm.15251198824366928061 (origial) to __pfx_show_cpuinfo.llvm.10047843810948474008 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.1768504738091882651 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.1768504738091882651 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.1768504738091882651 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: correlate __pfx_c_show.llvm.1768504738091882651 (origial) to __pfx_c_show.llvm.14107081093236395767 (patched)
vmlinux.o: warning: objtool: no correlation: c_start.llvm.1768504738091882651
vmlinux.o: warning: objtool: no correlation: c_stop.llvm.1768504738091882651
vmlinux.o: warning: objtool: no correlation: c_next.llvm.1768504738091882651
vmlinux.o: new function: c_start.llvm.10047843810948474008
vmlinux.o: new function: c_stop.llvm.10047843810948474008
vmlinux.o: new function: c_next.llvm.10047843810948474008
vmlinux.o: changed function: c_start.llvm.14107081093236395767
vmlinux.o: changed function: c_stop.llvm.14107081093236395767
vmlinux.o: changed function: c_next.llvm.14107081093236395767
Building patch module: livepatch-min.ko
SUCCESS
And since we're here, it looks like there's a type:
s/origial/original/g.
--
Joe
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 0/8] objtool/klp: klp-build LTO support and tests
2026-02-18 23:00 ` [PATCH 0/8] objtool/klp: klp-build LTO support and tests Joe Lawrence
@ 2026-02-19 3:08 ` Song Liu
2026-02-19 20:47 ` Song Liu
2026-02-19 20:51 ` Josh Poimboeuf
0 siblings, 2 replies; 14+ messages in thread
From: Song Liu @ 2026-02-19 3:08 UTC (permalink / raw)
To: Joe Lawrence; +Cc: live-patching, jpoimboe, jikos, mbenes, pmladek, kernel-team
On Wed, Feb 18, 2026 at 3:00 PM Joe Lawrence <joe.lawrence@redhat.com> wrote:
>
> On Thu, Feb 12, 2026 at 11:21:53AM -0800, Song Liu wrote:
[...]
> vmlinux.o: warning: objtool: correlate c_start.llvm.15251198824366928061 (origial) to c_start.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_stop.llvm.15251198824366928061 (origial) to c_stop.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_next.llvm.15251198824366928061 (origial) to c_next.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate show_cpuinfo.llvm.15251198824366928061 (origial) to show_cpuinfo.llvm.10047843810948474008 (patched)
> vmlinux.o: warning: objtool: correlate .str.llvm.1768504738091882651 (origial) to .str.llvm.7814622528726587167 (patched)
> vmlinux.o: warning: objtool: correlate crypto_seq_ops.llvm.1768504738091882651 (origial) to crypto_seq_ops.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_start.llvm.1768504738091882651 (origial) to c_start.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_stop.llvm.1768504738091882651 (origial) to c_stop.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_next.llvm.1768504738091882651 (origial) to c_next.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate c_show.llvm.1768504738091882651 (origial) to c_show.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.15251198824366928061 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.15251198824366928061 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.15251198824366928061 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_show_cpuinfo.llvm.15251198824366928061 (origial) to __pfx_show_cpuinfo.llvm.10047843810948474008 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.1768504738091882651 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.1768504738091882651 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.1768504738091882651 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: correlate __pfx_c_show.llvm.1768504738091882651 (origial) to __pfx_c_show.llvm.14107081093236395767 (patched)
> vmlinux.o: warning: objtool: no correlation: c_start.llvm.1768504738091882651
> vmlinux.o: warning: objtool: no correlation: c_stop.llvm.1768504738091882651
> vmlinux.o: warning: objtool: no correlation: c_next.llvm.1768504738091882651
> vmlinux.o: new function: c_start.llvm.10047843810948474008
> vmlinux.o: new function: c_stop.llvm.10047843810948474008
> vmlinux.o: new function: c_next.llvm.10047843810948474008
> vmlinux.o: changed function: c_start.llvm.14107081093236395767
> vmlinux.o: changed function: c_stop.llvm.14107081093236395767
> vmlinux.o: changed function: c_next.llvm.14107081093236395767
> Building patch module: livepatch-min.ko
> SUCCESS
Thanks for the test case. This one shows the worst case of the .llvm.
suffix issue.
We have
c_start.llvm.15251198824366928061
c_start.llvm.1768504738091882651
in the original kernel, and
c_start.llvm.14107081093236395767
c_start.llvm.10047843810948474008
in the patched kernel.
All of them are GLOBAL HIDDEN functions, so I don't think we can
reliably correlate them. Maybe we should fail the build in such cases.
Any comments and suggestions on this one? CC: Josh.
> And since we're here, it looks like there's a type:
> s/origial/original/g.
Fixed!
Thanks,
Song
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/8] objtool/klp: klp-build LTO support and tests
2026-02-19 3:08 ` Song Liu
@ 2026-02-19 20:47 ` Song Liu
2026-02-19 20:51 ` Josh Poimboeuf
1 sibling, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-19 20:47 UTC (permalink / raw)
To: Joe Lawrence; +Cc: live-patching, jpoimboe, jikos, mbenes, pmladek, kernel-team
On Wed, Feb 18, 2026 at 7:08 PM Song Liu <song@kernel.org> wrote:
>
> On Wed, Feb 18, 2026 at 3:00 PM Joe Lawrence <joe.lawrence@redhat.com> wrote:
> >
> > On Thu, Feb 12, 2026 at 11:21:53AM -0800, Song Liu wrote:
> [...]
> > vmlinux.o: warning: objtool: correlate c_start.llvm.15251198824366928061 (origial) to c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_stop.llvm.15251198824366928061 (origial) to c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_next.llvm.15251198824366928061 (origial) to c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate show_cpuinfo.llvm.15251198824366928061 (origial) to show_cpuinfo.llvm.10047843810948474008 (patched)
> > vmlinux.o: warning: objtool: correlate .str.llvm.1768504738091882651 (origial) to .str.llvm.7814622528726587167 (patched)
> > vmlinux.o: warning: objtool: correlate crypto_seq_ops.llvm.1768504738091882651 (origial) to crypto_seq_ops.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_start.llvm.1768504738091882651 (origial) to c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_stop.llvm.1768504738091882651 (origial) to c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_next.llvm.1768504738091882651 (origial) to c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_show.llvm.1768504738091882651 (origial) to c_show.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.15251198824366928061 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.15251198824366928061 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.15251198824366928061 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_show_cpuinfo.llvm.15251198824366928061 (origial) to __pfx_show_cpuinfo.llvm.10047843810948474008 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.1768504738091882651 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.1768504738091882651 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.1768504738091882651 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_show.llvm.1768504738091882651 (origial) to __pfx_c_show.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: no correlation: c_start.llvm.1768504738091882651
> > vmlinux.o: warning: objtool: no correlation: c_stop.llvm.1768504738091882651
> > vmlinux.o: warning: objtool: no correlation: c_next.llvm.1768504738091882651
> > vmlinux.o: new function: c_start.llvm.10047843810948474008
> > vmlinux.o: new function: c_stop.llvm.10047843810948474008
> > vmlinux.o: new function: c_next.llvm.10047843810948474008
> > vmlinux.o: changed function: c_start.llvm.14107081093236395767
> > vmlinux.o: changed function: c_stop.llvm.14107081093236395767
> > vmlinux.o: changed function: c_next.llvm.14107081093236395767
> > Building patch module: livepatch-min.ko
> > SUCCESS
>
> Thanks for the test case. This one shows the worst case of the .llvm.
> suffix issue.
>
> We have
> c_start.llvm.15251198824366928061
> c_start.llvm.1768504738091882651
> in the original kernel, and
> c_start.llvm.14107081093236395767
> c_start.llvm.10047843810948474008
> in the patched kernel.
>
> All of them are GLOBAL HIDDEN functions, so I don't think we can
> reliably correlate them. Maybe we should fail the build in such cases.
>
> Any comments and suggestions on this one? CC: Josh.
I fixed the correlation logic, with the min.patch from Joe that patches:
arch/x86/kernel/cpu/proc.c
crypto/proc.c
fs/proc/consoles.c
we got the following failure:
Diffing objects
vmlinux.o: error: objtool: Multiple (2) correlation candidates for
c_start.llvm.18238767671416440194
error: klp-build: objtool klp diff failed
With a smaller patch, that only patches:
arch/x86/kernel/cpu/proc.c
fs/proc/consoles.c
There will be only one c_start.llvm.<hash>. klp-build fails with:
Diffing objects
vmlinux.o: warning: objtool: correlate
c_start.llvm.18238767671416440194 (original) to
c_start.llvm.4054753011035506728 (patched)
vmlinux.o: warning: objtool: correlate
c_stop.llvm.18238767671416440194 (original) to
c_stop.llvm.4054753011035506728 (patched)
vmlinux.o: warning: objtool: correlate
c_next.llvm.18238767671416440194 (original) to
c_next.llvm.4054753011035506728 (patched)
vmlinux.o: warning: objtool: correlate
show_cpuinfo.llvm.18238767671416440194 (original) to
show_cpuinfo.llvm.4054753011035506728 (patched)
Building patch module: livepatch-0001-min.ko
error: klp-build: no changes detected
This is the best solution I can think of at the moment. I will send v2
patches soon.
Thanks,
Song
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/8] objtool/klp: klp-build LTO support and tests
2026-02-19 3:08 ` Song Liu
2026-02-19 20:47 ` Song Liu
@ 2026-02-19 20:51 ` Josh Poimboeuf
2026-02-19 21:31 ` Song Liu
1 sibling, 1 reply; 14+ messages in thread
From: Josh Poimboeuf @ 2026-02-19 20:51 UTC (permalink / raw)
To: Song Liu; +Cc: Joe Lawrence, live-patching, jikos, mbenes, pmladek, kernel-team
On Wed, Feb 18, 2026 at 07:08:55PM -0800, Song Liu wrote:
> On Wed, Feb 18, 2026 at 3:00 PM Joe Lawrence <joe.lawrence@redhat.com> wrote:
> >
> > On Thu, Feb 12, 2026 at 11:21:53AM -0800, Song Liu wrote:
> [...]
> > vmlinux.o: warning: objtool: correlate c_start.llvm.15251198824366928061 (origial) to c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_stop.llvm.15251198824366928061 (origial) to c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_next.llvm.15251198824366928061 (origial) to c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate show_cpuinfo.llvm.15251198824366928061 (origial) to show_cpuinfo.llvm.10047843810948474008 (patched)
> > vmlinux.o: warning: objtool: correlate .str.llvm.1768504738091882651 (origial) to .str.llvm.7814622528726587167 (patched)
> > vmlinux.o: warning: objtool: correlate crypto_seq_ops.llvm.1768504738091882651 (origial) to crypto_seq_ops.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_start.llvm.1768504738091882651 (origial) to c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_stop.llvm.1768504738091882651 (origial) to c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_next.llvm.1768504738091882651 (origial) to c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate c_show.llvm.1768504738091882651 (origial) to c_show.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.15251198824366928061 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.15251198824366928061 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.15251198824366928061 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_show_cpuinfo.llvm.15251198824366928061 (origial) to __pfx_show_cpuinfo.llvm.10047843810948474008 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_start.llvm.1768504738091882651 (origial) to __pfx_c_start.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_stop.llvm.1768504738091882651 (origial) to __pfx_c_stop.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_next.llvm.1768504738091882651 (origial) to __pfx_c_next.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: correlate __pfx_c_show.llvm.1768504738091882651 (origial) to __pfx_c_show.llvm.14107081093236395767 (patched)
> > vmlinux.o: warning: objtool: no correlation: c_start.llvm.1768504738091882651
> > vmlinux.o: warning: objtool: no correlation: c_stop.llvm.1768504738091882651
> > vmlinux.o: warning: objtool: no correlation: c_next.llvm.1768504738091882651
> > vmlinux.o: new function: c_start.llvm.10047843810948474008
> > vmlinux.o: new function: c_stop.llvm.10047843810948474008
> > vmlinux.o: new function: c_next.llvm.10047843810948474008
> > vmlinux.o: changed function: c_start.llvm.14107081093236395767
> > vmlinux.o: changed function: c_stop.llvm.14107081093236395767
> > vmlinux.o: changed function: c_next.llvm.14107081093236395767
> > Building patch module: livepatch-min.ko
> > SUCCESS
>
> Thanks for the test case. This one shows the worst case of the .llvm.
> suffix issue.
>
> We have
> c_start.llvm.15251198824366928061
> c_start.llvm.1768504738091882651
> in the original kernel, and
> c_start.llvm.14107081093236395767
> c_start.llvm.10047843810948474008
> in the patched kernel.
>
> All of them are GLOBAL HIDDEN functions, so I don't think we can
> reliably correlate them. Maybe we should fail the build in such cases.
I'm thinking the "correlate <orig> to <patched>" warnings would need to
be an error when there's ambiguity (i.e., two symbols with the same
".llvm.*" mangled name), as there's nothing preventing their symbols'
orders from getting swapped.
And note that changing a symbol from local to global (or vice versa) can
do exactly that, as globals always come at the end.
Also, this problem may be more widespread than the above, as there are a
lot of duplicately named functions in the kernel, with
CONFIG_DEBUG_SECTION_MISMATCH making the problem even worse in practice.
I think we may need to figure out a way to map sym.llvm.<hash> back to
its original FILE symbol so correlate_symbols() can reliably
disambiguate.
The hash seems to be file-specific. I don't think there's a way for
objtool to reverse engineer that.
DWARF could be used to map the symbol to its original file name, but we
can't necessarily rely on CONFIG_DEBUG_INFO.
However, I did find that LLVM has a hidden option:
-mllvm -use-source-filename-for-promoted-locals
which changes the hash to a file path:
c_start.llvm.arch_x86_kernel_cpu_proc_c
That would be (almost) everything we'd need to match a symbol to its
FILE symbol.
The only remaining ambiguity is that FILE symbols only have the
basename, not the full path. So a duplicate "basename+sym" would still
be ambiguous. But that seems much less likely.
We could possibly enforce a new requirement that "basename+sym" be
unique treewide. Then we could maybe even base sympos on that. That
also might help fix some of the other unique symbol headaches I remember
some people having with tracing and possibly elsewhere.
--
Josh
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/8] objtool/klp: klp-build LTO support and tests
2026-02-19 20:51 ` Josh Poimboeuf
@ 2026-02-19 21:31 ` Song Liu
0 siblings, 0 replies; 14+ messages in thread
From: Song Liu @ 2026-02-19 21:31 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: Joe Lawrence, live-patching, jikos, mbenes, pmladek, kernel-team
On Thu, Feb 19, 2026 at 12:51 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
[...]
> >
> > Thanks for the test case. This one shows the worst case of the .llvm.
> > suffix issue.
> >
> > We have
> > c_start.llvm.15251198824366928061
> > c_start.llvm.1768504738091882651
> > in the original kernel, and
> > c_start.llvm.14107081093236395767
> > c_start.llvm.10047843810948474008
> > in the patched kernel.
> >
> > All of them are GLOBAL HIDDEN functions, so I don't think we can
> > reliably correlate them. Maybe we should fail the build in such cases.
>
> I'm thinking the "correlate <orig> to <patched>" warnings would need to
> be an error when there's ambiguity (i.e., two symbols with the same
> ".llvm.*" mangled name), as there's nothing preventing their symbols'
> orders from getting swapped.
Agreed. I changed the logic to error out when there is ambiguity.
> And note that changing a symbol from local to global (or vice versa) can
> do exactly that, as globals always come at the end.
>
> Also, this problem may be more widespread than the above, as there are a
> lot of duplicately named functions in the kernel, with
> CONFIG_DEBUG_SECTION_MISMATCH making the problem even worse in practice.
>
> I think we may need to figure out a way to map sym.llvm.<hash> back to
> its original FILE symbol so correlate_symbols() can reliably
> disambiguate.
>
> The hash seems to be file-specific. I don't think there's a way for
> objtool to reverse engineer that.
>
> DWARF could be used to map the symbol to its original file name, but we
> can't necessarily rely on CONFIG_DEBUG_INFO.
>
> However, I did find that LLVM has a hidden option:
>
> -mllvm -use-source-filename-for-promoted-locals
>
> which changes the hash to a file path:
>
> c_start.llvm.arch_x86_kernel_cpu_proc_c
>
> That would be (almost) everything we'd need to match a symbol to its
> FILE symbol.
I am aware of this option. I think it makes kallsyms too ugly tough.
Also, at the moment, llvm adds these suffixes even when there is
no ambiguity. As a result, there are too many of them. Yonghong
is working on a LLVM change so that it only adds suffixes when
necessary (https://github.com/llvm/llvm-project/pull/178587). But
this won't be available until LLVM-23.
At the moment, I think error out on ambiguity is probably good
enough. This should not happen too often in real world patches.
Does this sound like a viable solution for now?
Thanks,
Song
[...]
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-02-19 21:31 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-12 19:21 [PATCH 0/8] objtool/klp: klp-build LTO support and tests Song Liu
2026-02-12 19:21 ` [PATCH 1/8] objtool/klp: Remove redundent strcmp in correlate_symbols Song Liu
2026-02-12 19:21 ` [PATCH 2/8] objtool/klp: Remove trailing '_' in demangle_name() Song Liu
2026-02-12 19:21 ` [PATCH 3/8] objtool/klp: Use sym->demangled_name for symbol_name hash Song Liu
2026-02-12 19:21 ` [PATCH 4/8] objtool/klp: Also demangle global objects Song Liu
2026-02-12 19:21 ` [PATCH 5/8] objtool/klp: Remove .llvm suffix in demangle_name() Song Liu
2026-02-12 19:21 ` [PATCH 6/8] objtool/klp: Match symbols based on demangled_name for global variables Song Liu
2026-02-12 19:22 ` [PATCH 7/8] objtool/klp: Correlate locals to globals Song Liu
2026-02-12 19:22 ` [PATCH 8/8] livepatch: Add tests for klp-build toolchain Song Liu
2026-02-18 23:00 ` [PATCH 0/8] objtool/klp: klp-build LTO support and tests Joe Lawrence
2026-02-19 3:08 ` Song Liu
2026-02-19 20:47 ` Song Liu
2026-02-19 20:51 ` Josh Poimboeuf
2026-02-19 21:31 ` Song Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox