Skip to contentSkip to conversation

introducing a new, dedicated memory dump mechanism

RFC PATCH Superseded Wen Congyang 2 participants 37 messages Mar 1, 2012 – Mar 2, 2012 Kbuild

v7 of 15 Superseded Latest is v15 →

lore
Share & tools
lore
#0 lore raw

v7 cover introducing a new, dedicated memory dump mechanism

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

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.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 now.
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. The cpu's state is stored in QEMU note. You neet to modify crash to use it to calculate phys_base.
5. 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.
6. This patchset is based on the upstream tree, and apply one patch that is still in Luiz Capitulino's tree, because I use the API qemu_get_fd() in this patchset.

Changes from v6 to v7:
1. addressed Jan's comments
2. fix some bugs
3. store cpu's state into the vmcore

Changes from v5 to v6:
1. allow user to dump a fraction of the memory
2. fix some bugs

Changes from v4 to v5:
1. convert the new command dump to QAPI

Changes 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.

Changes 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 write cpu status to core file
target-i386: add API to get dump info
make gdb_id() generally avialable
introduce a new monitor command 'dump' to dump guest's memory support to cancel the current dumping
support to query dumping status
run dump at the background
support detached dump
allow user to dump a fraction of the memory

 Makefile.target                   |    3 +
 configure                         |    8 +
 cpu-all.h                         |   60 +++
 cpu-common.h                      |    2 +
 dump.c                            |  904 +++++++++++++++++++++++++++++++++++++
 dump.h                            |   23 +
 exec.c                            |   11 +
 gdbstub.c                         |    9 -
 gdbstub.h                         |    9 +
 hmp-commands.hx                   |   43 ++
 hmp.c                             |   87 ++++
 hmp.h                             |    3 +
 memory_mapping.c                  |  232 ++++++++++
 memory_mapping.h                  |   54 +++
 monitor.c                         |    7 +
 qapi-schema.json                  |   57 +++
 qmp-commands.hx                   |  109 +++++
 target-i386/arch_dump.c           |  437 ++++++++++++++++++
 target-i386/arch_memory_mapping.c |  256 +++++++++++
 vl.c                              |    5 +-
 20 files changed, 2308 insertions(+), 11 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
 create mode 100644 target-i386/arch_memory_mapping.c
#1 lore raw

RFC PATCH v7 1/14 Add API to create memory mapping list

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.

---
 Makefile.target  |    1 +
 memory_mapping.c |  134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |   44 ++++++++++++++++++
 3 files changed, 179 insertions(+), 0 deletions(-)
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h
Makefile.target +1 -0
index 68a5641..9227e4e 100644
@@ -208,6 +208,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
+obj-y += memory_mapping.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
memory_mapping.c new file +134 -0

134 lines not on this page · raw message

memory_mapping.h new file +44 -0

44 lines not on this page · raw message

Signature · 1 line
1.7.1
#2 lore raw

Re: [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 01/14 v7] Add API to create memory mapping list
Date: Thu, 01 Mar 2012 10:39:35 +0800

memory_mapping.c line 48

Quoted 4 lines
memory_mapping.c new file +3 -0
+static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
+                                                   MemoryMapping *mapping)
 
+void memory_mapping_list_add_sorted(MemoryMappingList *list,

These functions not only sort but also merge elements of mapping list. Is there another name that represents what these are doing more properly?

Quoted 18 lines
memory_mapping.c new file +18 -0
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length)
+{
+    MemoryMapping *memory_mapping, *last_mapping;
+
+    if (QTAILQ_EMPTY(&list->head)) {
+        create_new_memory_mapping(list, phys_addr, virt_addr, length);
+        return;
+    }
+
+    last_mapping = list->last_mapping;
+    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;
+        }

memory_mapping.c line 76

Quoted 10 lines
memory_mapping.c new file +10 -0
+    }
+
+    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;
+            list->last_mapping = last_mapping;
+            return;
+        }

Please don't use a single variable in multiple meanings in the same function. It appears to me that the variable last_mapping is used as n-th entry connected to the list->head within this for loop. So this_mapping, for example, is reasonable rather than last_mapping. All use of last_mapping within the for loop can be replaced with memory_mapping, right?

Quoted 9 lines
memory_mapping.c new file +9 -0
+
+        if (phys_addr + length < last_mapping->phys_addr) {
+            /* create a new region before last_mapping */
+            break;
+        }
+
+        if (phys_addr >= (last_mapping->phys_addr + last_mapping->length)) {
+            /* last_mapping does not contain this region */
+            continue;

memory_mapping.c line 95

Quoted 10 lines
memory_mapping.c new file +10 -0
+        }
+
+        if ((virt_addr - last_mapping->virt_addr) !=
+            (phys_addr - last_mapping->phys_addr)) {
+            /*
+             * last_mapping contains this region, but we cannot merge this
+             * region into last_mapping. Try the next memory mapping.
+             */
+            continue;
+        }

Does this condition means the current mapping and the last mapping are contiguous both phisically and viurtually? If so, it's better to write the condition so readers can understand that more easily.

Quoted 9 lines
memory_mapping.c new file +9 -0
+
+        /* merge this region into last_mapping */
+        if (virt_addr < last_mapping->virt_addr) {
+            last_mapping->length += last_mapping->virt_addr - virt_addr;
+            last_mapping->virt_addr = virt_addr;
+        }
+
+        if ((virt_addr + length) >
+            (last_mapping->virt_addr + last_mapping->length)) {

memory_mapping.c line 114

Quoted 10 lines
memory_mapping.c new file +10 -0
+            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
+        }
+
+        list->last_mapping = last_mapping;
+        return;
+    }
+
+    /* this region can not be merged into any existed memory mapping. */
+    create_new_memory_mapping(list, phys_addr, virt_addr, length);
+}

How about adding helper functions for expressing each conditionals? Just like below. Then I think the code gets more readable.

bool mapping_proper_succeor(MemoryMapping *map,

                              target_phys_addr_t phys_addr,
                              target_virt_addr_t virt_addr);
  bool mapping_physically_contains(MemoryMapping *map,
                        target_phys_addr_t phys_addr);
  bool mapping_physically_virtually_contiguous(MemoryMapping *map,
                                               target_phys_addr_t phys_addr,
                                               target_virt_addr_t virt_addr);
  void mapping_merge(MemoryMapping *map, target_phys_addr_t phys_addr,
                     target_virt_addr_t virt_addr);

I'm not confident of the naming, these are example, and assuming define all as static inline functions.

Thanks.
HATAYAMA, Daisuke

#3 lore raw

Re: [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list

At 03/01/2012 04:33 PM, HATAYAMA Daisuke Wrote:

Quoted 40 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 01/14 v7] Add API to create memory mapping list
Date: Thu, 01 Mar 2012 10:39:35 +0800

memory_mapping.c line 48

Quoted 4 lines
memory_mapping.c new file +3 -0
+static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
+                                                   MemoryMapping *mapping)
 
+void memory_mapping_list_add_sorted(MemoryMappingList *list,

These functions not only sort but also merge elements of mapping list. Is there another name that represents what these are doing more properly?

Quoted 27 lines
memory_mapping.c new file +27 -0
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length)
+{
+    MemoryMapping *memory_mapping, *last_mapping;
+
+    if (QTAILQ_EMPTY(&list->head)) {
+        create_new_memory_mapping(list, phys_addr, virt_addr, length);
+        return;
+    }
+
+    last_mapping = list->last_mapping;
+    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;
+            list->last_mapping = last_mapping;
+            return;
Quoted 8 lines
Quoted 1 line

+ }

Please don't use a single variable in multiple meanings in the same function. It appears to me that the variable last_mapping is used as n-th entry connected to the list->head within this for loop. So this_mapping, for example, is reasonable rather than last_mapping. All use of last_mapping within the for loop can be replaced with memory_mapping, right?

OK

Quoted 16 lines
Quoted 16 lines
memory_mapping.c new file +15 -0
+
+        if (phys_addr + length < last_mapping->phys_addr) {
+            /* create a new region before last_mapping */
+            break;
+        }
+
+        if (phys_addr >= (last_mapping->phys_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 cannot merge this
Quoted 8 lines

memory_mapping.c line 95

Quoted 4 lines
memory_mapping.c new file +4 -0
+             * region into last_mapping. Try the next memory mapping.
+             */
+            continue;
+        }

Does this condition means the current mapping and the last mapping are contiguous both phisically and viurtually? If so, it's better to write the condition so readers can understand that more easily.

current mapping and last mapping are always contiguous both phisically and virtually.

Quoted 35 lines
Quoted 10 lines
memory_mapping.c new file +9 -0
+
+        /* merge this region into last_mapping */
+        if (virt_addr < last_mapping->virt_addr) {
+            last_mapping->length += last_mapping->virt_addr - virt_addr;
+            last_mapping->virt_addr = virt_addr;
+        }
+
+        if ((virt_addr + length) >
+            (last_mapping->virt_addr + last_mapping->length)) {

memory_mapping.c line 114

Quoted 10 lines
memory_mapping.c new file +10 -0
+            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
+        }
+
+        list->last_mapping = last_mapping;
+        return;
+    }
+
+    /* this region can not be merged into any existed memory mapping. */
+    create_new_memory_mapping(list, phys_addr, virt_addr, length);
+}

