Re: [PATCH] add support to "virsh dump-guest-memory"(qemu memory dump)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At 2012-8-20 16:32, qiaonuohan wrote:

I have modified the patches, and they are based on crash 6.0.9.

I find some mistakes in my former patches, please ignore them and refer
to the attachments of this mail.

--
--
Regards
Qiao Nuohan


>From 2807425ceee28e0bdf54557028ec188d1f204e16 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Mon, 20 Aug 2012 17:15:21 +0800
Subject: [PATCH 3/3] display registers stored in qemu note section

---
 defs.h    |    2 +
 help.c    |   15 ++++++++-
 netdump.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 netdump.h |   24 +++++++++++++
 4 files changed, 149 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index 9a37864..b8724fc 100755
--- a/defs.h
+++ b/defs.h
@@ -4213,6 +4213,7 @@ int cleanup_memory_driver(void);
 #define END_OF_HELP_DATA       "END_OF_HELP_DATA"
 void help_init(void);
 void cmd_usage(char *, int);
+void dump_register(void);
 void display_version(void);
 void display_help_screen(char *);
 #ifdef ARM
@@ -5007,6 +5008,7 @@ 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 qemu_mem_dump_kdump_backup_region_init(void);
+void dump_register_for_qemu_mem_dump(void);
 
 /*
  *  diskdump.c
diff --git a/help.c b/help.c
index 6ab9eea..b292f24 100755
--- a/help.c
+++ b/help.c
@@ -466,7 +466,7 @@ cmd_help(void)
 	oflag = 0;
 
         while ((c = getopt(argcnt, args, 
-	        "efNDdmM:ngcaBbHhkKsvVoptTzLxO")) != EOF) {
+	        "efNDdmM:ngcaBbHhkKsvVoptTzLxOq")) != EOF) {
                 switch(c)
                 {
 		case 'e':
@@ -601,6 +601,10 @@ cmd_help(void)
 			dumpfile_memory(DUMPFILE_ENVIRONMENT);
 			return;
 
+		case 'q':
+			dump_register();
+			return;
+
                 default:  
 			argerrs++;
                         break;
@@ -627,6 +631,15 @@ cmd_help(void)
         } while (args[optind]);
 }
 
+void
+dump_register(void)
+{
+	if (pc->flags2 & QEMU_MEM_DUMP)
+		dump_register_for_qemu_mem_dump();
+	else
+		option_not_supported('q');
+}
+
 /*
  *  Format and display the help menu.
  */
diff --git a/netdump.c b/netdump.c
index 823c9e4..9762c40 100644
--- a/netdump.c
+++ b/netdump.c
@@ -1875,6 +1875,16 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
 	if (xen_core)
 		uptr = (ulong *)roundup((ulong)uptr, 4);
 
+	if (store && qemuinfo) {
+		for(i=0; i<NR_CPUS; i++) {
+			if (!nd->nt_qemu_percpu[i]) {
+				nd->nt_qemu_percpu[i] = (void *)uptr;
+				nd->num_qemu_notes++;
+				break;
+			}
+		}
+	}
+
 	if (vmcoreinfo || eraseinfo) {
                 netdump_print("                         ");
                 ptr += note->n_namesz + 1;
@@ -2152,6 +2162,16 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
 			uptr = (ulonglong *)roundup((ulong)uptr, 4);
 	}
 
