From: Wen Congyang <wency@cn.fujitsu.com>
To: qemu-devel <qemu-devel@nongnu.org>,
Jan Kiszka <jan.kiszka@siemens.com>,
Dave Anderson <anderson@redhat.com>,
HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Subject: [Qemu-devel] [RFC][PATCH 5/5v2] introduce a new monitor command 'dump' to dump guest's memory
Date: Fri, 09 Dec 2011 16:09:42 +0800 [thread overview]
Message-ID: <4EE1C246.6060503@cn.fujitsu.com> (raw)
In-Reply-To: <4EE1BF66.7030602@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
Makefile.target | 8 +-
dump.c | 722 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
dump.h | 6 +
hmp-commands.hx | 16 ++
monitor.c | 3 +
qmp-commands.hx | 24 ++
6 files changed, 775 insertions(+), 4 deletions(-)
create mode 100644 dump.c
create mode 100644 dump.h
diff --git a/Makefile.target b/Makefile.target
index 778f514..49164d3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -118,7 +118,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
- user-exec.o $(oslib-obj-y)
+ user-exec.o $(oslib-obj-y) dump.o
obj-$(TARGET_HAS_BFLT) += flatload.o
@@ -156,7 +156,7 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
LIBS+=-lmx
obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
- gdbstub.o user-exec.o
+ gdbstub.o user-exec.o dump.o
obj-i386-y += ioport-user.o
@@ -178,7 +178,7 @@ $(call set-vpath, $(SRC_PATH)/bsd-user)
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
- gdbstub.o uaccess.o user-exec.o
+ gdbstub.o uaccess.o user-exec.o dump.o
obj-i386-y += ioport-user.o
@@ -194,7 +194,7 @@ endif #CONFIG_BSD_USER
# System emulator target
ifdef CONFIG_SOFTMMU
-obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
+obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o dump.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-$(CONFIG_NO_PCI) += pci-stub.o
diff --git a/dump.c b/dump.c
new file mode 100644
index 0000000..b9af75c
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,722 @@
+/*
+ * QEMU dump
+ *
+ * Copyright Fujitsu, Corp. 2011
+ *
+ * Authors:
+ * Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include <unistd.h>
+#include <elf.h>
+#include <sys/procfs.h>
+#include "cpu.h"
+#include "cpu-all.h"
+#include "targphys.h"
+#include "monitor.h"
+#include "kvm.h"
+#include "dump.h"
+#include "sysemu.h"
+#include "bswap.h"
+#include "memory_mapping.h"
+
+static inline int cpuid(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+ return env->host_tid;
+#else
+ return env->cpu_index + 1;
+#endif
+}
+
+#if defined(TARGET_I386)
+
+#ifdef TARGET_X86_64
+typedef struct {
+ target_ulong r15, r14, r13, r12, rbp, rbx, r11, r10;
+ target_ulong r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax;
+ target_ulong rip, cs, eflags;
+ target_ulong rsp, ss;
+ target_ulong fs_base, gs_base;
+ target_ulong ds, es, fs, gs;
+} x86_64_user_regs_struct;
+
+static int x86_64_write_elf64_note(Monitor *mon, int fd, CPUState *env,
+ target_phys_addr_t *offset)
+{
+ x86_64_user_regs_struct regs;
+ Elf64_Nhdr *note;
+ char *buf;
+ int descsz, note_size, name_size = 5;
+ const char *name = "CORE";
+ int id = cpuid(env);
+ int ret;
+
+ regs.r15 = env->regs[15];
+ regs.r14 = env->regs[14];
+ regs.r13 = env->regs[13];
+ regs.r12 = env->regs[12];
+ regs.r11 = env->regs[11];
+ regs.r10 = env->regs[10];
+ regs.r9 = env->regs[9];
+ regs.r8 = env->regs[8];
+ regs.rbp = env->regs[R_EBP];
+ regs.rsp = env->regs[R_ESP];
+ regs.rdi = env->regs[R_EDI];
+ regs.rsi = env->regs[R_ESI];
+ regs.rdx = env->regs[R_EDX];
+ regs.rcx = env->regs[R_ECX];
+ regs.rbx = env->regs[R_EBX];
+ regs.rax = env->regs[R_EAX];
+ regs.rip = env->eip;
+ regs.eflags = env->eflags;
+
+ regs.orig_rax = 0; /* FIXME */
+ regs.cs = env->segs[R_CS].selector;
+ regs.ss = env->segs[R_SS].selector;
+ regs.fs_base = env->segs[R_FS].base;
+ regs.gs_base = env->segs[R_GS].base;
+ regs.ds = env->segs[R_DS].selector;
+ regs.es = env->segs[R_ES].selector;
+ regs.fs = env->segs[R_FS].selector;
+ regs.gs = env->segs[R_GS].selector;
+
+ descsz = 336; /* sizeof(prstatus_t) is 336 on x86_64 box */
+ note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+ (descsz + 3) / 4) * 4;
+ note = g_malloc(note_size);
+
+ memset(note, 0, note_size);
+ note->n_namesz = cpu_to_le32(name_size);
+ note->n_descsz = cpu_to_le32(descsz);
+ note->n_type = cpu_to_le32(NT_PRSTATUS);
+ buf = (char *)note;
+ buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4;
+ memcpy(buf, name, name_size);
+ buf += ((name_size + 3) / 4) * 4;
+ memcpy(buf + 32, &id, 4); /* pr_pid */
+ buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong);
+ memcpy(buf, ®s, sizeof(x86_64_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ return -1;
+ }
+
+ *offset += note_size;
+
+ return 0;
+}
+#endif
+
+/* This function is copied from crash */
+static target_ulong get_phys_base_addr(CPUState *env, target_ulong *base_vaddr)
+{
+ int i;
+ target_ulong kernel_base = -1;
+ target_ulong last, mask;
+
+ for (i = 30, last = -1; (kernel_base == -1) && (i >= 20); i--) {
+ mask = ~((1LL << i) - 1);
+ *base_vaddr = env->idt.base & mask;
+ if (*base_vaddr == last) {
+ continue;
+ }
+
+ kernel_base = cpu_get_phys_page_debug(env, *base_vaddr);
+ last = *base_vaddr;
+ }
+
+ return kernel_base;
+}
+
+typedef struct {
+ uint32_t ebx, ecx, edx, esi, edi, ebp, eax;
+ unsigned short ds, __ds, es, __es;
+ unsigned short fs, __fs, gs, __gs;
+ uint32_t orig_eax, eip;
+ unsigned short cs, __cs;
+ uint32_t eflags, esp;
+ unsigned short ss, __ss;
+} x86_user_regs_struct;
+
+static int x86_write_elf64_note(Monitor *mon, int fd, CPUState *env,
+ target_phys_addr_t *offset)
+{
+ x86_user_regs_struct regs;
+ Elf64_Nhdr *note;
+ char *buf;
+ int descsz, note_size, name_size = 5;
+ const char *name = "CORE";
+ int id = cpuid(env);
+ int ret;
+
+ regs.ebp = env->regs[R_EBP] & 0xffffffff;
+ regs.esp = env->regs[R_ESP] & 0xffffffff;
+ regs.edi = env->regs[R_EDI] & 0xffffffff;
+ regs.esi = env->regs[R_ESI] & 0xffffffff;
+ regs.edx = env->regs[R_EDX] & 0xffffffff;
+ regs.ecx = env->regs[R_ECX] & 0xffffffff;
+ regs.ebx = env->regs[R_EBX] & 0xffffffff;
+ regs.eax = env->regs[R_EAX] & 0xffffffff;
+ regs.eip = env->eip & 0xffffffff;
+ regs.eflags = env->eflags & 0xffffffff;
+
+ regs.cs = env->segs[R_CS].selector;
+ regs.__cs = 0;
+ regs.ss = env->segs[R_SS].selector;
+ regs.__ss = 0;
+ regs.ds = env->segs[R_DS].selector;
+ regs.__ds = 0;
+ regs.es = env->segs[R_ES].selector;
+ regs.__es = 0;
+ regs.fs = env->segs[R_FS].selector;
+ regs.__fs = 0;
+ regs.gs = env->segs[R_GS].selector;
+ regs.__gs = 0;
+
+ descsz = 144; /* sizeof(prstatus_t) is 144 on x86 box */
+ note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+ (descsz + 3) / 4) * 4;
+ note = g_malloc(note_size);
+
+ memset(note, 0, note_size);
+ note->n_namesz = cpu_to_le32(name_size);
+ note->n_descsz = cpu_to_le32(descsz);
+ note->n_type = cpu_to_le32(NT_PRSTATUS);
+ buf = (char *)note;
+ buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4;
+ memcpy(buf, name, name_size);
+ buf += ((name_size + 3) / 4) * 4;
+ memcpy(buf + 24, &id, 4); /* pr_pid */
+ buf += descsz - sizeof(x86_user_regs_struct)-4;
+ memcpy(buf, ®s, sizeof(x86_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ return -1;
+ }
+
+ *offset += note_size;
+
+ return 0;
+}
+
+static int x86_write_elf32_note(Monitor *mon, int fd, CPUState *env,
+ target_phys_addr_t *offset)
+{
+ x86_user_regs_struct regs;
+ Elf32_Nhdr *note;
+ char *buf;
+ int descsz, note_size, name_size = 5;
+ const char *name = "CORE";
+ int id = cpuid(env);
+ int ret;
+
+ regs.ebp = env->regs[R_EBP] & 0xffffffff;
+ regs.esp = env->regs[R_ESP] & 0xffffffff;
+ regs.edi = env->regs[R_EDI] & 0xffffffff;
+ regs.esi = env->regs[R_ESI] & 0xffffffff;
+ regs.edx = env->regs[R_EDX] & 0xffffffff;
+ regs.ecx = env->regs[R_ECX] & 0xffffffff;
+ regs.ebx = env->regs[R_EBX] & 0xffffffff;
+ regs.eax = env->regs[R_EAX] & 0xffffffff;
+ regs.eip = env->eip & 0xffffffff;
+ regs.eflags = env->eflags & 0xffffffff;
+
+ regs.cs = env->segs[R_CS].selector;
+ regs.__cs = 0;
+ regs.ss = env->segs[R_SS].selector;
+ regs.__ss = 0;
+ regs.ds = env->segs[R_DS].selector;
+ regs.__ds = 0;
+ regs.es = env->segs[R_ES].selector;
+ regs.__es = 0;
+ regs.fs = env->segs[R_FS].selector;
+ regs.__fs = 0;
+ regs.gs = env->segs[R_GS].selector;
+ regs.__gs = 0;
+
+ descsz = 144; /* sizeof(prstatus_t) is 144 on x86 box */
+ note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+ (descsz + 3) / 4) * 4;
+ note = g_malloc(note_size);
+
+ memset(note, 0, note_size);
+ note->n_namesz = cpu_to_le32(name_size);
+ note->n_descsz = cpu_to_le32(descsz);
+ note->n_type = cpu_to_le32(NT_PRSTATUS);
+ buf = (char *)note;
+ buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+ memcpy(buf, name, name_size);
+ buf += ((name_size + 3) / 4) * 4;
+ memcpy(buf + 24, &id, 4); /* pr_pid */
+ buf += descsz - sizeof(x86_user_regs_struct)-4;
+ memcpy(buf, ®s, sizeof(x86_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ return -1;
+ }
+
+ *offset += note_size;
+
+ return 0;
+}
+#endif
+
+static int write_elf64_header(Monitor *mon, int fd, int phdr_num, int machine,
+ int endian)
+{
+ Elf64_Ehdr elf_header;
+ int ret;
+
+ memset(&elf_header, 0, sizeof(Elf64_Ehdr));
+ memcpy(&elf_header, ELFMAG, 4);
+ elf_header.e_ident[EI_CLASS] = ELFCLASS64;
+ elf_header.e_ident[EI_DATA] = endian;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_type = cpu_to_le16(ET_CORE);
+ elf_header.e_machine = cpu_to_le16(machine);
+ elf_header.e_version = cpu_to_le32(EV_CURRENT);
+ elf_header.e_ehsize = cpu_to_le16(sizeof(elf_header));
+ elf_header.e_phoff = cpu_to_le64(sizeof(Elf64_Ehdr));
+ elf_header.e_phentsize = cpu_to_le16(sizeof(Elf64_Phdr));
+ elf_header.e_phnum = cpu_to_le16(phdr_num);
+
+ lseek(fd, 0, SEEK_SET);
+ ret = write(fd, &elf_header, sizeof(elf_header));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf header.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_header(Monitor *mon, int fd, int phdr_num, int machine,
+ int endian)
+{
+ Elf32_Ehdr elf_header;
+ int ret;
+
+ memset(&elf_header, 0, sizeof(Elf32_Ehdr));
+ memcpy(&elf_header, ELFMAG, 4);
+ elf_header.e_ident[EI_CLASS] = ELFCLASS32;
+ elf_header.e_ident[EI_DATA] = endian;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_type = cpu_to_le16(ET_CORE);
+ elf_header.e_machine = cpu_to_le16(machine);
+ elf_header.e_version = cpu_to_le32(EV_CURRENT);
+ elf_header.e_ehsize = cpu_to_le16(sizeof(elf_header));
+ elf_header.e_phoff = cpu_to_le32(sizeof(Elf32_Ehdr));
+ elf_header.e_phentsize = cpu_to_le16(sizeof(Elf32_Phdr));
+ elf_header.e_phnum = cpu_to_le16(phdr_num);
+
+ lseek(fd, 0, SEEK_SET);
+ ret = write(fd, &elf_header, sizeof(elf_header));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf header.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf64_load(Monitor *mon, int fd, MemoryMapping *memory_mapping,
+ int phdr_index, target_phys_addr_t offset)
+{
+ Elf64_Phdr phdr;
+ off_t phdr_offset;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = cpu_to_le32(PT_LOAD);
+ phdr.p_offset = cpu_to_le64(offset);
+ phdr.p_paddr = cpu_to_le64(memory_mapping->phys_addr);
+ if (offset == -1) {
+ phdr.p_filesz = 0;
+ } else {
+ phdr.p_filesz = cpu_to_le64(memory_mapping->length);
+ }
+ phdr.p_memsz = cpu_to_le64(memory_mapping->length);
+ phdr.p_vaddr = cpu_to_le64(memory_mapping->virt_addr);
+
+ phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf64_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_load(Monitor *mon, int fd, MemoryMapping *memory_mapping,
+ int phdr_index, target_phys_addr_t offset)
+{
+ Elf32_Phdr phdr;
+ off_t phdr_offset;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = cpu_to_le32(PT_LOAD);
+ phdr.p_offset = cpu_to_le32(offset);
+ phdr.p_paddr = cpu_to_le32(memory_mapping->phys_addr);
+ if (offset == -1) {
+ phdr.p_filesz = 0;
+ } else {
+ phdr.p_filesz = cpu_to_le32(memory_mapping->length);
+ }
+ phdr.p_memsz = cpu_to_le32(memory_mapping->length);
+ phdr.p_vaddr = cpu_to_le32(memory_mapping->virt_addr);
+
+ phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf32_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf64_notes(Monitor *mon, int fd, int phdr_index,
+ target_phys_addr_t *offset, bool lma)
+{
+ CPUState *env;
+ int ret;
+ target_phys_addr_t begin = *offset;
+ Elf64_Phdr phdr;
+ off_t phdr_offset;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+ if (lma) {
+ ret = x86_64_write_elf64_note(mon, fd, env, offset);
+ } else {
+#endif
+ ret = x86_write_elf64_note(mon, fd, env, offset);
+#ifdef TARGET_X86_64
+ }
+#endif
+#else
+ ret = -1; /* Not supported */
+#endif
+
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf notes.\n");
+ return -1;
+ }
+ }
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = cpu_to_le32(PT_NOTE);
+ phdr.p_offset = cpu_to_le64(begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = cpu_to_le64(*offset - begin);
+ phdr.p_memsz = cpu_to_le64(*offset - begin);
+ phdr.p_vaddr = 0;
+
+ phdr_offset = sizeof(Elf64_Ehdr);
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf64_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_notes(Monitor *mon, int fd, int phdr_index,
+ target_phys_addr_t *offset)
+{
+ CPUState *env;
+ int ret;
+ target_phys_addr_t begin = *offset;
+ Elf32_Phdr phdr;
+ off_t phdr_offset;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+#if defined(TARGET_I386)
+ ret = x86_write_elf32_note(mon, fd, env, offset);
+#else
+ ret = -1; /* Not supported */
+#endif
+
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf notes.\n");
+ return -1;
+ }
+ }
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = cpu_to_le32(PT_NOTE);
+ phdr.p_offset = cpu_to_le32(begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = cpu_to_le32(*offset - begin);
+ phdr.p_memsz = cpu_to_le32(*offset - begin);
+ phdr.p_vaddr = 0;
+
+ phdr_offset = sizeof(Elf32_Ehdr);
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf32_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_data(Monitor *mon, int fd, void *buf, int length,
+ target_phys_addr_t *offset)
+{
+ int ret;
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, buf, length);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to save memory.\n");
+ return -1;
+ }
+
+ *offset += length;
+ return 0;
+}
+
+/* write the memroy to vmcore. 1 page per I/O. */
+static int write_memory(Monitor *mon, int fd, RAMBlock *block,
+ target_phys_addr_t *offset)
+{
+ int i, ret;
+
+ for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
+ ret = write_data(mon, fd, block->host + i * TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE, offset);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+
+ if ((block->length % TARGET_PAGE_SIZE) != 0) {
+ ret = write_data(mon, fd, block->host + i * TARGET_PAGE_SIZE,
+ block->length % TARGET_PAGE_SIZE, offset);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* get the memory's offset in the vmcore */
+static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
+ target_phys_addr_t memory_offset)
+{
+ RAMBlock *block;
+ target_phys_addr_t offset = memory_offset;
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (phys_addr >= block->offset &&
+ phys_addr < block->offset + block->length) {
+ return phys_addr - block->offset + offset;
+ }
+ offset += block->length;
+ }
+
+ return -1;
+}
+
+static int create_vmcore(Monitor *mon, int fd)
+{
+ CPUState *env;
+ target_phys_addr_t kernel_base = -1;
+ target_ulong base_vaddr;
+ target_phys_addr_t offset, memory_offset;
+ int phdr_num, phdr_index;
+ RAMBlock *block;
+ bool lma = false;
+ int ret;
+ int type, machine, endian;
+ MemoryMappingList list;
+ MemoryMapping *memory_mapping;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_synchronize_state(env);
+ }
+
+ list.num = 0;
+ QTAILQ_INIT(&list.head);
+ get_memory_mapping(&list);
+
+#if defined(TARGET_I386)
+
+#ifdef TARGET_X86_64
+ lma = !!(first_cpu->hflags & HF_LMA_MASK);
+#endif
+
+ kernel_base = get_phys_base_addr(first_cpu, &base_vaddr);
+ if (kernel_base == -1) {
+ monitor_printf(mon, "dump: can not get phys_base\n");
+ goto error;
+ }
+#endif
+
+#if defined(TARGET_I386)
+ if (lma) {
+ machine = EM_X86_64;
+ } else {
+ machine = EM_386;
+ }
+ endian = ELFDATA2LSB;
+#else
+ monitor_printf(mon, "dump: unsupported target.\n")
+ goto error;
+#endif
+
+ if (sizeof(ram_addr_t) == 4) {
+ type = 0; /* use elf32 */
+#if defined(TARGET_I386)
+ } else if (!lma) {
+ type = 0; /* the guest os is not in IA-32e mode */
+#endif
+ } else {
+ type = 1; /* use elf64 */
+ }
+
+ phdr_num = 1; /* PT_NOTE */
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+ if (lma) {
+ create_new_memory_mapping_head(&list, kernel_base, base_vaddr,
+ TARGET_PAGE_SIZE);
+ }
+#endif
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (!lma && (block->offset + block->length > UINT_MAX)) {
+ type = 1; /* The memory size is greater than 4G */
+ break;
+ }
+ }
+#endif
+
+ /* the type of phdr->num is uint16_t, so we should avoid overflow */
+ if (list.num > (1 << 16) - 2) {
+ phdr_num = (1 << 16) - 1;
+ } else {
+ phdr_num += list.num;
+ }
+
+ /* write elf header to vmcore */
+ if (type == 1) {
+ ret = write_elf64_header(mon, fd, phdr_num, machine, endian);
+ } else {
+ ret = write_elf32_header(mon, fd, phdr_num, machine, endian);
+ }
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* write elf notes to vmcore */
+ phdr_index = 0;
+ if (type == 1) {
+ offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_num;
+ ret = write_elf64_notes(mon, fd, phdr_index++, &offset, lma);
+ } else {
+ offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_num;
+ ret = write_elf32_notes(mon, fd, phdr_index++, &offset);
+ }
+
+ if (ret < 0) {
+ goto error;
+ }
+
+ memory_offset = offset;
+ /* write all memory to vmcore */
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ ret = write_memory(mon, fd, block, &offset);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* write PT_LOAD program header to vmcore */
+ QTAILQ_FOREACH(memory_mapping, &list.head, next) {
+ offset = get_offset(memory_mapping->phys_addr, memory_offset);
+ if (type == 1) {
+ ret = write_elf64_load(mon, fd, memory_mapping, phdr_index++,
+ offset);
+ } else {
+ ret = write_elf32_load(mon, fd, memory_mapping, phdr_index++,
+ offset);
+ }
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ free_memory_mapping_list(&list);
+ return 0;
+
+error:
+ free_memory_mapping_list(&list);
+ return -1;
+}
+
+int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *file = qdict_get_str(qdict, "file");
+ const char *p;
+ int fd = -1;
+
+#if !defined(WIN32)
+ if (strstart(file, "fd:", &p)) {
+ fd = monitor_get_fd(mon, p);
+ if (fd == -1) {
+ monitor_printf(mon, "dump: invalid file descriptor"
+ " identifier\n");
+ return -1;
+ }
+ }
+#endif
+
+ if (strstart(file, "file:", &p)) {
+ fd = open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+ if (fd < 0) {
+ monitor_printf(mon, "dump: failed to open %s\n", p);
+ return -1;
+ }
+ }
+
+ if (fd == -1) {
+ monitor_printf(mon, "unknown dump protocol: %s\n", file);
+ return -1;
+ }
+
+ vm_stop(RUN_STATE_PAUSED);
+ if (create_vmcore(mon, fd) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/dump.h b/dump.h
new file mode 100644
index 0000000..c91fa2c
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,6 @@
+#ifndef DUMP_H
+#define DUMP_H
+
+int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+#endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 79a9195..83df152 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -772,6 +772,22 @@ Migrate to @var{uri} (using -d to not wait for completion).
ETEXI
{
+ .name = "dump",
+ .args_type = "file:s",
+ .params = "file",
+ .help = "dump to file",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_dump,
+ },
+
+
+STEXI
+@item dump @var{file}
+@findex dump
+Dump to @var{file}.
+ETEXI
+
+ {
.name = "migrate_cancel",
.args_type = "",
.params = "",
diff --git a/monitor.c b/monitor.c
index 1be222e..9f26c3d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -73,6 +73,9 @@
#endif
#include "hw/lm32_pic.h"
+/* for dump */
+#include "dump.h"
+
//#define DEBUG
//#define DEBUG_COMPLETION
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 94da2a8..4ea50e0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -485,6 +485,30 @@ Notes:
EQMP
{
+ .name = "dump",
+ .args_type = "file:s",
+ .params = "file",
+ .help = "dump to file",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_dump,
+ },
+
+SQMP
+dump
+-------
+
+Dump to file.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "migrate_cancel",
.args_type = "",
.params = "",
--
1.7.1
next prev parent reply other threads:[~2011-12-09 8:07 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-09 7:57 [Qemu-devel] [RFC][PATCT 0/5 v2] dump memory when host pci device is used by guest Wen Congyang
2011-12-09 8:06 ` [Qemu-devel] [RFC][PATCH 1/5 v2] Add API to create memory mapping list Wen Congyang
2011-12-13 13:03 ` Jan Kiszka
2011-12-14 8:10 ` Wen Congyang
2011-12-09 8:07 ` [Qemu-devel] [RFC][PATCH 2/5 v2] Add API to check whether a physical address is I/O address Wen Congyang
2011-12-09 8:08 ` [Qemu-devel] [RFC][PATCH 3/5 v2] target-i386: implement cpu_get_memory_mapping() Wen Congyang
2011-12-09 8:09 ` [Qemu-devel] [RFC][PATCH 4/5 v2] Add API to get memory mapping Wen Congyang
2011-12-09 8:09 ` Wen Congyang [this message]
2011-12-13 3:12 ` [Qemu-devel] [RFC][PATCT 0/5 v2] dump memory when host pci device is used by guest HATAYAMA Daisuke
2011-12-13 3:35 ` Wen Congyang
2011-12-13 6:01 ` HATAYAMA Daisuke
2011-12-13 9:20 ` Wen Congyang
2011-12-15 1:30 ` HATAYAMA Daisuke
2011-12-15 8:57 ` Wen Congyang
2011-12-13 12:55 ` Jan Kiszka
2011-12-14 2:43 ` Wen Congyang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EE1C246.6060503@cn.fujitsu.com \
--to=wency@cn.fujitsu.com \
--cc=anderson@redhat.com \
--cc=d.hatayama@jp.fujitsu.com \
--cc=jan.kiszka@siemens.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.