How about adding helper functions for expressing each conditionals? Just like below. Then I think the code gets more readable.

bool mapping_proper_succeor(MemoryMapping *map,

                              target_phys_addr_t phys_addr,
                              target_virt_addr_t virt_addr);
  bool mapping_physically_contains(MemoryMapping *map,
                        target_phys_addr_t phys_addr);
  bool mapping_physically_virtually_contiguous(MemoryMapping *map,
                                               target_phys_addr_t phys_addr,
                                               target_virt_addr_t virt_addr);
  void mapping_merge(MemoryMapping *map, target_phys_addr_t phys_addr,
                     target_virt_addr_t virt_addr);
Quoted 2 lines

I'm not confident of the naming, these are example, and assuming define all as static inline functions.

Hmm, I think this inline functions make the code more readable. So I will modify my code.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#4 lore raw

RFC PATCH v7 2/14 Add API to check whether a physical address is I/O address

In reply to Wen Congyang

This API will be used in the following patch.

---
 cpu-common.h |    2 ++
 exec.c       |   11 +++++++++++
 2 files changed, 13 insertions(+), 0 deletions(-)
cpu-common.h +2 -0
index a40c57d..fde3e5d 100644
@@ -71,6 +71,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 cpu_physical_memory_is_io(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
exec.c +11 -0
index b81677a..2114dd5 100644
@@ -4435,3 +4435,14 @@ bool virtio_is_big_endian(void)
 #undef env
 
 #endif
+
+bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr)
+{
+    ram_addr_t pd;
+    PhysPageDesc p;
+
+    p = phys_page_find(phys_addr >> TARGET_PAGE_BITS);
+    pd = p.phys_offset;
+
+    return !is_ram_rom_romd(pd);
+}
Signature · 1 line
1.7.1
#5 lore raw

RFC PATCH v7 3/14 target-i386: implement cpu_get_memory_mapping()

In reply to Wen Congyang

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

---
 Makefile.target                   |    1 +
 configure                         |    4 +
 cpu-all.h                         |   10 ++
 target-i386/arch_memory_mapping.c |  256 +++++++++++++++++++++++++++++++++++++
 4 files changed, 271 insertions(+), 0 deletions(-)
 create mode 100644 target-i386/arch_memory_mapping.c
Makefile.target +1 -0
index 9227e4e..a87e678 100644
@@ -84,6 +84,7 @@ libobj-y += op_helper.o helper.o
 ifeq ($(TARGET_BASE_ARCH), i386)
 libobj-y += cpuid.o
 endif
+libobj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += arch_memory_mapping.o
 libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
configure +4 -0
index f9d5330..ddc54f5 100755
@@ -3630,6 +3630,10 @@ case "$target_arch2" in
       fi
     fi
 esac
+case "$target_arch2" in
+  i386|x86_64)
+    echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak
+esac
 if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then
   echo "CONFIG_PSERIES=y" >> $config_target_mak
 fi
cpu-all.h +10 -0
index e2c3c49..cb72680 100644
@@ -22,6 +22,7 @@
 #include "qemu-common.h"
 #include "qemu-tls.h"
 #include "cpu-common.h"
+#include "memory_mapping.h"
 
 /* some important defines:
  *
@@ -523,4 +524,13 @@ 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(CONFIG_HAVE_GET_MEMORY_MAPPING)
+int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+#else
+static inline int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
+{
+    return -1;
+}
+#endif
+
 #endif /* CPU_ALL_H */
target-i386/arch_memory_mapping.c new file +256 -0

256 lines not on this page · raw message

Signature · 1 line
1.7.1
#6 lore raw

Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 10:41:47 +0800

Quoted 18 lines
target-i386/arch_memory_mapping.c new file +18 -0
+int 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-i386/arch_memory_mapping.c line 256

Quoted 10 lines
target-i386/arch_memory_mapping.c new file +10 -0
+        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);
+    }
+
+    return 0;
+}

Does this assume paging mode? I don't know qemu very well, but qemu dump command runs externally to guest machine, so I think the machine could be in the state with paging disabled where CR4 doesn't refer to page table as expected.

Thanks.
HATAYAMA, Daisuke

#7 lore raw

Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()

At 03/01/2012 02:13 PM, HATAYAMA Daisuke Wrote:

Quoted 29 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 10:41:47 +0800

Quoted 25 lines
target-i386/arch_memory_mapping.c new file +25 -0
+int 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);
+    }
Quoted 8 lines

target-i386/arch_memory_mapping.c line 256

Quoted 3 lines
target-i386/arch_memory_mapping.c new file +3 -0
+
+    return 0;
+}

Does this assume paging mode? I don't know qemu very well, but qemu dump command runs externally to guest machine, so I think the machine could be in the state with paging disabled where CR4 doesn't refer to page table as expected.

CR4? I think you want to say CR3.

Yes, the guest may be in the state without paging mode. I will fix it.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#8 lore raw

Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 14:21:37 +0800

Quoted 39 lines

At 03/01/2012 02:13 PM, HATAYAMA Daisuke Wrote:

Quoted 29 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 10:41:47 +0800

Quoted 25 lines
target-i386/arch_memory_mapping.c new file +25 -0
+int 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);
+    }
Quoted 8 lines

target-i386/arch_memory_mapping.c line 256

Quoted 3 lines
target-i386/arch_memory_mapping.c new file +3 -0
+
+    return 0;
+}

Does this assume paging mode? I don't know qemu very well, but qemu dump command runs externally to guest machine, so I think the machine could be in the state with paging disabled where CR4 doesn't refer to page table as expected.

Quoted 4 lines

CR4? I think you want to say CR3.

Yes, the guest may be in the state without paging mode. I will fix it.

Hmmm, now I think dump command needs to have a option to specify whether to do paging or not during dumping. Doing always paging is problematic. Also generated formats should be as simple as possible, different from the format this current version generates. The reasons I have are as follows:

- The qemu dump command runs outside of guest machine. If machine is in the state with paging disabled and CR3 doesn't has page table address, qemu dump command cannot do paging.

- We cannot do paging if guest machine state is severe. For example, when page table data is corrupted in some reason. In general, we should use minimum kinds of data only during dumping.

- There's also kdump specific issue. On kdump there are two kinds of kernels, 1st kernel and 2nd kernel, and when crash happens, execution is transmitted from the 1st to the 2nd, and then the 2nd kernel copies the 1st kernel's kernel image. The problem is that at catastrophic situation, kdump can also hang even in the 2nd kernel. At this point, the 2nd kernel refers to the 2nd kernel's page table. So paging at the situation leads to lost of the 1st kernel's memory.

- OTOH, gdb cannot perform paging, so, for gdb support, qemu dump needs to have paging mode. The period when qemu dump can produce the dump gdb can read is limited to the machine state with paging enabled and the 1st krenel, but I think no choise.

* There's a way of getting the 1st kernel's image as linear image from the dumpfile generated at the 2nd kernel generated without paging. But it uses kenrel's specific information, so I don't think qemu should do this.

- Well, it's possible to generate dumpfile while enabling both physical and linear address access together. It's just what Wen is doing now. But I think it better to do that more simply: that is, if non-paging mode, produce dumpfile as raw format; if paging mode, produce as linear format.

* For example, the current implementation assigns both virtual and physical address to a single PT_LOAD entry. But the memory areas mapped to by a single PT_LOAD is restricted to the ones contiguous both physically and virtually. Due to this, I guess there's a case where the number of program headers grows seriously in the worst case. It might reach ELF's limit size.

* Also, by this, it's necessary to reduce the number of program headers as much as possible, and now qemu dump tries to merge them in PATCH 01, but it looks to me too complicated.

How do other people think?

Thanks.
HATAYAMA, Daisuke

#9 lore raw

RFC PATCH v7 4/14 Add API to get memory mapping

In reply to Wen Congyang

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.

---
 memory_mapping.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |    8 ++++++
 2 files changed, 79 insertions(+), 0 deletions(-)
memory_mapping.c +71 -0
index 84fb2c8..3743805 100644
@@ -132,3 +132,74 @@ void memory_mapping_list_init(MemoryMappingList *list)
     list->last_mapping = NULL;
     QTAILQ_INIT(&list->head);
 }