+	if (store && qemuinfo) {
+		for(i=0; i<NR_CPUS; i++) {
+			if (!nd->nt_qemu_percpu[i]) {
+				nd->nt_qemu_percpu[i] = (void *)uptr;
+				nd->num_qemu_notes++;
+				break;
+			}
+		}
+	}
+
 	if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS))) {
 		iptr = (int *)uptr;
 		for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) {
@@ -3707,3 +3727,92 @@ error(INFO, "qemu mem dump: backup region is used: %lx\n", backup_offset + total
 error:
 	error(WARNING, "failed to init kexec backup region\n");
 }
+
+void
+dump_register_for_qemu_mem_dump(void)
+{
+	int i;
+	QEMUCPUState *ptr;
+	FILE *fpsave;
+
+	fpsave = nd->ofp;
+	nd->ofp = fp;
+
+	for (i=0; i<nd->num_qemu_notes; i++) {
+		ptr = (QEMUCPUState *)nd->nt_qemu_percpu[i];
+
+		if (i)
+			netdump_print("\n");
+		netdump_print("CPU %d:\n", i);
+
+		netdump_print("  version:%08lx      size:%08lx\n",
+			ptr->version, ptr->size);
+		netdump_print("  rax:%016llx  rbx:%016llx  rcx:%016llx\n",
+			ptr->rax, ptr->rbx, ptr->rcx);
+		netdump_print("  rdx:%016llx  rsi:%016llx  rdi:%016llx\n",
+			ptr->rdx, ptr->rsi, ptr->rdi);
+		netdump_print("  rsp:%016llx  rbp:%016llx  ",
+			ptr->rsp, ptr->rbp);
+	
+		if (DUMPFILE_FORMAT(nd->flags) == KDUMP_ELF64) {
+			netdump_print("r8:%016llx\n",
+				ptr->r8);
+			netdump_print("  r9:%016llx   r10:%016llx  r11:%016llx\n",
+				ptr->r9, ptr->r10, ptr->r11);
+			netdump_print("  r12:%016llx  r13:%016llx  r14:%016llx\n",
+				ptr->r12, ptr->r13, ptr->r14);
+			netdump_print("  r15:%016llx",
+				ptr->r15);
+		} else
+                        netdump_print("\n");
+
+		netdump_print("  rip:%016llx  rflags:%016llx\n",
+			ptr->rip, ptr->rflags);
+		netdump_print("  cs:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->cs.selector, ptr->cs.limit, ptr->cs.flags,
+			ptr->cs.pad, ptr->cs.base);
+		netdump_print("  ds:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->ds.selector, ptr->ds.limit, ptr->ds.flags,
+			ptr->ds.pad, ptr->ds.base);
+		netdump_print("  es:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->es.selector, ptr->es.limit, ptr->es.flags,
+			ptr->es.pad, ptr->es.base);
+		netdump_print("  fs:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->fs.selector, ptr->fs.limit, ptr->fs.flags,
+			ptr->fs.pad, ptr->fs.base);
+		netdump_print("  gs:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->gs.selector, ptr->gs.limit, ptr->gs.flags,
+			ptr->gs.pad, ptr->gs.base);
+		netdump_print("  ss:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->ss.selector, ptr->ss.limit, ptr->ss.flags,
+			ptr->ss.pad, ptr->ss.base);
+		netdump_print("  ldt:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->ldt.selector, ptr->ldt.limit, ptr->ldt.flags,
+			ptr->ldt.pad, ptr->ldt.base);
+		netdump_print("  tr:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->tr.selector, ptr->tr.limit, ptr->tr.flags,
+			ptr->tr.pad, ptr->tr.base);
+		netdump_print("  gdt:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->gdt.selector, ptr->gdt.limit, ptr->gdt.flags,
+			ptr->gdt.pad, ptr->gdt.base);
+		netdump_print("  idt:\n    selector:%08lx  limit:%08lx  flags:%08lx\n\
+    pad:%08lx  base:%016llx\n",
+			ptr->idt.selector, ptr->idt.limit, ptr->idt.flags,
+			ptr->idt.pad, ptr->idt.base);
+		netdump_print("  cr[0]:%016llx  cr[1]:%016llx  cr[2]:%016llx\n",
+			ptr->cr[0], ptr->cr[1], ptr->cr[2]);
+		netdump_print("  cr[3]:%016llx  cr[4]:%016llx\n",
+			ptr->cr[3], ptr->cr[4]);
+	}
+
+	nd->ofp = fpsave;
+}
diff --git a/netdump.h b/netdump.h
index 4a6d661..50a7003 100644
--- a/netdump.h
+++ b/netdump.h
@@ -67,7 +67,9 @@ struct vmcore_data {
 	uint page_size;
 	ulong switch_stack;
 	uint num_prstatus_notes;
+	uint num_qemu_notes;
 	void *nt_prstatus_percpu[NR_CPUS];
+	void *nt_qemu_percpu[NR_CPUS];
 	struct xen_kdump_data *xen_kdump_data;
 	void *vmcoreinfo;
 	uint size_vmcoreinfo;
@@ -177,3 +179,25 @@ struct proc_kcore_data {
 	Elf32_Phdr *load32;
 };
 
+struct QEMUCPUSegment {
+    uint32_t selector;
+    uint32_t limit;
+    uint32_t flags;
+    uint32_t pad;
+    uint64_t base;
+};
+
+typedef struct QEMUCPUSegment QEMUCPUSegment;
+
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;
-- 
1.7.1

>From 3fccdcfaabcc5c0cc932836d4f0b626b9eff0c3f Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Mon, 20 Aug 2012 17:08:27 +0800
Subject: [PATCH 1/3] add support to qemu memory dump

---
 defs.h    |    1 +
 main.c    |    2 ++
 netdump.c |   16 ++++++++++++----
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/defs.h b/defs.h
index 4a8e2e3..d37e453 100755
--- a/defs.h
+++ b/defs.h
@@ -492,6 +492,7 @@ struct program_context {
 #define FLAT_FORMAT() (pc->flags2 & FLAT)
 #define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES)
 #define RADIX_OVERRIDE (0x80ULL)
+#define QEMU_MEM_DUMP (0x100ULL)
 	char *cleanup;
 	char *namelist_orig;
 	char *namelist_debug_orig;
diff --git a/main.c b/main.c
index 2dbe902..9dced6e 100755
--- a/main.c
+++ b/main.c
@@ -1330,6 +1330,8 @@ dump_program_context(void)
 		fprintf(fp, "%sLIVE_DUMP", others++ ? "|" : "");
 	if (pc->flags2 & RADIX_OVERRIDE)
 		fprintf(fp, "%sRADIX_OVERRIDE", others++ ? "|" : "");
+	if (pc->flags2 & QEMU_MEM_DUMP)
+		fprintf(fp, "%sQEMU_MEM_DUMP", others++ ? "|" : "");
 	fprintf(fp, ")\n");
 
 	fprintf(fp, "         namelist: %s\n", pc->namelist);
diff --git a/netdump.c b/netdump.c
index 9fecbf3..55073dd 100644
--- a/netdump.c
+++ b/netdump.c
@@ -1670,13 +1670,13 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
 	char buf[BUFSIZE];
 	char *ptr;
 	ulong *uptr;
-	int xen_core, vmcoreinfo, eraseinfo;
+	int xen_core, vmcoreinfo, eraseinfo, qemuinfo;
 	uint64_t remaining, notesize;
 
 	note = (Elf32_Nhdr *)((char *)nd->elf32 + offset);
 
         BZERO(buf, BUFSIZE);
-	xen_core = vmcoreinfo = eraseinfo = FALSE;
+	xen_core = vmcoreinfo = eraseinfo = qemuinfo = FALSE;
         ptr = (char *)note + sizeof(Elf32_Nhdr);
 
 	if (ptr > (nd->elf_header + nd->header_size)) {
@@ -1767,6 +1767,7 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
 		xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen");
 		vmcoreinfo = STRNEQ(buf, "VMCOREINFO");
 		eraseinfo = STRNEQ(buf, "ERASEINFO");
+		qemuinfo = STRNEQ(buf, "QEMU");
 		if (xen_core) {
 			netdump_print("(unknown Xen n_type)\n"); 
 			if (store)
@@ -1785,6 +1786,9 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
 				pc->flags2 |= ERASEINFO_DATA;
 		} else
 			netdump_print("(?)\n");
+
+		if (qemuinfo)
+			pc->flags2 |= QEMU_MEM_DUMP;
 		break;
 
 	case NT_XEN_KDUMP_CR3: 
@@ -1900,14 +1904,14 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
 	ulonglong *uptr;
 	int *iptr;
 	ulong *up;
-	int xen_core, vmcoreinfo, eraseinfo;
+	int xen_core, vmcoreinfo, eraseinfo, qemuinfo;
 	uint64_t remaining, notesize;
 
 	note = (Elf64_Nhdr *)((char *)nd->elf64 + offset);
 
         BZERO(buf, BUFSIZE);
         ptr = (char *)note + sizeof(Elf64_Nhdr);
-	xen_core = vmcoreinfo = eraseinfo = FALSE;
+	xen_core = vmcoreinfo = eraseinfo = qemuinfo = FALSE;
 
 	if (ptr > (nd->elf_header + nd->header_size)) {
 		error(WARNING, 
@@ -2028,6 +2032,7 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
 		xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen");
 		vmcoreinfo = STRNEQ(buf, "VMCOREINFO");
 		eraseinfo = STRNEQ(buf, "ERASEINFO");
+		qemuinfo = STRNEQ(buf, "QEMU");
                 if (xen_core) {
                         netdump_print("(unknown Xen n_type)\n");
 			if (store)
@@ -2050,6 +2055,9 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
 				pc->flags2 |= ERASEINFO_DATA;
                 } else
                         netdump_print("(?)\n");
+
+		if (qemuinfo)
+			pc->flags2 |= QEMU_MEM_DUMP;
                 break;
 
 	case NT_XEN_KDUMP_CR3: 
-- 
1.7.1

>From 8273482d58440947bbf345dbd69b446c2071da5f Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Mon, 20 Aug 2012 17:13:07 +0800
Subject: [PATCH 2/3] support core dump file when kdump is operating

---
 defs.h    |    3 +
 main.c    |    2 +
 netdump.c |  224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 netdump.h |    5 ++
 4 files changed, 234 insertions(+), 0 deletions(-)

diff --git a/defs.h b/defs.h
index d37e453..9a37864 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))
 
@@ -5004,6 +5006,7 @@ int proc_kcore_init(FILE *);
 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 qemu_mem_dump_kdump_backup_region_init(void);
 
 /*
  *  diskdump.c
diff --git a/main.c b/main.c
index 9dced6e..033bfa1 100755
--- a/main.c
+++ b/main.c
@@ -640,6 +640,8 @@ main_loop(void)
         if (!(pc->flags & GDB_INIT)) {
 		gdb_session_init();
 		show_untrusted_files();
+		if (pc->flags2 & QEMU_MEM_DUMP)
+			qemu_mem_dump_kdump_backup_region_init();
 		if (SADUMP_DUMPFILE())
 			sadump_kdump_backup_region_init();
 		if (XEN_HYPER_MODE()) {
diff --git a/netdump.c b/netdump.c
index 55073dd..823c9e4 100644
--- a/netdump.c
+++ b/netdump.c
@@ -502,6 +502,20 @@ read_netdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
 	off_t offset;
 	struct pt_load_segment *pls;
 	int i;
+ 
+	if (nd->flags & QEMU_MEM_DUMP_KDUMP_BACKUP &&
+	    paddr >= nd->backup_src_start &&
+	    paddr < nd->backup_src_start + nd->backup_src_size) {
+		ulong orig_paddr;
+
+		orig_paddr = paddr;
+		paddr += nd->backup_offset - nd->backup_src_start;
+
+		if (CRASHDEBUG(1))
+			error(INFO,
+			    "qemu_mem_dump: kdump backup region: %#lx => %#lx\n",
+			    orig_paddr, paddr);
+	}
 
 	offset = 0;
 
@@ -3483,3 +3497,213 @@ kdump_get_osrelease(void)
 	} else 
 		pc->flags2 &= ~GET_OSRELEASE;
 }
+
+/**
+ * kdump saves the first 640kB physical memory for BIOS to use the
+ * range on boot of 2nd kernel. qemu mem dump translates read request to the
+ * 640kB region as to the back up region. This function searchs kexec
+ * resources for the backup region.
+ */
+void
+qemu_mem_dump_kdump_backup_region_init(void)
+{
+	char buf[BUFSIZE];
+	ulong i, total, kexec_crash_image_p, elfcorehdr_p;
+	uint16_t e_phnum, e_phentsize;
+	ulong backup_offset;
+	ulong backup_src_start, backup_src_size;
+	int kimage_segment_len;
+	size_t bufsize;
+
+	Elf64_Off e_phoff64 = 0;
+	Elf32_Off e_phoff32 = 0;
+
+	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, "qemu mem dump: 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,
+	"qemu mem dump: elfcorehdr not found in segments of kexec_crash_image\n");
+		goto error;
+	}
+	
+	if (nd->flags & KDUMP_ELF32) {
+		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 = 0;
+		Elf64_Off p_offset64 = 0;
+		Elf32_Addr p_paddr32 = 0;
+		Elf64_Addr p_paddr64 = 0;
+		uint32_t p_memsz32 = 0;
+		uint64_t p_memsz64 = 0;
+
+		if (nd->flags & KDUMP_ELF32) {
+			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 (nd->flags & KDUMP_ELF32) {
+			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,
+				"qemu mem dump: kexec backup region found: "
+				"START: %#08lx SIZE: %#08lx OFFSET: %#08lx\n",
+				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,
+				"qemu mem dump: kexec backup region found: "
+				"START: %#016lx SIZE: %#016lx OFFSET: %#016lx\n",
+				backup_src_start, backup_src_size, backup_offset);
+
+				break;
+			}
+		}
+	}
+
+	if (!backup_offset) {
+		if (CRASHDEBUG(1))
+	error(WARNING, "qemu mem dump: 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 region is initialized
+		 * with 0 filled if kdump has not run.
+		 */
+		for (j = 0; j < bufsize; ++j) {
+			if (backup_buf[j]) {
+
+				nd->flags |= QEMU_MEM_DUMP_KDUMP_BACKUP;
+				nd->backup_src_start = backup_src_start;
+				nd->backup_src_size = backup_src_size;
+				nd->backup_offset = backup_offset;
+
+				if (CRASHDEBUG(1))
+error(INFO, "qemu mem dump: backup region is used: %lx\n", backup_offset + total + j);
+
+				return;
+			}
+		}
+	}
+
+	if (CRASHDEBUG(1))
+		error(INFO, "qemu mem dump: kexec backup region not used\n");
+
+	return;
+
+error:
+	error(WARNING, "failed to init kexec backup region\n");
+}
diff --git a/netdump.h b/netdump.h
index 2e296ad..4a6d661 100644
--- a/netdump.h
+++ b/netdump.h
@@ -71,6 +71,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
+	ulong backup_src_start;
+	ulong backup_src_size;
+	ulong backup_offset;
 };
 
 /*
-- 
1.7.1

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux