FYI: x86_64 bug when using gdb with vmcore

Simon Horman horms at verge.net.au
Wed Feb 17 02:18:39 EST 2010


On Fri, Feb 05, 2010 at 11:53:18AM -0500, Dave Anderson wrote:
> 
> The kexec/arch/x86_64/crashdump-x86_64.h file contains a
> stale PAGE_OFFSET value.  In 2.6.27 it was changed from
> 0xffff810000000000UL to 0xffff880000000000UL.  This is
> only a problem when using gdb with the vmlinux/vmcore
> pair, because gdb relies upon the PT_LOAD segment's p_vaddr
> values in the ELF header to be correct.
> 
> Anyway, in the RHEL6 kexec-tools, this simple patch 
> was made:
> 
> -#define PAGE_OFFSET            0xffff810000000000UL
> +#define PAGE_OFFSET            0xffff880000000000UL
> 
> which is OK since the RHEL6 version of kexec-tools
> will only be used with RHEL6 kernels.  
> 
> But for backwards compatibility, the better way to do 
> it would be to check the utsname of the running kernel, 
> and use the right value.
> 
> But again, this is only required for gdb usage.  The 
> crash utility (and makedumpfile) make kernel version checks 
> to determine which x86_64 PAGE_OFFSET value is applicable,
> and don't rely on the ELF header p_vaddr values for
> the unity-mapped regions.  

Hi Dave,

Something like this?

----------------------------------------------------------------------

x86_64: use correct PAGE_OFFSET

This fixes a bug when using gdb with vmcore
as explained by Dave Anderson:

The kexec/arch/x86_64/crashdump-x86_64.h file contains a
stale PAGE_OFFSET value.  In 2.6.27 it was changed from
0xffff810000000000UL to 0xffff880000000000UL.  This is
only a problem when using gdb with the vmlinux/vmcore
pair, because gdb relies upon the PT_LOAD segment's p_vaddr
values in the ELF header to be correct.

Cc: Dave Anderson <anderson at redhat.com>
Signed-off-by: Simon Horman <horms at verge.net.au>

Index: kexec-tools/kexec/arch/x86_64/crashdump-x86_64.c
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/crashdump-x86_64.c	2010-02-17 16:04:18.000000000 +1100
+++ kexec-tools/kexec/arch/x86_64/crashdump-x86_64.c	2010-02-17 16:18:42.000000000 +1100
@@ -36,15 +36,6 @@
 #include "crashdump-x86_64.h"
 #include <x86/x86-linux.h>
 
-static struct crash_elf_info elf_info =
-{
-	class: ELFCLASS64,
-	data: ELFDATA2LSB,
-	machine: EM_X86_64,
-	backup_src_start: BACKUP_SRC_START,
-	backup_src_end: BACKUP_SRC_END,
-	page_offset: PAGE_OFFSET,
-};
 
 /* Forward Declaration. */
 static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end);
@@ -604,6 +595,16 @@ int load_crashdump_segments(struct kexec
 	int nr_ranges, align = 1024, i;
 	struct memory_range *mem_range, *memmap_p;
 
+	struct crash_elf_info elf_info =
+	{
+		class: ELFCLASS64,
+		data: ELFDATA2LSB,
+		machine: EM_X86_64,
+		backup_src_start: BACKUP_SRC_START,
+		backup_src_end: BACKUP_SRC_END,
+		page_offset: page_offset,
+	};
+
 	if (get_kernel_paddr(info))
 		return -1;
 
Index: kexec-tools/kexec/arch/x86_64/crashdump-x86_64.h
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/crashdump-x86_64.h	2010-02-17 16:04:18.000000000 +1100
+++ kexec-tools/kexec/arch/x86_64/crashdump-x86_64.h	2010-02-17 17:41:10.000000000 +1100
@@ -1,12 +1,16 @@
 #ifndef CRASHDUMP_X86_64_H
 #define CRASHDUMP_X86_64_H
 
+#include "../../kexec.h"
+
 int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 				unsigned long max_addr, unsigned long min_base);
 
 #define __START_KERNEL_map      0xffffffff80000000UL
-#define PAGE_OFFSET		0xffff810000000000UL
-#define __pa(x)                 (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
+
+extern unsigned long page_offset;
+
+#define __pa(x)                 (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - page_offset)
 
 #define MAXMEM           0x3fffffffffffUL
 
Index: kexec-tools/kexec/kexec.c
===================================================================
--- kexec-tools.orig/kexec/kexec.c	2010-02-17 16:04:18.000000000 +1100
+++ kexec-tools/kexec/kexec.c	2010-02-17 16:11:06.000000000 +1100
@@ -1041,6 +1041,8 @@ int main(int argc, char *argv[])
 	};
 	static const char short_options[] = KEXEC_OPT_STR;
 