+
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
+    return -2;
+#endif
+
+    /* 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's list does not conatin the region
+                 * [offset, offset+length)
+                 */
+                create_new_memory_mapping(list, offset, 0, length);
+                length = 0;
+                break;
+            }
+
+            if ((memory_mapping->phys_addr + memory_mapping->length) <=
+                offset) {
+                continue;
+            }
+
+            if (memory_mapping->phys_addr > offset) {
+                /*
+                 * memory_mapping's 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)) {
+                length = 0;
+                break;
+            }
+            length -= memory_mapping->phys_addr + memory_mapping->length -
+                      offset;
+            offset = memory_mapping->phys_addr + memory_mapping->length;
+        }
+
+        if (length > 0) {
+            /*
+             * memory_mapping's list does not conatin the region
+             * [offset, memory_mapping->phys_addr)
+             */
+            create_new_memory_mapping(list, offset, 0, length);
+        }
+    }
+
+    return 0;
+}
memory_mapping.h +8 -0
index 633fcb9..5760d1d 100644
@@ -41,4 +41,12 @@ void memory_mapping_list_add_sorted(MemoryMappingList *list,
 void memory_mapping_list_free(MemoryMappingList *list);
 void memory_mapping_list_init(MemoryMappingList *list);
 
+/*
+ * Return value:
+ *    0: success
+ *   -1: failed
+ *   -2: unsupported
+ */
+int qemu_get_guest_memory_mapping(MemoryMappingList *list);
+
 #endif
Signature · 1 line
1.7.1
#10 lore raw

Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 10:43:13 +0800

Quoted 10 lines
memory_mapping.c +10 -0
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 155

Quoted 10 lines
memory_mapping.c +10 -0
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
+    return -2;
+#endif
+
+    /* some memory may be not mapped, add them into memory mapping's list */

The part from here is logic fully for 2nd kernel? If so, I think it better to describe why this addtional mapping is needed; we should assume most people doesn't know kdump mechanism.

Quoted 40 lines
memory_mapping.c +40 -0
+    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's list does not conatin the region
+                 * [offset, offset+length)
+                 */
+                create_new_memory_mapping(list, offset, 0, length);
+                length = 0;
+                break;
+            }
+
+            if ((memory_mapping->phys_addr + memory_mapping->length) <=
+                offset) {
+                continue;
+            }
+
+            if (memory_mapping->phys_addr > offset) {
+                /*
+                 * memory_mapping's 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)) {
+                length = 0;
+                break;
+            }
+            length -= memory_mapping->phys_addr + memory_mapping->length -
+                      offset;
+            offset = memory_mapping->phys_addr + memory_mapping->length;
+        }
+
+        if (length > 0) {

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 205

Quoted 10 lines
memory_mapping.c +10 -0
+            /*
+             * memory_mapping's list does not conatin the region
+             * [offset, memory_mapping->phys_addr)
+             */
+            create_new_memory_mapping(list, offset, 0, length);
+        }
+    }
+
+    return 0;
+}

I think it more readable if shortening memory_mapping->phys_addr and memmory_maping->length at the berinning of the innermost foreach loop.

  m_phys_addr = memory_mapping->phys_addr;
  m_length = memory_mapping->length;

Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

#11 lore raw

Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping

At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:

Quoted 20 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 10:43:13 +0800

Quoted 16 lines
memory_mapping.c +16 -0
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
Quoted 8 lines

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 155

Quoted 4 lines
memory_mapping.c +4 -0
+    return -2;
+#endif
+
+    /* some memory may be not mapped, add them into memory mapping's list */

The part from here is logic fully for 2nd kernel? If so, I think it better to describe why this addtional mapping is needed; we should assume most people doesn't know kdump mechanism.

Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel, we need this logic for 1st kernel.

Thanks
Wen Congyang

Quoted 64 lines
Quoted 41 lines
memory_mapping.c +40 -0
+    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's list does not conatin the region
+                 * [offset, offset+length)
+                 */
+                create_new_memory_mapping(list, offset, 0, length);
+                length = 0;
+                break;
+            }
+
+            if ((memory_mapping->phys_addr + memory_mapping->length) <=
+                offset) {
+                continue;
+            }
+
+            if (memory_mapping->phys_addr > offset) {
+                /*
+                 * memory_mapping's 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)) {
+                length = 0;
+                break;
+            }
+            length -= memory_mapping->phys_addr + memory_mapping->length -
+                      offset;
+            offset = memory_mapping->phys_addr + memory_mapping->length;
+        }
+
+        if (length > 0) {

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 205

Quoted 10 lines
memory_mapping.c +10 -0
+            /*
+             * memory_mapping's list does not conatin the region
+             * [offset, memory_mapping->phys_addr)
+             */
+            create_new_memory_mapping(list, offset, 0, length);
+        }
+    }
+
+    return 0;
+}

I think it more readable if shortening memory_mapping->phys_addr and memmory_maping->length at the berinning of the innermost foreach loop.

  m_phys_addr = memory_mapping->phys_addr;
  m_length = memory_mapping->length;

Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

#12 lore raw

Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 14:17:53 +0800

Quoted 30 lines

At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:

Quoted 20 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 10:43:13 +0800

Quoted 16 lines
memory_mapping.c +16 -0
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
Quoted 8 lines

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 155

Quoted 4 lines
memory_mapping.c +4 -0
+    return -2;
+#endif
+
+    /* some memory may be not mapped, add them into memory mapping's list */

The part from here is logic fully for 2nd kernel? If so, I think it better to describe why this addtional mapping is needed; we should assume most people doesn't know kdump mechanism.

Quoted 3 lines

Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel, we need this logic for 1st kernel.

So you should describe two cases explicitly. I don't understand them from ``some memory''.

and please consider cleanup below too. Conditionals over two lines are hard to read.

Quoted 8 lines
Quoted 8 lines

I think it more readable if shortening memory_mapping->phys_addr and memmory_maping->length at the berinning of the innermost foreach loop.

  m_phys_addr = memory_mapping->phys_addr;
  m_length = memory_mapping->length;

Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

#13 lore raw

Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping

At 03/01/2012 03:11 PM, HATAYAMA Daisuke Wrote:

Quoted 38 lines

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 14:17:53 +0800

Quoted 30 lines

At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:

Quoted 20 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 10:43:13 +0800

Quoted 16 lines
memory_mapping.c +16 -0
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
Quoted 8 lines

memory_mapping.c void memory_mapping_list_init(MemoryMappingList *list) · line 155

Quoted 4 lines
memory_mapping.c +4 -0
+    return -2;
+#endif
+
+    /* some memory may be not mapped, add them into memory mapping's list */

The part from here is logic fully for 2nd kernel? If so, I think it better to describe why this addtional mapping is needed; we should assume most people doesn't know kdump mechanism.

Quoted 3 lines

Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel, we need this logic for 1st kernel.

Quoted 5 lines

So you should describe two cases explicitly. I don't understand them from ``some memory''.

and please consider cleanup below too. Conditionals over two lines are hard to read.

OK. I will fix it.

Thanks
Wen Congyang

Quoted 14 lines
Quoted 9 lines
Quoted 9 lines

I think it more readable if shortening memory_mapping->phys_addr and memmory_maping->length at the berinning of the innermost foreach loop.

  m_phys_addr = memory_mapping->phys_addr;
  m_length = memory_mapping->length;

Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

#14 lore raw

RFC PATCH v7 5/14 target-i386: Add API to write elf notes to core file

In reply to Wen Congyang

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

---
 Makefile.target         |    1 +
 configure               |    4 +
 cpu-all.h               |   23 +++++
 target-i386/arch_dump.c |  249 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 target-i386/arch_dump.c
Makefile.target +1 -0
index a87e678..cfd3113 100644
@@ -210,6 +210,7 @@ obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
 obj-y += memory_mapping.o
+obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
configure +4 -0
index ddc54f5..d2f24d3 100755
@@ -3649,6 +3649,10 @@ if test "$target_softmmu" = "yes" ; then
   if test "$smartcard_nss" = "yes" ; then
     echo "subdir-$target: subdir-libcacard" >> $config_host_mak
   fi
+  case "$target_arch2" in
+    i386|x86_64)
+      echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak
+  esac
 fi
 if test "$target_user_only" = "yes" ; then
   echo "CONFIG_USER_ONLY=y" >> $config_target_mak
cpu-all.h +23 -0
index cb72680..f7c6321 100644
@@ -533,4 +533,27 @@ static inline int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
 }
 #endif
 
+typedef int (*write_core_dump_function)
+    (target_phys_addr_t offset, void *buf, size_t size, void *opaque);
+#if defined(CONFIG_HAVE_CORE_DUMP)
+int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque);
+#else
+static inline int cpu_write_elf64_note(write_core_dump_function f,
+                                       CPUState *env, int cpuid,
+                                       target_phys_addr_t *offset, void *opaque)
+{
+    return -1;
+}
+
+static inline int cpu_write_elf32_note(write_core_dump_function f,
+                                       CPUState *env, int cpuid,
+                                       target_phys_addr_t *offset, void *opaque)
+{
+    return -1;
+}
+#endif
+
 #endif /* CPU_ALL_H */
