On Sun, 22 Mar 2026 09:15:39 -0400 Sasha Levin <[email protected]> wrote:
> This series adds CONFIG_KALLSYMS_LINEINFO, which embeds source file:line
> information directly in the kernel image so that stack traces annotate
> every frame with the originating source location - no external tools, no
> debug symbols at runtime, and safe to use in NMI/panic context.
Thanks, I've updated mm.git's mm-nonmm-unstable branch to this version.
> Changes since v3
> =================
>
> - Remove redundant gen_lineinfo entry in scripts/Makefile for
> CONFIG_KALLSYMS_LINEINFO_MODULES (depends on CONFIG_KALLSYMS_LINEINFO
> which already builds it). (Reported by Petr Pavlu)
>
> - Use R_* constants from <elf.h> instead of hardcoded relocation type
> values in r_type_abs32(). (Reported by Petr Pavlu)
>
> - Simplify duplicated-path detection in make_relative(): replace loop
> over every '/' with a direct midpoint check, since true path
> duplication always splits at len/2. (Suggested by Petr Pavlu)
>
> - Fix comment in process_dwarf(): sections in ET_REL objects have
> sh_addr == 0 and therefore overlapping address ranges; this is
> expected behavior, not a "may" situation. (Reported by Petr Pavlu)
>
> - Use U32_MAX instead of UINT_MAX for the module raw_offset bounds
> check, matching the u32 type of the addrs array.
> (Reported by Petr Pavlu)
>
> - Document the assumption that .text is at the start of the MOD_TEXT
> segment in module_lookup_lineinfo(). A proper fix using ELF
> relocations is planned for a future series.
> (Reported by Petr Pavlu)
>
> - Wrap -fno-inline-functions-called-once in $(call cc-option,...) for
> clang compatibility. Clang does not support this GCC-specific flag;
> the noinline attribute is sufficient.
Here's how v3 altered mm.git:
kernel/module/kallsyms.c | 8 +++++--
lib/tests/Makefile | 2 -
scripts/Makefile | 1
scripts/gen_lineinfo.c | 40 +++++++++++++++++--------------------
4 files changed, 26 insertions(+), 25 deletions(-)
--- a/kernel/module/kallsyms.c~b
+++ a/kernel/module/kallsyms.c
@@ -547,13 +547,17 @@ bool module_lookup_lineinfo(struct modul
if (hdr->files_size < hdr->num_files * sizeof(u32))
return false;
- /* Compute offset from module .text base */
+ /*
+ * Compute offset from module .text base.
+ * NOTE: This assumes .text is at the start of the MOD_TEXT segment.
+ * A proper fix would use ELF relocations to reference .text directly.
+ */
text_base = (unsigned long)mod->mem[MOD_TEXT].base;
if (addr < text_base)
return false;
raw_offset = addr - text_base;
- if (raw_offset > UINT_MAX)
+ if (raw_offset > U32_MAX)
return false;
tbl.blk_addrs = base + hdr->blocks_offset;
--- a/lib/tests/Makefile~b
+++ a/lib/tests/Makefile
@@ -36,7 +36,7 @@ obj-$(CONFIG_LIVEUPDATE_TEST) += liveupd
CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o
-CFLAGS_lineinfo_kunit.o += -fno-inline-functions-called-once
+CFLAGS_lineinfo_kunit.o += $(call cc-option,-fno-inline-functions-called-once)
obj-$(CONFIG_LINEINFO_KUNIT_TEST) += lineinfo_kunit.o
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
--- a/scripts/gen_lineinfo.c~b
+++ a/scripts/gen_lineinfo.c
@@ -206,14 +206,11 @@ static const char *make_relative(const c
*/
{
size_t len = strlen(path);
+ size_t mid = len / 2;
- for (p = path; (p = strchr(p, '/')) != NULL; p++) {
- size_t prefix = p - path;
- size_t rest = len - prefix - 1;
-
- if (rest == prefix && !memcmp(path, p + 1, prefix))
- return p + 1;
- }
+ if (len > 1 && path[mid] == '/' &&
+ !memcmp(path, path + mid + 1, mid))
+ return path + mid + 1;
}
/*
@@ -340,17 +337,17 @@ static void find_text_section_range(Elf
static unsigned int r_type_abs32(unsigned int e_machine)
{
switch (e_machine) {
- case EM_X86_64: return 10; /* R_X86_64_32 */
- case EM_386: return 1; /* R_386_32 */
- case EM_AARCH64: return 258; /* R_AARCH64_ABS32 */
- case EM_ARM: return 2; /* R_ARM_ABS32 */
- case EM_RISCV: return 1; /* R_RISCV_32 */
- case EM_S390: return 4; /* R_390_32 */
- case EM_MIPS: return 2; /* R_MIPS_32 */
- case EM_PPC64: return 1; /* R_PPC64_ADDR32 */
- case EM_PPC: return 1; /* R_PPC_ADDR32 */
- case EM_LOONGARCH: return 1; /* R_LARCH_32 */
- case EM_PARISC: return 1; /* R_PARISC_DIR32 */
+ case EM_X86_64: return R_X86_64_32;
+ case EM_386: return R_386_32;
+ case EM_AARCH64: return R_AARCH64_ABS32;
+ case EM_ARM: return R_ARM_ABS32;
+ case EM_RISCV: return R_RISCV_32;
+ case EM_S390: return R_390_32;
+ case EM_MIPS: return R_MIPS_32;
+ case EM_PPC64: return R_PPC64_ADDR32;
+ case EM_PPC: return R_PPC_ADDR32;
+ case EM_LOONGARCH: return R_LARCH_32;
+ case EM_PARISC: return R_PARISC_DIR32;
default: return 0;
}
}
@@ -492,9 +489,10 @@ static void process_dwarf(Dwarf *dwarf,
/*
* In module mode, keep only .text addresses.
- * In ET_REL .ko files, .init.text/.exit.text may
- * overlap with .text address ranges, so we must
- * explicitly check against the .text bounds.
+ * In ET_REL .ko files, .text, .init.text and
+ * .exit.text all have sh_addr == 0 and therefore
+ * overlapping address ranges. Explicitly check
+ * against the .text bounds.
*/
if (module_mode && text_section_end >
text_section_start &&
(addr < text_section_start || addr >=
text_section_end))
--- a/scripts/Makefile~b
+++ a/scripts/Makefile
@@ -5,7 +5,6 @@
hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms
hostprogs-always-$(CONFIG_KALLSYMS_LINEINFO) += gen_lineinfo
-hostprogs-always-$(CONFIG_KALLSYMS_LINEINFO_MODULES) += gen_lineinfo
hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
_