All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest
@ 2012-01-04  5:44 Wen Congyang
  2012-01-04  6:04 ` [Qemu-devel] [RFC][PATCH 01/14 v4] Add API to create memory mapping list Wen Congyang
                   ` (14 more replies)
  0 siblings, 15 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  5:44 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Hi, all

'virsh dump' can not work when host pci device is used by guest. We have
discussed this issue here:
http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html

We have determined to introduce a new command dump to dump memory. The core
file's format can be elf.

Note:
1. The guest should be x86 or x86_64. The other arch is not supported.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
3. If the OS is in the second kernel, gdb may not work well, and crash can
   work by specifying '--machdep phys_addr=xxx' in the command line. The
   reason is that the second kernel will update the page table, and we can
   not get the page table for the first kernel.
4. If the guest OS is 32 bit and the memory size is larger than 4G, the vmcore
   is elf64 format. You should use the gdb which is built with --enable-64-bit-bfd.

Change from v3 to v4:
1. support it to run asynchronously
2. add API to cancel dumping and query dumping progress
3. add API to control dumping speed
4. auto cancel dumping when the user resumes vm, and the status is failed.

Change from v2 to v3:
1. address Jan Kiszka's comment

Changes from v1 to v2:
1. fix virt addr in the vmcore.

Wen Congyang (14):
  Add API to create memory mapping list
  Add API to check whether a physical address is I/O address
  target-i386: implement cpu_get_memory_mapping()
  Add API to get memory mapping
  target-i386: Add API to write elf notes to core file
  target-i386: Add API to add extra memory mapping
  target-i386: add API to get dump info
  introduce a new monitor command 'dump' to dump guest's memory
  run dump at the background
  support detached dump
  support to cancel the current dumping
  support to set dumping speed
  support to query dumping status
  auto cancel dumping after vm state is changed to run

 Makefile.target         |   11 +-
 cpu-all.h               |   18 +
 cpu-common.h            |    2 +
 dump.c                  |  796 +++++++++++++++++++++++++++++++++++++++++++++++
 dump.h                  |   14 +
 exec.c                  |   20 ++
 hmp-commands.hx         |   47 +++
 hmp.c                   |   24 ++
 hmp.h                   |    3 +
 memory_mapping.c        |  185 +++++++++++
 memory_mapping.h        |   39 +++
 monitor.c               |   10 +
 qapi-schema.json        |   54 ++++
 qmp-commands.hx         |  117 +++++++
 target-i386/arch-dump.c |  574 ++++++++++++++++++++++++++++++++++
 15 files changed, 1909 insertions(+), 5 deletions(-)
 create mode 100644 dump.c
 create mode 100644 dump.h
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h
 create mode 100644 target-i386/arch-dump.c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 01/14 v4] Add API to create memory mapping list
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
@ 2012-01-04  6:04 ` Wen Congyang
  2012-01-04  6:05 ` [Qemu-devel] [RFC][PATCH 02/14 v4] Add API to check whether a physical address is I/O address Wen Congyang
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:04 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

The memory mapping list stores virtual address and physical address mapping.
The folloing patch will use this information to create PT_LOAD in the vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target  |    1 +
 memory_mapping.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |   38 ++++++++++++++++
 3 files changed, 169 insertions(+), 0 deletions(-)
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h

diff --git a/Makefile.target b/Makefile.target
index 3261383..0d5286e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -197,6 +197,7 @@ obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-y += memory.o
+obj-y += memory_mapping.o
 LIBS+=-lz
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
diff --git a/memory_mapping.c b/memory_mapping.c
new file mode 100644
index 0000000..d83b7d7
--- /dev/null
+++ b/memory_mapping.c
@@ -0,0 +1,130 @@
+/*
+ * QEMU memory mapping
+ *
+ * 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 "cpu.h"
+#include "cpu-all.h"
+#include "memory_mapping.h"
+
+static MemoryMapping *last_mapping;
+
+static void create_new_memory_mapping(MemoryMappingList *list,
+                                      target_phys_addr_t phys_addr,
+                                      target_phys_addr_t virt_addr,
+                                      ram_addr_t length)
+{
+    MemoryMapping *memory_mapping, *p;
+
+    memory_mapping = g_malloc(sizeof(MemoryMapping));
+    memory_mapping->phys_addr = phys_addr;
+    memory_mapping->virt_addr = virt_addr;
+    memory_mapping->length = length;
+    last_mapping = memory_mapping;
+    list->num++;
+    QTAILQ_FOREACH(p, &list->head, next) {
+        if (p->phys_addr >= memory_mapping->phys_addr) {
+            QTAILQ_INSERT_BEFORE(p, memory_mapping, next);
+            return;
+        }
+    }
+    QTAILQ_INSERT_TAIL(&list->head, memory_mapping, next);
+    return;
+}
+
+void create_new_memory_mapping_head(MemoryMappingList *list,
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length)
+{
+    MemoryMapping *memory_mapping;
+
+    memory_mapping = g_malloc(sizeof(MemoryMapping));
+    memory_mapping->phys_addr = phys_addr;
+    memory_mapping->virt_addr = virt_addr;
+    memory_mapping->length = length;
+    last_mapping = memory_mapping;
+    list->num++;
+    QTAILQ_INSERT_HEAD(&list->head, memory_mapping, next);
+    return;
+}
+
+void add_to_memory_mapping(MemoryMappingList *list,
+                           target_phys_addr_t phys_addr,
+                           target_phys_addr_t virt_addr,
+                           ram_addr_t length)
+{
+    MemoryMapping *memory_mapping;
+
+    if (QTAILQ_EMPTY(&list->head)) {
+        create_new_memory_mapping(list, phys_addr, virt_addr, length);
+        return;
+    }
+
+    if (last_mapping) {
+        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
+            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
+            last_mapping->length += length;
+            return;
+        }
+    }
+
+    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
+        last_mapping = memory_mapping;
+        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
+            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
+            last_mapping->length += length;
+            return;
+        }
+
+        if (!(phys_addr >= (last_mapping->phys_addr)) ||
+            !(phys_addr < (last_mapping->phys_addr + last_mapping->length))) {
+            /* last_mapping does not contain this region */
+            continue;
+        }
+        if (!(virt_addr >= (last_mapping->virt_addr)) ||
+            !(virt_addr < (last_mapping->virt_addr + last_mapping->length))) {
+            /* last_mapping does not contain this region */
+            continue;
+        }
+        if ((virt_addr - last_mapping->virt_addr) !=
+            (phys_addr - last_mapping->phys_addr)) {
+            /*
+             * last_mapping contains this region, but we should create another
+             * mapping region.
+             */
+            break;
+        }
+
+        /* merge this region into last_mapping */
+        if ((virt_addr + length) >
+            (last_mapping->virt_addr + last_mapping->length)) {
+            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
+        }
+        return;
+    }
+
+    /* this region can not be merged into any existed memory mapping. */
+    create_new_memory_mapping(list, phys_addr, virt_addr, length);
+    return;
+}
+
+void free_memory_mapping_list(MemoryMappingList *list)
+{
+    MemoryMapping *p, *q;
+
+    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
+        QTAILQ_REMOVE(&list->head, p, next);
+        g_free(p);
+    }
+
+    list->num = 0;
+}
diff --git a/memory_mapping.h b/memory_mapping.h
new file mode 100644
index 0000000..a4b1532
--- /dev/null
+++ b/memory_mapping.h
@@ -0,0 +1,38 @@
+#ifndef MEMORY_MAPPING_H
+#define MEMORY_MAPPING_H
+
+#include "qemu-queue.h"
+
+typedef struct MemoryMapping {
+    target_phys_addr_t phys_addr;
+    target_ulong virt_addr;
+    ram_addr_t length;
+    QTAILQ_ENTRY(MemoryMapping) next;
+} MemoryMapping;
+
+typedef struct MemoryMappingList {
+    unsigned int num;
+    QTAILQ_HEAD(, MemoryMapping) head;
+} MemoryMappingList;
+
+/*
+ * crash needs some memory mapping should be at the head of the list. It will
+ * cause the list is not sorted. So the caller must add the special memory
+ * mapping after adding all the normal memory mapping into list.
+ */
+void create_new_memory_mapping_head(MemoryMappingList *list,
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length);
+/*
+ * add or merge the memory region into the memory mapping's list. The list is
+ * sorted by phys_addr.
+ */
+void add_to_memory_mapping(MemoryMappingList *list,
+                           target_phys_addr_t phys_addr,
+                           target_phys_addr_t virt_addr,
+                           ram_addr_t length);
+
+void free_memory_mapping_list(MemoryMappingList *list);
+
+#endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 02/14 v4] Add API to check whether a physical address is I/O address
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
  2012-01-04  6:04 ` [Qemu-devel] [RFC][PATCH 01/14 v4] Add API to create memory mapping list Wen Congyang
@ 2012-01-04  6:05 ` Wen Congyang
  2012-01-04  6:06 ` [Qemu-devel] [RFC][PATCH 03/14 v4] target-i386: implement cpu_get_memory_mapping() Wen Congyang
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:05 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

This API will be used in the following patch.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-common.h |    2 ++
 exec.c       |   20 ++++++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/cpu-common.h b/cpu-common.h
index 3fe44d2..0309137 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -70,6 +70,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
 void cpu_unregister_map_client(void *cookie);
 
+bool is_io_addr(target_phys_addr_t phys_addr);
+
 /* Coalesced MMIO regions are areas where write operations can be reordered.
  * This usually implies that write operations are side-effect free.  This allows
  * batching which can make a major impact on performance when using
diff --git a/exec.c b/exec.c
index b02199b..227d2ea 100644
--- a/exec.c
+++ b/exec.c
@@ -4688,3 +4688,23 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
 #undef env
 
 #endif
+
+bool is_io_addr(target_phys_addr_t phys_addr)
+{
+    ram_addr_t pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(phys_addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+        /* I/O region */
+        return true;
+    }
+
+    return false;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 03/14 v4] target-i386: implement cpu_get_memory_mapping()
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
  2012-01-04  6:04 ` [Qemu-devel] [RFC][PATCH 01/14 v4] Add API to create memory mapping list Wen Congyang
  2012-01-04  6:05 ` [Qemu-devel] [RFC][PATCH 02/14 v4] Add API to check whether a physical address is I/O address Wen Congyang
@ 2012-01-04  6:06 ` Wen Congyang
  2012-01-04  6:07 ` [Qemu-devel] [RFC][PATCH 04/14 v4] Add API to get memory mapping Wen Congyang
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:06 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Walk cpu's page table and collect all virtual address and physical address mapping.
Then, add these mapping into memory mapping list.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target         |    2 +-
 cpu-all.h               |    7 ++
 target-i386/arch-dump.c |  254 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 262 insertions(+), 1 deletions(-)
 create mode 100644 target-i386/arch-dump.c

diff --git a/Makefile.target b/Makefile.target
index 0d5286e..29562ad 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -73,7 +73,7 @@ libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
 libobj-y += fpu/softfloat.o
 libobj-y += op_helper.o helper.o
 ifeq ($(TARGET_BASE_ARCH), i386)
-libobj-y += cpuid.o
+libobj-y += cpuid.o arch-dump.o
 endif
 libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
diff --git a/cpu-all.h b/cpu-all.h
index 734833a..bc32c11 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -22,6 +22,7 @@
 #include "qemu-common.h"
 #include "qemu-tls.h"
 #include "cpu-common.h"
+#include "memory_mapping.h"
 
 /* some important defines:
  *
@@ -575,4 +576,10 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
+#if defined(TARGET_I386)
+void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+#else
+#define cpu_get_memory_mapping(list, env)
+#endif
+
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
new file mode 100644
index 0000000..2e921c7
--- /dev/null
+++ b/target-i386/arch-dump.c
@@ -0,0 +1,254 @@
+/*
+ * i386 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 "cpu.h"
+#include "cpu-all.h"
+
+/* PAE Paging or IA-32e Paging */
+static void walk_pte(MemoryMappingList *list, target_phys_addr_t pte_start_addr,
+                     int32_t a20_mask, target_ulong start_line_addr)
+{
+    target_phys_addr_t pte_addr, start_paddr;
+    uint64_t pte;
+    target_ulong start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pte_addr = (pte_start_addr + i * 8) & a20_mask;
+        pte = ldq_phys(pte_addr);
+        if (!(pte & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        start_paddr = (pte & ~0xfff) & ~(0x1ULL << 63);
+        if (is_io_addr(start_paddr)) {
+            /* I/O region */
+            continue;
+        }
+
+        start_vaddr = start_line_addr | ((i & 0x1fff) << 12);
+        add_to_memory_mapping(list, start_paddr, start_vaddr, 1 << 12);
+    }
+}
+
+/* 32-bit Paging */
+static void walk_pte2(MemoryMappingList *list,
+                      target_phys_addr_t pte_start_addr, int32_t a20_mask,
+                      target_ulong start_line_addr)
+{
+    target_phys_addr_t pte_addr, start_paddr;
+    uint32_t pte;
+    target_ulong start_vaddr;
+    int i;
+
+    for (i = 0; i < 1024; i++) {
+        pte_addr = (pte_start_addr + i * 4) & a20_mask;
+        pte = ldl_phys(pte_addr);
+        if (!(pte & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        start_paddr = pte & ~0xfff;
+        if (is_io_addr(start_paddr)) {
+            /* I/O region */
+            continue;
+        }
+
+        start_vaddr = start_line_addr | ((i & 0x3ff) << 12);
+        add_to_memory_mapping(list, start_paddr, start_vaddr, 1 << 12);
+    }
+}
+
+/* PAE Paging or IA-32e Paging */
+static void walk_pde(MemoryMappingList *list, target_phys_addr_t pde_start_addr,
+                     int32_t a20_mask, target_ulong start_line_addr)
+{
+    target_phys_addr_t pde_addr, pte_start_addr, start_paddr;
+    uint64_t pde;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pde_addr = (pde_start_addr + i * 8) & a20_mask;
+        pde = ldq_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = start_line_addr | ((i & 0x1ff) << 21);
+        if (pde & PG_PSE_MASK) {
+            /* 2 MB page */
+            start_paddr = (pde & ~0x1fffff) & ~(0x1ULL << 63);
+            if (is_io_addr(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            add_to_memory_mapping(list, start_paddr, start_vaddr, 1 << 21);
+            continue;
+        }
+
+        pte_start_addr = (pde & ~0xfff) & a20_mask;
+        walk_pte(list, pte_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* 32-bit Paging */
+static void walk_pde2(MemoryMappingList *list,
+                      target_phys_addr_t pde_start_addr, int32_t a20_mask,
+                      bool pse)
+{
+    target_phys_addr_t pde_addr, pte_start_addr, start_paddr;
+    uint32_t pde;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 1024; i++) {
+        pde_addr = (pde_start_addr + i * 4) & a20_mask;
+        pde = ldl_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = (((unsigned int)i & 0x3ff) << 22);
+        if ((pde & PG_PSE_MASK) && pse) {
+            /* 4 MB page */
+            start_paddr = (pde & ~0x3fffff) | ((pde & 0x1fe000) << 19);
+            if (is_io_addr(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            add_to_memory_mapping(list, start_paddr, start_vaddr, 1 << 22);
+            continue;
+        }
+
+        pte_start_addr = (pde & ~0xfff) & a20_mask;
+        walk_pte2(list, pte_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* PAE Paging */
+static void walk_pdpe2(MemoryMappingList *list,
+                       target_phys_addr_t pdpe_start_addr, int32_t a20_mask)
+{
+    target_phys_addr_t pdpe_addr, pde_start_addr;
+    uint64_t pdpe;
+    target_ulong line_addr;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask;
+        pdpe = ldq_phys(pdpe_addr);
+        if (!(pdpe & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = (((unsigned int)i & 0x3) << 30);
+        pde_start_addr = (pdpe & ~0xfff) & a20_mask;
+        walk_pde(list, pde_start_addr, a20_mask, line_addr);
+    }
+}
+
+#ifdef TARGET_X86_64
+/* IA-32e Paging */
+static void walk_pdpe(MemoryMappingList *list,
+                      target_phys_addr_t pdpe_start_addr, int32_t a20_mask,
+                      target_ulong start_line_addr)
+{
+    target_phys_addr_t pdpe_addr, pde_start_addr, start_paddr;
+    uint64_t pdpe;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask;
+        pdpe = ldq_phys(pdpe_addr);
+        if (!(pdpe & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = start_line_addr | ((i & 0x1ffULL) << 30);
+        if (pdpe & PG_PSE_MASK) {
+            /* 1 GB page */
+            start_paddr = (pdpe & ~0x3fffffff) & ~(0x1ULL << 63);
+            if (is_io_addr(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            add_to_memory_mapping(list, start_paddr, start_vaddr, 1 << 30);
+            continue;
+        }
+
+        pde_start_addr = (pdpe & ~0xfff) & a20_mask;
+        walk_pde(list, pde_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* IA-32e Paging */
+static void walk_pml4e(MemoryMappingList *list,
+                       target_phys_addr_t pml4e_start_addr, int32_t a20_mask)
+{
+    target_phys_addr_t pml4e_addr, pdpe_start_addr;
+    uint64_t pml4e;
+    target_ulong line_addr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pml4e_addr = (pml4e_start_addr + i * 8) & a20_mask;
+        pml4e = ldq_phys(pml4e_addr);
+        if (!(pml4e & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = ((i & 0x1ffULL) << 39) | (0xffffULL << 48);
+        pdpe_start_addr = (pml4e & ~0xfff) & a20_mask;
+        walk_pdpe(list, pdpe_start_addr, a20_mask, line_addr);
+    }
+}
+#endif
+
+void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
+{
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            target_phys_addr_t pml4e_addr;
+
+            pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
+            walk_pml4e(list, pml4e_addr, env->a20_mask);
+        } else
+#endif
+        {
+            target_phys_addr_t pdpe_addr;
+
+            pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask;
+            walk_pdpe2(list, pdpe_addr, env->a20_mask);
+        }
+    } else {
+        target_phys_addr_t pde_addr;
+        bool pse;
+
+        pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
+        pse = !!(env->cr[4] & CR4_PSE_MASK);
+        walk_pde2(list, pde_addr, env->a20_mask, pse);
+    }
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 04/14 v4] Add API to get memory mapping
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (2 preceding siblings ...)
  2012-01-04  6:06 ` [Qemu-devel] [RFC][PATCH 03/14 v4] target-i386: implement cpu_get_memory_mapping() Wen Congyang