target-i386/arch_dump.c new file +249 -0

249 lines not on this page · raw message

Signature · 1 line
1.7.1
#15 lore raw

RFC PATCH v7 6/14 target-i386: Add API to write cpu status to core file

In reply to Wen Congyang

The core file has register's value. But it does not include all register. Store the cpu status into QEMU note, and the user can get more information from vmcore.

---
 cpu-all.h               |   20 ++++++
 target-i386/arch_dump.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 0 deletions(-)
cpu-all.h +20 -0
index f7c6321..ad69269 100644
@@ -540,6 +540,10 @@ int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
 int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
 #else
 static inline int cpu_write_elf64_note(write_core_dump_function f,
                                        CPUState *env, int cpuid,
@@ -554,6 +558,22 @@ static inline int cpu_write_elf32_note(write_core_dump_function f,
 {
     return -1;
 }
+
+static inline int cpu_write_elf64_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque);
+{
+    return -1;
+}
+
+static inline int cpu_write_elf32_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque)
+{
+    return -1;
+}
 #endif
 
 #endif /* CPU_ALL_H */
target-i386/arch_dump.c +154 -0

157 lines not on this page · raw message

Signature · 1 line
1.7.1
#16 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 12 lines
target-i386/arch_dump.c +12 -0
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;

<cut>

target-i386/arch_dump.c int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid, · line 287

Quoted 5 lines
target-i386/arch_dump.c +5 -0
+static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
+{
+    memset(s, 0, sizeof(QEMUCPUState));
+
+    s->version = 1;

It seems to me better to prepare a macro:

  #define QEMUCPUSTATE_VERSION (1)

and use it as:

  s->version = QEMUCPUSTATE_VERSION;

and add comment above the macro definition indicating: please count up QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState, and modify the tools using this information accordingly.

Thanks.
HATAYAMA, Daisuke

#17 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:

Quoted 27 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 12 lines
target-i386/arch_dump.c +12 -0
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;

<cut>

target-i386/arch_dump.c int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid, · line 287

Quoted 5 lines
target-i386/arch_dump.c +5 -0
+static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
+{
+    memset(s, 0, sizeof(QEMUCPUState));
+
+    s->version = 1;

It seems to me better to prepare a macro:

  #define QEMUCPUSTATE_VERSION (1)
Quoted 7 lines

and use it as:

  s->version = QEMUCPUSTATE_VERSION;

and add comment above the macro definition indicating: please count up QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState, and modify the tools using this information accordingly.

Yes, I will fix it.

PS: Do you have any comment about QEMUCPUState? I think the content is enough to calculate phys_base now.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#18 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 13:05:31 +0800

Quoted 32 lines

At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:

Quoted 31 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 12 lines
target-i386/arch_dump.c +12 -0
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;

<cut>

target-i386/arch_dump.c int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid, · line 287

Quoted 5 lines
target-i386/arch_dump.c +5 -0
+static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
+{
+    memset(s, 0, sizeof(QEMUCPUState));
+
+    s->version = 1;

It seems to me better to prepare a macro:

  #define QEMUCPUSTATE_VERSION (1)

and use it as:

  s->version = QEMUCPUSTATE_VERSION;
Quoted 9 lines
Quoted 3 lines

and add comment above the macro definition indicating: please count up QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState, and modify the tools using this information accordingly.

Yes, I will fix it.

PS: Do you have any comment about QEMUCPUState? I think the content is enough to calculate phys_base now.

Yes, for the purpose it might be enough. But looking at CPUX86State, there are still useful states for debugging to know guest machine state at crash, such as device states, NMI states, TSC, etc.

For now, I think it's OK to pick up minimum kinds of registers only. If they are classified sufficiently in their types such as general registers, floating-point registers, control registers, processor features and so on, it's possible to add new note later easily.

Thanks.
HATAYAMA, Daisuke

#19 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

In reply to Wen Congyang

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 16 lines
target-i386/arch_dump.c +16 -0
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);

target-i386/arch_dump.c int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid, · line 354

Quoted 10 lines
target-i386/arch_dump.c +10 -0
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = 0;
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));

x86_64_write_elf64_note() and x86_write_elf64_note() does the same processing for note data. Is it better to do this in helper functions in common?

Thanks.
HATAYAMA, Daisuke

#20 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

At 03/01/2012 01:10 PM, HATAYAMA Daisuke Wrote:

Quoted 26 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 22 lines
target-i386/arch_dump.c +22 -0
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    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 = 0;
+    buf = (char *)note;
Quoted 8 lines

target-i386/arch_dump.c int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid, · line 354

Quoted 4 lines
target-i386/arch_dump.c +4 -0
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));

x86_64_write_elf64_note() and x86_write_elf64_note() does the same processing for note data. Is it better to do this in helper functions in common?

I forgot to merge them. I will fix it.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#21 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

In reply to Wen Congyang

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 5 lines
target-i386/arch_dump.c +5 -0
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;

<cut>

Quoted 1 line

+ note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +

                            ELF64_Nhdr?

Thanks.
HATAYAMA, Daisuke

#22 lore raw

Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file

At 03/02/2012 09:09 AM, HATAYAMA Daisuke Wrote:

Quoted 12 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

Quoted 5 lines
target-i386/arch_dump.c +5 -0
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;

<cut>

Quoted 3 lines
Quoted 1 line

+ note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +

                            ELF64_Nhdr?

Yes, it's my misss, and I will fix it.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#23 lore raw

RFC PATCH v7 7/14 target-i386: add API to get dump info

In reply to Wen Congyang

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

---
 cpu-all.h               |    7 +++++++
 dump.h                  |   23 +++++++++++++++++++++++
 target-i386/arch_dump.c |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 0 deletions(-)
 create mode 100644 dump.h
cpu-all.h +7 -0
index ad69269..a77f9e8 100644
@@ -23,6 +23,7 @@
 #include "qemu-tls.h"
 #include "cpu-common.h"
 #include "memory_mapping.h"
+#include "dump.h"
 
 /* some important defines:
  *
@@ -544,6 +545,7 @@ int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
                              target_phys_addr_t *offset, void *opaque);
 int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
                              target_phys_addr_t *offset, void *opaque);
+int cpu_get_dump_info(ArchDumpInfo *info);
 #else
 static inline int cpu_write_elf64_note(write_core_dump_function f,
                                        CPUState *env, int cpuid,
@@ -574,6 +576,11 @@ static inline int cpu_write_elf32_qemunote(write_core_dump_function f,
 {
     return -1;
 }
+
+static inline int cpu_get_dump_info(ArchDumpInfo *info)
+{
+    return -1;
+}
 #endif
 
 #endif /* CPU_ALL_H */
dump.h new file +23 -0
new file mode 100644
index 0000000..28340cf
@@ -0,0 +1,23 @@
+/*
+ * QEMU dump
+ *
+ * Copyright Fujitsu, Corp. 2011, 2012
+ *
+ * Authors:
+ *     Wen Congyang <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#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
target-i386/arch_dump.c +34 -0
index 560c8a3..e4351f4 100644
@@ -13,6 +13,7 @@
 
 #include "cpu.h"
 #include "cpu-all.h"
+#include "dump.h"
 #include "elf.h"
 
 #ifdef TARGET_X86_64
@@ -401,3 +402,36 @@ int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
 
     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 (block->offset + block->length > UINT_MAX) {
+                /* The memory size is greater than 4G */
+                info->d_class = ELFCLASS64;
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
Signature · 1 line
1.7.1
#24 lore raw

RFC PATCH v7 8/14 make gdb_id() generally avialable

In reply to Wen Congyang

The following patch also needs this API, so make it generally avialable

---
 gdbstub.c |    9 ---------
 gdbstub.h |    9 +++++++++
 2 files changed, 9 insertions(+), 9 deletions(-)
gdbstub.c +0 -9
index 7d470b6..046b036 100644
@@ -1939,15 +1939,6 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #endif
 }
 
-static inline int gdb_id(CPUState *env)
-{
-#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
-    return env->host_tid;
-#else
-    return env->cpu_index + 1;
-#endif
-}
-
 static CPUState *find_cpu(uint32_t thread_id)
 {
     CPUState *env;
gdbstub.h +9 -0
index d82334f..f30bfe8 100644
@@ -30,6 +30,15 @@ void gdb_register_coprocessor(CPUState *env,
                               gdb_reg_cb get_reg, gdb_reg_cb set_reg,
                               int num_regs, const char *xml, int g_pos);
 
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+    return env->host_tid;
+#else
+    return env->cpu_index + 1;
+#endif
+}
+
 #endif
 
 #ifdef CONFIG_USER_ONLY
