Hello Dave, The patch has been modified. For every bit of flag has been occupied, I use flag2 to indicate qemu memory dump. According to HATAYAMA's suggest, I made another two patch. The 0002 patch is used to deal with the reserved 640KB area. And the 0003 is used to display register in qemu note section. Now, I am still working on "see dump image from the 2nd kernel's view"(See HATAYAMA's mail). As HATAYAMA suggested, only hint message about calculating phys_base is needed. Then what do think? Is it suitable add some brief explanation in program_usage_info? BTW, the following files are what you want, including the core of RHEL6.2 x86_64 & RHEL6.2 i386 https://skydrive.live.com/redir?resid=62F21E6013CBFCB9!111&authkey=!AF1s2nd-xYJnL3w https://skydrive.live.com/redir?resid=62F21E6013CBFCB9!112&authkey=!AIp0uoevnNiJLYY https://skydrive.live.com/redir?resid=62F21E6013CBFCB9!113&authkey=!ACnO0HEhUQmhz4M https://skydrive.live.com/redir?resid=62F21E6013CBFCB9!114&authkey=!AD58FzZrGwz3H0E -- -- Regards Qiao Nuohan
>From cd2b212a947426f9c3f72af8371c5dbd2c3a565e Mon Sep 17 00:00:00 2001 From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx> Date: Mon, 16 Jul 2012 05:26:27 +0800 Subject: [PATCH 3/3] display registers stored in qemu note section --- netdump.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 210 insertions(+), 0 deletions(-) diff --git a/netdump.c b/netdump.c index db65704..61467b9 100644 --- a/netdump.c +++ b/netdump.c @@ -1715,12 +1715,14 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store) char *ptr; ulong *uptr; int xen_core, vmcoreinfo, eraseinfo; + int qemu_info; uint64_t remaining, notesize; note = (Elf32_Nhdr *)((char *)nd->elf32 + offset); BZERO(buf, BUFSIZE); xen_core = vmcoreinfo = eraseinfo = FALSE; + qemu_info = FALSE; ptr = (char *)note + sizeof(Elf32_Nhdr); if (ptr > (nd->elf_header + nd->header_size)) { @@ -1811,6 +1813,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"); + qemu_info = STRNEQ(buf, "QEMU"); if (xen_core) { netdump_print("(unknown Xen n_type)\n"); if (store) @@ -1904,6 +1907,103 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store) if (xen_core) uptr = (ulong *)roundup((ulong)uptr, 4); + if (CRASHDEBUG(1) & qemu_info) { + netdump_print("version:%08lx size:%08lx\n", + ((QEMUCPUState *)uptr)->version, + ((QEMUCPUState *)uptr)->size); + netdump_print("rax:%016llx rbx:%016llx rcx:%016llx\n", + ((QEMUCPUState *)uptr)->rax, + ((QEMUCPUState *)uptr)->rbx, + ((QEMUCPUState *)uptr)->rcx); + netdump_print("rdx:%016llx rsi:%016llx rdi:%016llx\n", + ((QEMUCPUState *)uptr)->rdx, + ((QEMUCPUState *)uptr)->rsi, + ((QEMUCPUState *)uptr)->rdi); + netdump_print("rsp:%016llx rbp:%016llx\n", + ((QEMUCPUState *)uptr)->rsp, + ((QEMUCPUState *)uptr)->rbp); + netdump_print("rip:%016llx rflags:%016llx\n", + ((QEMUCPUState *)uptr)->rip, + ((QEMUCPUState *)uptr)->rflags); + netdump_print("cs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->cs.selector, + ((QEMUCPUState *)uptr)->cs.limit, + ((QEMUCPUState *)uptr)->cs.flags, + ((QEMUCPUState *)uptr)->cs.pad, + ((QEMUCPUState *)uptr)->cs.base); + netdump_print("ds:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ds.selector, + ((QEMUCPUState *)uptr)->ds.limit, + ((QEMUCPUState *)uptr)->ds.flags, + ((QEMUCPUState *)uptr)->ds.pad, + ((QEMUCPUState *)uptr)->ds.base); + netdump_print("es:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->es.selector, + ((QEMUCPUState *)uptr)->es.limit, + ((QEMUCPUState *)uptr)->es.flags, + ((QEMUCPUState *)uptr)->es.pad, + ((QEMUCPUState *)uptr)->es.base); + netdump_print("fs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->fs.selector, + ((QEMUCPUState *)uptr)->fs.limit, + ((QEMUCPUState *)uptr)->fs.flags, + ((QEMUCPUState *)uptr)->fs.pad, + ((QEMUCPUState *)uptr)->fs.base); + netdump_print("gs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->gs.selector, + ((QEMUCPUState *)uptr)->gs.limit, + ((QEMUCPUState *)uptr)->gs.flags, + ((QEMUCPUState *)uptr)->gs.pad, + ((QEMUCPUState *)uptr)->gs.base); + netdump_print("ss:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ss.selector, + ((QEMUCPUState *)uptr)->ss.limit, + ((QEMUCPUState *)uptr)->ss.flags, + ((QEMUCPUState *)uptr)->ss.pad, + ((QEMUCPUState *)uptr)->ss.base); + netdump_print("ldt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ldt.selector, + ((QEMUCPUState *)uptr)->ldt.limit, + ((QEMUCPUState *)uptr)->ldt.flags, + ((QEMUCPUState *)uptr)->ldt.pad, + ((QEMUCPUState *)uptr)->ldt.base); + netdump_print("tr:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->tr.selector, + ((QEMUCPUState *)uptr)->tr.limit, + ((QEMUCPUState *)uptr)->tr.flags, + ((QEMUCPUState *)uptr)->tr.pad, + ((QEMUCPUState *)uptr)->tr.base); + netdump_print("gdt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->gdt.selector, + ((QEMUCPUState *)uptr)->gdt.limit, + ((QEMUCPUState *)uptr)->gdt.flags, + ((QEMUCPUState *)uptr)->gdt.pad, + ((QEMUCPUState *)uptr)->gdt.base); + netdump_print("idt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->idt.selector, + ((QEMUCPUState *)uptr)->idt.limit, + ((QEMUCPUState *)uptr)->idt.flags, + ((QEMUCPUState *)uptr)->idt.pad, + ((QEMUCPUState *)uptr)->idt.base); + netdump_print("cr[0]:%016llx cr[1]:%016llx cr[2]:%016llx\n", + ((QEMUCPUState *)uptr)->cr[0], + ((QEMUCPUState *)uptr)->cr[1], + ((QEMUCPUState *)uptr)->cr[2]); + netdump_print("cr[3]:%016llx cr[4]:%016llx\n", + ((QEMUCPUState *)uptr)->cr[3], + ((QEMUCPUState *)uptr)->cr[4]); + } + if (vmcoreinfo || eraseinfo) { netdump_print(" "); ptr += note->n_namesz + 1; @@ -1948,6 +2048,7 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store) int *iptr; ulong *up; int xen_core, vmcoreinfo, eraseinfo; + int qemu_info; uint64_t remaining, notesize; note = (Elf64_Nhdr *)((char *)nd->elf64 + offset); @@ -1955,6 +2056,7 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store) BZERO(buf, BUFSIZE); ptr = (char *)note + sizeof(Elf64_Nhdr); xen_core = vmcoreinfo = eraseinfo = FALSE; + qemu_info = FALSE; if (ptr > (nd->elf_header + nd->header_size)) { error(WARNING, @@ -2075,6 +2177,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"); + qemu_info = STRNEQ(buf, "QEMU"); if (xen_core) { netdump_print("(unknown Xen n_type)\n"); if (store) @@ -2180,6 +2283,113 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store) uptr = (ulonglong *)roundup((ulong)uptr, 4); } + if (CRASHDEBUG(1) & qemu_info) { + netdump_print("version:%08lx size:%08lx\n", + ((QEMUCPUState *)uptr)->version, + ((QEMUCPUState *)uptr)->size); + netdump_print("rax:%016llx rbx:%016llx rcx:%016llx\n", + ((QEMUCPUState *)uptr)->rax, + ((QEMUCPUState *)uptr)->rbx, + ((QEMUCPUState *)uptr)->rcx); + netdump_print("rdx:%016llx rsi:%016llx rdi:%016llx\n", + ((QEMUCPUState *)uptr)->rdx, + ((QEMUCPUState *)uptr)->rsi, + ((QEMUCPUState *)uptr)->rdi); + netdump_print("rsp:%016llx rbp:%016llx r8:%016llx\n", + ((QEMUCPUState *)uptr)->rsp, + ((QEMUCPUState *)uptr)->rbp, + ((QEMUCPUState *)uptr)->r8); + netdump_print("r9:%016llx r10:%016llx r11:%016llx\n", + ((QEMUCPUState *)uptr)->r9, + ((QEMUCPUState *)uptr)->r10, + ((QEMUCPUState *)uptr)->r11); + netdump_print("r12:%016llx r13:%016llx r14:%016llx\n", + ((QEMUCPUState *)uptr)->r12, + ((QEMUCPUState *)uptr)->r13, + ((QEMUCPUState *)uptr)->r14); + netdump_print("r15:%016llx rip:%016llx rflags:%016llx\n", + ((QEMUCPUState *)uptr)->r15, + ((QEMUCPUState *)uptr)->rip, + ((QEMUCPUState *)uptr)->rflags); + netdump_print("cs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->cs.selector, + ((QEMUCPUState *)uptr)->cs.limit, + ((QEMUCPUState *)uptr)->cs.flags, + ((QEMUCPUState *)uptr)->cs.pad, + ((QEMUCPUState *)uptr)->cs.base); + netdump_print("ds:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ds.selector, + ((QEMUCPUState *)uptr)->ds.limit, + ((QEMUCPUState *)uptr)->ds.flags, + ((QEMUCPUState *)uptr)->ds.pad, + ((QEMUCPUState *)uptr)->ds.base); + netdump_print("es:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->es.selector, + ((QEMUCPUState *)uptr)->es.limit, + ((QEMUCPUState *)uptr)->es.flags, + ((QEMUCPUState *)uptr)->es.pad, + ((QEMUCPUState *)uptr)->es.base); + netdump_print("fs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->fs.selector, + ((QEMUCPUState *)uptr)->fs.limit, + ((QEMUCPUState *)uptr)->fs.flags, + ((QEMUCPUState *)uptr)->fs.pad, + ((QEMUCPUState *)uptr)->fs.base); + netdump_print("gs:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->gs.selector, + ((QEMUCPUState *)uptr)->gs.limit, + ((QEMUCPUState *)uptr)->gs.flags, + ((QEMUCPUState *)uptr)->gs.pad, + ((QEMUCPUState *)uptr)->gs.base); + netdump_print("ss:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ss.selector, + ((QEMUCPUState *)uptr)->ss.limit, + ((QEMUCPUState *)uptr)->ss.flags, + ((QEMUCPUState *)uptr)->ss.pad, + ((QEMUCPUState *)uptr)->ss.base); + netdump_print("ldt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->ldt.selector, + ((QEMUCPUState *)uptr)->ldt.limit, + ((QEMUCPUState *)uptr)->ldt.flags, + ((QEMUCPUState *)uptr)->ldt.pad, + ((QEMUCPUState *)uptr)->ldt.base); + netdump_print("tr:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->tr.selector, + ((QEMUCPUState *)uptr)->tr.limit, + ((QEMUCPUState *)uptr)->tr.flags, + ((QEMUCPUState *)uptr)->tr.pad, + ((QEMUCPUState *)uptr)->tr.base); + netdump_print("gdt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->gdt.selector, + ((QEMUCPUState *)uptr)->gdt.limit, + ((QEMUCPUState *)uptr)->gdt.flags, + ((QEMUCPUState *)uptr)->gdt.pad, + ((QEMUCPUState *)uptr)->gdt.base); + netdump_print("idt:\n selector:%08lx limit:%08lx flags:%08lx\n\ + pad:%08lx base:%016llx\n", + ((QEMUCPUState *)uptr)->idt.selector, + ((QEMUCPUState *)uptr)->idt.limit, + ((QEMUCPUState *)uptr)->idt.flags, + ((QEMUCPUState *)uptr)->idt.pad, + ((QEMUCPUState *)uptr)->idt.base); + netdump_print("cr[0]:%016llx cr[1]:%016llx cr[2]:%016llx\n", + ((QEMUCPUState *)uptr)->cr[0], + ((QEMUCPUState *)uptr)->cr[1], + ((QEMUCPUState *)uptr)->cr[2]); + netdump_print("cr[3]:%016llx cr[4]:%016llx\n", + ((QEMUCPUState *)uptr)->cr[3], + ((QEMUCPUState *)uptr)->cr[4]); + } + if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS))) { iptr = (int *)uptr; for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { -- 1.7.1
>From 600d836e6735c7ed4658cfbb4e5638424ec25d9f Mon Sep 17 00:00:00 2001 From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx> Date: Mon, 16 Jul 2012 05:10:08 +0800 Subject: [PATCH 1/3] add support to qemu memory dump --- defs.h | 18 +++++- filesys.c | 6 ++- kernel.c | 2 + main.c | 35 +++++++--- memory.c | 18 ++++- netdump.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- netdump.h | 23 +++++++ task.c | 8 ++- tools.c | 4 +- x86_64.c | 2 +- 10 files changed, 296 insertions(+), 31 deletions(-) diff --git a/defs.h b/defs.h index caa87c0..698240a 100755 --- a/defs.h +++ b/defs.h @@ -250,6 +250,7 @@ struct number_option { #define NETDUMP_DUMPFILE() (pc->flags & (NETDUMP|REM_NETDUMP)) #define DISKDUMP_DUMPFILE() (pc->flags & DISKDUMP) #define KDUMP_DUMPFILE() (pc->flags & KDUMP) +#define QEMU_MEM_DUMP_DUMPFILE() (pc->flags2 & QEMU_MEM_DUMP) #define XENDUMP_DUMPFILE() (pc->flags & XENDUMP) #define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) #define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) @@ -260,7 +261,7 @@ struct number_option { #define NETDUMP_LOCAL (0x1) /* netdump_data flags */ #define NETDUMP_REMOTE (0x2) -#define VMCORE_VALID() (nd->flags & (NETDUMP_LOCAL|NETDUMP_REMOTE|KDUMP_LOCAL)) +#define VMCORE_VALID() (nd->flags & (NETDUMP_LOCAL|NETDUMP_REMOTE|KDUMP_LOCAL|QEMU_MEM_DUMP_LOCAL)) #define NETDUMP_ELF32 (0x4) #define NETDUMP_ELF64 (0x8) #define PARTIAL_DUMP (0x10) /* netdump or diskdump */ @@ -270,11 +271,14 @@ struct number_option { #define KCORE_LOCAL (0x100) #define KCORE_ELF32 (0x200) #define KCORE_ELF64 (0x400) +#define QEMU_MEM_DUMP_LOCAL (0x800) +#define QEMU_MEM_DUMP_ELF32 (0x1000) +#define QEMU_MEM_DUMP_ELF64 (0x2000) #define KVMDUMP_LOCAL (0x1) #define KVMDUMP_VALID() (kvm->flags & (KVMDUMP_LOCAL)) #define DUMPFILE_FORMAT(flags) ((flags) & \ - (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64)) + (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64|QEMU_MEM_DUMP_ELF32|QEMU_MEM_DUMP_ELF64)) #define DISKDUMP_LOCAL (0x1) #define KDUMP_CMPRS_LOCAL (0x2) @@ -484,6 +488,7 @@ struct program_context { #define ERASEINFO_DATA (0x10ULL) #define GDB_CMD_MODE (0x20ULL) #define LIVE_DUMP (0x40ULL) +#define QEMU_MEM_DUMP (0x80ULL) #define FLAT_FORMAT() (pc->flags2 & FLAT) #define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES) char *cleanup; @@ -4982,6 +4987,15 @@ 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 *); +struct vmcore_data *get_qemu_mem_dump_vmcore_data(void); +int is_qemu_mem_dump(char *, ulong); +int qemu_mem_dump_init(char *, FILE *); +ulong get_qemu_mem_dump_panic_task(void); +uint qemu_mem_dump_page_size(void); +int qemu_mem_dump_free_memory(void); +int qemu_mem_dump_memory_used(void); +int qemu_mem_dump_memory_dump(FILE *); +void get_qemu_mem_dump_regs(struct bt_info *, ulong *, ulong *); /* * diskdump.c diff --git a/filesys.c b/filesys.c index 6fc7d42..4295fa6 100755 --- a/filesys.c +++ b/filesys.c @@ -207,7 +207,7 @@ memory_source_init(void) error(FATAL, "%s: %s\n", pc->dumpfile, strerror(ENOENT)); - if (!(pc->flags & DUMPFILE_TYPES)) + if (!(pc->flags & DUMPFILE_TYPES || pc->flags2 & QEMU_MEM_DUMP)) error(FATAL, "%s: dump format not supported!\n", pc->dumpfile); @@ -215,6 +215,10 @@ memory_source_init(void) if (!netdump_init(pc->dumpfile, fp)) error(FATAL, "%s: initialization failed\n", pc->dumpfile); + } else if (pc->flags2 & QEMU_MEM_DUMP) { + if (!qemu_mem_dump_init(pc->dumpfile, fp)) + error(FATAL, "%s: initialization failed\n", + pc->dumpfile); } else if (pc->flags & KDUMP) { if (!kdump_init(pc->dumpfile, fp)) error(FATAL, "%s: initialization failed\n", diff --git a/kernel.c b/kernel.c index e2707d3..a5c49a7 100755 --- a/kernel.c +++ b/kernel.c @@ -2382,6 +2382,8 @@ back_trace(struct bt_info *bt) get_netdump_regs(bt, &eip, &esp); else if (KDUMP_DUMPFILE()) get_kdump_regs(bt, &eip, &esp); + else if (QEMU_MEM_DUMP_DUMPFILE()) + get_qemu_mem_dump_regs(bt, &eip, &esp); else if (DISKDUMP_DUMPFILE()) get_diskdump_regs(bt, &eip, &esp); else if (KVMDUMP_DUMPFILE()) diff --git a/main.c b/main.c index 7b06cc9..5c363c5 100755 --- a/main.c +++ b/main.c @@ -425,7 +425,7 @@ main(int argc, char **argv) pc->flags2 |= FLAT; if (STREQ(argv[optind], "/dev/mem")) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -437,7 +437,7 @@ main(int argc, char **argv) pc->live_memsrc = argv[optind]; } else if (is_proc_kcore(argv[optind], KCORE_LOCAL)) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -449,7 +449,7 @@ main(int argc, char **argv) pc->live_memsrc = argv[optind]; } else if (is_netdump(argv[optind], NETDUMP_LOCAL)) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -466,7 +466,7 @@ main(int argc, char **argv) } } else if (is_kdump(argv[optind], KDUMP_LOCAL)) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -476,8 +476,19 @@ main(int argc, char **argv) pc->readmem = read_kdump; pc->writemem = write_kdump; + } else if (is_qemu_mem_dump(argv[optind], QEMU_MEM_DUMP_LOCAL)) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { + error(INFO, + "too many dumpfile arguments\n"); + program_usage(SHORT_FORM); + } + pc->flags2 |= QEMU_MEM_DUMP; + pc->dumpfile = argv[optind]; + pc->readmem = read_netdump; + pc->writemem = write_netdump; + } else if (is_kvmdump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -496,7 +507,7 @@ main(int argc, char **argv) pc->kvmdump_mapfile = argv[optind]; } else if (is_xendump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -511,7 +522,7 @@ main(int argc, char **argv) pc->flags |= (SYSMAP|SYSMAP_ARG); } else if (is_diskdump(argv[optind])) { - if ((pc->flags & MEMORY_SOURCES) && + if ((pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) && (!dumpfile_is_split())) { error(INFO, "too many dumpfile arguments\n"); @@ -523,7 +534,7 @@ main(int argc, char **argv) pc->writemem = write_diskdump; } else if (is_lkcd_compressed_dump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -534,7 +545,7 @@ main(int argc, char **argv) pc->writemem = write_lkcd_dumpfile; } else if (is_mclx_compressed_dump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -545,7 +556,7 @@ main(int argc, char **argv) pc->writemem = write_mclx_dumpfile; } else if (is_s390_dump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if (pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); @@ -556,7 +567,7 @@ main(int argc, char **argv) pc->writemem = write_s390_dumpfile; } else if (is_sadump(argv[optind])) { - if ((pc->flags & MEMORY_SOURCES) && + if ((pc->flags & MEMORY_SOURCES || pc->flags2 & QEMU_MEM_DUMP) && !sadump_is_diskset()) { error(INFO, "too many dumpfile arguments\n"); @@ -1315,6 +1326,8 @@ dump_program_context(void) fprintf(fp, "%sREMOTE_DAEMON", others++ ? "|" : ""); if (pc->flags2 & LIVE_DUMP) fprintf(fp, "%sLIVE_DUMP", 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/memory.c b/memory.c index 703e623..20b5af8 100755 --- a/memory.c +++ b/memory.c @@ -14321,9 +14321,13 @@ memory_page_size(void) break; default: - psz = 0; - error(FATAL, "memory_page_size: invalid pc->flags: %lx\n", - pc->flags & MEMORY_SOURCES); + if (pc->flags2 & QEMU_MEM_DUMP) + psz = qemu_mem_dump_page_size(); + else { + psz = 0; + error(FATAL, "memory_page_size: invalid pc->flags: %lx\n", + pc->flags & MEMORY_SOURCES); + } } return psz; @@ -14522,6 +14526,8 @@ dumpfile_memory(int cmd) retval = remote_memory_used(); else if (pc->flags & NETDUMP) retval = netdump_memory_used(); + else if (pc->flags2 & QEMU_MEM_DUMP) + retval = qemu_mem_dump_memory_used(); else if (pc->flags & KDUMP) retval = kdump_memory_used(); else if (pc->flags & XENDUMP) @@ -14545,6 +14551,8 @@ dumpfile_memory(int cmd) retval = remote_free_memory(); else if (pc->flags & NETDUMP) retval = netdump_free_memory(); + else if (pc->flags2 & QEMU_MEM_DUMP) + retval = qemu_mem_dump_free_memory(); else if (pc->flags & KDUMP) retval = kdump_free_memory(); else if (pc->flags & XENDUMP) @@ -14566,8 +14574,10 @@ dumpfile_memory(int cmd) case DUMPFILE_MEM_DUMP: if (REMOTE_DUMPFILE()) retval = remote_memory_dump(0); - else if (pc->flags & NETDUMP) + else if (pc->flags & NETDUMP) retval = netdump_memory_dump(fp); + else if (pc->flags2 & QEMU_MEM_DUMP) + retval = qemu_mem_dump_memory_dump(fp); else if (pc->flags & KDUMP) retval = kdump_memory_dump(fp); else if (pc->flags & XENDUMP) diff --git a/netdump.c b/netdump.c index 9fecbf3..792881f 100644 --- a/netdump.c +++ b/netdump.c @@ -42,6 +42,7 @@ static int proc_kcore_init_32(FILE *fp); static int proc_kcore_init_64(FILE *fp); static char *get_regs_from_note(char *, ulong *, ulong *); static void kdump_get_osrelease(void); +static int check_elf_note(char *, int , char *, int); #define ELFSTORE 1 #define ELFREAD 0 @@ -205,9 +206,12 @@ is_netdump(char *file, ulong source_query) size = (size_t)load32->p_offset; if ((load32->p_offset & (MIN_PAGE_SIZE-1)) && - (load32->p_align == 0)) - tmp_flags |= KDUMP_ELF32; - else + (load32->p_align == 0)) { + if (check_elf_note(eheader, fd, file, 0)) + tmp_flags |= QEMU_MEM_DUMP_ELF32; + else + tmp_flags |= KDUMP_ELF32; + } else tmp_flags |= NETDUMP_ELF32; } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && (swap16(elf64->e_type, swap) == ET_CORE) && @@ -258,9 +262,12 @@ is_netdump(char *file, ulong source_query) &eheader[sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)]; size = (size_t)load64->p_offset; if ((load64->p_offset & (MIN_PAGE_SIZE-1)) && - (load64->p_align == 0)) - tmp_flags |= KDUMP_ELF64; - else + (load64->p_align == 0)) { + if (check_elf_note(eheader, fd, file, 1)) + tmp_flags |= QEMU_MEM_DUMP_ELF64; + else + tmp_flags |= KDUMP_ELF64; + } else tmp_flags |= NETDUMP_ELF64; } else { if (CRASHDEBUG(2)) @@ -292,6 +299,13 @@ is_netdump(char *file, ulong source_query) break; else goto bailout; + + case QEMU_MEM_DUMP_ELF32: + case QEMU_MEM_DUMP_ELF64: + if (source_query & QEMU_MEM_DUMP_LOCAL) + break; + else + goto bailout; } if ((tmp_elf_header = (char *)malloc(size)) == NULL) { @@ -327,6 +341,7 @@ is_netdump(char *file, ulong source_query) { case NETDUMP_ELF32: case KDUMP_ELF32: + case QEMU_MEM_DUMP_ELF32: nd->header_size = load32->p_offset; nd->elf32 = (Elf32_Ehdr *)&nd->elf_header[0]; nd->num_pt_load_segments = nd->elf32->e_phnum - 1; @@ -356,6 +371,7 @@ is_netdump(char *file, ulong source_query) case NETDUMP_ELF64: case KDUMP_ELF64: + case QEMU_MEM_DUMP_ELF64: nd->header_size = load64->p_offset; nd->elf64 = (Elf64_Ehdr *)&nd->elf_header[0]; nd->num_pt_load_segments = nd->elf64->e_phnum - 1; @@ -521,6 +537,8 @@ read_netdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) case NETDUMP_ELF64: case KDUMP_ELF32: case KDUMP_ELF64: + case QEMU_MEM_DUMP_ELF32: + case QEMU_MEM_DUMP_ELF64: if (nd->num_pt_load_segments == 1) { offset = (off_t)paddr + (off_t)nd->header_size - (off_t)nd->pt_load_segments[0].phys_start; @@ -611,6 +629,8 @@ write_netdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) case NETDUMP_ELF64: case KDUMP_ELF32: case KDUMP_ELF64: + case QEMU_MEM_DUMP_ELF32: + case QEMU_MEM_DUMP_ELF64: if (nd->num_pt_load_segments == 1) { offset = (off_t)paddr + (off_t)nd->header_size; break; @@ -744,6 +764,8 @@ get_netdump_panic_task(void) case KDUMP_ELF32: case KDUMP_ELF64: + case QEMU_MEM_DUMP_ELF32: + case QEMU_MEM_DUMP_ELF64: crashing_cpu = -1; if (kernel_symbol_exists("crashing_cpu")) { get_symbol_data("crashing_cpu", sizeof(int), &i); @@ -932,6 +954,12 @@ 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_LOCAL) + netdump_print("%sQEMU_MEM_DUMP_LOCAL", others++ ? "|" : ""); + if (nd->flags & QEMU_MEM_DUMP_ELF32) + netdump_print("%sQEMU_MEM_DUMP_ELF32", others++ ? "|" : ""); + if (nd->flags & QEMU_MEM_DUMP_ELF64) + netdump_print("%sQEMU_MEM_DUMP_ELF64", others++ ? "|" : ""); netdump_print(") %s\n", FLAT_FORMAT() ? "[FLAT]" : ""); if ((pc->flags & RUNTIME) && symbol_exists("dump_level")) { int dump_level; @@ -1064,6 +1092,7 @@ netdump_memory_dump(FILE *fp) { case NETDUMP_ELF32: case KDUMP_ELF32: + case QEMU_MEM_DUMP_ELF32: dump_Elf32_Ehdr(nd->elf32); dump_Elf32_Phdr(nd->notes32, ELFREAD); for (i = 0; i < nd->num_pt_load_segments; i++) @@ -1078,6 +1107,7 @@ netdump_memory_dump(FILE *fp) case NETDUMP_ELF64: case KDUMP_ELF64: + case QEMU_MEM_DUMP_ELF64: dump_Elf64_Ehdr(nd->elf64); dump_Elf64_Phdr(nd->notes64, ELFREAD); for (i = 0; i < nd->num_pt_load_segments; i++) @@ -1854,6 +1884,9 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store) if ((nd->flags & KDUMP_ELF32) && (note->n_namesz == 5)) uptr = (ulong *)(ptr + ((note->n_namesz + 3) & ~3)); + if ((nd->flags & QEMU_MEM_DUMP_ELF32) && (note->n_namesz == 5)) + uptr = (ulong *)(ptr + ((note->n_namesz + 3) & ~3)); + if (xen_core) uptr = (ulong *)roundup((ulong)uptr, 4); @@ -2126,6 +2159,9 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store) if ((nd->flags & KDUMP_ELF64) && (note->n_namesz == 5)) uptr = (ulonglong *)(ptr + ((note->n_namesz + 3) & ~3)); + if ((nd->flags & QEMU_MEM_DUMP_ELF64) && (note->n_namesz == 5)) + uptr = (ulonglong *)(ptr + ((note->n_namesz + 3) & ~3)); + if (xen_core) uptr = (ulonglong *)roundup((ulong)uptr, 4); } @@ -2290,7 +2326,7 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) if (is_task_active(bt->task)) bt->flags |= BT_DUMPFILE_SEARCH; - if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) && + if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE() || QEMU_MEM_DUMP_DUMPFILE()) && VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) || (KDUMP_DUMPFILE() && (kt->flags & DWARF_UNWIND) && (bt->flags & BT_DUMPFILE_SEARCH))) { @@ -2321,7 +2357,7 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) ULONG(user_regs + rsp_offset), ULONG(user_regs + rip_offset)); - if (KDUMP_DUMPFILE()) { + if (KDUMP_DUMPFILE() || QEMU_MEM_DUMP_DUMPFILE()) { *rspp = ULONG(user_regs + rsp_offset); *ripp = ULONG(user_regs + rip_offset); @@ -3475,3 +3511,162 @@ kdump_get_osrelease(void) } else pc->flags2 &= ~GET_OSRELEASE; } + +int +is_qemu_mem_dump(char *file, ulong source_query) +{ + return is_netdump(file, source_query); +} + +int +qemu_mem_dump_init(char *unused, FILE *fptr) +{ + return netdump_init(unused, fptr); +} + +ulong +get_qemu_mem_dump_panic_task(void) +{ + return get_netdump_panic_task(); +} + +uint +qemu_mem_dump_page_size() +{ + uint pagesz; + + if (!VMCORE_VALID()) + return 0; + + if (!(pagesz = nd->page_size)) + pagesz = (uint)getpagesize(); + + return pagesz; +} + +int +qemu_mem_dump_free_memory() +{ + return netdump_free_memory(); +} + +int +qemu_mem_dump_memory_used() +{ + return netdump_memory_used(); +} + +int +qemu_mem_dump_memory_dump(FILE *fp) +{ + return netdump_memory_dump(fp); +} + +void +get_qemu_mem_dump_regs(struct bt_info *bt, ulong *eip, ulong *esp) +{ + get_netdump_regs(bt, eip, esp); +} + +struct vmcore_data * +get_qemu_mem_dump_vmcore_data(void) +{ + if (!VMCORE_VALID() || !QEMU_MEM_DUMP_DUMPFILE()) + return NULL; + + return &vmcore_data; +} + +static int +check_elf_note(char *eheader, int fd, char *file, int machine_type) +{ + int qemu_memory_dump; + Elf32_Phdr *load32; + Elf64_Phdr *load64; + ulong offset; + ulong filesz; + char *pnotes; + char buf[BUFSIZE]; + char *tmp_note; + Elf32_Nhdr *tmp_note32; + Elf64_Nhdr *tmp_note64; + uint32_t namesz, descsz, type; + char *name, *desc; + int num; + + qemu_memory_dump = FALSE; + + load32 = (Elf32_Phdr *)&eheader[sizeof(Elf32_Ehdr)]; + load64 = (Elf64_Phdr *)&eheader[sizeof(Elf64_Ehdr)]; + + if (machine_type == 0) { + if (!(load32->p_type == PT_NOTE)) + return qemu_memory_dump; + + offset = load32->p_offset; + filesz = load32->p_filesz; + } else { + if (!(load64->p_type == PT_NOTE)) + return qemu_memory_dump; + + offset = load64->p_offset; + filesz = load64->p_filesz; + } + + if ((pnotes = (char *)malloc(filesz)) == NULL) { + fprintf(stderr, "cannot malloc elf note buffer\n"); + clean_exit(1); + } + + if (FLAT_FORMAT()) { + if (!read_flattened_format(fd, offset, pnotes, filesz)) { + free(pnotes); + return qemu_memory_dump; + } + } else { + if (lseek(fd, offset, SEEK_SET) != offset) { + sprintf(buf, "%s: lseek", file); + perror(buf); + return qemu_memory_dump; + } + if (read(fd, pnotes, filesz) != filesz) { + sprintf(buf, "%s: read", file); + perror(buf); + free(pnotes); + return qemu_memory_dump; + } + } + + tmp_note = pnotes; + num = 0; + + while (tmp_note < pnotes + filesz) + { + if (machine_type == 0) { + tmp_note32 = (Elf32_Nhdr *)tmp_note; + namesz = tmp_note32->n_namesz; + descsz = tmp_note32->n_descsz; + type = tmp_note32->n_type; + + name = (char *)tmp_note + ((sizeof(Elf32_Nhdr) + 3) / 4) * 4; + } else { + tmp_note64 = (Elf64_Nhdr *)tmp_note; + namesz = tmp_note64->n_namesz; + descsz = tmp_note64->n_descsz; + type = tmp_note64->n_type; + + name = (char *)tmp_note + ((sizeof(Elf64_Nhdr) + 3) / 4) * 4; + } + desc = name + ((namesz + 3) / 4) * 4; + + if (STREQ(name, "QEMU")) { + qemu_memory_dump = TRUE; + nd->nt_qemu_percpu[num] = desc; + num++; + } + + tmp_note = desc + (descsz + 3) / 4 * 4; + } + + return qemu_memory_dump; +} diff --git a/netdump.h b/netdump.h index 2e296ad..ced0451 100644 --- a/netdump.h +++ b/netdump.h @@ -68,6 +68,7 @@ struct vmcore_data { ulong switch_stack; uint num_prstatus_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; @@ -172,3 +173,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; diff --git a/task.c b/task.c index 30de29a..e6fa46a 100755 --- a/task.c +++ b/task.c @@ -463,7 +463,7 @@ task_init(void) tt->this_task = pid_to_task(active_pid); } else { - if (KDUMP_DUMPFILE()) + if (KDUMP_DUMPFILE() || QEMU_MEM_DUMP_DUMPFILE()) map_cpus_to_prstatus(); else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) map_cpus_to_prstatus_kdump_cmprs(); @@ -6031,6 +6031,10 @@ get_dumpfile_panic_task(void) tt->panic_task : get_netdump_panic_task(); if (task) return task; + } else if (QEMU_MEM_DUMP_DUMPFILE()) { + task = get_qemu_mem_dump_panic_task(); + if (task) + return task; } else if (KDUMP_DUMPFILE()) { task = get_kdump_panic_task(); if (task) @@ -6100,7 +6104,7 @@ populate_panic_threads(void) } if (!found && !(kt->flags & SMP) && - (LKCD_DUMPFILE() || NETDUMP_DUMPFILE() || + (LKCD_DUMPFILE() || NETDUMP_DUMPFILE() || QEMU_MEM_DUMP_DUMPFILE() || KDUMP_DUMPFILE() || DISKDUMP_DUMPFILE() || KVMDUMP_DUMPFILE())) tt->panic_threads[0] = get_dumpfile_panic_task(); } diff --git a/tools.c b/tools.c index 77f145e..48a14d3 100755 --- a/tools.c +++ b/tools.c @@ -5313,7 +5313,7 @@ machine_type_mismatch(char *file, char *e_machine, char *alt, ulong query) if (machine_type(e_machine) || machine_type(alt)) return FALSE; - if (query == KDUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ + if (query == KDUMP_LOCAL || query == QEMU_MEM_DUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ return TRUE; error(WARNING, "machine type mismatch:\n"); @@ -5425,7 +5425,7 @@ endian_mismatch(char *file, char dumpfile_endian, ulong query) break; } - if (query == KDUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ + if (query == KDUMP_LOCAL || query == QEMU_MEM_DUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ return TRUE; error(WARNING, "endian mismatch:\n"); diff --git a/x86_64.c b/x86_64.c index 3ceae3e..64a3160 100755 --- a/x86_64.c +++ b/x86_64.c @@ -5865,7 +5865,7 @@ x86_64_calc_phys_base(void) return; } - if ((vd = get_kdump_vmcore_data())) { + if ((vd = get_kdump_vmcore_data()) || (vd = get_qemu_mem_dump_vmcore_data())) { for (i = 0; i < vd->num_pt_load_segments; i++) { phdr = vd->load64 + i; if ((phdr->p_vaddr >= __START_KERNEL_map) && -- 1.7.1
>From d45501b34baf8b4884d1a19ffc6325118c0fa21a Mon Sep 17 00:00:00 2001 From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx> Date: Mon, 16 Jul 2012 05:11:03 +0800 Subject: [PATCH 2/3] support core dump file when kdump is operating --- defs.h | 2 + main.c | 2 + netdump.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netdump.h | 5 ++ 4 files changed, 233 insertions(+), 0 deletions(-) diff --git a/defs.h b/defs.h index 698240a..2967472 100755 --- a/defs.h +++ b/defs.h @@ -274,6 +274,7 @@ struct number_option { #define QEMU_MEM_DUMP_LOCAL (0x800) #define QEMU_MEM_DUMP_ELF32 (0x1000) #define QEMU_MEM_DUMP_ELF64 (0x2000) +#define QEMU_MEM_DUMP_KDUMP_BACKUP (0x4000) #define KVMDUMP_LOCAL (0x1) #define KVMDUMP_VALID() (kvm->flags & (KVMDUMP_LOCAL)) @@ -4996,6 +4997,7 @@ int qemu_mem_dump_free_memory(void); int qemu_mem_dump_memory_used(void); int qemu_mem_dump_memory_dump(FILE *); void get_qemu_mem_dump_regs(struct bt_info *, ulong *, ulong *); +void qemu_mem_dump_kdump_backup_region_init(void); /* * diskdump.c diff --git a/main.c b/main.c index 5c363c5..92fa31a 100755 --- a/main.c +++ b/main.c @@ -638,6 +638,8 @@ main_loop(void) if (!(pc->flags & GDB_INIT)) { gdb_session_init(); show_untrusted_files(); + if (QEMU_MEM_DUMP_DUMPFILE()) + 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 792881f..db65704 100644 --- a/netdump.c +++ b/netdump.c @@ -519,6 +519,20 @@ read_netdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) 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: %#llx => %#llx\n", + orig_paddr, paddr); + } + offset = 0; /* @@ -3670,3 +3684,213 @@ check_elf_note(char *eheader, int fd, char *file, int machine_type) return qemu_memory_dump; } + +/** + * 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 seachs 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 & QEMU_MEM_DUMP_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 & QEMU_MEM_DUMP_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 & QEMU_MEM_DUMP_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 resion 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 ced0451..f0cd43c 100644 --- a/netdump.h +++ b/netdump.h @@ -72,6 +72,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