@ 2012-01-04  6:07 ` Wen Congyang
  2012-01-04  6:08 ` [Qemu-devel] [RFC][PATCH 05/14 v4] target-i386: Add API to write elf notes to core file Wen Congyang
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:07 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Add API to get all virtual address and physical address mapping.
If there is no virtual address for some physical address, the virtual
address is 0.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 memory_mapping.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |    1 +
 2 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/memory_mapping.c b/memory_mapping.c
index d83b7d7..55c9266 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -128,3 +128,58 @@ void free_memory_mapping_list(MemoryMappingList *list)
 
     list->num = 0;
 }
+
+void get_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+
+    last_mapping = NULL;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_get_memory_mapping(list, env);
+    }
+
+    /* some memory may be not mapped, add them into memory mapping's list */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        offset = block->offset;
+        length = block->length;
+
+        QTAILQ_FOREACH(memory_mapping, &list->head, next) {
+            if (memory_mapping->phys_addr >= (offset + length)) {
+                /*
+                 * memory_mapping'list does not conatin the region
+                 * [offset, offset+length)
+                 */
+                create_new_memory_mapping(list, offset, 0, length);
+                break;
+            }
+
+            if ((memory_mapping->phys_addr + memory_mapping->length) <=
+                offset) {
+                continue;
+            }
+
+            if (memory_mapping->phys_addr > offset) {
+                /*
+                 * memory_mapping'list does not conatin the region
+                 * [offset, memory_mapping->phys_addr)
+                 */
+                create_new_memory_mapping(list, offset, 0,
+                                          memory_mapping->phys_addr - offset);
+            }
+
+            if ((offset + length) <=
+                (memory_mapping->phys_addr + memory_mapping->length)) {
+                break;
+            }
+            length -= memory_mapping->phys_addr + memory_mapping->length -
+                      offset;
+            offset = memory_mapping->phys_addr + memory_mapping->length;
+        }
+    }
+
+    return;
+}
diff --git a/memory_mapping.h b/memory_mapping.h
index a4b1532..679f9ef 100644
--- a/memory_mapping.h
+++ b/memory_mapping.h
@@ -34,5 +34,6 @@ void add_to_memory_mapping(MemoryMappingList *list,
                            ram_addr_t length);
 
 void free_memory_mapping_list(MemoryMappingList *list);
+void get_memory_mapping(MemoryMappingList *list);
 
 #endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 05/14 v4] target-i386: Add API to write elf notes to core file
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (3 preceding siblings ...)
  2012-01-04  6:07 ` [Qemu-devel] [RFC][PATCH 04/14 v4] Add API to get memory mapping Wen Congyang
@ 2012-01-04  6:08 ` Wen Congyang
  2012-01-04  6:09 ` [Qemu-devel] [RFC][PATCH 06/14 v4] target-i386: Add API to add extra memory mapping Wen Congyang
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:08 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

The core file contains register's value. These APIs write registers to
core file, and them will be called in the following patch.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |    6 +
 target-i386/arch-dump.c |  243 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+), 0 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index bc32c11..ffb539c 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -578,8 +578,14 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
 
 #if defined(TARGET_I386)
 void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+int cpu_write_elf64_note(int fd, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset);
+int cpu_write_elf32_note(int fd, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset);
 #else
 #define cpu_get_memory_mapping(list, env)
+#define cpu_write_elf64_note(fd, env, cpuid, offset) ({ -1; })
+#define cpu_write_elf32_note(fd, env, cpuid, offset) ({ -1; })
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index 2e921c7..4c0ff77 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -11,8 +11,11 @@
  *
  */
 
+#include <elf.h>
+
 #include "cpu.h"
 #include "cpu-all.h"
+#include "monitor.h"
 
 /* PAE Paging or IA-32e Paging */
 static void walk_pte(MemoryMappingList *list, target_phys_addr_t pte_start_addr,
@@ -252,3 +255,243 @@ void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
         walk_pde2(list, pde_addr, env->a20_mask, pse);
     }
 }
+
+#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(int fd, CPUState *env, int id,
+                                   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 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, &regs, sizeof(x86_64_user_regs_struct));
+
+    lseek(fd, *offset, SEEK_SET);
+    ret = write(fd, note, note_size);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+#endif
+
+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(int fd, CPUState *env, int id,
+                                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 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, &regs, sizeof(x86_user_regs_struct));
+
+    lseek(fd, *offset, SEEK_SET);
+    ret = write(fd, note, note_size);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+
+static int x86_write_elf32_note(int fd, CPUState *env, int id,
+                                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 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, &regs, sizeof(x86_user_regs_struct));
+
+    lseek(fd, *offset, SEEK_SET);
+    ret = write(fd, note, note_size);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+
+int cpu_write_elf64_note(int fd, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset)
+{
+    int ret;
+#ifdef TARGET_X86_64
+    bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
+
+    if (lma) {
+        ret = x86_64_write_elf64_note(fd, env, cpuid, offset);
+    } else {
+#endif
+        ret = x86_write_elf64_note(fd, env, cpuid, offset);
+#ifdef TARGET_X86_64
+    }
+#endif
+
+    return ret;
+}
+
+int cpu_write_elf32_note(int fd, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset)
+{
+    return x86_write_elf32_note(fd, env, cpuid, offset);
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 06/14 v4] target-i386: Add API to add extra memory mapping
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (4 preceding siblings ...)
  2012-01-04  6:08 ` [Qemu-devel] [RFC][PATCH 05/14 v4] target-i386: Add API to write elf notes to core file Wen Congyang
@ 2012-01-04  6:09 ` Wen Congyang
  2012-01-04  6:10 ` [Qemu-devel] [RFC][PATCH 07/14 v4] target-i386: add API to get dump info Wen Congyang
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:09 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Crash needs extra memory mapping to determine phys_base.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |    2 ++
 target-i386/arch-dump.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index ffb539c..684d7ef 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -582,10 +582,12 @@ int cpu_write_elf64_note(int fd, CPUState *env, int cpuid,
                          target_phys_addr_t *offset);
 int cpu_write_elf32_note(int fd, CPUState *env, int cpuid,
                          target_phys_addr_t *offset);
+int cpu_add_extra_memory_mapping(MemoryMappingList *list);
 #else
 #define cpu_get_memory_mapping(list, env)
 #define cpu_write_elf64_note(fd, env, cpuid, offset) ({ -1; })
 #define cpu_write_elf32_note(fd, env, cpuid, offset) ({ -1; })
+#define cpu_add_extra_memory_mapping(list) ({ 0; })
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index 4c0ff77..d96f6ae 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -495,3 +495,46 @@ int cpu_write_elf32_note(int fd, CPUState *env, int cpuid,
 {
     return x86_write_elf32_note(fd, env, cpuid, offset);
 }
+
+/* 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;
+}
+
+int cpu_add_extra_memory_mapping(MemoryMappingList *list)
+{
+#ifdef TARGET_X86_64
+    target_phys_addr_t kernel_base = -1;
+    target_ulong base_vaddr;
+    bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
+
+    if (!lma) {
+        return 0;
+    }
+
+    kernel_base = get_phys_base_addr(first_cpu, &base_vaddr);
+    if (kernel_base == -1) {
+        return -1;
+    }
+
+    create_new_memory_mapping_head(list, kernel_base, base_vaddr,
+                                   TARGET_PAGE_SIZE);
+#endif
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 07/14 v4] target-i386: add API to get dump info
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (5 preceding siblings ...)
  2012-01-04  6:09 ` [Qemu-devel] [RFC][PATCH 06/14 v4] target-i386: Add API to add extra memory mapping Wen Congyang
@ 2012-01-04  6:10 ` Wen Congyang
  2012-01-04  6:11 ` [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:10 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Dump info contains: endian, class and architecture. The next
patch will use these information to create vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |    3 +++
 dump.h                  |   10 ++++++++++
 target-i386/arch-dump.c |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 0 deletions(-)
 create mode 100644 dump.h

diff --git a/cpu-all.h b/cpu-all.h
index 684d7ef..199b756 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -23,6 +23,7 @@
 #include "qemu-tls.h"
 #include "cpu-common.h"
 #include "memory_mapping.h"
+#include "dump.h"
 
 /* some important defines:
  *
@@ -583,11 +584,13 @@ int cpu_write_elf64_note(int fd, CPUState *env, int cpuid,
 int cpu_write_elf32_note(int fd, CPUState *env, int cpuid,
                          target_phys_addr_t *offset);
 int cpu_add_extra_memory_mapping(MemoryMappingList *list);
+int cpu_get_dump_info(ArchDumpInfo *info);
 #else
 #define cpu_get_memory_mapping(list, env)
 #define cpu_write_elf64_note(fd, env, cpuid, offset) ({ -1; })
 #define cpu_write_elf32_note(fd, env, cpuid, offset) ({ -1; })
 #define cpu_add_extra_memory_mapping(list) ({ 0; })
+#define cpu_get_dump_info(info) ({ -1; })
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/dump.h b/dump.h
new file mode 100644
index 0000000..a36468b
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,10 @@
+#ifndef DUMP_H
+#define DUMP_H
+
+typedef struct ArchDumpInfo {
+    int d_machine;  /* Architecture */
+    int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
+    int d_class;    /* ELFCLASS32 or ELFCLASS64 */
+} ArchDumpInfo;
+
+#endif
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index d96f6ae..92a53bc 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -15,6 +15,7 @@
 
 #include "cpu.h"
 #include "cpu-all.h"
+#include "dump.h"
 #include "monitor.h"
 
 /* PAE Paging or IA-32e Paging */
@@ -538,3 +539,36 @@ int cpu_add_extra_memory_mapping(MemoryMappingList *list)
 #endif
     return 0;
 }
+
+int cpu_get_dump_info(ArchDumpInfo *info)
+{
+    bool lma = false;
+    RAMBlock *block;
+
+#ifdef TARGET_X86_64
+    lma = !!(first_cpu->hflags & HF_LMA_MASK);
+#endif
+
+    if (lma) {
+        info->d_machine = EM_X86_64;
+    } else {
+        info->d_machine = EM_386;
+    }
+    info->d_endian = ELFDATA2LSB;
+
+    if (lma) {
+        info->d_class = ELFCLASS64;
+    } else {
+        info->d_class = ELFCLASS32;
+    }
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (!lma && (block->offset + block->length > UINT_MAX)) {
+            /* The memory size is greater than 4G */
+            info->d_class = ELFCLASS32;
+            break;
+        }
+    }
+
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (6 preceding siblings ...)
  2012-01-04  6:10 ` [Qemu-devel] [RFC][PATCH 07/14 v4] target-i386: add API to get dump info Wen Congyang
@ 2012-01-04  6:11 ` Wen Congyang
  2012-01-10 13:30   ` Luiz Capitulino
  2012-01-04  6:12 ` [Qemu-devel] [RFC][PATCH 09/14 v4] run dump at the background Wen Congyang
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:11 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target |    8 +-
 dump.c          |  588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 dump.h          |    4 +
 hmp-commands.hx |   16 ++
 monitor.c       |    3 +
 qmp-commands.hx |   26 +++
 6 files changed, 641 insertions(+), 4 deletions(-)
 create mode 100644 dump.c

diff --git a/Makefile.target b/Makefile.target
index 29562ad..f7cc2b9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -110,7 +110,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
 
@@ -148,7 +148,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
 
@@ -170,7 +170,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
 