Signature · 1 line
1.7.1
#25 lore raw

RFC PATCH v7 9/14 introduce a new monitor command 'dump' to dump guest's memory

In reply to Wen Congyang
---
 Makefile.target  |    2 +-
 dump.c           |  637 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hmp-commands.hx  |   20 ++
 hmp.c            |    9 +
 hmp.h            |    1 +
 qapi-schema.json |   13 ++
 qmp-commands.hx  |   29 +++
 7 files changed, 710 insertions(+), 1 deletions(-)
 create mode 100644 dump.c
Makefile.target +1 -1
index cfd3113..4ae59f5 100644
@@ -210,7 +210,7 @@ obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
 obj-y += memory_mapping.o
-obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o
+obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o dump.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
dump.c new file +637 -0

637 lines not on this page · raw message

hmp-commands.hx +20 -0
index 64b3656..19200ad 100644
@@ -880,6 +880,26 @@ server will ask the spice/vnc client to automatically reconnect using the
 new parameters (if specified) once the vm migration finished successfully.
 ETEXI
 
+#if defined(CONFIG_HAVE_CORE_DUMP)
+    {
+        .name       = "dump",
+        .args_type  = "file:s",
+        .params     = "file",
+        .help       = "dump to file",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd = hmp_dump,
+    },
+
+
+STEXI
+@item dump @var{file}
+@findex dump
+Dump to @var{file}. The file can be processed with crash or gdb.
+    file: destination file(started with "file:") or destination file descriptor
+          (started with "fd:")
+ETEXI
+#endif
+
     {
         .name       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
hmp.c +9 -0
index 3a54455..309ccec 100644
@@ -856,3 +856,12 @@ void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
 
     hmp_handle_error(mon, &error);
 }
+
+void hmp_dump(Monitor *mon, const QDict *qdict)
+{
+    Error *errp = NULL;
+    const char *file = qdict_get_str(qdict, "file");
+
+    qmp_dump(file, &errp);
+    hmp_handle_error(mon, &errp);
+}
hmp.h +1 -0
index 5409464..b055e50 100644
@@ -59,5 +59,6 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
 void hmp_block_stream(Monitor *mon, const QDict *qdict);
 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
+void hmp_dump(Monitor *mon, const QDict *qdict);
 
 #endif
qapi-schema.json +13 -0
index d0b6792..3c4aa70 100644
@@ -1593,3 +1593,16 @@
 { 'command': 'qom-list-types',
   'data': { '*implements': 'str', '*abstract': 'bool' },
   'returns': [ 'ObjectTypeInfo' ] }
+
+##
+# @dump
+#
+# Dump guest's memory to vmcore.
+#
+# @file: the filename or file descriptor of the vmcore.
+#
+# Returns: nothing on success
+#
+# Since: 1.1
+##
+{ 'command': 'dump', 'data': { 'file': 'str' } }
qmp-commands.hx +29 -0
index 705f704..1199316 100644
@@ -586,6 +586,35 @@ Example:
 
 EQMP
 
+#if defined(CONFIG_HAVE_CORE_DUMP)
+    {
+        .name       = "dump",
+        .args_type  = "file:s",
+        .params     = "file",
+        .help       = "dump to file",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = qmp_marshal_input_dump,
+    },
+
+SQMP
+dump
+
+
+Dump to file. The file can be processed with crash or gdb.
+
+Arguments:
+
+- "file": destination file(started with "file:") or destination file descriptor
+          (started with "fd:") (json-string)
+
+Example:
+
+-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
+<- { "return": {} }
+
+EQMP
+#endif
+
     {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
Signature · 1 line
1.7.1
#26 lore raw

Re: [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
Date: Thu, 01 Mar 2012 10:51:42 +0800

Quoted 4 lines
dump.c new file +4 -0
+    /*
+     * calculate phdr_num
+     *
+     * the type of phdr->num is uint16_t, so we should avoid overflow

dump.c line 553

Quoted 10 lines
dump.c new file +10 -0
+     */
+    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;
+}

Though e_phnum is uint16_t at default, there's extension up to uint32_t. Look at relatively new manual page. This is from FC14's.

e_phnum This member holds the number of entries in the
program header table. Thus the product of
e_phentsize and e_phnum gives the table's size in bytes. If a file has no program header, e_phnum holds the value zero.

If the number of entries in the program header
table is larger than or equal to PN_XNUM
(0xffff), this member holds PN_XNUM (0xffff) and the real number of entries in the program header table is held in the sh_info member of the
initial entry in section header table.
Otherwise, the sh_info member of the initial entry contains the value zero.

PN_XNUM This is defined as 0xffff, the largest
number e_phnum can have, specifying where the actual number of program headers is assigned.

Recent kernel, gdb and tools in binutils supports this. But crash doesn't, so you need to fix this.

I'm interested in the number of program headers at worst case. According to Intel Programming Guide 3A, Table 4-1. shows physical-address width on IA-32e is up to 52 and linear-address width is 48. Can the number exceed this limit in theory? Also how many program headers are created typically?

Thanks.
HATAYAMA, Daisuke

#27 lore raw

Re: [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory

At 03/01/2012 03:04 PM, HATAYAMA Daisuke Wrote:

Quoted 37 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
Date: Thu, 01 Mar 2012 10:51:42 +0800

Quoted 4 lines
dump.c new file +4 -0
+    /*
+     * calculate phdr_num
+     *
+     * the type of phdr->num is uint16_t, so we should avoid overflow

dump.c line 553

Quoted 10 lines
dump.c new file +10 -0
+     */
+    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;
+}

Though e_phnum is uint16_t at default, there's extension up to uint32_t. Look at relatively new manual page. This is from FC14's.

e_phnum This member holds the number of entries in the
program header table. Thus the product of
e_phentsize and e_phnum gives the table's size in bytes. If a file has no program header, e_phnum holds the value zero.

If the number of entries in the program header
table is larger than or equal to PN_XNUM
(0xffff), this member holds PN_XNUM (0xffff) and the real number of entries in the program header table is held in the sh_info member of the
initial entry in section header table.
Otherwise, the sh_info member of the initial entry contains the value zero.

Quoted 4 lines

PN_XNUM This is defined as 0xffff, the largest
number e_phnum can have, specifying where the actual number of program headers is assigned.

Good news.

Quoted 3 lines

Recent kernel, gdb and tools in binutils supports this. But crash doesn't, so you need to fix this.

I think it can be easily fixed.

Quoted 6 lines

I'm interested in the number of program headers at worst case. According to Intel Programming Guide 3A, Table 4-1. shows physical-address width on IA-32e is up to 52 and linear-address width is 48. Can the number exceed this limit in theory? Also how many program headers are created typically?

In my test, the guest has 512M memory, and it contains about 1000~2000 program headers.

In theory, if the guest has 2^52 memory, the number can still exceed this limit. Tha maxnium number is 2^52/2^12

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#28 lore raw

RFC PATCH v7 10/14 support to cancel the current dumping

In reply to Wen Congyang

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

---
 dump.c           |   13 +++++++++++++
 hmp-commands.hx  |   14 ++++++++++++++
 hmp.c            |    5 +++++
 hmp.h            |    1 +
 qapi-schema.json |   13 +++++++++++++
 qmp-commands.hx  |   21 +++++++++++++++++++++
 6 files changed, 67 insertions(+), 0 deletions(-)
dump.c +13 -0
index c9baedb..673720f 100644
@@ -635,3 +635,16 @@ void qmp_dump(const char *file, Error **errp)
 
     return;
 }
+
+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;
+}
hmp-commands.hx +14 -0
index 19200ad..e6db6b6 100644
@@ -901,6 +901,20 @@ ETEXI
 #endif
 
     {
+        .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]",
hmp.c +5 -0
index 309ccec..a20a7b0 100644
@@ -865,3 +865,8 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
     qmp_dump(file, &errp);
     hmp_handle_error(mon, &errp);
 }
+
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
+{
+    qmp_dump_cancel(NULL);
+}
hmp.h +1 -0
index b055e50..75c6c1d 100644
@@ -60,5 +60,6 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict);
 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 void hmp_dump(Monitor *mon, const QDict *qdict);
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
 
 #endif
qapi-schema.json +13 -0
index 3c4aa70..a764cd3 100644
@@ -1606,3 +1606,16 @@
 # Since: 1.1
 ##
 { 'command': 'dump', 'data': { 'file': 'str' } }
+
+##
+# @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' }
qmp-commands.hx +21 -0
index 1199316..a2d94a9 100644
@@ -616,6 +616,27 @@ EQMP
 #endif
 
     {
+        .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][,...]",
Signature · 1 line
1.7.1
#29 lore raw

RFC PATCH v7 11/14 support to query dumping status

In reply to Wen Congyang

Add API to allow the user to query dumping status.

