[PATCH] util_lib: Add direct map fallback in vaddr_to_offset()

Pnina Feder pnina.feder at mobileye.com
Thu Nov 6 04:03:44 PST 2025


The vmcore-dmesg tool could fail with the message:
"No program header covering vaddr 0x%llx found kexec bug?"

This occurred when a virtual address belonged to the kernel’s direct
mapping region, which may not be covered by any PT_LOAD segment in
the vmcore ELF headers.

Add a direct-map fallback in vaddr_to_offset() that converts such
virtual addresses using the known page and physical offsets. This
allows resolving these addresses correctly.

Tested on Linux 6.16 (RISC-V)

Signed-off-by: Pnina Feder <pnina.feder at mobileye.com>
---
 util_lib/elf_info.c | 58 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 10 deletions(-)

diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
index b005245..589bc1a 100644
--- a/util_lib/elf_info.c
+++ b/util_lib/elf_info.c
@@ -72,6 +72,7 @@ static uint16_t log_offset_len = UINT16_MAX;
 static uint16_t log_offset_text_len = UINT16_MAX;
 
 static uint64_t phys_offset = UINT64_MAX;
+static uint64_t page_offset = UINT64_MAX;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define ELFDATANATIVE ELFDATA2LSB
@@ -115,7 +116,26 @@ static uint64_t vaddr_to_offset(uint64_t vaddr)
 			continue;
 		return (vaddr - phdr[i].p_vaddr) + phdr[i].p_offset;
 	}
-	fprintf(stderr, "No program header covering vaddr 0x%llxfound kexec bug?\n",
+
+	/* Direct map fallback */
+	if (page_offset != UINT64_MAX &&
+		phys_offset != UINT64_MAX &&
+		vaddr >= page_offset) {
+
+		uint64_t paddr = 0;
+
+		paddr = vaddr - (page_offset - phys_offset);
+
+		for (i = 0; i < ehdr.e_phnum; i++) {
+			if (phdr[i].p_paddr > paddr)
+				continue;
+			if ((phdr[i].p_paddr + phdr[i].p_memsz) <= paddr)
+				continue;
+			return phdr[i].p_offset + (paddr - phdr[i].p_paddr);
+		}
+	}
+
+	fprintf(stderr, "No program header covering vaddr 0x%llx found kexec bug?\n",
 		(unsigned long long)vaddr);
 	exit(30);
 }
@@ -309,6 +329,20 @@ int get_pt_load(int idx,
 	return 1;
 }
 
+static inline int parse_phys_offset(const char *str, char *pos)
+{
+	char *endp;
+
+	phys_offset = strtoul(pos + strlen(str), &endp, 10);
+	if (strlen(endp) != 0)
+		phys_offset = strtoul(pos + strlen(str), &endp, 16);
+	if ((phys_offset == LONG_MAX) || strlen(endp) != 0) {
+		fprintf(stderr, "Invalid data %s\n", pos);
+		return -1;
+	}
+	return 0;
+}
+
 #define NOT_FOUND_LONG_VALUE		(-1)
 
 void (*arch_scan_vmcoreinfo)(char *pos);
@@ -319,7 +353,7 @@ void scan_vmcoreinfo(char *start, size_t size)
 	char *pos, *eol;
 	char temp_buf[1024];
 	bool last_line = false;
-	char *str, *endp;
+	char *str;
 
 #define SYMBOL(sym) {					\
 	.str = "SYMBOL(" #sym  ")=",			\
@@ -543,17 +577,21 @@ void scan_vmcoreinfo(char *start, size_t size)
 		/* Check for PHYS_OFFSET number */
 		str = "NUMBER(PHYS_OFFSET)=";
 		if (memcmp(str, pos, strlen(str)) == 0) {
-			phys_offset = strtoul(pos + strlen(str), &endp,
-							10);
-			if (strlen(endp) != 0)
-				phys_offset = strtoul(pos + strlen(str), &endp, 16);
-			if ((phys_offset == LONG_MAX) || strlen(endp) != 0) {
-				fprintf(stderr, "Invalid data %s\n",
-					pos);
+			if (parse_phys_offset(str, pos) != 0)
 				break;
-			}
 		}
 
+		/* Check for PHYS_OFFSET number on some arch it called phys_ram_base*/
+		str = "NUMBER(phys_ram_base)=";
+		if (memcmp(str, pos, strlen(str)) == 0) {
+			if (parse_phys_offset(str, pos) != 0)
+				break;
+		}
+
+		str = "NUMBER(PAGE_OFFSET)=";
+		if (memcmp(str, pos, strlen(str)) == 0)
+			page_offset = strtoull(pos + strlen(str), NULL, 16);
+
 		if (arch_scan_vmcoreinfo != NULL)
 			(*arch_scan_vmcoreinfo)(pos);
 
-- 
2.43.0




More information about the kexec mailing list