@@ -186,7 +186,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..ab29a4c
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,588 @@
+/*
+ * 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"
+
+#define CPU_CONVERT_TO_TARGET16(val) \
+({ \
+    uint16_t _val = (val); \
+    if (endian == ELFDATA2LSB) { \
+        _val = cpu_to_le16(_val); \
+    } else {\
+        _val = cpu_to_be16(_val); \
+    } \
+    _val; \
+})
+
+#define CPU_CONVERT_TO_TARGET32(val) \
+({ \
+    uint32_t _val = (val); \
+    if (endian == ELFDATA2LSB) { \
+        _val = cpu_to_le32(_val); \
+    } else {\
+        _val = cpu_to_be32(_val); \
+    } \
+    _val; \
+})
+
+#define CPU_CONVERT_TO_TARGET64(val) \
+({ \
+    uint64_t _val = (val); \
+    if (endian == ELFDATA2LSB) { \
+        _val = cpu_to_le64(_val); \
+    } else {\
+        _val = cpu_to_be64(_val); \
+    } \
+    _val; \
+})
+
+enum {
+    DUMP_STATE_ERROR,
+    DUMP_STATE_SETUP,
+    DUMP_STATE_CANCELLED,
+    DUMP_STATE_ACTIVE,
+    DUMP_STATE_COMPLETED,
+};
+
+typedef struct DumpState {
+    ArchDumpInfo dump_info;
+    MemoryMappingList list;
+    int phdr_num;
+    int state;
+    char *error;
+    Monitor *mon;
+    int fd;
+    target_phys_addr_t memory_offset;
+} DumpState;
+
+static DumpState *dump_get_current(void)
+{
+    static DumpState current_dump = {
+        .state = DUMP_STATE_SETUP,
+    };
+
+    return &current_dump;
+}
+
+static int dump_cleanup(DumpState *s)
+{
+    int ret = 0;
+
+    free_memory_mapping_list(&s->list);
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+
+    return ret;
+}
+
+static void dump_error(DumpState *s, const char *reason)
+{
+    s->state = DUMP_STATE_ERROR;
+    s->error = g_strdup(reason);
+    dump_cleanup(s);
+}
+
+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
+}
+
+static int write_elf64_header(DumpState *s)
+{
+    Elf64_Ehdr elf_header;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    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] = s->dump_info.d_endian;
+    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+    elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
+    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
+    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
+    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
+    elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
+    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
+    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
+
+    lseek(s->fd, 0, SEEK_SET);
+    ret = write(s->fd, &elf_header, sizeof(elf_header));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write elf header.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_header(DumpState *s)
+{
+    Elf32_Ehdr elf_header;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    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_CONVERT_TO_TARGET16(ET_CORE);
+    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
+    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
+    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
+    elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
+    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
+    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
+
+    lseek(s->fd, 0, SEEK_SET);
+    ret = write(s->fd, &elf_header, sizeof(elf_header));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write elf header.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
+                            int phdr_index, target_phys_addr_t offset)
+{
+    Elf64_Phdr phdr;
+    off_t phdr_offset;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&phdr, 0, sizeof(Elf64_Phdr));
+    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
+    phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
+    phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
+    if (offset == -1) {
+        phdr.p_filesz = 0;
+    } else {
+        phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
+    }
+    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
+    phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
+
+    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
+    lseek(s->fd, phdr_offset, SEEK_SET);
+    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
+                            int phdr_index, target_phys_addr_t offset)
+{
+    Elf32_Phdr phdr;
+    off_t phdr_offset;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&phdr, 0, sizeof(Elf32_Phdr));
+    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
+    phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
+    phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
+    if (offset == -1) {
+        phdr.p_filesz = 0;
+    } else {
+        phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
+    }
+    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
+    phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
+
+    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
+    lseek(s->fd, phdr_offset, SEEK_SET);
+    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf64_notes(DumpState *s, int phdr_index,
+                             target_phys_addr_t *offset)
+{
+    CPUState *env;
+    int ret;
+    target_phys_addr_t begin = *offset;
+    Elf64_Phdr phdr;
+    off_t phdr_offset;
+    int id;
+    int endian = s->dump_info.d_endian;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        id = cpuid(env);
+        ret = cpu_write_elf64_note(s->fd, env, id, offset);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write elf notes.\n");
+            return -1;
+        }
+    }
+
+    memset(&phdr, 0, sizeof(Elf64_Phdr));
+    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
+    phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
+    phdr.p_paddr = 0;
+    phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
+    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
+    phdr.p_vaddr = 0;
+
+    phdr_offset = sizeof(Elf64_Ehdr);
+    lseek(s->fd, phdr_offset, SEEK_SET);
+    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_notes(DumpState *s, 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;
+    int id;
+    int endian = s->dump_info.d_endian;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        id = cpuid(env);
+        ret = cpu_write_elf32_note(s->fd, env, id, offset);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write elf notes.\n");
+            return -1;
+        }
+    }
+
+    memset(&phdr, 0, sizeof(Elf32_Phdr));
+    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
+    phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
+    phdr.p_paddr = 0;
+    phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
+    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
+    phdr.p_vaddr = 0;
+
+    phdr_offset = sizeof(Elf32_Ehdr);
+    lseek(s->fd, phdr_offset, SEEK_SET);
+    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_data(DumpState *s, void *buf, int length,
+                      target_phys_addr_t *offset)
+{
+    int ret;
+
+    lseek(s->fd, *offset, SEEK_SET);
+    ret = write(s->fd, buf, length);
+    if (ret < 0) {
+        dump_error(s, "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(DumpState *s, RAMBlock *block,
+                        target_phys_addr_t *offset)
+{
+    int i, ret;
+
+    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
+        ret = write_data(s, 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(s, 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 DumpState *dump_init(Monitor *mon, int fd)
+{
+    CPUState *env;
+    DumpState *s = dump_get_current();
+    int ret;
+
+    vm_stop(RUN_STATE_PAUSED);
+    s->state = DUMP_STATE_SETUP;
+    s->error = NULL;
+    s->mon = mon;
+    s->fd = fd;
+
+    /*
+     * get dump info: endian, class and architecture.
+     * If the target architecture is not supported, cpu_get_dump_info() will
+     * return -1.
+     *
+     * if we use kvm, we should synchronize the register before we get dump
+     * info.
+     */
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_synchronize_state(env);
+    }
+    ret = cpu_get_dump_info(&s->dump_info);
+    if (ret < 0) {
+        monitor_printf(mon, "dump: unsupported target.\n");
+        return NULL;
+    }
+
+    /* get memory mapping */
+    s->list.num = 0;
+    QTAILQ_INIT(&s->list.head);
+    get_memory_mapping(&s->list);
+
+    /* crash needs extra memory mapping to determine phys_base. */
+    ret = cpu_add_extra_memory_mapping(&s->list);
+    if (ret < 0) {
+        monitor_printf(mon, "dump: failed to add extra memory mapping.\n");
+        return NULL;
+    }
+
+    /*
+     * calculate phdr_num
+     *
+     * the type of phdr->num is uint16_t, so we should avoid overflow
+     */
+    s->phdr_num = 1; /* PT_NOTE */
+    if (s->list.num > (1 << 16) - 2) {
+        s->phdr_num = (1 << 16) - 1;
+    } else {
+        s->phdr_num += s->list.num;
+    }
+
+    return s;
+}
+
+/* write elf header, PT_NOTE and elf note to vmcore. */
+static int dump_begin(DumpState *s)
+{
+    target_phys_addr_t offset;
+    int ret;
+
+    s->state = DUMP_STATE_ACTIVE;
+
+    /*
+     * the vmcore's format is:
+     *   --------------
+     *   |  elf header |
+     *   --------------
+     *   |  PT_NOTE    |
+     *   --------------
+     *   |  PT_LOAD    |
+     *   --------------
+     *   |  ......     |
+     *   --------------
+     *   |  PT_LOAD    |
+     *   --------------
+     *   |  elf note   |
+     *   --------------
+     *   |  memory     |
+     *   --------------
+     *
+     * we only know where the memory is saved after we write elf note into
+     * vmcore.
+     */
+
+    /* write elf header to vmcore */
+    if (s->dump_info.d_class == ELFCLASS64) {
+        ret = write_elf64_header(s);
+    } else {
+        ret = write_elf32_header(s);
+    }
+    if (ret < 0) {
+        return -1;
+    }
+
+    /* write elf notes to vmcore */
+    if (s->dump_info.d_class == ELFCLASS64) {
+        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
+        ret = write_elf64_notes(s, 0, &offset);
+    } else {
+        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
+        ret = write_elf32_notes(s, 0, &offset);
+    }
+
+    if (ret < 0) {
+        return -1;
+    }
+
+    s->memory_offset = offset;
+    return 0;
+}
+
+/* write PT_LOAD to vmcore */
+static int dump_completed(DumpState *s)
+{
+    target_phys_addr_t offset;
+    MemoryMapping *memory_mapping;
+    int phdr_index = 1, ret;
+
+    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
+        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
+        if (s->dump_info.d_class == ELFCLASS64) {
+            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
+        } else {
+            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
+        }
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    s->state = DUMP_STATE_COMPLETED;
+    dump_cleanup(s);
+    return 0;
+}
+
+/* write all memory to vmcore */
+static int dump_iterate(DumpState *s)
+{
+    RAMBlock *block;
+    target_phys_addr_t offset = s->memory_offset;
+    int ret;
+
+    /* write all memory to vmcore */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        ret = write_memory(s, block, &offset);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    return dump_completed(s);
+}
+
+static int create_vmcore(DumpState *s)
+{
+    int ret;
+
+    ret = dump_begin(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = dump_iterate(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+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;
+    DumpState *s;
+
+#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;
+    }
+
+    s = dump_init(mon, fd);
+    if (!s) {
+        return -1;
+    }
+
+    if (create_vmcore(s) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/dump.h b/dump.h
index a36468b..def6c0e 100644
--- a/dump.h
+++ b/dump.h
@@ -1,10 +1,14 @@
 #ifndef DUMP_H
 #define DUMP_H
 
+#include "qdict.h"
+
 typedef struct ArchDumpInfo {
     int d_machine;  /* Architecture */
     int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
     int d_class;    /* ELFCLASS32 or ELFCLASS64 */
 } ArchDumpInfo;
 
+int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
 #endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 14838b7..98c1c35 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -828,6 +828,22 @@ new parameters (if specified) once the vm migration finished successfully.
 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       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
         .params     = "device [new-image-file] [format]",
diff --git a/monitor.c b/monitor.c
index 7334401..edd6aa7 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 7e3f4b9..023cade 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -572,6 +572,32 @@ Example:
 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:
+
+- "file": Destination file (json-string)
+
+Example:
+
+-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
         .params     = "[user|tap|socket],id=str[,prop=value][,...]",
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 09/14 v4] run dump at the background
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (7 preceding siblings ...)
  2012-01-04  6:11 ` [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
@ 2012-01-04  6:12 ` Wen Congyang
  2012-01-04  6:13 ` [Qemu-devel] [RFC][PATCH 10/14 v4] support detached dump Wen Congyang
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:12 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

The new monitor command dump may take long time to finish. So we need run it
at the background.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c |  158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 139 insertions(+), 19 deletions(-)

diff --git a/dump.c b/dump.c
index ab29a4c..09ed96a 100644
--- a/dump.c
+++ b/dump.c
@@ -75,12 +75,20 @@ typedef struct DumpState {
     Monitor *mon;
     int fd;
     target_phys_addr_t memory_offset;
+    int64_t bandwidth;
+    RAMBlock *block;
+    ram_addr_t start;
+    target_phys_addr_t offset;
+    QEMUTimer *timer;
 } DumpState;
 
+#define DEFAULT_THROTTLE  (32 << 20)      /* Default dump speed throttling */
+
 static DumpState *dump_get_current(void)
 {
     static DumpState current_dump = {
         .state = DUMP_STATE_SETUP,
+        .bandwidth = DEFAULT_THROTTLE,
     };
 
     return &current_dump;
@@ -91,11 +99,21 @@ static int dump_cleanup(DumpState *s)
     int ret = 0;
 
     free_memory_mapping_list(&s->list);
+
     if (s->fd != -1) {
         close(s->fd);
         s->fd = -1;
     }
 
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+        qemu_free_timer(s->timer);
+    }
+
+    if (s->mon) {
+        monitor_resume(s->mon);
+    }
+
     return ret;
 }
 
@@ -330,25 +348,40 @@ static int write_data(DumpState *s, void *buf, int length,
 }
 
 /* write the memroy to vmcore. 1 page per I/O. */
-static int write_memory(DumpState *s, RAMBlock *block,
-                        target_phys_addr_t *offset)
+static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
+                        target_phys_addr_t *offset, int64_t *size,
+                        int64_t deadline)
 {
     int i, ret;
+    int64_t writen_size = 0;
+    int64_t time;
 
-    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
+    for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
                          TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
             return -1;
         }
+        writen_size += TARGET_PAGE_SIZE;
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            *size = writen_size;
+            return 1;
+        }
     }
 
-    if ((block->length % TARGET_PAGE_SIZE) != 0) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
-                         block->length % TARGET_PAGE_SIZE, offset);
+    if ((*size % TARGET_PAGE_SIZE) != 0) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
+                         *size % TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
             return -1;
         }
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            return 1;
+        }
     }
 
     return 0;
@@ -383,6 +416,9 @@ static DumpState *dump_init(Monitor *mon, int fd)
     s->error = NULL;
     s->mon = mon;
     s->fd = fd;
+    s->block = QLIST_FIRST(&ram_list.blocks);
+    s->start = 0;
+    s->timer = NULL;
 
     /*
      * get dump info: endian, class and architecture.
@@ -425,6 +461,11 @@ static DumpState *dump_init(Monitor *mon, int fd)
         s->phdr_num += s->list.num;
     }
 
+    if (monitor_suspend(mon) != 0) {
+        monitor_printf(mon, "terminal does not allow synchronous "
+                       "dump, continuing detached\n");
+    }
+
     return s;
 }
 
@@ -482,6 +523,7 @@ static int dump_begin(DumpState *s)
     }
 
     s->memory_offset = offset;
+    s->offset = offset;
     return 0;
 }
 
@@ -509,38 +551,116 @@ static int dump_completed(DumpState *s)
     return 0;
 }
 
-/* write all memory to vmcore */
-static int dump_iterate(DumpState *s)
+/*
+ * write memory to vmcore.
+ *
+ * this function has three return values:
+ *  -1 : there was one error
+ *   0 : We haven't finished, caller have to go again
+ *   1 : We have finished, we can go to complete phase
+ */
+static int dump_iterate(DumpState *s, int64_t deadline)
 {
-    RAMBlock *block;
-    target_phys_addr_t offset = s->memory_offset;
+    RAMBlock *block = s->block;
+    target_phys_addr_t offset = s->offset;
+    int64_t size, remain, writen_size;
+    int64_t total = s->bandwidth / 10;
     int ret;
 
-    /* write all memory to vmcore */
-    QLIST_FOREACH(block, &ram_list.blocks, next) {
-        ret = write_memory(s, block, &offset);
+    if ((block->length - s->start) >= total) {
+        size = total;
+    } else {
+        size = block->length - s->start;
+    }
+
+    ret = write_memory(s, block, s->start, &offset, &size, deadline);
+    if (ret < 0) {
+        return -1;
+    }
+
+    if (size == total || ret == 1) {
+        if ((size + s->start) == block->length) {
+            s->block = QLIST_NEXT(block, next);
+            s->start = 0;
+        } else {
+            s->start += size;
+        }
+        goto end;
+    }
+
+    while (size < total) {
+        block = QLIST_NEXT(block, next);
+        if (!block) {
+            /* we have finished */
+            return 1;
+        }
+
+        remain = total - size;
+        if (remain >= block->length) {
+            writen_size = block->length;
+        } else {
+            writen_size = remain;
+        }
+        ret = write_memory(s, block, 0, &offset, &writen_size, deadline);
         if (ret < 0) {
             return -1;
+        } else if (ret == 1) {
+            break;
         }
+        size += writen_size;
+    }
+    if (writen_size == block->length) {
+        s->block = QLIST_NEXT(block, next);
+        s->start = 0;
+    } else {
+        s->block = block;
+        s->start = writen_size;
+    }
+
+end:
+    s->offset = offset;
+    if (!s->block) {
+        /* we have finished */
+        return 1;
     }
 
-    return dump_completed(s);
+    return 0;
 }
 
-static int create_vmcore(DumpState *s)
+static void dump_rate_tick(void *opaque)
 {
+    DumpState *s = opaque;
+    int64_t begin, end;
     int ret;
 
-    ret = dump_begin(s);
+    begin = qemu_get_clock_ms(rt_clock);
+    ret = dump_iterate(s, begin + 100);
     if (ret < 0) {
-        return -1;
+        return;
+    } else if (ret == 1) {
+        dump_completed(s);
+        return;
+    }
+    end = qemu_get_clock_ms(rt_clock);
+    if (end - begin >= 100) {
+        qemu_mod_timer(s->timer, end + 10);
+    } else {
+        qemu_mod_timer(s->timer, begin + 100);
     }
+}
 
-    ret = dump_iterate(s);
+static int create_vmcore(DumpState *s)
+{
+    int ret;
+
+    ret = dump_begin(s);
     if (ret < 0) {
         return -1;
     }
 
+    s->timer = qemu_new_timer_ms(rt_clock, dump_rate_tick, s);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100);
+
     return 0;
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 10/14 v4] support detached dump
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (8 preceding siblings ...)
  2012-01-04  6:12 ` [Qemu-devel] [RFC][PATCH 09/14 v4] run dump at the background Wen Congyang
@ 2012-01-04  6:13 ` Wen Congyang
  2012-01-04  6:14 ` [Qemu-devel] [RFC][PATCH 11/14 v4] support to cancel the current dumping Wen Congyang
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:13 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Let the user to choose whether to block other monitor command while dumping.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c          |   24 +++++++++++++++++++-----
 hmp-commands.hx |    8 ++++----
 qmp-commands.hx |    7 ++++---
 3 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/dump.c b/dump.c
index 09ed96a..6acc252 100644
--- a/dump.c
+++ b/dump.c
@@ -74,6 +74,7 @@ typedef struct DumpState {
     char *error;
     Monitor *mon;
     int fd;
+    int detach;
     target_phys_addr_t memory_offset;
     int64_t bandwidth;
     RAMBlock *block;
@@ -110,6 +111,10 @@ static int dump_cleanup(DumpState *s)
         qemu_free_timer(s->timer);
     }
 
+    if (!s->detach && s->error) {
+        monitor_printf(s->mon, "%s", s->error);
+    }
+
     if (s->mon) {
         monitor_resume(s->mon);
     }
@@ -405,7 +410,7 @@ static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
     return -1;
 }
 
-static DumpState *dump_init(Monitor *mon, int fd)
+static DumpState *dump_init(Monitor *mon, int fd, int detach)
 {
     CPUState *env;
     DumpState *s = dump_get_current();
@@ -419,6 +424,7 @@ static DumpState *dump_init(Monitor *mon, int fd)
     s->block = QLIST_FIRST(&ram_list.blocks);
     s->start = 0;
     s->timer = NULL;
+    s->detach = detach;
 
     /*
      * get dump info: endian, class and architecture.
@@ -461,9 +467,12 @@ static DumpState *dump_init(Monitor *mon, int fd)
         s->phdr_num += s->list.num;
     }
 
-    if (monitor_suspend(mon) != 0) {
-        monitor_printf(mon, "terminal does not allow synchronous "
-                       "dump, continuing detached\n");
+    if (!detach) {
+        if (monitor_suspend(mon) != 0) {
+            monitor_printf(mon, "terminal does not allow synchronous "
+                           "dump, continuing detached\n");
+            s->detach = 1;
+        }
     }
 
     return s;
@@ -667,6 +676,7 @@ static int create_vmcore(DumpState *s)
 int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *file = qdict_get_str(qdict, "file");
+    int detach = qdict_get_try_bool(qdict, "detach", 0);
     const char *p;
     int fd = -1;
     DumpState *s;
@@ -695,11 +705,15 @@ int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
         return -1;
     }
 
-    s = dump_init(mon, fd);
+    s = dump_init(mon, fd, detach);
     if (!s) {
         return -1;
     }
 
+    if (s->detach) {
+        s->mon = NULL;
+    }
+
     if (create_vmcore(s) < 0) {
         return -1;
     }
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 98c1c35..ef0d53a 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -829,18 +829,18 @@ ETEXI
 
     {
         .name       = "dump",
-        .args_type  = "file:s",
+        .args_type  = "detach:-d,file:s",
         .params     = "file",
-        .help       = "dump to file",
+        .help       = "dump to file (using -d to not wait for completion)",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = do_dump,
     },
 
 
 STEXI
-@item dump @var{file}
+@item dump [-d] @var{file}
 @findex dump
-Dump to @var{file}.
+Dump to @var{file} (using -d to not wait for completion).
 ETEXI
 
     {
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 023cade..f359dff 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -573,9 +573,9 @@ EQMP
 
     {
         .name       = "dump",
-        .args_type  = "file:s",
+        .args_type  = "detach:-d,file:s",
         .params     = "file",
-        .help       = "dump to file",
+        .help       = "dump to file (using -d to not wait for completion)",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = do_dump,
     },
@@ -588,7 +588,8 @@ Dump to file.
 
 Arguments:
 
-- "file": Destination file (json-string)
+- "detach": detached dumping (json-bool, optional)
+- "file":   Destination file (json-string)
 
 Example:
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 11/14 v4] support to cancel the current dumping
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (9 preceding siblings ...)
  2012-01-04  6:13 ` [Qemu-devel] [RFC][PATCH 10/14 v4] support detached dump Wen Congyang
@ 2012-01-04  6:14 ` Wen Congyang
  2012-01-04  6:15 ` [Qemu-devel] [RFC][PATCH 12/14 v4] support to set dumping speed Wen Congyang
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:14 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Add API to allow the user to cancel the current dumping.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |   14 ++++++++++++++
 hmp-commands.hx  |   14 ++++++++++++++
 hmp.c            |    5 +++++
 hmp.h            |    1 +
 qapi-schema.json |   13 +++++++++++++
 qmp-commands.hx  |   21 +++++++++++++++++++++
 6 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index 6acc252..3848d25 100644
--- a/dump.c
+++ b/dump.c
@@ -24,6 +24,7 @@
 #include "sysemu.h"
 #include "bswap.h"
 #include "memory_mapping.h"
+#include "qmp-commands.h"
 
 #define CPU_CONVERT_TO_TARGET16(val) \
 ({ \
@@ -720,3 +721,16 @@ int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
     return 0;
 }
+
+void qmp_dump_cancel(Error **errp)
+{
+    DumpState *s = dump_get_current();
+
+    if (s->state != DUMP_STATE_ACTIVE) {
+        return;
+    }
+
+    s->state = DUMP_STATE_CANCELLED;
+    dump_cleanup(s);
+    return;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index ef0d53a..83d40b6 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -844,6 +844,20 @@ Dump to @var{file} (using -d to not wait for completion).
 ETEXI
 
     {
+        .name       = "dump_cancel",
+        .args_type  = "",
+        .params     = "",
+        .help       = "cancel the current VM dumping",
+        .mhandler.cmd = hmp_dump_cancel,
+    },
+
+STEXI
+@item dump_cancel
+@findex dump_cancel
+Cancel the current VM dumping.
+ETEXI
+
+    {
         .name       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
         .params     = "device [new-image-file] [format]",
diff --git a/hmp.c b/hmp.c
index e7659d5..7fc89db 100644
--- a/hmp.c
+++ b/hmp.c
@@ -679,3 +679,8 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
     int64_t value = qdict_get_int(qdict, "value");
     qmp_migrate_set_speed(value, NULL);
 }
+
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
+{
+    qmp_dump_cancel(NULL);
+}
diff --git a/hmp.h b/hmp.h
index 093242d..409e809 100644
--- a/hmp.h
+++ b/hmp.h
@@ -49,5 +49,6 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 44cf764..f5f79b0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1275,3 +1275,16 @@
 { 'command': 'qom-set',
   'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
   'gen': 'no' }
+
+##
+# @dump_cancel
+#
+# Cancel the current executing dumping process.
+#
+# Returns: nothing on success
+#
+# Notes: This command succeeds even if there is no dumping process running.
+#
+# Since: 1.1
+##
+{ 'command': 'dump_cancel' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f359dff..5207a41 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -599,6 +599,27 @@ Example:
 EQMP
 
     {
+        .name       = "dump_cancel",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_dump_cancel,
+    },
+
+SQMP
+dump_cancel
+
+
+Cancel the current dumping.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "dump_cancel" }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
         .params     = "[user|tap|socket],id=str[,prop=value][,...]",
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 12/14 v4] support to set dumping speed
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (10 preceding siblings ...)
  2012-01-04  6:14 ` [Qemu-devel] [RFC][PATCH 11/14 v4] support to cancel the current dumping Wen Congyang
@ 2012-01-04  6:15 ` Wen Congyang
  2012-01-04  6:16 ` [Qemu-devel] [RFC][PATCH 13/14 v4] support to query dumping status Wen Congyang
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:15 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Add API to allow the user to control dumping speed

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |   12 ++++++++++++
 hmp-commands.hx  |   15 +++++++++++++++
 hmp.c            |    6 ++++++
 hmp.h            |    1 +
 qapi-schema.json |   15 +++++++++++++++
 qmp-commands.hx  |   22 ++++++++++++++++++++++
 6 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index 3848d25..2131e22 100644
--- a/dump.c
+++ b/dump.c
@@ -85,6 +85,7 @@ typedef struct DumpState {
 } DumpState;
 
 #define DEFAULT_THROTTLE  (32 << 20)      /* Default dump speed throttling */
+#define MIN_THROTTLE  (1 << 10)       /* Miniumum dump speed */
 
 static DumpState *dump_get_current(void)
 {
@@ -734,3 +735,14 @@ void qmp_dump_cancel(Error **errp)
     dump_cleanup(s);
     return;
 }
+
+void qmp_dump_set_speed(int64_t value, Error **errp)
+{
+    DumpState *s = dump_get_current();
+
+    if (value < MIN_THROTTLE) {
+        value = MIN_THROTTLE;
+    }
+    s->bandwidth = value;
+    return;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 83d40b6..20543dd 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -858,6 +858,21 @@ Cancel the current VM dumping.
 ETEXI
 
     {
+        .name       = "dump_set_speed",
+        .args_type  = "value:o",
+        .params     = "value",
+        .help       = "set maximum speed (in bytes) for dumping. "
+        "Defaults to MB if no size suffix is specified, ie. B/K/M/G/T",
+        .mhandler.cmd = hmp_dump_set_speed,
+    },
+
+STEXI
+@item dump_set_speed @var{value}
+@findex dump_set_speed
+Set maximum speed to @var{value} (in bytes) for dumping.
+ETEXI
+
+    {
         .name       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
         .params     = "device [new-image-file] [format]",
diff --git a/hmp.c b/hmp.c
index 7fc89db..be64075 100644
--- a/hmp.c
+++ b/hmp.c
@@ -684,3 +684,9 @@ void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
 {
     qmp_dump_cancel(NULL);
 }
+
+void hmp_dump_set_speed(Monitor *mon, const QDict *qdict)
+{
+    int64_t value = qdict_get_int(qdict, "value");
+    qmp_dump_set_speed(value, NULL);
+}
diff --git a/hmp.h b/hmp.h
index 409e809..3aa947c 100644
--- a/hmp.h
+++ b/hmp.h
@@ -50,5 +50,6 @@ void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
+void hmp_dump_set_speed(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index f5f79b0..ca324d6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1288,3 +1288,18 @@
 # Since: 1.1
 ##
 { 'command': 'dump_cancel' }
+
+##
+# @dump_set_speed
+#
+# Set maximum speed for dumping.
+#
+# @value: maximum speed in bytes.
+#
+# Returns: nothing on success
+#
+# Notes: A value lesser than 1024 will be automatically round up to 1024.
+#
+# Since: 1.1
+##
+{ 'command': 'dump_set_speed', 'data': {'value': 'int'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5207a41..6f84cdc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -620,6 +620,28 @@ Example:
 EQMP
 
     {
+        .name       = "dump_set_speed",
+        .args_type  = "value:o",
+        .mhandler.cmd_new = qmp_marshal_input_dump_set_speed,
+    },
+
+SQMP
+dump_set_speed
+
+Set maximum speed for dumping.
+
+Arguments:
+
+- "value": maximum speed, in bytes per second (json-int)
+
+Example:
+
+-> { "execute": "dump_set_speed", "arguments": { "value": 1024 } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
         .params     = "[user|tap|socket],id=str[,prop=value][,...]",
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 13/14 v4] support to query dumping status
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (11 preceding siblings ...)
  2012-01-04  6:15 ` [Qemu-devel] [RFC][PATCH 12/14 v4] support to set dumping speed Wen Congyang
@ 2012-01-04  6:16 ` Wen Congyang
  2012-01-04  6:17 ` [Qemu-devel] [RFC][PATCH 14/14 v4] auto cancel dumping after vm state is changed to run Wen Congyang
  2012-01-10  7:44 ` [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:16 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

Add API to allow the user to query dumping status.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |   30 ++++++++++++++++++++++++++++++
 hmp-commands.hx  |    2 ++
 hmp.c            |   13 +++++++++++++
 hmp.h            |    1 +
 monitor.c        |    7 +++++++
 qapi-schema.json |   26 ++++++++++++++++++++++++++
 qmp-commands.hx  |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index 2131e22..4276cb8 100644
--- a/dump.c
+++ b/dump.c
@@ -746,3 +746,33 @@ void qmp_dump_set_speed(int64_t value, Error **errp)
     s->bandwidth = value;
     return;
 }
+
+DumpInfo *qmp_query_dump(Error **errp)
+{
+    DumpInfo *info = g_malloc0(sizeof(*info));
+    DumpState *s = dump_get_current();
+
+    switch (s->state) {
+    case DUMP_STATE_SETUP:
+        /* no migration has happened ever */
+        break;
+    case DUMP_STATE_ACTIVE:
+        info->has_status = true;
+        info->status = g_strdup("active");
+        break;
+    case DUMP_STATE_COMPLETED:
+        info->has_status = true;
+        info->status = g_strdup("completed");
+        break;
+    case DUMP_STATE_ERROR:
+        info->has_status = true;
+        info->status = g_strdup("failed");
+        break;
+    case DUMP_STATE_CANCELLED:
+        info->has_status = true;
+        info->status = g_strdup("cancelled");
+        break;
+    }
+
+    return info;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 20543dd..1eaaf18 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1397,6 +1397,8 @@ show device tree
 show qdev device model list
 @item info roms
 show roms
+@item info dump
+show dumping status
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index be64075..04ed86a 100644
--- a/hmp.c
+++ b/hmp.c
@@ -690,3 +690,16 @@ void hmp_dump_set_speed(Monitor *mon, const QDict *qdict)
     int64_t value = qdict_get_int(qdict, "value");
     qmp_dump_set_speed(value, NULL);
 }
+
+void hmp_info_dump(Monitor *mon)
+{
+    DumpInfo *info;
+
+    info = qmp_query_dump(NULL);
+
+    if (info->has_status) {
+        monitor_printf(mon, "Dumping status: %s\n", info->status);
+    }
+
+    qapi_free_DumpInfo(info);
+}
diff --git a/hmp.h b/hmp.h
index 3aa947c..5f58b9e 100644
--- a/hmp.h
+++ b/hmp.h
@@ -51,5 +51,6 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
 void hmp_dump_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_info_dump(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index edd6aa7..b1d09cc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2739,6 +2739,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = do_trace_print_events,
     },
     {
+        .name       = "dump",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show dumping status",
+        .mhandler.info = hmp_info_dump,
+    },
+    {
         .name       = NULL,
     },
 };
diff --git a/qapi-schema.json b/qapi-schema.json
index ca324d6..087027a 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1303,3 +1303,29 @@
 # Since: 1.1
 ##
 { 'command': 'dump_set_speed', 'data': {'value': 'int'} }
+
+##
+# @DumpInfo
+#
+# Information about current migration process.
+#
+# @status: #optional string describing the current dumping status.
+#          As of 1,1 this can be 'active', 'completed', 'failed' or
+#          'cancelled'. If this field is not returned, no migration process
+#          has been initiated
+#
+# Since: 1.1
+##
+{ 'type': 'DumpInfo',
+  'data': {'*status': 'str'} }
+
+##
+# @query-dump
+#
+# Returns information about current dumping process.
+#
+# Returns: @DumpInfo
+#
+# Since: 1.1
+##
+{ 'command': 'query-dump', 'returns': 'DumpInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6f84cdc..bccc3a4 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2040,6 +2040,53 @@ EQMP
     },
 
 SQMP
+query-dump
+-------------
+
+Dumping status.
+
+Return a json-object.
+
+The main json-object contains the following:
+
+- "status": migration status (json-string)
+     - Possible values: "active", "completed", "failed", "cancelled"
+
+Examples:
+
+1. Before the first migration
+
+-> { "execute": "query-dump" }
+<- { "return": {} }
+
+2. Migration is done and has succeeded
+
+-> { "execute": "query-dump" }
+<- { "return": { "status": "completed" } }
+
+3. Migration is done and has failed
+
+-> { "execute": "query-dump" }
+<- { "return": { "status": "failed" } }
+
+4. Migration is being performed:
+
+-> { "execute": "query-dump" }
+<- {
+      "return":{
+         "status":"active",
+      }
+   }
+
+EQMP
+
+    {
+        .name       = "query-dump",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_dump,
+    },
+
+SQMP
 query-balloon
 -------------
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [RFC][PATCH 14/14 v4] auto cancel dumping after vm state is changed to run
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (12 preceding siblings ...)
  2012-01-04  6:16 ` [Qemu-devel] [RFC][PATCH 13/14 v4] support to query dumping status Wen Congyang
@ 2012-01-04  6:17 ` Wen Congyang
  2012-01-10  7:44 ` [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
  14 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-04  6:17 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke

The command dump does not support to dump while vm is running. If the user resume
the vm, we should auto cancel dumping and set the status to failed.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index 4276cb8..2053c3e 100644
--- a/dump.c
+++ b/dump.c
@@ -82,6 +82,7 @@ typedef struct DumpState {
     ram_addr_t start;
     target_phys_addr_t offset;
     QEMUTimer *timer;
+    VMChangeStateEntry *handler;
 } DumpState;
 
 #define DEFAULT_THROTTLE  (32 << 20)      /* Default dump speed throttling */
@@ -113,6 +114,11 @@ static int dump_cleanup(DumpState *s)
         qemu_free_timer(s->timer);
     }
 
+    if (s->handler) {
+        qemu_del_vm_change_state_handler(s->handler);
+        s->handler = NULL;
+    }
+
     if (!s->detach && s->error) {
         monitor_printf(s->mon, "%s", s->error);
     }
@@ -675,6 +681,16 @@ static int create_vmcore(DumpState *s)
     return 0;
 }
 
+static void dump_vm_state_change(void *opaque, int running, RunState state)
+{
+    DumpState *s = opaque;
+
+    if (running) {
+        qmp_dump_cancel(NULL);
+        s->state = DUMP_STATE_ERROR;
+    }
+}
+
 int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *file = qdict_get_str(qdict, "file");
@@ -712,6 +728,8 @@ int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
         return -1;
     }
 
+    s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s);
+
     if (s->detach) {
         s->mon = NULL;
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest
  2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
                   ` (13 preceding siblings ...)
  2012-01-04  6:17 ` [Qemu-devel] [RFC][PATCH 14/14 v4] auto cancel dumping after vm state is changed to run Wen Congyang
@ 2012-01-10  7:44 ` Wen Congyang
  2012-01-10  9:41   ` Jan Kiszka
  14 siblings, 1 reply; 21+ messages in thread
From: Wen Congyang @ 2012-01-10  7:44 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka

Hi, Jan Kiszka
Do you have any time to review this patchset?

Thanks
Wen Congyang

At 01/04/2012 01:44 PM, Wen Congyang Wrote:
> Hi, all
> 
> 'virsh dump' can not work when host pci device is used by guest. We have
> discussed this issue here:
> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
> 
> We have determined to introduce a new command dump to dump memory. The core
> file's format can be elf.
> 
> Note:
> 1. The guest should be x86 or x86_64. The other arch is not supported.
> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>    reason is that the second kernel will update the page table, and we can
>    not get the page table for the first kernel.
> 4. If the guest OS is 32 bit and the memory size is larger than 4G, the vmcore
>    is elf64 format. You should use the gdb which is built with --enable-64-bit-bfd.
> 
> Change from v3 to v4:
> 1. support it to run asynchronously
> 2. add API to cancel dumping and query dumping progress
> 3. add API to control dumping speed
> 4. auto cancel dumping when the user resumes vm, and the status is failed.
> 
> Change from v2 to v3:
> 1. address Jan Kiszka's comment
> 
> Changes from v1 to v2:
> 1. fix virt addr in the vmcore.
> 
> Wen Congyang (14):
>   Add API to create memory mapping list
>   Add API to check whether a physical address is I/O address
>   target-i386: implement cpu_get_memory_mapping()
>   Add API to get memory mapping
>   target-i386: Add API to write elf notes to core file
>   target-i386: Add API to add extra memory mapping
>   target-i386: add API to get dump info
>   introduce a new monitor command 'dump' to dump guest's memory
>   run dump at the background
>   support detached dump
>   support to cancel the current dumping
>   support to set dumping speed
>   support to query dumping status
>   auto cancel dumping after vm state is changed to run
> 
>  Makefile.target         |   11 +-
>  cpu-all.h               |   18 +
>  cpu-common.h            |    2 +
>  dump.c                  |  796 +++++++++++++++++++++++++++++++++++++++++++++++
>  dump.h                  |   14 +
>  exec.c                  |   20 ++
>  hmp-commands.hx         |   47 +++
>  hmp.c                   |   24 ++
>  hmp.h                   |    3 +
>  memory_mapping.c        |  185 +++++++++++
>  memory_mapping.h        |   39 +++
>  monitor.c               |   10 +
>  qapi-schema.json        |   54 ++++
>  qmp-commands.hx         |  117 +++++++
>  target-i386/arch-dump.c |  574 ++++++++++++++++++++++++++++++++++
>  15 files changed, 1909 insertions(+), 5 deletions(-)
>  create mode 100644 dump.c
>  create mode 100644 dump.h
>  create mode 100644 memory_mapping.c
>  create mode 100644 memory_mapping.h
>  create mode 100644 target-i386/arch-dump.c
> 
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest
  2012-01-10  7:44 ` [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
@ 2012-01-10  9:41   ` Jan Kiszka
  0 siblings, 0 replies; 21+ messages in thread
From: Jan Kiszka @ 2012-01-10  9:41 UTC (permalink / raw)
  To: Wen Congyang; +Cc: qemu-devel

On 2012-01-10 08:44, Wen Congyang wrote:
> Hi, Jan Kiszka
> Do you have any time to review this patchset?

Will try to find some.

BTW, the title of this cover letter is a bit misleading. This series is
about introducing a new, dedicated memory dump mechanism.

Jan

> 
> Thanks
> Wen Congyang
> 
> At 01/04/2012 01:44 PM, Wen Congyang Wrote:
>> Hi, all
>>
>> 'virsh dump' can not work when host pci device is used by guest. We have
>> discussed this issue here:
>> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
>>
>> We have determined to introduce a new command dump to dump memory. The core
>> file's format can be elf.
>>
>> Note:
>> 1. The guest should be x86 or x86_64. The other arch is not supported.
>> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
>> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>>    reason is that the second kernel will update the page table, and we can
>>    not get the page table for the first kernel.
>> 4. If the guest OS is 32 bit and the memory size is larger than 4G, the vmcore
>>    is elf64 format. You should use the gdb which is built with --enable-64-bit-bfd.
>>
>> Change from v3 to v4:
>> 1. support it to run asynchronously
>> 2. add API to cancel dumping and query dumping progress
>> 3. add API to control dumping speed
>> 4. auto cancel dumping when the user resumes vm, and the status is failed.
>>
>> Change from v2 to v3:
>> 1. address Jan Kiszka's comment
>>
>> Changes from v1 to v2:
>> 1. fix virt addr in the vmcore.
>>
>> Wen Congyang (14):
>>   Add API to create memory mapping list
>>   Add API to check whether a physical address is I/O address
>>   target-i386: implement cpu_get_memory_mapping()
>>   Add API to get memory mapping
>>   target-i386: Add API to write elf notes to core file
>>   target-i386: Add API to add extra memory mapping
>>   target-i386: add API to get dump info
>>   introduce a new monitor command 'dump' to dump guest's memory
>>   run dump at the background
>>   support detached dump
>>   support to cancel the current dumping
>>   support to set dumping speed
>>   support to query dumping status
>>   auto cancel dumping after vm state is changed to run
>>
>>  Makefile.target         |   11 +-
>>  cpu-all.h               |   18 +
>>  cpu-common.h            |    2 +
>>  dump.c                  |  796 +++++++++++++++++++++++++++++++++++++++++++++++
>>  dump.h                  |   14 +
>>  exec.c                  |   20 ++
>>  hmp-commands.hx         |   47 +++
>>  hmp.c                   |   24 ++
>>  hmp.h                   |    3 +
>>  memory_mapping.c        |  185 +++++++++++
>>  memory_mapping.h        |   39 +++
>>  monitor.c               |   10 +
>>  qapi-schema.json        |   54 ++++
>>  qmp-commands.hx         |  117 +++++++
>>  target-i386/arch-dump.c |  574 ++++++++++++++++++++++++++++++++++
>>  15 files changed, 1909 insertions(+), 5 deletions(-)
>>  create mode 100644 dump.c
>>  create mode 100644 dump.h
>>  create mode 100644 memory_mapping.c
>>  create mode 100644 memory_mapping.h
>>  create mode 100644 target-i386/arch-dump.c
>>
>>
> 

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory
  2012-01-04  6:11 ` [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
@ 2012-01-10 13:30   ` Luiz Capitulino
  2012-01-11  0:59     ` Wen Congyang
  0 siblings, 1 reply; 21+ messages in thread
From: Luiz Capitulino @ 2012-01-10 13:30 UTC (permalink / raw)
  To: Wen Congyang; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel

On Wed, 04 Jan 2012 14:11:01 +0800
Wen Congyang <wency@cn.fujitsu.com> wrote:

> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> ---
>  Makefile.target |    8 +-
>  dump.c          |  588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  dump.h          |    4 +
>  hmp-commands.hx |   16 ++
>  monitor.c       |    3 +
>  qmp-commands.hx |   26 +++
>  6 files changed, 641 insertions(+), 4 deletions(-)
>  create mode 100644 dump.c
> 
> diff --git a/Makefile.target b/Makefile.target
> index 29562ad..f7cc2b9 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -110,7 +110,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
>  
> @@ -148,7 +148,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
>  
> @@ -170,7 +170,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
>  
> @@ -186,7 +186,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..ab29a4c
> --- /dev/null
> +++ b/dump.c
> @@ -0,0 +1,588 @@
> +/*
> + * 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"
> +
> +#define CPU_CONVERT_TO_TARGET16(val) \
> +({ \
> +    uint16_t _val = (val); \
> +    if (endian == ELFDATA2LSB) { \
> +        _val = cpu_to_le16(_val); \
> +    } else {\
> +        _val = cpu_to_be16(_val); \
> +    } \
> +    _val; \
> +})
> +
> +#define CPU_CONVERT_TO_TARGET32(val) \
> +({ \
> +    uint32_t _val = (val); \
> +    if (endian == ELFDATA2LSB) { \
> +        _val = cpu_to_le32(_val); \
> +    } else {\
> +        _val = cpu_to_be32(_val); \
> +    } \
> +    _val; \
> +})
> +
> +#define CPU_CONVERT_TO_TARGET64(val) \
> +({ \
> +    uint64_t _val = (val); \
> +    if (endian == ELFDATA2LSB) { \
> +        _val = cpu_to_le64(_val); \
> +    } else {\
> +        _val = cpu_to_be64(_val); \
> +    } \
> +    _val; \
> +})
> +
> +enum {
> +    DUMP_STATE_ERROR,
> +    DUMP_STATE_SETUP,
> +    DUMP_STATE_CANCELLED,
> +    DUMP_STATE_ACTIVE,
> +    DUMP_STATE_COMPLETED,
> +};
> +
> +typedef struct DumpState {
> +    ArchDumpInfo dump_info;
> +    MemoryMappingList list;
> +    int phdr_num;
> +    int state;
> +    char *error;
> +    Monitor *mon;
> +    int fd;
> +    target_phys_addr_t memory_offset;
> +} DumpState;
> +
> +static DumpState *dump_get_current(void)
> +{
> +    static DumpState current_dump = {
> +        .state = DUMP_STATE_SETUP,
> +    };
> +
> +    return &current_dump;
> +}
> +
> +static int dump_cleanup(DumpState *s)
> +{
> +    int ret = 0;
> +
> +    free_memory_mapping_list(&s->list);
> +    if (s->fd != -1) {
> +        close(s->fd);
> +        s->fd = -1;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dump_error(DumpState *s, const char *reason)
> +{
> +    s->state = DUMP_STATE_ERROR;
> +    s->error = g_strdup(reason);
> +    dump_cleanup(s);
> +}
> +
> +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
> +}
> +
> +static int write_elf64_header(DumpState *s)
> +{
> +    Elf64_Ehdr elf_header;
> +    int ret;
> +    int endian = s->dump_info.d_endian;
> +
> +    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] = s->dump_info.d_endian;
> +    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
> +    elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
> +
> +    lseek(s->fd, 0, SEEK_SET);
> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write elf header.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_elf32_header(DumpState *s)
> +{
> +    Elf32_Ehdr elf_header;
> +    int ret;
> +    int endian = s->dump_info.d_endian;
> +
> +    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_CONVERT_TO_TARGET16(ET_CORE);
> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
> +
> +    lseek(s->fd, 0, SEEK_SET);
> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write elf header.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
> +                            int phdr_index, target_phys_addr_t offset)
> +{
> +    Elf64_Phdr phdr;
> +    off_t phdr_offset;
> +    int ret;
> +    int endian = s->dump_info.d_endian;
> +
> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
> +    if (offset == -1) {
> +        phdr.p_filesz = 0;
> +    } else {
> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
> +    }
> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
> +
> +    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
> +    lseek(s->fd, phdr_offset, SEEK_SET);
> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write program header table.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
> +                            int phdr_index, target_phys_addr_t offset)
> +{
> +    Elf32_Phdr phdr;
> +    off_t phdr_offset;
> +    int ret;
> +    int endian = s->dump_info.d_endian;
> +
> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
> +    if (offset == -1) {
> +        phdr.p_filesz = 0;
> +    } else {
> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
> +    }
> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
> +
> +    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
> +    lseek(s->fd, phdr_offset, SEEK_SET);
> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write program header table.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_elf64_notes(DumpState *s, int phdr_index,
> +                             target_phys_addr_t *offset)
> +{
> +    CPUState *env;
> +    int ret;
> +    target_phys_addr_t begin = *offset;
> +    Elf64_Phdr phdr;
> +    off_t phdr_offset;
> +    int id;
> +    int endian = s->dump_info.d_endian;
> +
> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +        id = cpuid(env);
> +        ret = cpu_write_elf64_note(s->fd, env, id, offset);
> +        if (ret < 0) {
> +            dump_error(s, "dump: failed to write elf notes.\n");
> +            return -1;
> +        }
> +    }
> +
> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
> +    phdr.p_paddr = 0;
> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
> +    phdr.p_vaddr = 0;
> +
> +    phdr_offset = sizeof(Elf64_Ehdr);
> +    lseek(s->fd, phdr_offset, SEEK_SET);
> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write program header table.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_elf32_notes(DumpState *s, 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;
> +    int id;
> +    int endian = s->dump_info.d_endian;
> +
> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +        id = cpuid(env);
> +        ret = cpu_write_elf32_note(s->fd, env, id, offset);
> +        if (ret < 0) {
> +            dump_error(s, "dump: failed to write elf notes.\n");
> +            return -1;
> +        }
> +    }
> +
> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
> +    phdr.p_paddr = 0;
> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
> +    phdr.p_vaddr = 0;
> +
> +    phdr_offset = sizeof(Elf32_Ehdr);
> +    lseek(s->fd, phdr_offset, SEEK_SET);
> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
> +    if (ret < 0) {
> +        dump_error(s, "dump: failed to write program header table.\n");
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_data(DumpState *s, void *buf, int length,
> +                      target_phys_addr_t *offset)
> +{
> +    int ret;
> +
> +    lseek(s->fd, *offset, SEEK_SET);
> +    ret = write(s->fd, buf, length);
> +    if (ret < 0) {
> +        dump_error(s, "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(DumpState *s, RAMBlock *block,
> +                        target_phys_addr_t *offset)
> +{
> +    int i, ret;
> +
> +    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
> +        ret = write_data(s, 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(s, 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 DumpState *dump_init(Monitor *mon, int fd)
> +{
> +    CPUState *env;
> +    DumpState *s = dump_get_current();
> +    int ret;
> +
> +    vm_stop(RUN_STATE_PAUSED);
> +    s->state = DUMP_STATE_SETUP;
> +    s->error = NULL;
> +    s->mon = mon;
> +    s->fd = fd;
> +
> +    /*
> +     * get dump info: endian, class and architecture.
> +     * If the target architecture is not supported, cpu_get_dump_info() will
> +     * return -1.
> +     *
> +     * if we use kvm, we should synchronize the register before we get dump
> +     * info.
> +     */
> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +        cpu_synchronize_state(env);
> +    }
> +    ret = cpu_get_dump_info(&s->dump_info);
> +    if (ret < 0) {
> +        monitor_printf(mon, "dump: unsupported target.\n");
> +        return NULL;
> +    }
> +
> +    /* get memory mapping */
> +    s->list.num = 0;
> +    QTAILQ_INIT(&s->list.head);
> +    get_memory_mapping(&s->list);
> +
> +    /* crash needs extra memory mapping to determine phys_base. */
> +    ret = cpu_add_extra_memory_mapping(&s->list);
> +    if (ret < 0) {
> +        monitor_printf(mon, "dump: failed to add extra memory mapping.\n");
> +        return NULL;
> +    }
> +
> +    /*
> +     * calculate phdr_num
> +     *
> +     * the type of phdr->num is uint16_t, so we should avoid overflow
> +     */
> +    s->phdr_num = 1; /* PT_NOTE */
> +    if (s->list.num > (1 << 16) - 2) {
> +        s->phdr_num = (1 << 16) - 1;
> +    } else {
> +        s->phdr_num += s->list.num;
> +    }
> +
> +    return s;
> +}
> +
> +/* write elf header, PT_NOTE and elf note to vmcore. */
> +static int dump_begin(DumpState *s)
> +{
> +    target_phys_addr_t offset;
> +    int ret;
> +
> +    s->state = DUMP_STATE_ACTIVE;
> +
> +    /*
> +     * the vmcore's format is:
> +     *   --------------
> +     *   |  elf header |
> +     *   --------------
> +     *   |  PT_NOTE    |
> +     *   --------------
> +     *   |  PT_LOAD    |
> +     *   --------------
> +     *   |  ......     |
> +     *   --------------
> +     *   |  PT_LOAD    |
> +     *   --------------
> +     *   |  elf note   |
> +     *   --------------
> +     *   |  memory     |
> +     *   --------------
> +     *
> +     * we only know where the memory is saved after we write elf note into
> +     * vmcore.
> +     */
> +
> +    /* write elf header to vmcore */
> +    if (s->dump_info.d_class == ELFCLASS64) {
> +        ret = write_elf64_header(s);
> +    } else {
> +        ret = write_elf32_header(s);
> +    }
> +    if (ret < 0) {
> +        return -1;
> +    }
> +
> +    /* write elf notes to vmcore */
> +    if (s->dump_info.d_class == ELFCLASS64) {
> +        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
> +        ret = write_elf64_notes(s, 0, &offset);
> +    } else {
> +        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
> +        ret = write_elf32_notes(s, 0, &offset);
> +    }
> +
> +    if (ret < 0) {
> +        return -1;
> +    }
> +
> +    s->memory_offset = offset;
> +    return 0;
> +}
> +
> +/* write PT_LOAD to vmcore */
> +static int dump_completed(DumpState *s)
> +{
> +    target_phys_addr_t offset;
> +    MemoryMapping *memory_mapping;
> +    int phdr_index = 1, ret;
> +
> +    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
> +        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
> +        if (s->dump_info.d_class == ELFCLASS64) {
> +            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
> +        } else {
> +            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
> +        }
> +        if (ret < 0) {
> +            return -1;
> +        }
> +    }
> +
> +    s->state = DUMP_STATE_COMPLETED;
> +    dump_cleanup(s);
> +    return 0;
> +}
> +
> +/* write all memory to vmcore */
> +static int dump_iterate(DumpState *s)
> +{
> +    RAMBlock *block;
> +    target_phys_addr_t offset = s->memory_offset;
> +    int ret;
> +
> +    /* write all memory to vmcore */
> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
> +        ret = write_memory(s, block, &offset);
> +        if (ret < 0) {
> +            return -1;
> +        }
> +    }
> +
> +    return dump_completed(s);
> +}
> +
> +static int create_vmcore(DumpState *s)
> +{
> +    int ret;
> +
> +    ret = dump_begin(s);
> +    if (ret < 0) {
> +        return -1;
> +    }
> +
> +    ret = dump_iterate(s);
> +    if (ret < 0) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)

This is not using the QAPI. Please, take a look at the document
docs/writing-qmp-commands.txt on how to do that. You can also look at the
various examples in hmp.c/qmp.c.

I haven't reviewed your approach for the asynchronous support yet. We're
discussing right now what to do wrt commands introducing their own async
support, will review it as soon as we have a decision.

Btw, I'd like to have an ack from Jan for the general approach of this
command.

> +{
> +    const char *file = qdict_get_str(qdict, "file");
> +    const char *p;
> +    int fd = -1;
> +    DumpState *s;
> +
> +#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;
> +    }
> +
> +    s = dump_init(mon, fd);
> +    if (!s) {
> +        return -1;
> +    }
> +
> +    if (create_vmcore(s) < 0) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> diff --git a/dump.h b/dump.h
> index a36468b..def6c0e 100644
> --- a/dump.h
> +++ b/dump.h
> @@ -1,10 +1,14 @@
>  #ifndef DUMP_H
>  #define DUMP_H
>  
> +#include "qdict.h"
> +
>  typedef struct ArchDumpInfo {
>      int d_machine;  /* Architecture */
>      int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
>      int d_class;    /* ELFCLASS32 or ELFCLASS64 */
>  } ArchDumpInfo;
>  
> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
> +
>  #endif
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 14838b7..98c1c35 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -828,6 +828,22 @@ new parameters (if specified) once the vm migration finished successfully.
>  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       = "snapshot_blkdev",
>          .args_type  = "device:B,snapshot-file:s?,format:s?",
>          .params     = "device [new-image-file] [format]",
> diff --git a/monitor.c b/monitor.c
> index 7334401..edd6aa7 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 7e3f4b9..023cade 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -572,6 +572,32 @@ Example:
>  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:
> +
> +- "file": Destination file (json-string)
> +
> +Example:
> +
> +-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
> +<- { "return": {} }
> +
> +EQMP
> +
> +    {
>          .name       = "netdev_add",
>          .args_type  = "netdev:O",
>          .params     = "[user|tap|socket],id=str[,prop=value][,...]",

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory
  2012-01-10 13:30   ` Luiz Capitulino
@ 2012-01-11  0:59     ` Wen Congyang
  2012-01-12 13:49       ` Luiz Capitulino
  0 siblings, 1 reply; 21+ messages in thread
From: Wen Congyang @ 2012-01-11  0:59 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel

At 01/10/2012 09:30 PM, Luiz Capitulino Wrote:
> On Wed, 04 Jan 2012 14:11:01 +0800
> Wen Congyang <wency@cn.fujitsu.com> wrote:
> 
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> ---
>>  Makefile.target |    8 +-
>>  dump.c          |  588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  dump.h          |    4 +
>>  hmp-commands.hx |   16 ++
>>  monitor.c       |    3 +
>>  qmp-commands.hx |   26 +++
>>  6 files changed, 641 insertions(+), 4 deletions(-)
>>  create mode 100644 dump.c
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index 29562ad..f7cc2b9 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -110,7 +110,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
>>  
>> @@ -148,7 +148,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
>>  
>> @@ -170,7 +170,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
>>  
>> @@ -186,7 +186,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..ab29a4c
>> --- /dev/null
>> +++ b/dump.c
>> @@ -0,0 +1,588 @@
>> +/*
>> + * 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"
>> +
>> +#define CPU_CONVERT_TO_TARGET16(val) \
>> +({ \
>> +    uint16_t _val = (val); \
>> +    if (endian == ELFDATA2LSB) { \
>> +        _val = cpu_to_le16(_val); \
>> +    } else {\
>> +        _val = cpu_to_be16(_val); \
>> +    } \
>> +    _val; \
>> +})
>> +
>> +#define CPU_CONVERT_TO_TARGET32(val) \
>> +({ \
>> +    uint32_t _val = (val); \
>> +    if (endian == ELFDATA2LSB) { \
>> +        _val = cpu_to_le32(_val); \
>> +    } else {\
>> +        _val = cpu_to_be32(_val); \
>> +    } \
>> +    _val; \
>> +})
>> +
>> +#define CPU_CONVERT_TO_TARGET64(val) \
>> +({ \
>> +    uint64_t _val = (val); \
>> +    if (endian == ELFDATA2LSB) { \
>> +        _val = cpu_to_le64(_val); \
>> +    } else {\
>> +        _val = cpu_to_be64(_val); \
>> +    } \
>> +    _val; \
>> +})
>> +
>> +enum {
>> +    DUMP_STATE_ERROR,
>> +    DUMP_STATE_SETUP,
>> +    DUMP_STATE_CANCELLED,
>> +    DUMP_STATE_ACTIVE,
>> +    DUMP_STATE_COMPLETED,
>> +};
>> +
>> +typedef struct DumpState {
>> +    ArchDumpInfo dump_info;
>> +    MemoryMappingList list;
>> +    int phdr_num;
>> +    int state;
>> +    char *error;
>> +    Monitor *mon;
>> +    int fd;
>> +    target_phys_addr_t memory_offset;
>> +} DumpState;
>> +
>> +static DumpState *dump_get_current(void)
>> +{
>> +    static DumpState current_dump = {
>> +        .state = DUMP_STATE_SETUP,
>> +    };
>> +
>> +    return &current_dump;
>> +}
>> +
>> +static int dump_cleanup(DumpState *s)
>> +{
>> +    int ret = 0;
>> +
>> +    free_memory_mapping_list(&s->list);
>> +    if (s->fd != -1) {
>> +        close(s->fd);
>> +        s->fd = -1;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +static void dump_error(DumpState *s, const char *reason)
>> +{
>> +    s->state = DUMP_STATE_ERROR;
>> +    s->error = g_strdup(reason);
>> +    dump_cleanup(s);
>> +}
>> +
>> +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
>> +}
>> +
>> +static int write_elf64_header(DumpState *s)
>> +{
>> +    Elf64_Ehdr elf_header;
>> +    int ret;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    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] = s->dump_info.d_endian;
>> +    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
>> +    elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
>> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
>> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
>> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
>> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
>> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
>> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
>> +
>> +    lseek(s->fd, 0, SEEK_SET);
>> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write elf header.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_elf32_header(DumpState *s)
>> +{
>> +    Elf32_Ehdr elf_header;
>> +    int ret;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    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_CONVERT_TO_TARGET16(ET_CORE);
>> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
>> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
>> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
>> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
>> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
>> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
>> +
>> +    lseek(s->fd, 0, SEEK_SET);
>> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write elf header.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
>> +                            int phdr_index, target_phys_addr_t offset)
>> +{
>> +    Elf64_Phdr phdr;
>> +    off_t phdr_offset;
>> +    int ret;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
>> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
>> +    if (offset == -1) {
>> +        phdr.p_filesz = 0;
>> +    } else {
>> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
>> +    }
>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
>> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
>> +
>> +    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write program header table.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
>> +                            int phdr_index, target_phys_addr_t offset)
>> +{
>> +    Elf32_Phdr phdr;
>> +    off_t phdr_offset;
>> +    int ret;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
>> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
>> +    if (offset == -1) {
>> +        phdr.p_filesz = 0;
>> +    } else {
>> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
>> +    }
>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
>> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
>> +
>> +    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write program header table.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_elf64_notes(DumpState *s, int phdr_index,
>> +                             target_phys_addr_t *offset)
>> +{
>> +    CPUState *env;
>> +    int ret;
>> +    target_phys_addr_t begin = *offset;
>> +    Elf64_Phdr phdr;
>> +    off_t phdr_offset;
>> +    int id;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>> +        id = cpuid(env);
>> +        ret = cpu_write_elf64_note(s->fd, env, id, offset);
>> +        if (ret < 0) {
>> +            dump_error(s, "dump: failed to write elf notes.\n");
>> +            return -1;
>> +        }
>> +    }
>> +
>> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
>> +    phdr.p_paddr = 0;
>> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
>> +    phdr.p_vaddr = 0;
>> +
>> +    phdr_offset = sizeof(Elf64_Ehdr);
>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write program header table.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_elf32_notes(DumpState *s, 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;
>> +    int id;
>> +    int endian = s->dump_info.d_endian;
>> +
>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>> +        id = cpuid(env);
>> +        ret = cpu_write_elf32_note(s->fd, env, id, offset);
>> +        if (ret < 0) {
>> +            dump_error(s, "dump: failed to write elf notes.\n");
>> +            return -1;
>> +        }
>> +    }
>> +
>> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
>> +    phdr.p_paddr = 0;
>> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
>> +    phdr.p_vaddr = 0;
>> +
>> +    phdr_offset = sizeof(Elf32_Ehdr);
>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
>> +    if (ret < 0) {
>> +        dump_error(s, "dump: failed to write program header table.\n");
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int write_data(DumpState *s, void *buf, int length,
>> +                      target_phys_addr_t *offset)
>> +{
>> +    int ret;
>> +
>> +    lseek(s->fd, *offset, SEEK_SET);
>> +    ret = write(s->fd, buf, length);
>> +    if (ret < 0) {
>> +        dump_error(s, "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(DumpState *s, RAMBlock *block,
>> +                        target_phys_addr_t *offset)
>> +{
>> +    int i, ret;
>> +
>> +    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
>> +        ret = write_data(s, 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(s, 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 DumpState *dump_init(Monitor *mon, int fd)
>> +{
>> +    CPUState *env;
>> +    DumpState *s = dump_get_current();
>> +    int ret;
>> +
>> +    vm_stop(RUN_STATE_PAUSED);
>> +    s->state = DUMP_STATE_SETUP;
>> +    s->error = NULL;
>> +    s->mon = mon;
>> +    s->fd = fd;
>> +
>> +    /*
>> +     * get dump info: endian, class and architecture.
>> +     * If the target architecture is not supported, cpu_get_dump_info() will
>> +     * return -1.
>> +     *
>> +     * if we use kvm, we should synchronize the register before we get dump
>> +     * info.
>> +     */
>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>> +        cpu_synchronize_state(env);
>> +    }
>> +    ret = cpu_get_dump_info(&s->dump_info);
>> +    if (ret < 0) {
>> +        monitor_printf(mon, "dump: unsupported target.\n");
>> +        return NULL;
>> +    }
>> +
>> +    /* get memory mapping */
>> +    s->list.num = 0;
>> +    QTAILQ_INIT(&s->list.head);
>> +    get_memory_mapping(&s->list);
>> +
>> +    /* crash needs extra memory mapping to determine phys_base. */
>> +    ret = cpu_add_extra_memory_mapping(&s->list);
>> +    if (ret < 0) {
>> +        monitor_printf(mon, "dump: failed to add extra memory mapping.\n");
>> +        return NULL;
>> +    }
>> +
>> +    /*
>> +     * calculate phdr_num
>> +     *
>> +     * the type of phdr->num is uint16_t, so we should avoid overflow
>> +     */
>> +    s->phdr_num = 1; /* PT_NOTE */
>> +    if (s->list.num > (1 << 16) - 2) {
>> +        s->phdr_num = (1 << 16) - 1;
>> +    } else {
>> +        s->phdr_num += s->list.num;
>> +    }
>> +
>> +    return s;
>> +}
>> +
>> +/* write elf header, PT_NOTE and elf note to vmcore. */
>> +static int dump_begin(DumpState *s)
>> +{
>> +    target_phys_addr_t offset;
>> +    int ret;
>> +
>> +    s->state = DUMP_STATE_ACTIVE;
>> +
>> +    /*
>> +     * the vmcore's format is:
>> +     *   --------------
>> +     *   |  elf header |
>> +     *   --------------
>> +     *   |  PT_NOTE    |
>> +     *   --------------
>> +     *   |  PT_LOAD    |
>> +     *   --------------
>> +     *   |  ......     |
>> +     *   --------------
>> +     *   |  PT_LOAD    |
>> +     *   --------------
>> +     *   |  elf note   |
>> +     *   --------------
>> +     *   |  memory     |
>> +     *   --------------
>> +     *
>> +     * we only know where the memory is saved after we write elf note into
>> +     * vmcore.
>> +     */
>> +
>> +    /* write elf header to vmcore */
>> +    if (s->dump_info.d_class == ELFCLASS64) {
>> +        ret = write_elf64_header(s);
>> +    } else {
>> +        ret = write_elf32_header(s);
>> +    }
>> +    if (ret < 0) {
>> +        return -1;
>> +    }
>> +
>> +    /* write elf notes to vmcore */
>> +    if (s->dump_info.d_class == ELFCLASS64) {
>> +        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
>> +        ret = write_elf64_notes(s, 0, &offset);
>> +    } else {
>> +        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
>> +        ret = write_elf32_notes(s, 0, &offset);
>> +    }
>> +
>> +    if (ret < 0) {
>> +        return -1;
>> +    }
>> +
>> +    s->memory_offset = offset;
>> +    return 0;
>> +}
>> +
>> +/* write PT_LOAD to vmcore */
>> +static int dump_completed(DumpState *s)
>> +{
>> +    target_phys_addr_t offset;
>> +    MemoryMapping *memory_mapping;
>> +    int phdr_index = 1, ret;
>> +
>> +    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
>> +        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
>> +        if (s->dump_info.d_class == ELFCLASS64) {
>> +            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
>> +        } else {
>> +            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
>> +        }
>> +        if (ret < 0) {
>> +            return -1;
>> +        }
>> +    }
>> +
>> +    s->state = DUMP_STATE_COMPLETED;
>> +    dump_cleanup(s);
>> +    return 0;
>> +}
>> +
>> +/* write all memory to vmcore */
>> +static int dump_iterate(DumpState *s)
>> +{
>> +    RAMBlock *block;
>> +    target_phys_addr_t offset = s->memory_offset;
>> +    int ret;
>> +
>> +    /* write all memory to vmcore */
>> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
>> +        ret = write_memory(s, block, &offset);
>> +        if (ret < 0) {
>> +            return -1;
>> +        }
>> +    }
>> +
>> +    return dump_completed(s);
>> +}
>> +
>> +static int create_vmcore(DumpState *s)
>> +{
>> +    int ret;
>> +
>> +    ret = dump_begin(s);
>> +    if (ret < 0) {
>> +        return -1;
>> +    }
>> +
>> +    ret = dump_iterate(s);
>> +    if (ret < 0) {
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
> 
> This is not using the QAPI. Please, take a look at the document
> docs/writing-qmp-commands.txt on how to do that. You can also look at the
> various examples in hmp.c/qmp.c.

Yes, I have read it. But I need monitor to get fd, and I do not find such
examples. The command migrate also needs fd, and it is not converted to use
the QAPI. So, I do not know how to do that.

Thanks
Wen Congyang

> 
> I haven't reviewed your approach for the asynchronous support yet. We're
> discussing right now what to do wrt commands introducing their own async
> support, will review it as soon as we have a decision.
> 
> Btw, I'd like to have an ack from Jan for the general approach of this
> command.
> 
>> +{
>> +    const char *file = qdict_get_str(qdict, "file");
>> +    const char *p;
>> +    int fd = -1;
>> +    DumpState *s;
>> +
>> +#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;
>> +    }
>> +
>> +    s = dump_init(mon, fd);
>> +    if (!s) {
>> +        return -1;
>> +    }
>> +
>> +    if (create_vmcore(s) < 0) {
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> diff --git a/dump.h b/dump.h
>> index a36468b..def6c0e 100644
>> --- a/dump.h
>> +++ b/dump.h
>> @@ -1,10 +1,14 @@
>>  #ifndef DUMP_H
>>  #define DUMP_H
>>  
>> +#include "qdict.h"
>> +
>>  typedef struct ArchDumpInfo {
>>      int d_machine;  /* Architecture */
>>      int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
>>      int d_class;    /* ELFCLASS32 or ELFCLASS64 */
>>  } ArchDumpInfo;
>>  
>> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
>> +
>>  #endif
>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>> index 14838b7..98c1c35 100644
>> --- a/hmp-commands.hx
>> +++ b/hmp-commands.hx
>> @@ -828,6 +828,22 @@ new parameters (if specified) once the vm migration finished successfully.
>>  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       = "snapshot_blkdev",
>>          .args_type  = "device:B,snapshot-file:s?,format:s?",
>>          .params     = "device [new-image-file] [format]",
>> diff --git a/monitor.c b/monitor.c
>> index 7334401..edd6aa7 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 7e3f4b9..023cade 100644
>> --- a/qmp-commands.hx
>> +++ b/qmp-commands.hx
>> @@ -572,6 +572,32 @@ Example:
>>  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:
>> +
>> +- "file": Destination file (json-string)
>> +
>> +Example:
>> +
>> +-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
>> +<- { "return": {} }
>> +
>> +EQMP
>> +
>> +    {
>>          .name       = "netdev_add",
>>          .args_type  = "netdev:O",
>>          .params     = "[user|tap|socket],id=str[,prop=value][,...]",
> 
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory
  2012-01-11  0:59     ` Wen Congyang
@ 2012-01-12 13:49       ` Luiz Capitulino
  2012-01-13  8:35         ` Wen Congyang
  0 siblings, 1 reply; 21+ messages in thread
From: Luiz Capitulino @ 2012-01-12 13:49 UTC (permalink / raw)
  To: Wen Congyang; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel

On Wed, 11 Jan 2012 08:59:24 +0800
Wen Congyang <wency@cn.fujitsu.com> wrote:

> At 01/10/2012 09:30 PM, Luiz Capitulino Wrote:
> > On Wed, 04 Jan 2012 14:11:01 +0800
> > Wen Congyang <wency@cn.fujitsu.com> wrote:
> > 
> >> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> >> ---
> >>  Makefile.target |    8 +-
> >>  dump.c          |  588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  dump.h          |    4 +
> >>  hmp-commands.hx |   16 ++
> >>  monitor.c       |    3 +
> >>  qmp-commands.hx |   26 +++
> >>  6 files changed, 641 insertions(+), 4 deletions(-)
> >>  create mode 100644 dump.c
> >>
> >> diff --git a/Makefile.target b/Makefile.target
> >> index 29562ad..f7cc2b9 100644
> >> --- a/Makefile.target
> >> +++ b/Makefile.target
> >> @@ -110,7 +110,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
> >>  
> >> @@ -148,7 +148,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
> >>  
> >> @@ -170,7 +170,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
> >>  
> >> @@ -186,7 +186,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..ab29a4c
> >> --- /dev/null
> >> +++ b/dump.c
> >> @@ -0,0 +1,588 @@
> >> +/*
> >> + * 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"
> >> +
> >> +#define CPU_CONVERT_TO_TARGET16(val) \
> >> +({ \
> >> +    uint16_t _val = (val); \
> >> +    if (endian == ELFDATA2LSB) { \
> >> +        _val = cpu_to_le16(_val); \
> >> +    } else {\
> >> +        _val = cpu_to_be16(_val); \
> >> +    } \
> >> +    _val; \
> >> +})
> >> +
> >> +#define CPU_CONVERT_TO_TARGET32(val) \
> >> +({ \
> >> +    uint32_t _val = (val); \
> >> +    if (endian == ELFDATA2LSB) { \
> >> +        _val = cpu_to_le32(_val); \
> >> +    } else {\
> >> +        _val = cpu_to_be32(_val); \
> >> +    } \
> >> +    _val; \
> >> +})
> >> +
> >> +#define CPU_CONVERT_TO_TARGET64(val) \
> >> +({ \
> >> +    uint64_t _val = (val); \
> >> +    if (endian == ELFDATA2LSB) { \
> >> +        _val = cpu_to_le64(_val); \
> >> +    } else {\
> >> +        _val = cpu_to_be64(_val); \
> >> +    } \
> >> +    _val; \
> >> +})
> >> +
> >> +enum {
> >> +    DUMP_STATE_ERROR,
> >> +    DUMP_STATE_SETUP,
> >> +    DUMP_STATE_CANCELLED,
> >> +    DUMP_STATE_ACTIVE,
> >> +    DUMP_STATE_COMPLETED,
> >> +};
> >> +
> >> +typedef struct DumpState {
> >> +    ArchDumpInfo dump_info;
> >> +    MemoryMappingList list;
> >> +    int phdr_num;
> >> +    int state;
> >> +    char *error;
> >> +    Monitor *mon;
> >> +    int fd;
> >> +    target_phys_addr_t memory_offset;
> >> +} DumpState;
> >> +
> >> +static DumpState *dump_get_current(void)
> >> +{
> >> +    static DumpState current_dump = {
> >> +        .state = DUMP_STATE_SETUP,
> >> +    };
> >> +
> >> +    return &current_dump;
> >> +}
> >> +
> >> +static int dump_cleanup(DumpState *s)
> >> +{
> >> +    int ret = 0;
> >> +
> >> +    free_memory_mapping_list(&s->list);
> >> +    if (s->fd != -1) {
> >> +        close(s->fd);
> >> +        s->fd = -1;
> >> +    }
> >> +
> >> +    return ret;
> >> +}
> >> +
> >> +static void dump_error(DumpState *s, const char *reason)
> >> +{
> >> +    s->state = DUMP_STATE_ERROR;
> >> +    s->error = g_strdup(reason);
> >> +    dump_cleanup(s);
> >> +}
> >> +
> >> +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
> >> +}
> >> +
> >> +static int write_elf64_header(DumpState *s)
> >> +{
> >> +    Elf64_Ehdr elf_header;
> >> +    int ret;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    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] = s->dump_info.d_endian;
> >> +    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
> >> +    elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
> >> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
> >> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
> >> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
> >> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
> >> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
> >> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
> >> +
> >> +    lseek(s->fd, 0, SEEK_SET);
> >> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write elf header.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_elf32_header(DumpState *s)
> >> +{
> >> +    Elf32_Ehdr elf_header;
> >> +    int ret;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    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_CONVERT_TO_TARGET16(ET_CORE);
> >> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
> >> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
> >> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
> >> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
> >> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
> >> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
> >> +
> >> +    lseek(s->fd, 0, SEEK_SET);
> >> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write elf header.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
> >> +                            int phdr_index, target_phys_addr_t offset)
> >> +{
> >> +    Elf64_Phdr phdr;
> >> +    off_t phdr_offset;
> >> +    int ret;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
> >> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
> >> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
> >> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
> >> +    if (offset == -1) {
> >> +        phdr.p_filesz = 0;
> >> +    } else {
> >> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
> >> +    }
> >> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
> >> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
> >> +
> >> +    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
> >> +    lseek(s->fd, phdr_offset, SEEK_SET);
> >> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write program header table.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
> >> +                            int phdr_index, target_phys_addr_t offset)
> >> +{
> >> +    Elf32_Phdr phdr;
> >> +    off_t phdr_offset;
> >> +    int ret;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
> >> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
> >> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
> >> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
> >> +    if (offset == -1) {
> >> +        phdr.p_filesz = 0;
> >> +    } else {
> >> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
> >> +    }
> >> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
> >> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
> >> +
> >> +    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
> >> +    lseek(s->fd, phdr_offset, SEEK_SET);
> >> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write program header table.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_elf64_notes(DumpState *s, int phdr_index,
> >> +                             target_phys_addr_t *offset)
> >> +{
> >> +    CPUState *env;
> >> +    int ret;
> >> +    target_phys_addr_t begin = *offset;
> >> +    Elf64_Phdr phdr;
> >> +    off_t phdr_offset;
> >> +    int id;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> >> +        id = cpuid(env);
> >> +        ret = cpu_write_elf64_note(s->fd, env, id, offset);
> >> +        if (ret < 0) {
> >> +            dump_error(s, "dump: failed to write elf notes.\n");
> >> +            return -1;
> >> +        }
> >> +    }
> >> +
> >> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
> >> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
> >> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
> >> +    phdr.p_paddr = 0;
> >> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
> >> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
> >> +    phdr.p_vaddr = 0;
> >> +
> >> +    phdr_offset = sizeof(Elf64_Ehdr);
> >> +    lseek(s->fd, phdr_offset, SEEK_SET);
> >> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write program header table.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_elf32_notes(DumpState *s, 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;
> >> +    int id;
> >> +    int endian = s->dump_info.d_endian;
> >> +
> >> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> >> +        id = cpuid(env);
> >> +        ret = cpu_write_elf32_note(s->fd, env, id, offset);
> >> +        if (ret < 0) {
> >> +            dump_error(s, "dump: failed to write elf notes.\n");
> >> +            return -1;
> >> +        }
> >> +    }
> >> +
> >> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
> >> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
> >> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
> >> +    phdr.p_paddr = 0;
> >> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
> >> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
> >> +    phdr.p_vaddr = 0;
> >> +
> >> +    phdr_offset = sizeof(Elf32_Ehdr);
> >> +    lseek(s->fd, phdr_offset, SEEK_SET);
> >> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
> >> +    if (ret < 0) {
> >> +        dump_error(s, "dump: failed to write program header table.\n");
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int write_data(DumpState *s, void *buf, int length,
> >> +                      target_phys_addr_t *offset)
> >> +{
> >> +    int ret;
> >> +
> >> +    lseek(s->fd, *offset, SEEK_SET);
> >> +    ret = write(s->fd, buf, length);
> >> +    if (ret < 0) {
> >> +        dump_error(s, "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(DumpState *s, RAMBlock *block,
> >> +                        target_phys_addr_t *offset)
> >> +{
> >> +    int i, ret;
> >> +
> >> +    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
> >> +        ret = write_data(s, 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(s, 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 DumpState *dump_init(Monitor *mon, int fd)
> >> +{
> >> +    CPUState *env;
> >> +    DumpState *s = dump_get_current();
> >> +    int ret;
> >> +
> >> +    vm_stop(RUN_STATE_PAUSED);
> >> +    s->state = DUMP_STATE_SETUP;
> >> +    s->error = NULL;
> >> +    s->mon = mon;
> >> +    s->fd = fd;
> >> +
> >> +    /*
> >> +     * get dump info: endian, class and architecture.
> >> +     * If the target architecture is not supported, cpu_get_dump_info() will
> >> +     * return -1.
> >> +     *
> >> +     * if we use kvm, we should synchronize the register before we get dump
> >> +     * info.
> >> +     */
> >> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> >> +        cpu_synchronize_state(env);
> >> +    }
> >> +    ret = cpu_get_dump_info(&s->dump_info);
> >> +    if (ret < 0) {
> >> +        monitor_printf(mon, "dump: unsupported target.\n");
> >> +        return NULL;
> >> +    }
> >> +
> >> +    /* get memory mapping */
> >> +    s->list.num = 0;
> >> +    QTAILQ_INIT(&s->list.head);
> >> +    get_memory_mapping(&s->list);
> >> +
> >> +    /* crash needs extra memory mapping to determine phys_base. */
> >> +    ret = cpu_add_extra_memory_mapping(&s->list);
> >> +    if (ret < 0) {
> >> +        monitor_printf(mon, "dump: failed to add extra memory mapping.\n");
> >> +        return NULL;
> >> +    }
> >> +
> >> +    /*
> >> +     * calculate phdr_num
> >> +     *
> >> +     * the type of phdr->num is uint16_t, so we should avoid overflow
> >> +     */
> >> +    s->phdr_num = 1; /* PT_NOTE */
> >> +    if (s->list.num > (1 << 16) - 2) {
> >> +        s->phdr_num = (1 << 16) - 1;
> >> +    } else {
> >> +        s->phdr_num += s->list.num;
> >> +    }
> >> +
> >> +    return s;
> >> +}
> >> +
> >> +/* write elf header, PT_NOTE and elf note to vmcore. */
> >> +static int dump_begin(DumpState *s)
> >> +{
> >> +    target_phys_addr_t offset;
> >> +    int ret;
> >> +
> >> +    s->state = DUMP_STATE_ACTIVE;
> >> +
> >> +    /*
> >> +     * the vmcore's format is:
> >> +     *   --------------
> >> +     *   |  elf header |
> >> +     *   --------------
> >> +     *   |  PT_NOTE    |
> >> +     *   --------------
> >> +     *   |  PT_LOAD    |
> >> +     *   --------------
> >> +     *   |  ......     |
> >> +     *   --------------
> >> +     *   |  PT_LOAD    |
> >> +     *   --------------
> >> +     *   |  elf note   |
> >> +     *   --------------
> >> +     *   |  memory     |
> >> +     *   --------------
> >> +     *
> >> +     * we only know where the memory is saved after we write elf note into
> >> +     * vmcore.
> >> +     */
> >> +
> >> +    /* write elf header to vmcore */
> >> +    if (s->dump_info.d_class == ELFCLASS64) {
> >> +        ret = write_elf64_header(s);
> >> +    } else {
> >> +        ret = write_elf32_header(s);
> >> +    }
> >> +    if (ret < 0) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    /* write elf notes to vmcore */
> >> +    if (s->dump_info.d_class == ELFCLASS64) {
> >> +        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
> >> +        ret = write_elf64_notes(s, 0, &offset);
> >> +    } else {
> >> +        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
> >> +        ret = write_elf32_notes(s, 0, &offset);
> >> +    }
> >> +
> >> +    if (ret < 0) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    s->memory_offset = offset;
> >> +    return 0;
> >> +}
> >> +
> >> +/* write PT_LOAD to vmcore */
> >> +static int dump_completed(DumpState *s)
> >> +{
> >> +    target_phys_addr_t offset;
> >> +    MemoryMapping *memory_mapping;
> >> +    int phdr_index = 1, ret;
> >> +
> >> +    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
> >> +        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
> >> +        if (s->dump_info.d_class == ELFCLASS64) {
> >> +            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
> >> +        } else {
> >> +            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
> >> +        }
> >> +        if (ret < 0) {
> >> +            return -1;
> >> +        }
> >> +    }
> >> +
> >> +    s->state = DUMP_STATE_COMPLETED;
> >> +    dump_cleanup(s);
> >> +    return 0;
> >> +}
> >> +
> >> +/* write all memory to vmcore */
> >> +static int dump_iterate(DumpState *s)
> >> +{
> >> +    RAMBlock *block;
> >> +    target_phys_addr_t offset = s->memory_offset;
> >> +    int ret;
> >> +
> >> +    /* write all memory to vmcore */
> >> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
> >> +        ret = write_memory(s, block, &offset);
> >> +        if (ret < 0) {
> >> +            return -1;
> >> +        }
> >> +    }
> >> +
> >> +    return dump_completed(s);
> >> +}
> >> +
> >> +static int create_vmcore(DumpState *s)
> >> +{
> >> +    int ret;
> >> +
> >> +    ret = dump_begin(s);
> >> +    if (ret < 0) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    ret = dump_iterate(s);
> >> +    if (ret < 0) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
> > 
> > This is not using the QAPI. Please, take a look at the document
> > docs/writing-qmp-commands.txt on how to do that. You can also look at the
> > various examples in hmp.c/qmp.c.
> 
> Yes, I have read it. But I need monitor to get fd, and I do not find such
> examples. The command migrate also needs fd, and it is not converted to use
> the QAPI. So, I do not know how to do that.

I have a first try on converting the migrate command to the QAPI in
this branch:

 http://repo.or.cz/w/qemu/qmp-unstable.git/shortlog/refs/heads/qmp-wip/qapi-commands-conv/set-complex/v1

I guess all you need is the qemu_get_fd() function.

> 
> Thanks
> Wen Congyang
> 
> > 
> > I haven't reviewed your approach for the asynchronous support yet. We're
> > discussing right now what to do wrt commands introducing their own async
> > support, will review it as soon as we have a decision.
> > 
> > Btw, I'd like to have an ack from Jan for the general approach of this
> > command.
> > 
> >> +{
> >> +    const char *file = qdict_get_str(qdict, "file");
> >> +    const char *p;
> >> +    int fd = -1;
> >> +    DumpState *s;
> >> +
> >> +#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;
> >> +    }
> >> +
> >> +    s = dump_init(mon, fd);
> >> +    if (!s) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    if (create_vmcore(s) < 0) {
> >> +        return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/dump.h b/dump.h
> >> index a36468b..def6c0e 100644
> >> --- a/dump.h
> >> +++ b/dump.h
> >> @@ -1,10 +1,14 @@
> >>  #ifndef DUMP_H
> >>  #define DUMP_H
> >>  
> >> +#include "qdict.h"
> >> +
> >>  typedef struct ArchDumpInfo {
> >>      int d_machine;  /* Architecture */
> >>      int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
> >>      int d_class;    /* ELFCLASS32 or ELFCLASS64 */
> >>  } ArchDumpInfo;
> >>  
> >> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
> >> +
> >>  #endif
> >> diff --git a/hmp-commands.hx b/hmp-commands.hx
> >> index 14838b7..98c1c35 100644
> >> --- a/hmp-commands.hx
> >> +++ b/hmp-commands.hx
> >> @@ -828,6 +828,22 @@ new parameters (if specified) once the vm migration finished successfully.
> >>  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       = "snapshot_blkdev",
> >>          .args_type  = "device:B,snapshot-file:s?,format:s?",
> >>          .params     = "device [new-image-file] [format]",
> >> diff --git a/monitor.c b/monitor.c
> >> index 7334401..edd6aa7 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 7e3f4b9..023cade 100644
> >> --- a/qmp-commands.hx
> >> +++ b/qmp-commands.hx
> >> @@ -572,6 +572,32 @@ Example:
> >>  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:
> >> +
> >> +- "file": Destination file (json-string)
> >> +
> >> +Example:
> >> +
> >> +-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
> >> +<- { "return": {} }
> >> +
> >> +EQMP
> >> +
> >> +    {
> >>          .name       = "netdev_add",
> >>          .args_type  = "netdev:O",
> >>          .params     = "[user|tap|socket],id=str[,prop=value][,...]",
> > 
> > 
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory
  2012-01-12 13:49       ` Luiz Capitulino
@ 2012-01-13  8:35         ` Wen Congyang
  0 siblings, 0 replies; 21+ messages in thread
From: Wen Congyang @ 2012-01-13  8:35 UTC (permalink / raw)
  To: Luiz Capitulino; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel

At 01/12/2012 09:49 PM, Luiz Capitulino Wrote:
> On Wed, 11 Jan 2012 08:59:24 +0800
> Wen Congyang <wency@cn.fujitsu.com> wrote:
> 
>> At 01/10/2012 09:30 PM, Luiz Capitulino Wrote:
>>> On Wed, 04 Jan 2012 14:11:01 +0800
>>> Wen Congyang <wency@cn.fujitsu.com> wrote:
>>>
>>>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>>>> ---
>>>>  Makefile.target |    8 +-
>>>>  dump.c          |  588 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  dump.h          |    4 +
>>>>  hmp-commands.hx |   16 ++
>>>>  monitor.c       |    3 +
>>>>  qmp-commands.hx |   26 +++
>>>>  6 files changed, 641 insertions(+), 4 deletions(-)
>>>>  create mode 100644 dump.c
>>>>
>>>> diff --git a/Makefile.target b/Makefile.target
>>>> index 29562ad..f7cc2b9 100644
>>>> --- a/Makefile.target
>>>> +++ b/Makefile.target
>>>> @@ -110,7 +110,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
>>>>  
>>>> @@ -148,7 +148,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
>>>>  
>>>> @@ -170,7 +170,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
>>>>  
>>>> @@ -186,7 +186,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..ab29a4c
>>>> --- /dev/null
>>>> +++ b/dump.c
>>>> @@ -0,0 +1,588 @@
>>>> +/*
>>>> + * 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"
>>>> +
>>>> +#define CPU_CONVERT_TO_TARGET16(val) \
>>>> +({ \
>>>> +    uint16_t _val = (val); \
>>>> +    if (endian == ELFDATA2LSB) { \
>>>> +        _val = cpu_to_le16(_val); \
>>>> +    } else {\
>>>> +        _val = cpu_to_be16(_val); \
>>>> +    } \
>>>> +    _val; \
>>>> +})
>>>> +
>>>> +#define CPU_CONVERT_TO_TARGET32(val) \
>>>> +({ \
>>>> +    uint32_t _val = (val); \
>>>> +    if (endian == ELFDATA2LSB) { \
>>>> +        _val = cpu_to_le32(_val); \
>>>> +    } else {\
>>>> +        _val = cpu_to_be32(_val); \
>>>> +    } \
>>>> +    _val; \
>>>> +})
>>>> +
>>>> +#define CPU_CONVERT_TO_TARGET64(val) \
>>>> +({ \
>>>> +    uint64_t _val = (val); \
>>>> +    if (endian == ELFDATA2LSB) { \
>>>> +        _val = cpu_to_le64(_val); \
>>>> +    } else {\
>>>> +        _val = cpu_to_be64(_val); \
>>>> +    } \
>>>> +    _val; \
>>>> +})
>>>> +
>>>> +enum {
>>>> +    DUMP_STATE_ERROR,
>>>> +    DUMP_STATE_SETUP,
>>>> +    DUMP_STATE_CANCELLED,
>>>> +    DUMP_STATE_ACTIVE,
>>>> +    DUMP_STATE_COMPLETED,
>>>> +};
>>>> +
>>>> +typedef struct DumpState {
>>>> +    ArchDumpInfo dump_info;
>>>> +    MemoryMappingList list;
>>>> +    int phdr_num;
>>>> +    int state;
>>>> +    char *error;
>>>> +    Monitor *mon;
>>>> +    int fd;
>>>> +    target_phys_addr_t memory_offset;
>>>> +} DumpState;
>>>> +
>>>> +static DumpState *dump_get_current(void)
>>>> +{
>>>> +    static DumpState current_dump = {
>>>> +        .state = DUMP_STATE_SETUP,
>>>> +    };
>>>> +
>>>> +    return &current_dump;
>>>> +}
>>>> +
>>>> +static int dump_cleanup(DumpState *s)
>>>> +{
>>>> +    int ret = 0;
>>>> +
>>>> +    free_memory_mapping_list(&s->list);
>>>> +    if (s->fd != -1) {
>>>> +        close(s->fd);
>>>> +        s->fd = -1;
>>>> +    }
>>>> +
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +static void dump_error(DumpState *s, const char *reason)
>>>> +{
>>>> +    s->state = DUMP_STATE_ERROR;
>>>> +    s->error = g_strdup(reason);
>>>> +    dump_cleanup(s);
>>>> +}
>>>> +
>>>> +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
>>>> +}
>>>> +
>>>> +static int write_elf64_header(DumpState *s)
>>>> +{
>>>> +    Elf64_Ehdr elf_header;
>>>> +    int ret;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    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] = s->dump_info.d_endian;
>>>> +    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
>>>> +    elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
>>>> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
>>>> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
>>>> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
>>>> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
>>>> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
>>>> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
>>>> +
>>>> +    lseek(s->fd, 0, SEEK_SET);
>>>> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write elf header.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_elf32_header(DumpState *s)
>>>> +{
>>>> +    Elf32_Ehdr elf_header;
>>>> +    int ret;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    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_CONVERT_TO_TARGET16(ET_CORE);
>>>> +    elf_header.e_machine = CPU_CONVERT_TO_TARGET16(s->dump_info.d_machine);
>>>> +    elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
>>>> +    elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
>>>> +    elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
>>>> +    elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
>>>> +    elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(s->phdr_num);
>>>> +
>>>> +    lseek(s->fd, 0, SEEK_SET);
>>>> +    ret = write(s->fd, &elf_header, sizeof(elf_header));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write elf header.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
>>>> +                            int phdr_index, target_phys_addr_t offset)
>>>> +{
>>>> +    Elf64_Phdr phdr;
>>>> +    off_t phdr_offset;
>>>> +    int ret;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
>>>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
>>>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
>>>> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
>>>> +    if (offset == -1) {
>>>> +        phdr.p_filesz = 0;
>>>> +    } else {
>>>> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
>>>> +    }
>>>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
>>>> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
>>>> +
>>>> +    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
>>>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>>>> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write program header table.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
>>>> +                            int phdr_index, target_phys_addr_t offset)
>>>> +{
>>>> +    Elf32_Phdr phdr;
>>>> +    off_t phdr_offset;
>>>> +    int ret;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
>>>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
>>>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
>>>> +    phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
>>>> +    if (offset == -1) {
>>>> +        phdr.p_filesz = 0;
>>>> +    } else {
>>>> +        phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
>>>> +    }
>>>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
>>>> +    phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
>>>> +
>>>> +    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
>>>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>>>> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write program header table.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_elf64_notes(DumpState *s, int phdr_index,
>>>> +                             target_phys_addr_t *offset)
>>>> +{
>>>> +    CPUState *env;
>>>> +    int ret;
>>>> +    target_phys_addr_t begin = *offset;
>>>> +    Elf64_Phdr phdr;
>>>> +    off_t phdr_offset;
>>>> +    int id;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>>>> +        id = cpuid(env);
>>>> +        ret = cpu_write_elf64_note(s->fd, env, id, offset);
>>>> +        if (ret < 0) {
>>>> +            dump_error(s, "dump: failed to write elf notes.\n");
>>>> +            return -1;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    memset(&phdr, 0, sizeof(Elf64_Phdr));
>>>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
>>>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
>>>> +    phdr.p_paddr = 0;
>>>> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
>>>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
>>>> +    phdr.p_vaddr = 0;
>>>> +
>>>> +    phdr_offset = sizeof(Elf64_Ehdr);
>>>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>>>> +    ret = write(s->fd, &phdr, sizeof(Elf64_Phdr));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write program header table.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_elf32_notes(DumpState *s, 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;
>>>> +    int id;
>>>> +    int endian = s->dump_info.d_endian;
>>>> +
>>>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>>>> +        id = cpuid(env);
>>>> +        ret = cpu_write_elf32_note(s->fd, env, id, offset);
>>>> +        if (ret < 0) {
>>>> +            dump_error(s, "dump: failed to write elf notes.\n");
>>>> +            return -1;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    memset(&phdr, 0, sizeof(Elf32_Phdr));
>>>> +    phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
>>>> +    phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
>>>> +    phdr.p_paddr = 0;
>>>> +    phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
>>>> +    phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
>>>> +    phdr.p_vaddr = 0;
>>>> +
>>>> +    phdr_offset = sizeof(Elf32_Ehdr);
>>>> +    lseek(s->fd, phdr_offset, SEEK_SET);
>>>> +    ret = write(s->fd, &phdr, sizeof(Elf32_Phdr));
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "dump: failed to write program header table.\n");
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int write_data(DumpState *s, void *buf, int length,
>>>> +                      target_phys_addr_t *offset)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    lseek(s->fd, *offset, SEEK_SET);
>>>> +    ret = write(s->fd, buf, length);
>>>> +    if (ret < 0) {
>>>> +        dump_error(s, "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(DumpState *s, RAMBlock *block,
>>>> +                        target_phys_addr_t *offset)
>>>> +{
>>>> +    int i, ret;
>>>> +
>>>> +    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
>>>> +        ret = write_data(s, 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(s, 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 DumpState *dump_init(Monitor *mon, int fd)
>>>> +{
>>>> +    CPUState *env;
>>>> +    DumpState *s = dump_get_current();
>>>> +    int ret;
>>>> +
>>>> +    vm_stop(RUN_STATE_PAUSED);
>>>> +    s->state = DUMP_STATE_SETUP;
>>>> +    s->error = NULL;
>>>> +    s->mon = mon;
>>>> +    s->fd = fd;
>>>> +
>>>> +    /*
>>>> +     * get dump info: endian, class and architecture.
>>>> +     * If the target architecture is not supported, cpu_get_dump_info() will
>>>> +     * return -1.
>>>> +     *
>>>> +     * if we use kvm, we should synchronize the register before we get dump
>>>> +     * info.
>>>> +     */
>>>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>>>> +        cpu_synchronize_state(env);
>>>> +    }
>>>> +    ret = cpu_get_dump_info(&s->dump_info);
>>>> +    if (ret < 0) {
>>>> +        monitor_printf(mon, "dump: unsupported target.\n");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    /* get memory mapping */
>>>> +    s->list.num = 0;
>>>> +    QTAILQ_INIT(&s->list.head);
>>>> +    get_memory_mapping(&s->list);
>>>> +
>>>> +    /* crash needs extra memory mapping to determine phys_base. */
>>>> +    ret = cpu_add_extra_memory_mapping(&s->list);
>>>> +    if (ret < 0) {
>>>> +        monitor_printf(mon, "dump: failed to add extra memory mapping.\n");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * calculate phdr_num
>>>> +     *
>>>> +     * the type of phdr->num is uint16_t, so we should avoid overflow
>>>> +     */
>>>> +    s->phdr_num = 1; /* PT_NOTE */
>>>> +    if (s->list.num > (1 << 16) - 2) {
>>>> +        s->phdr_num = (1 << 16) - 1;
>>>> +    } else {
>>>> +        s->phdr_num += s->list.num;
>>>> +    }
>>>> +
>>>> +    return s;
>>>> +}
>>>> +
>>>> +/* write elf header, PT_NOTE and elf note to vmcore. */
>>>> +static int dump_begin(DumpState *s)
>>>> +{
>>>> +    target_phys_addr_t offset;
>>>> +    int ret;
>>>> +
>>>> +    s->state = DUMP_STATE_ACTIVE;
>>>> +
>>>> +    /*
>>>> +     * the vmcore's format is:
>>>> +     *   --------------
>>>> +     *   |  elf header |
>>>> +     *   --------------
>>>> +     *   |  PT_NOTE    |
>>>> +     *   --------------
>>>> +     *   |  PT_LOAD    |
>>>> +     *   --------------
>>>> +     *   |  ......     |
>>>> +     *   --------------
>>>> +     *   |  PT_LOAD    |
>>>> +     *   --------------
>>>> +     *   |  elf note   |
>>>> +     *   --------------
>>>> +     *   |  memory     |
>>>> +     *   --------------
>>>> +     *
>>>> +     * we only know where the memory is saved after we write elf note into
>>>> +     * vmcore.
>>>> +     */
>>>> +
>>>> +    /* write elf header to vmcore */
>>>> +    if (s->dump_info.d_class == ELFCLASS64) {
>>>> +        ret = write_elf64_header(s);
>>>> +    } else {
>>>> +        ret = write_elf32_header(s);
>>>> +    }
>>>> +    if (ret < 0) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    /* write elf notes to vmcore */
>>>> +    if (s->dump_info.d_class == ELFCLASS64) {
>>>> +        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
>>>> +        ret = write_elf64_notes(s, 0, &offset);
>>>> +    } else {
>>>> +        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
>>>> +        ret = write_elf32_notes(s, 0, &offset);
>>>> +    }
>>>> +
>>>> +    if (ret < 0) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    s->memory_offset = offset;
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +/* write PT_LOAD to vmcore */
>>>> +static int dump_completed(DumpState *s)
>>>> +{
>>>> +    target_phys_addr_t offset;
>>>> +    MemoryMapping *memory_mapping;
>>>> +    int phdr_index = 1, ret;
>>>> +
>>>> +    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
>>>> +        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
>>>> +        if (s->dump_info.d_class == ELFCLASS64) {
>>>> +            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
>>>> +        } else {
>>>> +            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
>>>> +        }
>>>> +        if (ret < 0) {
>>>> +            return -1;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    s->state = DUMP_STATE_COMPLETED;
>>>> +    dump_cleanup(s);
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +/* write all memory to vmcore */
>>>> +static int dump_iterate(DumpState *s)
>>>> +{
>>>> +    RAMBlock *block;
>>>> +    target_phys_addr_t offset = s->memory_offset;
>>>> +    int ret;
>>>> +
>>>> +    /* write all memory to vmcore */
>>>> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
>>>> +        ret = write_memory(s, block, &offset);
>>>> +        if (ret < 0) {
>>>> +            return -1;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    return dump_completed(s);
>>>> +}
>>>> +
>>>> +static int create_vmcore(DumpState *s)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    ret = dump_begin(s);
>>>> +    if (ret < 0) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    ret = dump_iterate(s);
>>>> +    if (ret < 0) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
>>>
>>> This is not using the QAPI. Please, take a look at the document
>>> docs/writing-qmp-commands.txt on how to do that. You can also look at the
>>> various examples in hmp.c/qmp.c.
>>
>> Yes, I have read it. But I need monitor to get fd, and I do not find such
>> examples. The command migrate also needs fd, and it is not converted to use
>> the QAPI. So, I do not know how to do that.
> 
> I have a first try on converting the migrate command to the QAPI in
> this branch:
> 
>  http://repo.or.cz/w/qemu/qmp-unstable.git/shortlog/refs/heads/qmp-wip/qapi-commands-conv/set-complex/v1
> 
> I guess all you need is the qemu_get_fd() function.

Yes, that is what I need.

I reread my patchset and migration's code, and I think we also need two more APIs to
suspend/resume monitor:

>From 6e4fc82c50ad0c816d7af2f63e32d018455e867a Mon Sep 17 00:00:00 2001
From: Wen Congyang <wency@cn.fujitsu.com>
Date: Fri, 13 Jan 2012 14:51:48 +0800
Subject: [PATCH] monitor: introduce qemu_suspend_monitor()/qemu_resume_monitor()

Introduce two APIs to suspend/resume cur_mon. It can be used in asynchronous
monitor command.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 monitor.c |   10 ++++++++++
 monitor.h |    2 ++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/monitor.c b/monitor.c
index 56f3778..4a264d3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4594,6 +4594,11 @@ static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
     monitor_resume(mon);
 }
 
+int qemu_suspend_monitor(void)
+{
+    return monitor_suspend(cur_mon);
+}
+
 int monitor_suspend(Monitor *mon)
 {
     if (!mon->rs)
@@ -4602,6 +4607,11 @@ int monitor_suspend(Monitor *mon)
     return 0;
 }
 
+void qemu_resume_monitor(void)
+{
+    monitor_resume(cur_mon);
+}
+
 void monitor_resume(Monitor *mon)
 {
     if (!mon->rs)
diff --git a/monitor.h b/monitor.h
index 274cd39..aa15ad7 100644
--- a/monitor.h
+++ b/monitor.h
@@ -43,7 +43,9 @@ int monitor_cur_is_qmp(void);
 void monitor_protocol_event(MonitorEvent event, QObject *data);
 void monitor_init(CharDriverState *chr, int flags);
 
+int qemu_suspend_monitor(void);
 int monitor_suspend(Monitor *mon);
+void qemu_resume_monitor(void);
 void monitor_resume(Monitor *mon);
 
 int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
-- 
1.7.1


Thanks
Wen Congyang
> 
>>
>> Thanks
>> Wen Congyang
>>
>>>
>>> I haven't reviewed your approach for the asynchronous support yet. We're
>>> discussing right now what to do wrt commands introducing their own async
>>> support, will review it as soon as we have a decision.
>>>
>>> Btw, I'd like to have an ack from Jan for the general approach of this
>>> command.
>>>
>>>> +{
>>>> +    const char *file = qdict_get_str(qdict, "file");
>>>> +    const char *p;
>>>> +    int fd = -1;
>>>> +    DumpState *s;
>>>> +
>>>> +#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;
>>>> +    }
>>>> +
>>>> +    s = dump_init(mon, fd);
>>>> +    if (!s) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    if (create_vmcore(s) < 0) {
>>>> +        return -1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/dump.h b/dump.h
>>>> index a36468b..def6c0e 100644
>>>> --- a/dump.h
>>>> +++ b/dump.h
>>>> @@ -1,10 +1,14 @@
>>>>  #ifndef DUMP_H
>>>>  #define DUMP_H
>>>>  
>>>> +#include "qdict.h"
>>>> +
>>>>  typedef struct ArchDumpInfo {
>>>>      int d_machine;  /* Architecture */
>>>>      int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
>>>>      int d_class;    /* ELFCLASS32 or ELFCLASS64 */
>>>>  } ArchDumpInfo;
>>>>  
>>>> +int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
>>>> +
>>>>  #endif
>>>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>>>> index 14838b7..98c1c35 100644
>>>> --- a/hmp-commands.hx
>>>> +++ b/hmp-commands.hx
>>>> @@ -828,6 +828,22 @@ new parameters (if specified) once the vm migration finished successfully.
>>>>  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       = "snapshot_blkdev",
>>>>          .args_type  = "device:B,snapshot-file:s?,format:s?",
>>>>          .params     = "device [new-image-file] [format]",
>>>> diff --git a/monitor.c b/monitor.c
>>>> index 7334401..edd6aa7 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 7e3f4b9..023cade 100644
>>>> --- a/qmp-commands.hx
>>>> +++ b/qmp-commands.hx
>>>> @@ -572,6 +572,32 @@ Example:
>>>>  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:
>>>> +
>>>> +- "file": Destination file (json-string)
>>>> +
>>>> +Example:
>>>> +
>>>> +-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
>>>> +<- { "return": {} }
>>>> +
>>>> +EQMP
>>>> +
>>>> +    {
>>>>          .name       = "netdev_add",
>>>>          .args_type  = "netdev:O",
>>>>          .params     = "[user|tap|socket],id=str[,prop=value][,...]",
>>>
>>>
>>
> 
> 

^ permalink raw reply related	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2012-01-13  8:33 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-04  5:44 [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
2012-01-04  6:04 ` [Qemu-devel] [RFC][PATCH 01/14 v4] Add API to create memory mapping list Wen Congyang
2012-01-04  6:05 ` [Qemu-devel] [RFC][PATCH 02/14 v4] Add API to check whether a physical address is I/O address Wen Congyang
2012-01-04  6:06 ` [Qemu-devel] [RFC][PATCH 03/14 v4] target-i386: implement cpu_get_memory_mapping() Wen Congyang
2012-01-04  6:07 ` [Qemu-devel] [RFC][PATCH 04/14 v4] Add API to get memory mapping Wen Congyang
2012-01-04  6:08 ` [Qemu-devel] [RFC][PATCH 05/14 v4] target-i386: Add API to write elf notes to core file Wen Congyang
2012-01-04  6:09 ` [Qemu-devel] [RFC][PATCH 06/14 v4] target-i386: Add API to add extra memory mapping Wen Congyang
2012-01-04  6:10 ` [Qemu-devel] [RFC][PATCH 07/14 v4] target-i386: add API to get dump info Wen Congyang
2012-01-04  6:11 ` [Qemu-devel] [RFC][PATCH 08/14 v4] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
2012-01-10 13:30   ` Luiz Capitulino
2012-01-11  0:59     ` Wen Congyang
2012-01-12 13:49       ` Luiz Capitulino
2012-01-13  8:35         ` Wen Congyang
2012-01-04  6:12 ` [Qemu-devel] [RFC][PATCH 09/14 v4] run dump at the background Wen Congyang
2012-01-04  6:13 ` [Qemu-devel] [RFC][PATCH 10/14 v4] support detached dump Wen Congyang
2012-01-04  6:14 ` [Qemu-devel] [RFC][PATCH 11/14 v4] support to cancel the current dumping Wen Congyang
2012-01-04  6:15 ` [Qemu-devel] [RFC][PATCH 12/14 v4] support to set dumping speed Wen Congyang
2012-01-04  6:16 ` [Qemu-devel] [RFC][PATCH 13/14 v4] support to query dumping status Wen Congyang
2012-01-04  6:17 ` [Qemu-devel] [RFC][PATCH 14/14 v4] auto cancel dumping after vm state is changed to run Wen Congyang
2012-01-10  7:44 ` [Qemu-devel] [RFC][PATCT 0/14 v4] dump memory when host pci device is used by guest Wen Congyang
2012-01-10  9:41   ` Jan Kiszka

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.