---
 dump.c           |   32 ++++++++++++++++++++++++++++++++
 hmp-commands.hx  |    2 ++
 hmp.c            |   17 +++++++++++++++++
 hmp.h            |    1 +
 monitor.c        |    7 +++++++
 qapi-schema.json |   26 ++++++++++++++++++++++++++
 qmp-commands.hx  |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 137 insertions(+), 0 deletions(-)
dump.c +32 -0
index 673720f..48779d8 100644
@@ -648,3 +648,35 @@ void qmp_dump_cancel(Error **errp)
     dump_cleanup(s);
     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");
+        info->has_error = true;
+        info->error = g_strdup(s->error);
+        break;
+    case DUMP_STATE_CANCELLED:
+        info->has_status = true;
+        info->status = g_strdup("cancelled");
+        break;
+    }
+
+    return info;
+}
hmp-commands.hx +2 -0
index e6db6b6..0c0a7b4 100644
@@ -1434,6 +1434,8 @@ show device tree
 show qdev device model list
 @item info roms
 show roms
+@item info dump
+show dumping status
 @end table
 ETEXI
 
hmp.c +17 -0
index a20a7b0..476d355 100644
@@ -870,3 +870,20 @@ void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
 {
     qmp_dump_cancel(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);
+    }
+
+    if (info->has_error) {
+        monitor_printf(mon, "Dumping failed reason: %s\n", info->error);
+    }
+
+    qapi_free_DumpInfo(info);
+}
hmp.h +1 -0
index 75c6c1d..3d105a9 100644
@@ -61,5 +61,6 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 void hmp_dump(Monitor *mon, const QDict *qdict);
 void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
+void hmp_info_dump(Monitor *mon);
 
 #endif
monitor.c +7 -0
index 96af5e0..f240895 100644
@@ -2603,6 +2603,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,
     },
 };
qapi-schema.json +26 -0
index a764cd3..1e9af32 100644
@@ -1619,3 +1619,29 @@
 # Since: 1.1
 ##
 { 'command': 'dump_cancel' }
+
+##
+# @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', '*error': 'str' } }
+
+##
+# @query-dump
+#
+# Returns information about current dumping process.
+#
+# Returns: @DumpInfo
+#
+# Since: 1.1
+##
+{ 'command': 'query-dump', 'returns': 'DumpInfo' }
qmp-commands.hx +52 -0

64 lines not on this page · raw message

Signature · 1 line
1.7.1
#30 lore raw

RFC PATCH v7 12/14 run dump at the background

In reply to Wen Congyang

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

---
 dump.c |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 vl.c   |    5 +-
 2 files changed, 150 insertions(+), 23 deletions(-)
dump.c +147 -21
index 48779d8..8224116 100644
@@ -78,9 +78,21 @@ typedef struct DumpState {
     bool resume;
     char *error;
     target_phys_addr_t memory_offset;
+
+    /*
+     * Return value:
+     * -2: EAGAIN
+     * -1: error
+     *  0: success
+     */
     write_core_dump_function f;
     void (*cleanup)(void *opaque);
+    int (*dump_begin_iterate)(struct DumpState *, void *opaque);
     void *opaque;
+    RAMBlock *block;
+    ram_addr_t start;
+    target_phys_addr_t offset;
+    VMChangeStateEntry *handler;
 } DumpState;
 
 static DumpState *dump_get_current(void)
@@ -98,6 +110,12 @@ static int dump_cleanup(DumpState *s)
 
     memory_mapping_list_free(&s->list);
     s->cleanup(s->opaque);
+
+    if (s->handler) {
+        qemu_del_vm_change_state_handler(s->handler);
+        s->handler = NULL;
+    }
+
     if (s->resume) {
         vm_start();
     }
@@ -323,40 +341,70 @@ static int write_elf32_notes(DumpState *s, int phdr_index,
     return 0;
 }
 
+/*
+ * Return value:
+ *     -2: blocked
+ *     -1: failed
+ *      0: sucess
+ */
 static int write_data(DumpState *s, void *buf, int length,
                       target_phys_addr_t *offset)
 {
     int ret;
 
     ret = s->f(*offset, buf, length, s->opaque);
-    if (ret < 0) {
+    if (ret == -1) {
         dump_error(s, "dump: failed to save memory.\n");
         return -1;
     }
 
+    if (ret == -2) {
+        return -2;
+    }
+
     *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)
+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,
+    *size = block->length - start;
+    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;
+            *size = writen_size;
+            return ret;
+        }
+
+        writen_size += TARGET_PAGE_SIZE;
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            *size = writen_size;
+            return -2;
         }
     }
 
-    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;
+            *size = writen_size;
+            return ret;
+        }
+
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            return -2;
         }
     }
 
@@ -435,6 +483,7 @@ static int dump_begin(DumpState *s)
     }
 
     s->memory_offset = offset;
+    s->offset = offset;
     return 0;
 }
 
@@ -462,22 +511,65 @@ static int dump_completed(DumpState *s)
     return 0;
 }
 
-/* write all memory to vmcore */
-static int dump_iterate(DumpState *s)
+static int get_next_block(DumpState *s, RAMBlock *block)
 {
+    while (1) {
+        block = QLIST_NEXT(block, next);
+        if (!block) {
+            /* no more block */
+            return 1;
+        }
+
+        s->start = 0;
+        s->block = block;
+
+        return 0;
+    }
+}
+
+/* write memory to vmcore */
+static void dump_iterate(void *opaque)
+{
+    DumpState *s = opaque;
     RAMBlock *block;
-    target_phys_addr_t offset = s->memory_offset;
+    target_phys_addr_t offset = s->offset;
+    int64_t size;
+    int64_t deadline, now;
     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;
+    now = qemu_get_clock_ms(rt_clock);
+    deadline = now + 5;
+    while(1) {
+        block = s->block;
+        ret = write_memory(s, block, s->start, &offset, &size, deadline);
+        if (ret == -1) {
+            return;
+        }
+
+        if (ret == -2) {
+            break;
+        }
+
+        ret = get_next_block(s, block);
+        if (ret == 1) {
+            dump_completed(s);
+            return;
         }
     }
 
-    return dump_completed(s);
+    if (size == block->length - s->start) {
+        ret = get_next_block(s, block);
+        if (ret == 1) {
+            dump_completed(s);
+            return;
+        }
+    } else {
+        s->start += size;
+    }
+
+    s->offset = offset;
+
+    return;
 }
 
 static int create_vmcore(DumpState *s)
@@ -489,7 +581,7 @@ static int create_vmcore(DumpState *s)
         return -1;
     }
 
-    ret = dump_iterate(s);
+    ret = s->dump_begin_iterate(s, s->opaque);
     if (ret < 0) {
         return -1;
     }
@@ -497,6 +589,17 @@ 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;
+        s->error = g_strdup("vm state is changed to run\n");
+    }
+}
+
 static DumpState *dump_init(Error **errp)
 {
     CPUState *env;
@@ -514,6 +617,9 @@ static DumpState *dump_init(Error **errp)
         g_free(s->error);
         s->error = NULL;
     }
+    s->block = QLIST_FIRST(&ram_list.blocks);
+    s->start = 0;
+    s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s);
 
     /*
      * get dump info: endian, class and architecture.
@@ -560,14 +666,24 @@ static int fd_write_vmcore(target_phys_addr_t offset, void *buf, size_t size,
 
     ret = lseek(fd, offset, SEEK_SET);
     if (ret < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            return -2;
+        }
         return -1;
     }
 
     ret = write(fd, buf, size);
-    if (ret != size) {
+    if (ret < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            return -2;
+        }
         return -1;
     }
 
+    if (ret != size) {
+        return -2;
+    }
+
     return 0;
 }
 
@@ -576,10 +692,18 @@ static void fd_cleanup(void *opaque)
     int fd = (int)(intptr_t)opaque;
 
     if (fd != -1) {
+        qemu_set_fd_handler(fd, NULL, NULL, NULL);
         close(fd);
     }
 }
 
+static int fd_dump_begin_iterate(DumpState *s, void *opaque)
+{
+    int fd = (int)(intptr_t)opaque;
+
+    return qemu_set_fd_handler(fd, NULL, dump_iterate, s);
+}
+
 static DumpState *dump_init_fd(int fd, Error **errp)
 {
     DumpState *s = dump_init(errp);
@@ -590,7 +714,9 @@ static DumpState *dump_init_fd(int fd, Error **errp)
 
     s->f = fd_write_vmcore;
     s->cleanup = fd_cleanup;
+    s->dump_begin_iterate = fd_dump_begin_iterate;
     s->opaque = (void *)(intptr_t)fd;
+    fcntl(fd, F_SETFL, O_NONBLOCK);
 
     return s;
 }
vl.c +3 -2
index 1d4c350..fcc1c57 100644
@@ -1248,11 +1248,12 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
 
 void vm_state_notify(int running, RunState state)
 {
-    VMChangeStateEntry *e;
+    VMChangeStateEntry *e, *next;
 
     trace_vm_state_notify(running, state);
 
-    for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
+    /* e->cb() may remove itself */
+    QLIST_FOREACH_SAFE(e, &vm_change_state_head, entries, next) {
         e->cb(e->opaque, running, state);
     }
 }