+	arch_init();
+
 	opterr = 0; /* Don't complain about unrecognized options here */
 	while ((opt = getopt_long(argc, argv, short_options,
 				  options, 0)) != -1) {
Index: kexec-tools/kexec/Makefile
===================================================================
--- kexec-tools.orig/kexec/Makefile	2010-02-17 16:06:32.000000000 +1100
+++ kexec-tools/kexec/Makefile	2010-02-17 16:11:11.000000000 +1100
@@ -44,6 +44,8 @@ $(ARCH)_ADD_BUFFER		= kexec/add_buffer.c
 KEXEC_SRCS += $($(ARCH)_ADD_BUFFER)
 $(ARCH)_ARCH_REUSE_INITRD	= kexec/arch_reuse_initrd.c
 KEXEC_SRCS += $($(ARCH)_ARCH_REUSE_INITRD)
+$(ARCH)_ARCH_INIT		= kexec/arch_init.c
+KEXEC_SRCS += $($(ARCH)_ARCH_INIT)
 
 include $(srcdir)/kexec/arch/alpha/Makefile
 include $(srcdir)/kexec/arch/arm/Makefile
Index: kexec-tools/kexec/arch/x86_64/Makefile
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/Makefile	2010-02-17 17:33:59.000000000 +1100
+++ kexec-tools/kexec/arch/x86_64/Makefile	2010-02-17 17:36:22.000000000 +1100
@@ -13,6 +13,8 @@ x86_64_KEXEC_SRCS += kexec/arch/x86_64/k
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-elf-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-elf-rel-x86_64.c
 
+x86_64_ARCH_INIT = kexec/arch/x86_64/arch_init.c
+
 dist += kexec/arch/x86_64/Makefile $(x86_64_KEXEC_SRCS)			\
 	kexec/arch/x86_64/kexec-x86_64.h kexec/arch/x86_64/crashdump-x86_64.h \
 	kexec/arch/x86_64/include/arch/options.h
Index: kexec-tools/kexec/arch/x86_64/arch_init.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ kexec-tools/kexec/arch/x86_64/arch_init.c	2010-02-17 18:06:52.000000000 +1100
@@ -0,0 +1,83 @@
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "crashdump-x86_64.h"
+
+#define KERNEL_VERSION(major, minor, patch) \
+	(((major) << 16) | ((minor) << 8) | patch)
+
+long kernel_version(void)
+{
+	struct utsname utsname;
+	unsigned long major, minor, patch;
+	char *p;
+
+	if (uname(&utsname) < 0) {
+		fprintf(stderr, "uname failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	p = utsname.release;
+	major = strtoul(p, &p, 10);
+	if (major == ULONG_MAX) {
+		fprintf(stderr, "strtoul failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (*p++ != '.') {
+		fprintf(stderr, "Unsupported utsname.release: %s\n",
+			utsname.release);
+		return -1;
+	}
+
+	minor = strtoul(p, &p, 10);
+	if (major == ULONG_MAX) {
+		fprintf(stderr, "strtoul failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (*p++ != '.') {
+		fprintf(stderr, "Unsupported utsname.release: %s\n",
+			utsname.release);
+		return -1;
+	}
+
+	patch = strtoul(p, &p, 10);
+	if (major == ULONG_MAX) {
+		fprintf(stderr, "strtoul failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (major >= 256 || minor >= 256 || patch >= 256) {
+		fprintf(stderr, "Unsupported utsname.release: %s\n",
+			utsname.release);
+		return -1;
+	}
+
+	return KERNEL_VERSION(major, minor, patch);
+}
+
+#define PAGE_OFFSET_PRE_2_6_27	0xffff810000000000UL
+#define PAGE_OFFSET		0xffff880000000000UL
+
+unsigned long page_offset;
+
+int arch_init(void)
+{
+	int kv;
+
+	kv = kernel_version();
+	if (kv < 0)
+		return -1;
+
+	if (kv < KERNEL_VERSION(2, 4, 27))
+		page_offset = PAGE_OFFSET_PRE_2_6_27;
+	else
+		page_offset = PAGE_OFFSET;
+
+	return 0;
+}
Index: kexec-tools/kexec/arch_init.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ kexec-tools/kexec/arch_init.c	2010-02-17 16:12:14.000000000 +1100
@@ -0,0 +1,4 @@
+int arch_init(void)
+{
+	return 0;
+}
Index: kexec-tools/kexec/kexec.h
===================================================================
--- kexec-tools.orig/kexec/kexec.h	2010-02-17 16:12:44.000000000 +1100
+++ kexec-tools/kexec/kexec.h	2010-02-17 16:13:03.000000000 +1100
@@ -249,6 +249,8 @@ int kexec_iomem_for_each_line(char *matc
 int parse_iomem_single(char *str, uint64_t *start, uint64_t *end);
 const char * proc_iomem(void);
 
+int arch_init(void);
+
 extern int add_backup_segments(struct kexec_info *info,
 			       unsigned long backup_base,
 			       unsigned long backup_size);



More information about the kexec mailing list