>From 0d9e9498a301a3d14fb6b5b0449c2aaf4d072252 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
Date: Wed, 22 Aug 2012 16:46:20 +0800
Subject: [PATCH 4/4] support core dump file with kdump backup region

---
 defs.h    |    6 +-
 main.c    |    3 +-
 netdump.c |  270 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 netdump.h |    5 +
 sadump.c  |  163 +------------------------------------
 5 files changed, 284 insertions(+), 163 deletions(-)

diff --git a/defs.h b/defs.h
index 96c9997..444888e 100755
--- a/defs.h
+++ b/defs.h
@@ -273,6 +273,8 @@ struct number_option {
 #define KCORE_LOCAL    (0x100)     
 #define KCORE_ELF32    (0x200)
 #define KCORE_ELF64    (0x400)
+#define QEMU_MEM_DUMP_KDUMP_BACKUP \
+                       (0x800)
 #define KVMDUMP_LOCAL    (0x1)
 #define KVMDUMP_VALID()  (kvm->flags & (KVMDUMP_LOCAL))
 
@@ -5006,6 +5008,8 @@ int read_proc_kcore(int, void *, int, ulong, physaddr_t);
 int write_proc_kcore(int, void *, int, ulong, physaddr_t);
 int kcore_memory_dump(FILE *);
 void dump_register_for_qemu_mem_dump(void);
+void *get_vmcore_data(void);
+void kdump_backup_region_init(void);
 
 /*
  *  diskdump.c
@@ -5115,7 +5119,7 @@ void sadump_show_diskset(void);
 int sadump_is_zero_excluded(void);
 void sadump_set_zero_excluded(void);
 void sadump_unset_zero_excluded(void);
-void sadump_kdump_backup_region_init(void);
+void *get_sadump_data(void);
 
 /*
  * qemu.c
diff --git a/main.c b/main.c
index 9dced6e..7650b8c 100755
--- a/main.c
+++ b/main.c
@@ -640,8 +640,7 @@ main_loop(void)
         if (!(pc->flags & GDB_INIT)) {
 		gdb_session_init();
 		show_untrusted_files();
-		if (SADUMP_DUMPFILE())
-			sadump_kdump_backup_region_init();
+		kdump_backup_region_init();
 		if (XEN_HYPER_MODE()) {
 #ifdef XEN_HYPERVISOR_ARCH
 			machdep_init(POST_GDB);
diff --git a/netdump.c b/netdump.c
index bdc2757..b4f0311 100644
--- a/netdump.c
+++ b/netdump.c
@@ -20,6 +20,7 @@
 
 #include "defs.h"
 #include "netdump.h"
+#include "sadump.h"
 
 static struct vmcore_data vmcore_data = { 0 };
 static struct vmcore_data *nd = &vmcore_data;
@@ -932,6 +933,8 @@ netdump_memory_dump(FILE *fp)
 		netdump_print("%sKDUMP_ELF64", others++ ? "|" : "");
 	if (nd->flags & PARTIAL_DUMP)
 		netdump_print("%sPARTIAL_DUMP", others++ ? "|" : "");
+	if (nd->flags & QEMU_MEM_DUMP_KDUMP_BACKUP)
+		netdump_print("%sQEMU_MEM_DUMP_KDUMP_BACKUP", others++ ? "|" : "");
 	netdump_print(") %s\n", FLAT_FORMAT() ? "[FLAT]" : "");
 	if ((pc->flags & RUNTIME) && symbol_exists("dump_level")) {
 		int dump_level;
@@ -1072,6 +1075,10 @@ netdump_memory_dump(FILE *fp)
         	}
 	}
 	netdump_print("\n");
+	netdump_print("       backup_src_start: %llx\n", nd->backup_src_start);
+	netdump_print("        backup_src_size: %lx\n", nd->backup_src_size);
+	netdump_print("          backup_offset: %llx\n", nd->backup_offset);
+	netdump_print("\n");
 
         switch (DUMPFILE_FORMAT(nd->flags))
 	{
@@ -2746,6 +2753,18 @@ read_kdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
 {
 	physaddr_t paddr_in = paddr;
 
+	if (nd->flags & QEMU_MEM_DUMP_KDUMP_BACKUP &&
+	    paddr >= nd->backup_src_start &&
+	    paddr < nd->backup_src_start + nd->backup_src_size) {
+
+		paddr += nd->backup_offset - nd->backup_src_start;
+
+		if (CRASHDEBUG(1))
+			error(INFO,
+			    "qemu_mem_dump: kdump backup region: %#llx => %#llx\n",
+			    paddr_in, paddr);
+	}
+
 	if (XEN_CORE_DUMPFILE() && !XEN_HYPER_MODE()) {
 	    	if (!(nd->xen_kdump_data->flags & KDUMP_P2M_INIT)) {
         		if (!machdep->xen_kdump_p2m_create)
@@ -3605,3 +3624,254 @@ dump_register_for_qemu_mem_dump(void)
 
 	nd->ofp = fpsave;
 }
+
+void *
+get_vmcore_data(void)
+{
+	return nd;
+}
+
+/**
+ * kdump saves the first 640kB physical memory for BIOS to use the
+ * range on boot of 2nd kernel. Read request to the 640k should be 
+ * translated to the back up region. This function searches kexec
+ * resources for the backup region.
+ */
+void
+kdump_backup_region_init(void)
+{
+	char buf[BUFSIZE];
+	ulong i, total, kexec_crash_image_p, elfcorehdr_p;
+	Elf32_Off e_phoff32;
+	Elf64_Off e_phoff64;
+	uint16_t e_phnum, e_phentsize;
+	ulonglong backup_offset;
+	ulonglong backup_src_start;
+	ulong backup_src_size;
+	int kimage_segment_len;
+	size_t bufsize;
+	void *vd;
+	int archflag;  /* indicate the arch of core file: 1 -> 32bit */
+	char typename[BUFSIZE];
+
+	e_phoff32 = e_phoff64 = 0;
+	archflag = 0;
+
+	if (SADUMP_DUMPFILE()) {
+		vd = get_sadump_data();
+		archflag = 0;
+		sprintf(typename, "sadump");
+	} else if (pc->flags2 & QEMU_MEM_DUMP) {
+		vd = get_vmcore_data();
+		if (((struct vmcore_data *)vd)->flags & KDUMP_ELF32)
+			archflag = 1;
+		else
+			archflag = 0;
+		sprintf(typename, "qemu mem dump");
+	} else
+		return;
+
+	if (!readmem(symbol_value("kexec_crash_image"), KVADDR,
+		     &kexec_crash_image_p, sizeof(ulong),
+		     "kexec backup region: kexec_crash_image",
+		     QUIET|RETURN_ON_ERROR))
+		goto error;
+
+	if (!kexec_crash_image_p) {
+		if (CRASHDEBUG(1))
+			error(INFO, "%s: kexec_crash_image not loaded\n", typename);
+		return;
+	}
+
+	kimage_segment_len = get_array_length("kimage.segment", NULL,
+					      STRUCT_SIZE("kexec_segment"));
+
+	if (!readmem(kexec_crash_image_p + MEMBER_OFFSET("kimage", "segment"),
+		     KVADDR, buf, MEMBER_SIZE("kimage", "segment"),
+		     "kexec backup region: kexec_crash_image->segment",
+		     QUIET|RETURN_ON_ERROR))
+		goto error;
+
+	elfcorehdr_p = 0;
+	for (i = 0; i < kimage_segment_len; ++i) {
+		char e_ident[EI_NIDENT];
+		ulong mem;
+
+		mem = ULONG(buf + i * STRUCT_SIZE("kexec_segment") +
+			    MEMBER_OFFSET("kexec_segment", "mem"));
+		if (!mem)
+			continue;
+
+		if (!readmem(mem, PHYSADDR, e_ident, SELFMAG,
+			     "elfcorehdr: e_ident",
+			     QUIET|RETURN_ON_ERROR))
+			goto error;
+
+		if (strncmp(ELFMAG, e_ident, SELFMAG) == 0) {
+			elfcorehdr_p = mem;
+			break;
+		}
+	}
+	if (!elfcorehdr_p) {
+		if (CRASHDEBUG(1))
+			error(INFO,
+	"%s: elfcorehdr not found in segments of kexec_crash_image\n", typename);
+		goto error;
+	}
+	
+	if (archflag) {
+		if (!readmem(elfcorehdr_p, PHYSADDR, buf, STRUCT_SIZE("elf32_hdr"),
+			"elfcorehdr", QUIET|RETURN_ON_ERROR))
+			goto error;
+
+		e_phnum = USHORT(buf + MEMBER_OFFSET("elf32_hdr", "e_phnum"));
+		e_phentsize = USHORT(buf + MEMBER_OFFSET("elf32_hdr", "e_phentsize"));
+		e_phoff32 = ULONG(buf + MEMBER_OFFSET("elf32_hdr", "e_phoff"));
+	} else {
+		if (!readmem(elfcorehdr_p, PHYSADDR, buf, STRUCT_SIZE("elf64_hdr"),
+			    "elfcorehdr", QUIET|RETURN_ON_ERROR))
+			goto error;
+
+		e_phnum = USHORT(buf + MEMBER_OFFSET("elf64_hdr", "e_phnum"));
+		e_phentsize = USHORT(buf + MEMBER_OFFSET("elf64_hdr", "e_phentsize"));
+		e_phoff64 = ULONG(buf + MEMBER_OFFSET("elf64_hdr", "e_phoff"));
+	}
+
+	backup_src_start = backup_src_size = backup_offset = 0;
+
+	for (i = 0; i < e_phnum; ++i) {
+		uint32_t p_type;
+		Elf32_Off p_offset32;
+		Elf64_Off p_offset64;
+		Elf32_Addr p_paddr32;
+		Elf64_Addr p_paddr64;
+		uint32_t p_memsz32;
+		uint64_t p_memsz64;
+
+		if (archflag) {
+			if (!readmem(elfcorehdr_p + e_phoff32 + i * e_phentsize,
+				    PHYSADDR, buf, e_phentsize,
+				    "elfcorehdr: program header",
+				    QUIET|RETURN_ON_ERROR))
+				goto error;
+
+			p_type = UINT(buf+MEMBER_OFFSET("elf32_phdr","p_type"));
+			p_offset32 = ULONG(buf+MEMBER_OFFSET("elf32_phdr","p_offset"));
+			p_paddr32 = ULONG(buf+MEMBER_OFFSET("elf32_phdr","p_paddr"));
+			p_memsz32 = ULONG(buf+MEMBER_OFFSET("elf32_phdr","p_memsz"));
+		} else {
+			if (!readmem(elfcorehdr_p + e_phoff64 + i * e_phentsize,
+				    PHYSADDR, buf, e_phentsize,
+				    "elfcorehdr: program header",
+				    QUIET|RETURN_ON_ERROR))
+				goto error;
+
+			p_type = UINT(buf+MEMBER_OFFSET("elf64_phdr","p_type"));
+			p_offset64 = ULONG(buf+MEMBER_OFFSET("elf64_phdr","p_offset"));
+			p_paddr64 = ULONG(buf+MEMBER_OFFSET("elf64_phdr","p_paddr"));
+			p_memsz64 = ULONG(buf+MEMBER_OFFSET("elf64_phdr","p_memsz"));
+		}
+
+		/*
+		 * kexec marks backup region PT_LOAD by assigning
+		 * backup region address in p_offset, and p_addr in
+		 * p_offsets for other PT_LOAD entries.
+		 */
+		if (archflag) {
+			if (p_type == PT_LOAD &&
+			    p_paddr32 <= KEXEC_BACKUP_SRC_END &&
+			    p_paddr32 != p_offset32) {
+
+				backup_src_start = p_paddr32;
+				backup_src_size = p_memsz32;
+				backup_offset = p_offset32;
+
+				if (CRASHDEBUG(1))
+					error(INFO,
+				"%s: kexec backup region found: "
+				"START: %#016llx SIZE: %#016lx OFFSET: %#016llx\n",
+				typename, backup_src_start, backup_src_size, backup_offset);
+
+				break;
+			}
+		} else {
+			if (p_type == PT_LOAD &&
+			    p_paddr64 <= KEXEC_BACKUP_SRC_END &&
+			    p_paddr64 != p_offset64) {
+
+				backup_src_start = p_paddr64;
+				backup_src_size = p_memsz64;
+				backup_offset = p_offset64;
+
+				if (CRASHDEBUG(1))
+					error(INFO,
+				"%s: kexec backup region found: "
+				"START: %#016llx SIZE: %#016lx OFFSET: %#016llx\n",
+				typename, backup_src_start, backup_src_size, backup_offset);
+
+				break;
+			}
+		}
+	}
+
+	if (!backup_offset) {
+		if (CRASHDEBUG(1))
+	error(WARNING, "%s: backup region not found in elfcorehdr\n", typename);
+		return;
+	}
+
+	bufsize = BUFSIZE;
+	for (total = 0; total < backup_src_size; total += bufsize) {
+		char backup_buf[BUFSIZE];
+		int j;
+
+		if (backup_src_size - total < BUFSIZE)
+			bufsize = backup_src_size - total;
+
+		if (!readmem(backup_offset + total, PHYSADDR, backup_buf,
+			     bufsize, "backup source", QUIET|RETURN_ON_ERROR))
+			goto error;
+
+		/*
+		 * We're assuming the backup region is initialized
+		 * with 0 filled if kdump has not run.
+		 */
+		for (j = 0; j < bufsize; ++j) {
+			if (backup_buf[j]) {
+
+				if (SADUMP_DUMPFILE()) {
+					((struct sadump_data *)vd)->flags |=
+						SADUMP_KDUMP_BACKUP;
+					((struct sadump_data *)vd)->backup_src_start =
+						backup_src_start;
+					((struct sadump_data *)vd)->backup_src_size =
+						backup_src_size;
+					((struct sadump_data *)vd)->backup_offset =
+						backup_offset;
+				} else if (pc->flags2 & QEMU_MEM_DUMP) {
+					((struct vmcore_data *)vd)->flags |=
+						QEMU_MEM_DUMP_KDUMP_BACKUP;
+					((struct vmcore_data *)vd)->backup_src_start =
+						backup_src_start;
+					((struct vmcore_data *)vd)->backup_src_size =
+						backup_src_size;
+					((struct vmcore_data *)vd)->backup_offset =
+						backup_offset;
+				}
+
+				if (CRASHDEBUG(1))
+error(INFO, "%s: backup region is used: %llx\n", typename, backup_offset + total + j);
+
+				return;
+			}
+		}
+	}
+
+	if (CRASHDEBUG(1))
+		error(INFO, "%s: kexec backup region not used\n", typename);
+
+	return;
+
+error:
+	error(WARNING, "failed to init kexec backup region\n");
+}
diff --git a/netdump.h b/netdump.h
index 0c49871..98735e3 100644
--- a/netdump.h
+++ b/netdump.h
@@ -73,6 +73,11 @@ struct vmcore_data {
 	struct xen_kdump_data *xen_kdump_data;
 	void *vmcoreinfo;
 	uint size_vmcoreinfo;
+/* Backup Region, First 640K of System RAM. */
+#define KEXEC_BACKUP_SRC_END	0x0009ffff
+	ulonglong backup_src_start;
+	ulong backup_src_size;
+	ulonglong backup_offset;
 };
 
 /*
diff --git a/sadump.c b/sadump.c
index f15d6de..a1fc685 100644
--- a/sadump.c
+++ b/sadump.c
@@ -1608,165 +1608,8 @@ void sadump_unset_zero_excluded(void)
 	sd->flags &= ~SADUMP_ZERO_EXCLUDED;
 }
 
-/**
- * kdump saves the first 640kB physical memory for BIOS to use the
- * range on boot of 2nd kernel. sadump translates read request to the
- * 640kB region as to the back up region. This function seachs kexec
- * resources for the backup region.
- */
-void sadump_kdump_backup_region_init(void)
+void *
+get_sadump_data(void)
 {
-	char buf[BUFSIZE];
-	ulong i, total, kexec_crash_image_p, elfcorehdr_p;
-	Elf64_Off e_phoff;
-	uint16_t e_phnum, e_phentsize;
-	uint64_t backup_offset;
-	ulonglong backup_src_start;
-	ulong backup_src_size;
-	int kimage_segment_len;
-	size_t bufsize;
-
-	if (!readmem(symbol_value("kexec_crash_image"), KVADDR,
-		     &kexec_crash_image_p, sizeof(ulong),
-		     "kexec backup region: kexec_crash_image",
-		     QUIET|RETURN_ON_ERROR))
-		goto error;
-
-	if (!kexec_crash_image_p) {
-		if (CRASHDEBUG(1))
-			error(INFO, "sadump: kexec_crash_image not loaded\n");
-		return;
-	}
-
-	kimage_segment_len = get_array_length("kimage.segment", NULL,
-					      STRUCT_SIZE("kexec_segment"));
-
-	if (!readmem(kexec_crash_image_p + MEMBER_OFFSET("kimage", "segment"),
-		     KVADDR, buf, MEMBER_SIZE("kimage", "segment"),
-		     "kexec backup region: kexec_crash_image->segment",
-		     QUIET|RETURN_ON_ERROR))
-		goto error;
-
-	elfcorehdr_p = 0;
-	for (i = 0; i < kimage_segment_len; ++i) {
-		char e_ident[EI_NIDENT];
-		ulong mem;
-
-		mem = ULONG(buf + i * STRUCT_SIZE("kexec_segment") +
-			    MEMBER_OFFSET("kexec_segment", "mem"));
-		if (!mem)
-			continue;
-
-		if (!readmem(mem, PHYSADDR, e_ident, SELFMAG,
-			     "elfcorehdr: e_ident",
-			     QUIET|RETURN_ON_ERROR))
-			goto error;
-
-		if (strncmp(ELFMAG, e_ident, SELFMAG) == 0) {
-			elfcorehdr_p = mem;
-			break;
-		}
-	}
-	if (!elfcorehdr_p) {
-		if (CRASHDEBUG(1))
-			error(INFO,
-	"sadump: elfcorehdr not found in segments of kexec_crash_image\n");
-		goto error;
-	}
-	if (!readmem(elfcorehdr_p, PHYSADDR, buf, STRUCT_SIZE("elf64_hdr"),
-		     "elfcorehdr", QUIET|RETURN_ON_ERROR))
-		goto error;
-
-	e_phnum = USHORT(buf + MEMBER_OFFSET("elf64_hdr", "e_phnum"));
-	e_phentsize = USHORT(buf + MEMBER_OFFSET("elf64_hdr", "e_phentsize"));
-	e_phoff = ULONG(buf + MEMBER_OFFSET("elf64_hdr", "e_phoff"));
-
-	backup_src_start = backup_src_size = backup_offset = 0;
-
-	for (i = 0; i < e_phnum; ++i) {
-		uint32_t p_type;
-		Elf64_Off p_offset;
-		Elf64_Addr p_paddr;
-		uint64_t p_memsz;
-
-		if (!readmem(elfcorehdr_p + e_phoff + i * e_phentsize,
-			     PHYSADDR, buf, e_phentsize,
-			     "elfcorehdr: program heaer",
-			     QUIET|RETURN_ON_ERROR))
-			goto error;
-
-		p_type = UINT(buf+MEMBER_OFFSET("elf64_phdr","p_type"));
-		p_offset=ULONGLONG(buf+MEMBER_OFFSET("elf64_phdr","p_offset"));
-		p_paddr = ULONGLONG(buf+MEMBER_OFFSET("elf64_phdr","p_paddr"));
-		p_memsz = ULONGLONG(buf+MEMBER_OFFSET("elf64_phdr","p_memsz"));
-
-		/*
-		 * kexec marks backup region PT_LOAD by assigning
-		 * backup region address in p_offset, and p_addr in
-		 * p_offsets for other PT_LOAD entries.
-		 */
-		if (p_type == PT_LOAD &&
-		    p_paddr <= KEXEC_BACKUP_SRC_END &&
-		    p_paddr != p_offset) {
-
-			backup_src_start = p_paddr;
-			backup_src_size = p_memsz;
-			backup_offset = p_offset;
-
-			if (CRASHDEBUG(1))
-				error(INFO,
-				      "sadump: kexec backup region found: "
-			  "START: %#016llx SIZE: %#016lx OFFSET: %#016llx\n",
-			  backup_src_start, backup_src_size, backup_offset);
-
-			break;
-		}
-	}
-
-	if (!backup_offset) {
-		if (CRASHDEBUG(1))
-	error(WARNING, "sadump: backup region not found in elfcorehdr\n");
-		return;
-	}
-
-	bufsize = BUFSIZE;
-	for (total = 0; total < backup_src_size; total += bufsize) {
-		char backup_buf[BUFSIZE];
-		int j;
-
-		if (backup_src_size - total < BUFSIZE)
-			bufsize = backup_src_size - total;
-
-		if (!readmem(backup_offset + total, PHYSADDR, backup_buf,
-			     bufsize, "backup source", QUIET|RETURN_ON_ERROR))
-			goto error;
-
-		/*
-		 * We're assuming the backup resion is initialized
-		 * with 0 filled if kdump has not run.
-		 */
-		for (j = 0; j < bufsize; ++j) {
-			if (backup_buf[j]) {
-
-				sd->flags |= SADUMP_KDUMP_BACKUP;
-				sd->backup_src_start = backup_src_start;
-				sd->backup_src_size = backup_src_size;
-				sd->backup_offset = backup_offset;
-
-				if (CRASHDEBUG(1))
-error(INFO, "sadump: backup region is used: %lx\n", backup_offset + total + j);
-
-				return;
-			}
-		}
-	}
-
-	if (CRASHDEBUG(1))
-		error(INFO, "sadump: kexec backup region not used\n");
-
-	return;
-
-error:
-	error(WARNING, "failed to init kexec backup region\n");
-
+	return sd;
 }
-- 
1.7.1