Signature · 1 line
1.7.1
#31 lore raw

RFC PATCH v7 13/14 support detached dump

In reply to Wen Congyang

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

---
 dump.c           |    2 +-
 hmp-commands.hx  |    9 +++++----
 hmp.c            |   49 +++++++++++++++++++++++++++++++++++++++++++++++--
 qapi-schema.json |    3 ++-
 qmp-commands.hx  |    7 +++++--
 5 files changed, 60 insertions(+), 10 deletions(-)
dump.c +1 -1
index 8224116..dd3a72c 100644
@@ -721,7 +721,7 @@ static DumpState *dump_init_fd(int fd, Error **errp)
     return s;
 }
 
-void qmp_dump(const char *file, Error **errp)
+void qmp_dump(bool detach, const char *file, Error **errp)
 {
     const char *p;
     int fd = -1;
hmp-commands.hx +5 -4
index 0c0a7b4..bd0c95d 100644
@@ -883,20 +883,21 @@ ETEXI
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "file:s",
-        .params     = "file",
-        .help       = "dump to file",
+        .args_type  = "detach:-d,file:s",
+        .params     = "[-d] file",
+        .help       = "dump to file (using -d to not wait for completion)",
         .user_print = monitor_user_noop,
         .mhandler.cmd = hmp_dump,
     },
 
 
 STEXI
-@item dump @var{file}
+@item dump [-d] @var{file}
 @findex dump
 Dump to @var{file}. The file can be processed with crash or gdb.
     file: destination file(started with "file:") or destination file descriptor
           (started with "fd:")
+      -d: donot wait for completion.
 ETEXI
 #endif
 
hmp.c +47 -2

60 lines not on this page · raw message

qapi-schema.json +2 -1
index 1e9af32..ed157d7 100644
@@ -1599,13 +1599,14 @@
 #
 # Dump guest's memory to vmcore.
 #
+# @detach: detached dumping.
 # @file: the filename or file descriptor of the vmcore.
 #
 # Returns: nothing on success
 #
 # Since: 1.1
 ##
-{ 'command': 'dump', 'data': { 'file': 'str' } }
+{ 'command': 'dump', 'data': { 'detach': 'bool', 'file': 'str' } }
 
 ##
 # @dump_cancel
qmp-commands.hx +5 -2
index 666f1bc..c7b9c82 100644
@@ -589,8 +589,8 @@ EQMP
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "file:s",
-        .params     = "file",
+        .args_type  = "detach:-d,file:s",
+        .params     = "[-d] file",
         .help       = "dump to file",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = qmp_marshal_input_dump,
@@ -616,6 +616,9 @@ Notes:
 
 (1) The 'info dump' command should be used to check dumping's progress
     and final result (this information is provided by the 'status' member)
+(2) All boolean arguments default to false
+(3) The user Monitor's "detach" argument is invalid in QMP and should not
+    be used
 
 EQMP
 #endif
Signature · 1 line
1.7.1
#32 lore raw

RFC PATCH v7 14/14 allow user to dump a fraction of the memory

In reply to Wen Congyang
---
 dump.c           |  124 +++++++++++++++++++++++++++++++++++++++++++++++------
 hmp-commands.hx  |   14 ++++--
 hmp.c            |   13 +++++-
 memory_mapping.c |   27 ++++++++++++
 memory_mapping.h |    2 +
 qapi-schema.json |    6 ++-
 qmp-commands.hx  |    8 +++-
 7 files changed, 172 insertions(+), 22 deletions(-)
dump.c +110 -14
index dd3a72c..3aa160e 100644
@@ -91,6 +91,9 @@ typedef struct DumpState {
     void *opaque;
     RAMBlock *block;
     ram_addr_t start;
+    bool has_filter;
+    int64_t begin;
+    int64_t length;
     target_phys_addr_t offset;
     VMChangeStateEntry *handler;
 } DumpState;
@@ -413,17 +416,47 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
 
 /* 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)
+                                     DumpState *s)
 {
     RAMBlock *block;
-    target_phys_addr_t offset = memory_offset;
+    target_phys_addr_t offset = s->memory_offset;
+    int64_t size_in_block, start;
+
+    if (s->has_filter) {
+        if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
+            return -1;
+        }
+    }
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
-        if (phys_addr >= block->offset &&
-            phys_addr < block->offset + block->length) {
-            return phys_addr - block->offset + offset;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin <= block->offset) {
+                start = block->offset;
+            } else {
+                start = s->begin;
+            }
+
+            size_in_block = block->length - (start - block->offset);
+            if (s->begin + s->length < block->offset + block->length) {
+                size_in_block -= block->offset + block->length -
+                                 (s->begin + s->length);
+            }
+        } else {
+            start = block->offset;
+            size_in_block = block->length;
         }
-        offset += block->length;
+
+        if (phys_addr >= start && phys_addr < start + size_in_block) {
+            return phys_addr - start + offset;
+        }
+
+        offset += size_in_block;
     }
 
     return -1;
@@ -495,7 +528,7 @@ static int dump_completed(DumpState *s)
     int phdr_index = 1, ret;
 
     QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
-        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
+        offset = get_offset(memory_mapping->phys_addr, s);
         if (s->dump_info.d_class == ELFCLASS64) {
             ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
         } else {
@@ -522,6 +555,17 @@ static int get_next_block(DumpState *s, RAMBlock *block)
 
         s->start = 0;
         s->block = block;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin > block->offset) {
+                s->start = s->begin - block->offset;
+            }
+        }
 
         return 0;
     }
@@ -600,7 +644,36 @@ static void dump_vm_state_change(void *opaque, int running, RunState state)
     }
 }
 
-static DumpState *dump_init(Error **errp)
+static ram_addr_t get_start_block(DumpState *s)
+{
+    RAMBlock *block;
+
+    if (!s->has_filter) {
+        s->block = QLIST_FIRST(&ram_list.blocks);
+        return 0;
+    }
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (block->offset >= s->begin + s->length ||
+            block->offset + block->length <= s->begin) {
+            /* This block is out of the range */
+            continue;
+        }
+
+        s->block = block;
+        if (s->begin > block->offset ) {
+            s->start = s->begin - block->offset;
+        } else {
+            s->start = 0;
+        }
+        return s->start;
+    }
+
+    return -1;
+}
+
+static DumpState *dump_init(bool has_filter, int64_t begin, int64_t length,
+                            Error **errp)
 {
     CPUState *env;
     DumpState *s = dump_get_current();
@@ -617,8 +690,16 @@ static DumpState *dump_init(Error **errp)
         g_free(s->error);
         s->error = NULL;
     }
-    s->block = QLIST_FIRST(&ram_list.blocks);
-    s->start = 0;
+
+    s->has_filter = has_filter;
+    s->begin = begin;
+    s->length = length;
+    s->start = get_start_block(s);
+    if (s->start == -1) {
+        error_set(errp, QERR_INVALID_PARAMETER, "begin");
+        return NULL;
+    }
+
     s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s);
 
     /*
@@ -643,6 +724,10 @@ static DumpState *dump_init(Error **errp)
     memory_mapping_list_init(&s->list);
     qemu_get_guest_memory_mapping(&s->list);
 
+    if (s->has_filter) {
+        memory_mapping_filter(&s->list, s->begin, s->length);
+    }
+
     /*
      * calculate phdr_num
      *
@@ -704,9 +789,10 @@ static int fd_dump_begin_iterate(DumpState *s, void *opaque)
     return qemu_set_fd_handler(fd, NULL, dump_iterate, s);
 }
 
-static DumpState *dump_init_fd(int fd, Error **errp)
+static DumpState *dump_init_fd(int fd, bool has_filter, int64_t begin,
+                               int64_t length, Error **errp)
 {
-    DumpState *s = dump_init(errp);
+    DumpState *s = dump_init(has_filter, begin, length, errp);
 
     if (s == NULL) {
         return NULL;
@@ -721,12 +807,22 @@ static DumpState *dump_init_fd(int fd, Error **errp)
     return s;
 }
 
-void qmp_dump(bool detach, const char *file, Error **errp)
+void qmp_dump(bool detach, const char *file, bool has_begin, int64_t begin,
+              bool has_length, int64_t length, Error **errp)
 {
     const char *p;
     int fd = -1;
     DumpState *s;
 
+    if (has_begin && !has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "length");
+        return;
+    }
+    if (!has_begin && has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "begin");
+        return;
+    }
+
 #if !defined(WIN32)
     if (strstart(file, "fd:", &p)) {
         fd = qemu_get_fd(p);
@@ -750,7 +846,7 @@ void qmp_dump(bool detach, const char *file, Error **errp)
         return;
     }
 
-    s = dump_init_fd(fd, errp);
+    s = dump_init_fd(fd, has_begin, begin, length, errp);
     if (!s) {
         return;
     }
hmp-commands.hx +10 -4
index bd0c95d..8b2dd38 100644
@@ -883,21 +883,27 @@ ETEXI
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "detach:-d,file:s",
-        .params     = "[-d] file",
-        .help       = "dump to file (using -d to not wait for completion)",
+        .args_type  = "detach:-d,file:s,begin:i?,length:i?",
+        .params     = "[-d] file [begin] [length]",
+        .help       = "dump to file (using -d to not wait for completion)"
+                      "\n\t\t\t begin(optional): the starting physical address"
+                      "\n\t\t\t length(optional): the memory size, in bytes",
         .user_print = monitor_user_noop,
         .mhandler.cmd = hmp_dump,
     },
 
 
 STEXI
-@item dump [-d] @var{file}
+@item dump [-d] @var{file} @var{begin} @var{length}
 @findex dump
 Dump to @var{file}. The file can be processed with crash or gdb.
     file: destination file(started with "file:") or destination file descriptor
           (started with "fd:")
       -d: donot wait for completion.
+   begin: the starting physical address. It's optional, and should be specified
+          with length together.
+  length: the memory size, in bytes. It's optional, and should be specified with
+          begin together.
 ETEXI
 #endif
 
hmp.c +12 -1
index 707701b..326d277 100644
@@ -885,8 +885,19 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
     Error *errp = NULL;
     int detach = qdict_get_try_bool(qdict, "detach", 0);
     const char *file = qdict_get_str(qdict, "file");
+    bool has_begin = qdict_haskey(qdict, "begin");
+    bool has_length = qdict_haskey(qdict, "length");
+    int64_t begin = 0;
+    int64_t length = 0;
 
-    qmp_dump(!!detach, file, &errp);
+    if (has_begin) {
+        begin = qdict_get_int(qdict, "begin");
+    }
+    if (has_length) {
+        length = qdict_get_int(qdict, "length");
+    }
+
+    qmp_dump(!!detach, file, has_begin, begin, has_length, length, &errp);
     if (errp) {
         hmp_handle_error(mon, &errp);
         return;
memory_mapping.c +27 -0
index 3743805..0c6ddbe 100644
@@ -203,3 +203,30 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list)
 
     return 0;
 }
+
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length)
+{
+    MemoryMapping *cur, *next;
+
+    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
+        if (cur->phys_addr >= begin + length ||
+            cur->phys_addr + cur->length <= begin) {
+            QTAILQ_REMOVE(&list->head, cur, next);
+            list->num--;
+            continue;
+        }
+
+        if (cur->phys_addr < begin) {
+            cur->length -= begin - cur->phys_addr;
+            if (cur->virt_addr) {
+                cur->virt_addr += begin - cur->phys_addr;
+            }
+            cur->phys_addr = begin;
+        }
+
+        if (cur->phys_addr + cur->length > begin + length) {
+            cur->length -= cur->phys_addr + cur->length - begin - length;
+        }
+    }
+}
memory_mapping.h +2 -0
index 5760d1d..07270d5 100644
@@ -49,4 +49,6 @@ void memory_mapping_list_init(MemoryMappingList *list);
  */
 int qemu_get_guest_memory_mapping(MemoryMappingList *list);
 
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length);
 #endif
qapi-schema.json +5 -1
index ed157d7..1206d51 100644
@@ -1601,12 +1601,16 @@
 #
 # @detach: detached dumping.
 # @file: the filename or file descriptor of the vmcore.
+# @begin: if specified, the starting physical address.
+# @length: if specified, the memory size, in bytes.
 #
 # Returns: nothing on success
 #
 # Since: 1.1
 ##
-{ 'command': 'dump', 'data': { 'detach': 'bool', 'file': 'str' } }
+{ 'command': 'dump',
+  'data': { 'detach': 'bool', 'file': 'str', '*begin': 'int',
+            '*length': 'int' } }
 
 ##
 # @dump_cancel
qmp-commands.hx +6 -2
index c7b9c82..06ff121 100644
@@ -589,8 +589,8 @@ EQMP
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "detach:-d,file:s",
-        .params     = "[-d] file",
+        .args_type  = "detach:-d,file:s,begin:i?,end:i?",
+        .params     = "[-d] file [begin] [length]",
         .help       = "dump to file",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = qmp_marshal_input_dump,
@@ -606,6 +606,10 @@ Arguments:
 
 - "file": destination file(started with "file:") or destination file descriptor
           (started with "fd:") (json-string)
+- "begin": the starting physical address. It's optional, and should be specified
+           with length together (json-int)
+- "length": the memory size, in bytes. It's optional, and should be specified
+            with begin together (json-int)
 
 Example:
 
Signature · 1 line
1.7.1
#33 lore raw
In reply to Wen Congyang

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 10:35:44 +0800

Quoted 9 lines

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

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html

Quoted 6 lines

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 now.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.

Does this say the thing caused by gdb versions with no Dwarf V3 support? If so, it's better to write that too explicitly here.

Quoted 6 lines

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. The cpu's state is stored in QEMU note. You neet to modify crash to use it to calculate phys_base.

Again, you still need to fix crash utility to recover the 1st kernel's first 640kB physical memory that has been reserved during switch from 1st kernel to 2nd kernel.

Thanks.
HATAYAMA, Daisuke

#34 lore raw

At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:

Quoted 16 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 10:35:44 +0800

Quoted 12 lines

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

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html

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

Quoted 6 lines
Quoted 3 lines

Note:
1. The guest should be x86 or x86_64. The other arch is not supported now.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.

Does this say the thing caused by gdb versions with no Dwarf V3 support? If so, it's better to write that too explicitly here.

I donot know why gdb crashed, and I cannot reproduce this problem now.

Quoted 11 lines
Quoted 7 lines

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. The cpu's state is stored in QEMU note. You neet to modify crash to use it to calculate phys_base.

Again, you still need to fix crash utility to recover the 1st kernel's first 640kB physical memory that has been reserved during switch from 1st kernel to 2nd kernel.

It is another work, I will try to do it in the future.

Thanks
Wen Congyang

Quoted 5 lines

Thanks.
HATAYAMA, Daisuke

#35 lore raw

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 13:16:47 +0800

Quoted 17 lines

At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:

Quoted 16 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 10:35:44 +0800

Quoted 12 lines

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

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html

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

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

Note:
1. The guest should be x86 or x86_64. The other arch is not supported now.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.

Does this say the thing caused by gdb versions with no Dwarf V3 support? If so, it's better to write that too explicitly here.

I donot know why gdb crashed, and I cannot reproduce this problem now.

Sorry. I meant Dwarf4. Recent GCC emits binary with Dwarf4 in default, and older GDBs cannot handle them although I don't know this is the same as what you saw.

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

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. The cpu's state is stored in QEMU note. You neet to modify crash to use it to calculate phys_base.

Quoted 6 lines
Quoted 3 lines

Again, you still need to fix crash utility to recover the 1st kernel's first 640kB physical memory that has been reserved during switch from 1st kernel to 2nd kernel.

It is another work, I will try to do it in the future.

Please.

Thanks.
HATAYAMA, Daisuke

#36 lore raw

At 03/02/2012 08:49 AM, HATAYAMA Daisuke Wrote:

Quoted 28 lines

From: Wen Congyang <[email protected]>
Subject: Re: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 13:16:47 +0800

Quoted 24 lines

At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:

Quoted 22 lines

From: Wen Congyang <[email protected]>
Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 10:35:44 +0800

Quoted 9 lines

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

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html

Quoted 6 lines

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 now.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.

Does this say the thing caused by gdb versions with no Dwarf V3 support? If so, it's better to write that too explicitly here.

Quoted 6 lines
Quoted 2 lines

I donot know why gdb crashed, and I cannot reproduce this problem now.

Sorry. I meant Dwarf4. Recent GCC emits binary with Dwarf4 in default, and older GDBs cannot handle them although I don't know this is the same as what you saw.

I guess it is not, as I cannot reproduce this problem.

Thanks
Wen Congyang

Quoted 21 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

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. The cpu's state is stored in QEMU note. You neet to modify crash to use it to calculate phys_base.

Quoted 6 lines
Quoted 3 lines

Again, you still need to fix crash utility to recover the 1st kernel's first 640kB physical memory that has been reserved during switch from 1st kernel to 2nd kernel.

It is another work, I will try to do it in the future.

Please.

Thanks.
HATAYAMA, Daisuke