All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] dump: add 32-bit guest Windows support
@ 2022-03-25 19:51 Viktor Prutyanov
  2022-03-25 19:51 ` [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness Viktor Prutyanov
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Viktor Prutyanov @ 2022-03-25 19:51 UTC (permalink / raw)
  To: marcandre.lureau, f4bug; +Cc: yan, qemu-devel, viktor.prutyanov

Since 32-bit versions of Windows still exist, there is a need to take
live and crash dumps of such guests along with 64-bit guests. So, add
an ability for 'dump-guest-memory -w' to take dumps from 32-bit guest.
When running the command QEMU consumes 32-bit Complete Memory Dump
header passed by guest driver through vmcoreinfo device as it was
previously done for 64-bit headers. 32-bit vmcoreinfo guest driver in
upstream virtio-win can fill such a header.

Changes in v3:
    - some WIN_DUMP_* macros are replaced by similar functions where it
      is possible
Changes in v2:
    - no change in logic, just split patches
    - first introduce WIN_DUMP_* macros for x64 in a separate patch
    - rename WinContext to WinContext64 in a separate patch

Viktor Prutyanov (4):
  include/qemu: rename Windows context definitions to expose bitness
  dump/win_dump: add helper macros for Windows dump header access
  include/qemu: add 32-bit Windows dump structures
  dump/win_dump: add 32-bit guest Windows support

 contrib/elf2dmp/main.c       |   6 +-
 dump/win_dump.c              | 299 ++++++++++++++++++++++-------------
 include/qemu/win_dump_defs.h | 115 +++++++++++++-
 3 files changed, 305 insertions(+), 115 deletions(-)

-- 
2.35.1



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

* [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness
  2022-03-25 19:51 [PATCH v3 0/4] dump: add 32-bit guest Windows support Viktor Prutyanov
@ 2022-03-25 19:51 ` Viktor Prutyanov
  2022-04-06  7:24   ` Marc-André Lureau
  2022-03-25 19:51 ` [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access Viktor Prutyanov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Viktor Prutyanov @ 2022-03-25 19:51 UTC (permalink / raw)
  To: marcandre.lureau, f4bug; +Cc: yan, qemu-devel, viktor.prutyanov

Context structure in 64-bit Windows differs from 32-bit one and it
should be reflected in its name.

Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 contrib/elf2dmp/main.c       |  6 +++---
 dump/win_dump.c              | 14 +++++++-------
 include/qemu/win_dump_defs.h |  8 ++++----
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c
index 20b477d582..b9fc6d230c 100644
--- a/contrib/elf2dmp/main.c
+++ b/contrib/elf2dmp/main.c
@@ -141,10 +141,10 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
     return kdbg;
 }
 
-static void win_context_init_from_qemu_cpu_state(WinContext *ctx,
+static void win_context_init_from_qemu_cpu_state(WinContext64 *ctx,
         QEMUCPUState *s)
 {
-    WinContext win_ctx = (WinContext){
+    WinContext64 win_ctx = (WinContext64){
         .ContextFlags = WIN_CTX_X64 | WIN_CTX_INT | WIN_CTX_SEG | WIN_CTX_CTL,
         .MxCsr = INITIAL_MXCSR,
 
@@ -302,7 +302,7 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
     for (i = 0; i < qe->state_nr; i++) {
         uint64_t Prcb;
         uint64_t Context;
-        WinContext ctx;
+        WinContext64 ctx;
         QEMUCPUState *s = qe->state[i];
 
         if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
diff --git a/dump/win_dump.c b/dump/win_dump.c
index c5eb5a9aac..29b6e4f670 100644
--- a/dump/win_dump.c
+++ b/dump/win_dump.c
@@ -189,7 +189,7 @@ try_again:
 }
 
 struct saved_context {
-    WinContext ctx;
+    WinContext64 ctx;
     uint64_t addr;
 };
 
@@ -221,7 +221,7 @@ static void patch_and_save_context(WinDumpHeader64 *h,
         CPUX86State *env = &x86_cpu->env;
         uint64_t Prcb;
         uint64_t Context;
-        WinContext ctx;
+        WinContext64 ctx;
 
         if (cpu_memory_rw_debug(first_cpu,
                 KiProcessorBlock + i * sizeof(uint64_t),
@@ -241,8 +241,8 @@ static void patch_and_save_context(WinDumpHeader64 *h,
 
         saved_ctx[i].addr = Context;
 
-        ctx = (WinContext){
-            .ContextFlags = WIN_CTX_ALL,
+        ctx = (WinContext64){
+            .ContextFlags = WIN_CTX64_ALL,
             .MxCsr = env->mxcsr,
 
             .SegEs = env->segs[0].selector,
@@ -284,13 +284,13 @@ static void patch_and_save_context(WinDumpHeader64 *h,
         };
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
+                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 0)) {
             error_setg(errp, "win-dump: failed to save CPU #%d context", i);
             return;
         }
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                (uint8_t *)&ctx, sizeof(WinContext), 1)) {
+                (uint8_t *)&ctx, sizeof(WinContext64), 1)) {
             error_setg(errp, "win-dump: failed to write CPU #%d context", i);
             return;
         }
@@ -306,7 +306,7 @@ static void restore_context(WinDumpHeader64 *h,
 
     for (i = 0; i < h->NumberProcessors; i++) {
         if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
-                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
+                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 1)) {
             warn_report("win-dump: failed to restore CPU #%d context", i);
         }
     }
diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h
index 145096e8ee..5a5e5a5e09 100644
--- a/include/qemu/win_dump_defs.h
+++ b/include/qemu/win_dump_defs.h
@@ -97,8 +97,8 @@ typedef struct WinDumpHeader64 {
 #define WIN_CTX_FP  0x00000008L
 #define WIN_CTX_DBG 0x00000010L
 
-#define WIN_CTX_FULL    (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
-#define WIN_CTX_ALL     (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
+#define WIN_CTX64_FULL  (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
+#define WIN_CTX64_ALL   (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
 
 #define LIVE_SYSTEM_DUMP    0x00000161
 
@@ -107,7 +107,7 @@ typedef struct WinM128A {
     int64_t high;
 } QEMU_ALIGNED(16) WinM128A;
 
-typedef struct WinContext {
+typedef struct WinContext64 {
     uint64_t PHome[6];
 
     uint32_t ContextFlags;
@@ -174,6 +174,6 @@ typedef struct WinContext {
     uint64_t LastBranchFromRip;
     uint64_t LastExceptionToRip;
     uint64_t LastExceptionFromRip;
-} QEMU_ALIGNED(16) WinContext;
+} QEMU_ALIGNED(16) WinContext64;
 
 #endif /* QEMU_WIN_DUMP_DEFS_H */
-- 
2.35.1



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

* [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access
  2022-03-25 19:51 [PATCH v3 0/4] dump: add 32-bit guest Windows support Viktor Prutyanov
  2022-03-25 19:51 ` [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness Viktor Prutyanov
@ 2022-03-25 19:51 ` Viktor Prutyanov
  2022-04-06  7:24   ` Marc-André Lureau
  2022-03-25 19:51 ` [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures Viktor Prutyanov
  2022-03-25 19:51 ` [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support Viktor Prutyanov
  3 siblings, 1 reply; 11+ messages in thread
From: Viktor Prutyanov @ 2022-03-25 19:51 UTC (permalink / raw)
  To: marcandre.lureau, f4bug; +Cc: yan, qemu-devel, viktor.prutyanov

Perform read access to Windows dump header fields via helper macros.
This is preparation for the next 32-bit guest Windows dump support.

Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
---
 dump/win_dump.c | 100 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 35 deletions(-)

diff --git a/dump/win_dump.c b/dump/win_dump.c
index 29b6e4f670..df3b432ca5 100644
--- a/dump/win_dump.c
+++ b/dump/win_dump.c
@@ -24,11 +24,25 @@
 #include "hw/misc/vmcoreinfo.h"
 #include "win_dump.h"
 
-static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
+#define WIN_DUMP_PTR_SIZE sizeof(uint64_t)
+
+#define _WIN_DUMP_FIELD(f) (h->f)
+#define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
+
+#define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f)
+#define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
+
+#define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f)
+#define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
+
+#define WIN_DUMP_CTX_SIZE sizeof(WinContext64)
+
+static size_t write_run(uint64_t base_page, uint64_t page_count,
+        int fd, Error **errp)
 {
     void *buf;
-    uint64_t addr = run->BasePage << TARGET_PAGE_BITS;
-    uint64_t size = run->PageCount << TARGET_PAGE_BITS;
+    uint64_t addr = base_page << TARGET_PAGE_BITS;
+    uint64_t size = page_count << TARGET_PAGE_BITS;
     uint64_t len, l;
     size_t total = 0;
 
@@ -59,13 +73,14 @@ static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
 
 static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
 {
-    WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock;
-    WinDumpPhyMemRun64 *run = desc->Run;
+    uint64_t BasePage, PageCount;
     Error *local_err = NULL;
     int i;
 
-    for (i = 0; i < desc->NumberOfRuns; i++) {
-        s->written_size += write_run(run + i, s->fd, &local_err);
+    for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) {
+        BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage);
+        PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount);
+        s->written_size += write_run(BasePage, PageCount, s->fd, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
             return;
@@ -73,11 +88,24 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
     }
 }
 
+static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr)
+{
+    int ret;
+    uint64_t ptr64;
+
+    ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0);
+
+    *ptr = ptr64;
+
+    return ret;
+}
+
 static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
 {
     if (cpu_memory_rw_debug(first_cpu,
-            h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64,
-            (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) {
+            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64,
+            WIN_DUMP_FIELD_PTR(PfnDatabase),
+            WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
         error_setg(errp, "win-dump: failed to read MmPfnDatabase");
         return;
     }
@@ -87,16 +115,17 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
 {
     uint64_t KiBugcheckData;
 
-    if (cpu_memory_rw_debug(first_cpu,
-            h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64,
-            (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) {
+    if (cpu_read_ptr(first_cpu,
+            WIN_DUMP_FIELD(KdDebuggerDataBlock) +
+                KDBG_KI_BUGCHECK_DATA_OFFSET64,
+            &KiBugcheckData)) {
         error_setg(errp, "win-dump: failed to read KiBugcheckData");
         return;
     }
 
-    if (cpu_memory_rw_debug(first_cpu,
-            KiBugcheckData,
-            h->BugcheckData, sizeof(h->BugcheckData), 0)) {
+    if (cpu_memory_rw_debug(first_cpu, KiBugcheckData,
+            WIN_DUMP_FIELD(BugcheckData),
+            WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) {
         error_setg(errp, "win-dump: failed to read bugcheck data");
         return;
     }
@@ -105,8 +134,8 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
      * If BugcheckCode wasn't saved, we consider guest OS as alive.
      */
 
-    if (!h->BugcheckCode) {
-        h->BugcheckCode = LIVE_SYSTEM_DUMP;
+    if (!WIN_DUMP_FIELD(BugcheckCode)) {
+        *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP;
     }
 }
 
@@ -155,7 +184,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp)
 {
     const char OwnerTag[] = "KDBG";
     char read_OwnerTag[4];
-    uint64_t KdDebuggerDataBlock = h->KdDebuggerDataBlock;
+    uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
     bool try_fallback = true;
 
 try_again:
@@ -174,7 +203,7 @@ try_again:
              * we try to use KDBG obtained by guest driver.
              */
 
-            KdDebuggerDataBlock = h->BugcheckParameter1;
+            KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1);
             try_fallback = false;
             goto try_again;
         } else {
@@ -197,20 +226,21 @@ static void patch_and_save_context(WinDumpHeader64 *h,
                                    struct saved_context *saved_ctx,
                                    Error **errp)
 {
+    uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
     uint64_t KiProcessorBlock;
     uint16_t OffsetPrcbContext;
     CPUState *cpu;
     int i = 0;
 
-    if (cpu_memory_rw_debug(first_cpu,
-            h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
-            (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
+    if (cpu_read_ptr(first_cpu,
+            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
+            &KiProcessorBlock)) {
         error_setg(errp, "win-dump: failed to read KiProcessorBlock");
         return;
     }
 
     if (cpu_memory_rw_debug(first_cpu,
-            h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
+            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
             (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
         error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
         return;
@@ -223,17 +253,17 @@ static void patch_and_save_context(WinDumpHeader64 *h,
         uint64_t Context;
         WinContext64 ctx;
 
-        if (cpu_memory_rw_debug(first_cpu,
-                KiProcessorBlock + i * sizeof(uint64_t),
-                (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
+        if (cpu_read_ptr(first_cpu,
+                KiProcessorBlock + i * WIN_DUMP_PTR_SIZE,
+                &Prcb)) {
             error_setg(errp, "win-dump: failed to read"
                              " CPU #%d PRCB location", i);
             return;
         }
 
-        if (cpu_memory_rw_debug(first_cpu,
+        if (cpu_read_ptr(first_cpu,
                 Prcb + OffsetPrcbContext,
-                (uint8_t *)&Context, sizeof(Context), 0)) {
+                &Context)) {
             error_setg(errp, "win-dump: failed to read"
                              " CPU #%d ContextFrame location", i);
             return;
@@ -284,13 +314,13 @@ static void patch_and_save_context(WinDumpHeader64 *h,
         };
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 0)) {
+                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) {
             error_setg(errp, "win-dump: failed to save CPU #%d context", i);
             return;
         }
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                (uint8_t *)&ctx, sizeof(WinContext64), 1)) {
+                &ctx, WIN_DUMP_CTX_SIZE, 1)) {
             error_setg(errp, "win-dump: failed to write CPU #%d context", i);
             return;
         }
@@ -304,9 +334,9 @@ static void restore_context(WinDumpHeader64 *h,
 {
     int i;
 
-    for (i = 0; i < h->NumberProcessors; i++) {
+    for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
         if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
-                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 1)) {
+                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) {
             warn_report("win-dump: failed to restore CPU #%d context", i);
         }
     }
@@ -338,7 +368,7 @@ void create_win_dump(DumpState *s, Error **errp)
      * should be made from system context.
      */
 
-    first_x86_cpu->env.cr[3] = h->DirectoryTableBase;
+    first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
 
     check_kdbg(h, &local_err);
     if (local_err) {
@@ -348,7 +378,7 @@ void create_win_dump(DumpState *s, Error **errp)
 
     patch_header(h);
 
-    saved_ctx = g_new(struct saved_context, h->NumberProcessors);
+    saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
 
     /*
      * Always patch context because there is no way
@@ -361,7 +391,7 @@ void create_win_dump(DumpState *s, Error **errp)
         goto out_free;
     }
 
-    s->total_size = h->RequiredDumpSpace;
+    s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
 
     s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
     if (s->written_size != sizeof(*h)) {
-- 
2.35.1



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

* [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures
  2022-03-25 19:51 [PATCH v3 0/4] dump: add 32-bit guest Windows support Viktor Prutyanov
  2022-03-25 19:51 ` [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness Viktor Prutyanov
  2022-03-25 19:51 ` [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access Viktor Prutyanov
@ 2022-03-25 19:51 ` Viktor Prutyanov
  2022-04-06  7:51   ` Marc-André Lureau
  2022-03-25 19:51 ` [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support Viktor Prutyanov
  3 siblings, 1 reply; 11+ messages in thread
From: Viktor Prutyanov @ 2022-03-25 19:51 UTC (permalink / raw)
  To: marcandre.lureau, f4bug; +Cc: yan, qemu-devel, viktor.prutyanov

These structures are required to produce 32-bit guest Windows Complete
Memory Dump. Add 32-bit Windows dump header, CPU context and physical
memory descriptor structures along with corresponding definitions.

Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/qemu/win_dump_defs.h | 107 +++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h
index 5a5e5a5e09..73a44e2408 100644
--- a/include/qemu/win_dump_defs.h
+++ b/include/qemu/win_dump_defs.h
@@ -11,11 +11,22 @@
 #ifndef QEMU_WIN_DUMP_DEFS_H
 #define QEMU_WIN_DUMP_DEFS_H
 
+typedef struct WinDumpPhyMemRun32 {
+    uint32_t BasePage;
+    uint32_t PageCount;
+} QEMU_PACKED WinDumpPhyMemRun32;
+
 typedef struct WinDumpPhyMemRun64 {
     uint64_t BasePage;
     uint64_t PageCount;
 } QEMU_PACKED WinDumpPhyMemRun64;
 
+typedef struct WinDumpPhyMemDesc32 {
+    uint32_t NumberOfRuns;
+    uint32_t NumberOfPages;
+    WinDumpPhyMemRun32 Run[86];
+} QEMU_PACKED WinDumpPhyMemDesc32;
+
 typedef struct WinDumpPhyMemDesc64 {
     uint32_t NumberOfRuns;
     uint32_t unused;
@@ -33,6 +44,39 @@ typedef struct WinDumpExceptionRecord {
     uint64_t ExceptionInformation[15];
 } QEMU_PACKED WinDumpExceptionRecord;
 
+typedef struct WinDumpHeader32 {
+    char Signature[4];
+    char ValidDump[4];
+    uint32_t MajorVersion;
+    uint32_t MinorVersion;
+    uint32_t DirectoryTableBase;
+    uint32_t PfnDatabase;
+    uint32_t PsLoadedModuleList;
+    uint32_t PsActiveProcessHead;
+    uint32_t MachineImageType;
+    uint32_t NumberProcessors;
+    union {
+        struct {
+            uint32_t BugcheckCode;
+            uint32_t BugcheckParameter1;
+            uint32_t BugcheckParameter2;
+            uint32_t BugcheckParameter3;
+            uint32_t BugcheckParameter4;
+        };
+        uint8_t BugcheckData[20];
+    };
+    uint8_t VersionUser[32];
+    uint32_t reserved0;
+    uint32_t KdDebuggerDataBlock;
+    union {
+        WinDumpPhyMemDesc32 PhysicalMemoryBlock;
+        uint8_t PhysicalMemoryBlockBuffer[700];
+    };
+    uint8_t reserved1[3200];
+    uint32_t RequiredDumpSpace;
+    uint8_t reserved2[92];
+} QEMU_PACKED WinDumpHeader32;
+
 typedef struct WinDumpHeader64 {
     char Signature[4];
     char ValidDump[4];
@@ -81,25 +125,49 @@ typedef struct WinDumpHeader64 {
     uint8_t reserved[4018];
 } QEMU_PACKED WinDumpHeader64;
 
+typedef union WinDumpHeader {
+    struct {
+        char Signature[4];
+        char ValidDump[4];
+    };
+    WinDumpHeader32 x32;
+    WinDumpHeader64 x64;
+} WinDumpHeader;
+
 #define KDBG_OWNER_TAG_OFFSET64             0x10
 #define KDBG_MM_PFN_DATABASE_OFFSET64       0xC0
 #define KDBG_KI_BUGCHECK_DATA_OFFSET64      0x88
 #define KDBG_KI_PROCESSOR_BLOCK_OFFSET64    0x218
 #define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64   0x338
 
+#define KDBG_OWNER_TAG_OFFSET           KDBG_OWNER_TAG_OFFSET64
+#define KDBG_MM_PFN_DATABASE_OFFSET     KDBG_MM_PFN_DATABASE_OFFSET64
+#define KDBG_KI_BUGCHECK_DATA_OFFSET    KDBG_KI_BUGCHECK_DATA_OFFSET64
+#define KDBG_KI_PROCESSOR_BLOCK_OFFSET  KDBG_KI_PROCESSOR_BLOCK_OFFSET64
+#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET KDBG_OFFSET_PRCB_CONTEXT_OFFSET64
+
 #define VMCOREINFO_ELF_NOTE_HDR_SIZE    24
+#define VMCOREINFO_WIN_DUMP_NOTE_SIZE64 (sizeof(WinDumpHeader64) + \
+                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
+#define VMCOREINFO_WIN_DUMP_NOTE_SIZE32 (sizeof(WinDumpHeader32) + \
+                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
 
 #define WIN_CTX_X64 0x00100000L
+#define WIN_CTX_X86 0x00010000L
 
 #define WIN_CTX_CTL 0x00000001L
 #define WIN_CTX_INT 0x00000002L
 #define WIN_CTX_SEG 0x00000004L
 #define WIN_CTX_FP  0x00000008L
 #define WIN_CTX_DBG 0x00000010L
+#define WIN_CTX_EXT 0x00000020L
 
 #define WIN_CTX64_FULL  (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
 #define WIN_CTX64_ALL   (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
 
+#define WIN_CTX32_FULL (WIN_CTX_X86 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_SEG)
+#define WIN_CTX32_ALL (WIN_CTX32_FULL | WIN_CTX_FP | WIN_CTX_DBG | WIN_CTX_EXT)
+
 #define LIVE_SYSTEM_DUMP    0x00000161
 
 typedef struct WinM128A {
@@ -107,6 +175,40 @@ typedef struct WinM128A {
     int64_t high;
 } QEMU_ALIGNED(16) WinM128A;
 
+typedef struct WinContext32 {
+    uint32_t ContextFlags;
+
+    uint32_t Dr0;
+    uint32_t Dr1;
+    uint32_t Dr2;
+    uint32_t Dr3;
+    uint32_t Dr6;
+    uint32_t Dr7;
+
+    uint8_t  FloatSave[112];
+
+    uint32_t SegGs;
+    uint32_t SegFs;
+    uint32_t SegEs;
+    uint32_t SegDs;
+
+    uint32_t Edi;
+    uint32_t Esi;
+    uint32_t Ebx;
+    uint32_t Edx;
+    uint32_t Ecx;
+    uint32_t Eax;
+
+    uint32_t Ebp;
+    uint32_t Eip;
+    uint32_t SegCs;
+    uint32_t EFlags;
+    uint32_t Esp;
+    uint32_t SegSs;
+
+    uint8_t ExtendedRegisters[512];
+} QEMU_ALIGNED(16) WinContext32;
+
 typedef struct WinContext64 {
     uint64_t PHome[6];
 
@@ -176,4 +278,9 @@ typedef struct WinContext64 {
     uint64_t LastExceptionFromRip;
 } QEMU_ALIGNED(16) WinContext64;
 
+typedef union WinContext {
+    WinContext32 x32;
+    WinContext64 x64;
+} WinContext;
+
 #endif /* QEMU_WIN_DUMP_DEFS_H */
-- 
2.35.1



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

* [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support
  2022-03-25 19:51 [PATCH v3 0/4] dump: add 32-bit guest Windows support Viktor Prutyanov
                   ` (2 preceding siblings ...)
  2022-03-25 19:51 ` [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures Viktor Prutyanov
@ 2022-03-25 19:51 ` Viktor Prutyanov
  2022-04-06  8:00   ` Marc-André Lureau
  3 siblings, 1 reply; 11+ messages in thread
From: Viktor Prutyanov @ 2022-03-25 19:51 UTC (permalink / raw)
  To: marcandre.lureau, f4bug; +Cc: yan, qemu-devel, viktor.prutyanov

Before this patch, 'dump-guest-memory -w' was accepting only 64-bit
dump header provided by guest through vmcoreinfo and thus was unable
to produce 32-bit guest Windows dump. So, add 32-bit guest Windows
dumping support.

Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 dump/win_dump.c | 245 +++++++++++++++++++++++++++++-------------------
 1 file changed, 149 insertions(+), 96 deletions(-)

diff --git a/dump/win_dump.c b/dump/win_dump.c
index df3b432ca5..fda32da036 100644
--- a/dump/win_dump.c
+++ b/dump/win_dump.c
@@ -24,18 +24,24 @@
 #include "hw/misc/vmcoreinfo.h"
 #include "win_dump.h"
 
-#define WIN_DUMP_PTR_SIZE sizeof(uint64_t)
+static size_t win_dump_ptr_size(bool x64)
+{
+    return x64 ? sizeof(uint64_t) : sizeof(uint32_t);
+}
 
-#define _WIN_DUMP_FIELD(f) (h->f)
+#define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f)
 #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
 
-#define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f)
+#define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f)
 #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
 
-#define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f)
+#define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f))
 #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
 
-#define WIN_DUMP_CTX_SIZE sizeof(WinContext64)
+static size_t win_dump_ctx_size(bool x64)
+{
+    return x64 ? sizeof(WinContext64) : sizeof(WinContext32);
+}
 
 static size_t write_run(uint64_t base_page, uint64_t page_count,
         int fd, Error **errp)
@@ -71,7 +77,7 @@ static size_t write_run(uint64_t base_page, uint64_t page_count,
     return total;
 }
 
-static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
+static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp)
 {
     uint64_t BasePage, PageCount;
     Error *local_err = NULL;
@@ -88,22 +94,24 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
     }
 }
 
-static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr)
+static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr)
 {
     int ret;
+    uint32_t ptr32;
     uint64_t ptr64;
 
-    ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0);
+    ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32,
+            win_dump_ptr_size(x64), 0);
 
-    *ptr = ptr64;
+    *ptr = x64 ? ptr64 : ptr32;
 
     return ret;
 }
 
-static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
+static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp)
 {
     if (cpu_memory_rw_debug(first_cpu,
-            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64,
+            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET,
             WIN_DUMP_FIELD_PTR(PfnDatabase),
             WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
         error_setg(errp, "win-dump: failed to read MmPfnDatabase");
@@ -111,13 +119,12 @@ static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
     }
 }
 
-static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
+static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp)
 {
     uint64_t KiBugcheckData;
 
-    if (cpu_read_ptr(first_cpu,
-            WIN_DUMP_FIELD(KdDebuggerDataBlock) +
-                KDBG_KI_BUGCHECK_DATA_OFFSET64,
+    if (cpu_read_ptr(x64, first_cpu,
+            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET,
             &KiBugcheckData)) {
         error_setg(errp, "win-dump: failed to read KiBugcheckData");
         return;
@@ -142,30 +149,34 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
 /*
  * This routine tries to correct mistakes in crashdump header.
  */
-static void patch_header(WinDumpHeader64 *h)
+static void patch_header(WinDumpHeader *h, bool x64)
 {
     Error *local_err = NULL;
 
-    h->RequiredDumpSpace = sizeof(WinDumpHeader64) +
-            (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
-    h->PhysicalMemoryBlock.unused = 0;
-    h->unused1 = 0;
+    if (x64) {
+        h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) +
+            (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
+        h->x64.PhysicalMemoryBlock.unused = 0;
+        h->x64.unused1 = 0;
+    } else {
+        h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) +
+            (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
+    }
 
-    patch_mm_pfn_database(h, &local_err);
+    patch_mm_pfn_database(h, x64, &local_err);
     if (local_err) {
         warn_report_err(local_err);
         local_err = NULL;
     }
-    patch_bugcheck_data(h, &local_err);
+    patch_bugcheck_data(h, x64, &local_err);
     if (local_err) {
         warn_report_err(local_err);
     }
 }
 
-static void check_header(WinDumpHeader64 *h, Error **errp)
+static void check_header(WinDumpHeader *h, bool *x64, Error **errp)
 {
     const char Signature[] = "PAGE";
-    const char ValidDump[] = "DU64";
 
     if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
         error_setg(errp, "win-dump: invalid header, expected '%.4s',"
@@ -173,14 +184,17 @@ static void check_header(WinDumpHeader64 *h, Error **errp)
         return;
     }
 
-    if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) {
-        error_setg(errp, "win-dump: invalid header, expected '%.4s',"
-                         " got '%.4s'", ValidDump, h->ValidDump);
-        return;
+    if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) {
+        *x64 = false;
+    } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) {
+        *x64 = true;
+    } else {
+        error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64',"
+                         " got '%.4s'", h->ValidDump);
     }
 }
 
-static void check_kdbg(WinDumpHeader64 *h, Error **errp)
+static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp)
 {
     const char OwnerTag[] = "KDBG";
     char read_OwnerTag[4];
@@ -189,7 +203,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp)
 
 try_again:
     if (cpu_memory_rw_debug(first_cpu,
-            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64,
+            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET,
             (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
         error_setg(errp, "win-dump: failed to read OwnerTag");
         return;
@@ -214,15 +228,19 @@ try_again:
         }
     }
 
-    h->KdDebuggerDataBlock = KdDebuggerDataBlock;
+    if (x64) {
+        h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock;
+    } else {
+        h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock;
+    }
 }
 
 struct saved_context {
-    WinContext64 ctx;
+    WinContext ctx;
     uint64_t addr;
 };
 
-static void patch_and_save_context(WinDumpHeader64 *h,
+static void patch_and_save_context(WinDumpHeader *h, bool x64,
                                    struct saved_context *saved_ctx,
                                    Error **errp)
 {
@@ -232,15 +250,15 @@ static void patch_and_save_context(WinDumpHeader64 *h,
     CPUState *cpu;
     int i = 0;
 
-    if (cpu_read_ptr(first_cpu,
-            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
+    if (cpu_read_ptr(x64, first_cpu,
+            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET,
             &KiProcessorBlock)) {
         error_setg(errp, "win-dump: failed to read KiProcessorBlock");
         return;
     }
 
     if (cpu_memory_rw_debug(first_cpu,
-            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
+            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET,
             (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
         error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
         return;
@@ -251,17 +269,17 @@ static void patch_and_save_context(WinDumpHeader64 *h,
         CPUX86State *env = &x86_cpu->env;
         uint64_t Prcb;
         uint64_t Context;
-        WinContext64 ctx;
+        WinContext ctx;
 
-        if (cpu_read_ptr(first_cpu,
-                KiProcessorBlock + i * WIN_DUMP_PTR_SIZE,
+        if (cpu_read_ptr(x64, first_cpu,
+                KiProcessorBlock + i * win_dump_ptr_size(x64),
                 &Prcb)) {
             error_setg(errp, "win-dump: failed to read"
                              " CPU #%d PRCB location", i);
             return;
         }
 
-        if (cpu_read_ptr(first_cpu,
+        if (cpu_read_ptr(x64, first_cpu,
                 Prcb + OffsetPrcbContext,
                 &Context)) {
             error_setg(errp, "win-dump: failed to read"
@@ -271,56 +289,88 @@ static void patch_and_save_context(WinDumpHeader64 *h,
 
         saved_ctx[i].addr = Context;
 
-        ctx = (WinContext64){
-            .ContextFlags = WIN_CTX64_ALL,
-            .MxCsr = env->mxcsr,
-
-            .SegEs = env->segs[0].selector,
-            .SegCs = env->segs[1].selector,
-            .SegSs = env->segs[2].selector,
-            .SegDs = env->segs[3].selector,
-            .SegFs = env->segs[4].selector,
-            .SegGs = env->segs[5].selector,
-            .EFlags = cpu_compute_eflags(env),
-
-            .Dr0 = env->dr[0],
-            .Dr1 = env->dr[1],
-            .Dr2 = env->dr[2],
-            .Dr3 = env->dr[3],
-            .Dr6 = env->dr[6],
-            .Dr7 = env->dr[7],
-
-            .Rax = env->regs[R_EAX],
-            .Rbx = env->regs[R_EBX],
-            .Rcx = env->regs[R_ECX],
-            .Rdx = env->regs[R_EDX],
-            .Rsp = env->regs[R_ESP],
-            .Rbp = env->regs[R_EBP],
-            .Rsi = env->regs[R_ESI],
-            .Rdi = env->regs[R_EDI],
-            .R8  = env->regs[8],
-            .R9  = env->regs[9],
-            .R10 = env->regs[10],
-            .R11 = env->regs[11],
-            .R12 = env->regs[12],
-            .R13 = env->regs[13],
-            .R14 = env->regs[14],
-            .R15 = env->regs[15],
-
-            .Rip = env->eip,
-            .FltSave = {
+        if (x64) {
+            ctx.x64 = (WinContext64){
+                .ContextFlags = WIN_CTX64_ALL,
                 .MxCsr = env->mxcsr,
-            },
-        };
+
+                .SegEs = env->segs[0].selector,
+                .SegCs = env->segs[1].selector,
+                .SegSs = env->segs[2].selector,
+                .SegDs = env->segs[3].selector,
+                .SegFs = env->segs[4].selector,
+                .SegGs = env->segs[5].selector,
+                .EFlags = cpu_compute_eflags(env),
+
+                .Dr0 = env->dr[0],
+                .Dr1 = env->dr[1],
+                .Dr2 = env->dr[2],
+                .Dr3 = env->dr[3],
+                .Dr6 = env->dr[6],
+                .Dr7 = env->dr[7],
+
+                .Rax = env->regs[R_EAX],
+                .Rbx = env->regs[R_EBX],
+                .Rcx = env->regs[R_ECX],
+                .Rdx = env->regs[R_EDX],
+                .Rsp = env->regs[R_ESP],
+                .Rbp = env->regs[R_EBP],
+                .Rsi = env->regs[R_ESI],
+                .Rdi = env->regs[R_EDI],
+                .R8  = env->regs[8],
+                .R9  = env->regs[9],
+                .R10 = env->regs[10],
+                .R11 = env->regs[11],
+                .R12 = env->regs[12],
+                .R13 = env->regs[13],
+                .R14 = env->regs[14],
+                .R15 = env->regs[15],
+
+                .Rip = env->eip,
+                .FltSave = {
+                    .MxCsr = env->mxcsr,
+                },
+            };
+        } else {
+            ctx.x32 = (WinContext32){
+                .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG,
+
+                .SegEs = env->segs[0].selector,
+                .SegCs = env->segs[1].selector,
+                .SegSs = env->segs[2].selector,
+                .SegDs = env->segs[3].selector,
+                .SegFs = env->segs[4].selector,
+                .SegGs = env->segs[5].selector,
+                .EFlags = cpu_compute_eflags(env),
+
+                .Dr0 = env->dr[0],
+                .Dr1 = env->dr[1],
+                .Dr2 = env->dr[2],
+                .Dr3 = env->dr[3],
+                .Dr6 = env->dr[6],
+                .Dr7 = env->dr[7],
+
+                .Eax = env->regs[R_EAX],
+                .Ebx = env->regs[R_EBX],
+                .Ecx = env->regs[R_ECX],
+                .Edx = env->regs[R_EDX],
+                .Esp = env->regs[R_ESP],
+                .Ebp = env->regs[R_EBP],
+                .Esi = env->regs[R_ESI],
+                .Edi = env->regs[R_EDI],
+
+                .Eip = env->eip,
+            };
+        }
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) {
+                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) {
             error_setg(errp, "win-dump: failed to save CPU #%d context", i);
             return;
         }
 
         if (cpu_memory_rw_debug(first_cpu, Context,
-                &ctx, WIN_DUMP_CTX_SIZE, 1)) {
+                &ctx, win_dump_ctx_size(x64), 1)) {
             error_setg(errp, "win-dump: failed to write CPU #%d context", i);
             return;
         }
@@ -329,14 +379,14 @@ static void patch_and_save_context(WinDumpHeader64 *h,
     }
 }
 
-static void restore_context(WinDumpHeader64 *h,
+static void restore_context(WinDumpHeader *h, bool x64,
                             struct saved_context *saved_ctx)
 {
     int i;
 
     for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
         if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
-                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) {
+                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) {
             warn_report("win-dump: failed to restore CPU #%d context", i);
         }
     }
@@ -344,25 +394,28 @@ static void restore_context(WinDumpHeader64 *h,
 
 void create_win_dump(DumpState *s, Error **errp)
 {
-    WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
-            VMCOREINFO_ELF_NOTE_HDR_SIZE);
+    WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
     X86CPU *first_x86_cpu = X86_CPU(first_cpu);
     uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
     struct saved_context *saved_ctx = NULL;
     Error *local_err = NULL;
+    bool x64;
+    size_t hdr_size;
 
-    if (s->guest_note_size != sizeof(WinDumpHeader64) +
-            VMCOREINFO_ELF_NOTE_HDR_SIZE) {
+    if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 &&
+            s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) {
         error_setg(errp, "win-dump: invalid vmcoreinfo note size");
         return;
     }
 
-    check_header(h, &local_err);
+    check_header(h, &x64, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
     }
 
+    hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32);
+
     /*
      * Further access to kernel structures by virtual addresses
      * should be made from system context.
@@ -370,13 +423,13 @@ void create_win_dump(DumpState *s, Error **errp)
 
     first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
 
-    check_kdbg(h, &local_err);
+    check_kdbg(h, x64, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out_cr3;
     }
 
-    patch_header(h);
+    patch_header(h, x64);
 
     saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
 
@@ -385,7 +438,7 @@ void create_win_dump(DumpState *s, Error **errp)
      * to determine if the system-saved context is valid
      */
 
-    patch_and_save_context(h, saved_ctx, &local_err);
+    patch_and_save_context(h, x64, saved_ctx, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out_free;
@@ -393,20 +446,20 @@ void create_win_dump(DumpState *s, Error **errp)
 
     s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
 
-    s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
-    if (s->written_size != sizeof(*h)) {
+    s->written_size = qemu_write_full(s->fd, h, hdr_size);
+    if (s->written_size != hdr_size) {
         error_setg(errp, QERR_IO_ERROR);
         goto out_restore;
     }
 
-    write_runs(s, h, &local_err);
+    write_runs(s, h, x64, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out_restore;
     }
 
 out_restore:
-    restore_context(h, saved_ctx);
+    restore_context(h, x64, saved_ctx);
 out_free:
     g_free(saved_ctx);
 out_cr3:
-- 
2.35.1



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

* Re: [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness
  2022-03-25 19:51 ` [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness Viktor Prutyanov
@ 2022-04-06  7:24   ` Marc-André Lureau
  0 siblings, 0 replies; 11+ messages in thread
From: Marc-André Lureau @ 2022-04-06  7:24 UTC (permalink / raw)
  To: Viktor Prutyanov
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
<viktor.prutyanov@redhat.com> wrote:
>
> Context structure in 64-bit Windows differs from 32-bit one and it
> should be reflected in its name.
>
> Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> ---
>  contrib/elf2dmp/main.c       |  6 +++---
>  dump/win_dump.c              | 14 +++++++-------
>  include/qemu/win_dump_defs.h |  8 ++++----
>  3 files changed, 14 insertions(+), 14 deletions(-)
>
> diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c
> index 20b477d582..b9fc6d230c 100644
> --- a/contrib/elf2dmp/main.c
> +++ b/contrib/elf2dmp/main.c
> @@ -141,10 +141,10 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
>      return kdbg;
>  }
>
> -static void win_context_init_from_qemu_cpu_state(WinContext *ctx,
> +static void win_context_init_from_qemu_cpu_state(WinContext64 *ctx,
>          QEMUCPUState *s)
>  {
> -    WinContext win_ctx = (WinContext){
> +    WinContext64 win_ctx = (WinContext64){
>          .ContextFlags = WIN_CTX_X64 | WIN_CTX_INT | WIN_CTX_SEG | WIN_CTX_CTL,
>          .MxCsr = INITIAL_MXCSR,
>
> @@ -302,7 +302,7 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
>      for (i = 0; i < qe->state_nr; i++) {
>          uint64_t Prcb;
>          uint64_t Context;
> -        WinContext ctx;
> +        WinContext64 ctx;
>          QEMUCPUState *s = qe->state[i];
>
>          if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
> diff --git a/dump/win_dump.c b/dump/win_dump.c
> index c5eb5a9aac..29b6e4f670 100644
> --- a/dump/win_dump.c
> +++ b/dump/win_dump.c
> @@ -189,7 +189,7 @@ try_again:
>  }
>
>  struct saved_context {
> -    WinContext ctx;
> +    WinContext64 ctx;
>      uint64_t addr;
>  };
>
> @@ -221,7 +221,7 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>          CPUX86State *env = &x86_cpu->env;
>          uint64_t Prcb;
>          uint64_t Context;
> -        WinContext ctx;
> +        WinContext64 ctx;
>
>          if (cpu_memory_rw_debug(first_cpu,
>                  KiProcessorBlock + i * sizeof(uint64_t),
> @@ -241,8 +241,8 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>
>          saved_ctx[i].addr = Context;
>
> -        ctx = (WinContext){
> -            .ContextFlags = WIN_CTX_ALL,
> +        ctx = (WinContext64){
> +            .ContextFlags = WIN_CTX64_ALL,
>              .MxCsr = env->mxcsr,
>
>              .SegEs = env->segs[0].selector,
> @@ -284,13 +284,13 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>          };
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
> +                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 0)) {
>              error_setg(errp, "win-dump: failed to save CPU #%d context", i);
>              return;
>          }
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                (uint8_t *)&ctx, sizeof(WinContext), 1)) {
> +                (uint8_t *)&ctx, sizeof(WinContext64), 1)) {
>              error_setg(errp, "win-dump: failed to write CPU #%d context", i);
>              return;
>          }
> @@ -306,7 +306,7 @@ static void restore_context(WinDumpHeader64 *h,
>
>      for (i = 0; i < h->NumberProcessors; i++) {
>          if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
> -                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
> +                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 1)) {
>              warn_report("win-dump: failed to restore CPU #%d context", i);
>          }
>      }
> diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h
> index 145096e8ee..5a5e5a5e09 100644
> --- a/include/qemu/win_dump_defs.h
> +++ b/include/qemu/win_dump_defs.h
> @@ -97,8 +97,8 @@ typedef struct WinDumpHeader64 {
>  #define WIN_CTX_FP  0x00000008L
>  #define WIN_CTX_DBG 0x00000010L
>
> -#define WIN_CTX_FULL    (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
> -#define WIN_CTX_ALL     (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
> +#define WIN_CTX64_FULL  (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
> +#define WIN_CTX64_ALL   (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
>
>  #define LIVE_SYSTEM_DUMP    0x00000161
>
> @@ -107,7 +107,7 @@ typedef struct WinM128A {
>      int64_t high;
>  } QEMU_ALIGNED(16) WinM128A;
>
> -typedef struct WinContext {
> +typedef struct WinContext64 {
>      uint64_t PHome[6];
>
>      uint32_t ContextFlags;
> @@ -174,6 +174,6 @@ typedef struct WinContext {
>      uint64_t LastBranchFromRip;
>      uint64_t LastExceptionToRip;
>      uint64_t LastExceptionFromRip;
> -} QEMU_ALIGNED(16) WinContext;
> +} QEMU_ALIGNED(16) WinContext64;
>
>  #endif /* QEMU_WIN_DUMP_DEFS_H */
> --
> 2.35.1
>



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

* Re: [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access
  2022-03-25 19:51 ` [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access Viktor Prutyanov
@ 2022-04-06  7:24   ` Marc-André Lureau
  0 siblings, 0 replies; 11+ messages in thread
From: Marc-André Lureau @ 2022-04-06  7:24 UTC (permalink / raw)
  To: Viktor Prutyanov
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
<viktor.prutyanov@redhat.com> wrote:
>
> Perform read access to Windows dump header fields via helper macros.
> This is preparation for the next 32-bit guest Windows dump support.
>
> Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  dump/win_dump.c | 100 +++++++++++++++++++++++++++++++-----------------
>  1 file changed, 65 insertions(+), 35 deletions(-)
>
> diff --git a/dump/win_dump.c b/dump/win_dump.c
> index 29b6e4f670..df3b432ca5 100644
> --- a/dump/win_dump.c
> +++ b/dump/win_dump.c
> @@ -24,11 +24,25 @@
>  #include "hw/misc/vmcoreinfo.h"
>  #include "win_dump.h"
>
> -static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
> +#define WIN_DUMP_PTR_SIZE sizeof(uint64_t)
> +
> +#define _WIN_DUMP_FIELD(f) (h->f)
> +#define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
> +
> +#define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f)
> +#define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
> +
> +#define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f)
> +#define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
> +
> +#define WIN_DUMP_CTX_SIZE sizeof(WinContext64)
> +
> +static size_t write_run(uint64_t base_page, uint64_t page_count,
> +        int fd, Error **errp)
>  {
>      void *buf;
> -    uint64_t addr = run->BasePage << TARGET_PAGE_BITS;
> -    uint64_t size = run->PageCount << TARGET_PAGE_BITS;
> +    uint64_t addr = base_page << TARGET_PAGE_BITS;
> +    uint64_t size = page_count << TARGET_PAGE_BITS;
>      uint64_t len, l;
>      size_t total = 0;
>
> @@ -59,13 +73,14 @@ static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
>
>  static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
>  {
> -    WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock;
> -    WinDumpPhyMemRun64 *run = desc->Run;
> +    uint64_t BasePage, PageCount;
>      Error *local_err = NULL;
>      int i;
>
> -    for (i = 0; i < desc->NumberOfRuns; i++) {
> -        s->written_size += write_run(run + i, s->fd, &local_err);
> +    for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) {
> +        BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage);
> +        PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount);
> +        s->written_size += write_run(BasePage, PageCount, s->fd, &local_err);
>          if (local_err) {
>              error_propagate(errp, local_err);
>              return;
> @@ -73,11 +88,24 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
>      }
>  }
>
> +static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr)
> +{
> +    int ret;
> +    uint64_t ptr64;
> +
> +    ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0);
> +
> +    *ptr = ptr64;
> +
> +    return ret;
> +}
> +
>  static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
>  {
>      if (cpu_memory_rw_debug(first_cpu,
> -            h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64,
> -            (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) {
> +            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64,
> +            WIN_DUMP_FIELD_PTR(PfnDatabase),
> +            WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
>          error_setg(errp, "win-dump: failed to read MmPfnDatabase");
>          return;
>      }
> @@ -87,16 +115,17 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
>  {
>      uint64_t KiBugcheckData;
>
> -    if (cpu_memory_rw_debug(first_cpu,
> -            h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64,
> -            (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) {
> +    if (cpu_read_ptr(first_cpu,
> +            WIN_DUMP_FIELD(KdDebuggerDataBlock) +
> +                KDBG_KI_BUGCHECK_DATA_OFFSET64,
> +            &KiBugcheckData)) {
>          error_setg(errp, "win-dump: failed to read KiBugcheckData");
>          return;
>      }
>
> -    if (cpu_memory_rw_debug(first_cpu,
> -            KiBugcheckData,
> -            h->BugcheckData, sizeof(h->BugcheckData), 0)) {
> +    if (cpu_memory_rw_debug(first_cpu, KiBugcheckData,
> +            WIN_DUMP_FIELD(BugcheckData),
> +            WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) {
>          error_setg(errp, "win-dump: failed to read bugcheck data");
>          return;
>      }
> @@ -105,8 +134,8 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
>       * If BugcheckCode wasn't saved, we consider guest OS as alive.
>       */
>
> -    if (!h->BugcheckCode) {
> -        h->BugcheckCode = LIVE_SYSTEM_DUMP;
> +    if (!WIN_DUMP_FIELD(BugcheckCode)) {
> +        *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP;
>      }
>  }
>
> @@ -155,7 +184,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp)
>  {
>      const char OwnerTag[] = "KDBG";
>      char read_OwnerTag[4];
> -    uint64_t KdDebuggerDataBlock = h->KdDebuggerDataBlock;
> +    uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
>      bool try_fallback = true;
>
>  try_again:
> @@ -174,7 +203,7 @@ try_again:
>               * we try to use KDBG obtained by guest driver.
>               */
>
> -            KdDebuggerDataBlock = h->BugcheckParameter1;
> +            KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1);
>              try_fallback = false;
>              goto try_again;
>          } else {
> @@ -197,20 +226,21 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>                                     struct saved_context *saved_ctx,
>                                     Error **errp)
>  {
> +    uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
>      uint64_t KiProcessorBlock;
>      uint16_t OffsetPrcbContext;
>      CPUState *cpu;
>      int i = 0;
>
> -    if (cpu_memory_rw_debug(first_cpu,
> -            h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
> -            (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
> +    if (cpu_read_ptr(first_cpu,
> +            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
> +            &KiProcessorBlock)) {
>          error_setg(errp, "win-dump: failed to read KiProcessorBlock");
>          return;
>      }
>
>      if (cpu_memory_rw_debug(first_cpu,
> -            h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
> +            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
>              (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
>          error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
>          return;
> @@ -223,17 +253,17 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>          uint64_t Context;
>          WinContext64 ctx;
>
> -        if (cpu_memory_rw_debug(first_cpu,
> -                KiProcessorBlock + i * sizeof(uint64_t),
> -                (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
> +        if (cpu_read_ptr(first_cpu,
> +                KiProcessorBlock + i * WIN_DUMP_PTR_SIZE,
> +                &Prcb)) {
>              error_setg(errp, "win-dump: failed to read"
>                               " CPU #%d PRCB location", i);
>              return;
>          }
>
> -        if (cpu_memory_rw_debug(first_cpu,
> +        if (cpu_read_ptr(first_cpu,
>                  Prcb + OffsetPrcbContext,
> -                (uint8_t *)&Context, sizeof(Context), 0)) {
> +                &Context)) {
>              error_setg(errp, "win-dump: failed to read"
>                               " CPU #%d ContextFrame location", i);
>              return;
> @@ -284,13 +314,13 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>          };
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 0)) {
> +                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) {
>              error_setg(errp, "win-dump: failed to save CPU #%d context", i);
>              return;
>          }
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                (uint8_t *)&ctx, sizeof(WinContext64), 1)) {
> +                &ctx, WIN_DUMP_CTX_SIZE, 1)) {
>              error_setg(errp, "win-dump: failed to write CPU #%d context", i);
>              return;
>          }
> @@ -304,9 +334,9 @@ static void restore_context(WinDumpHeader64 *h,
>  {
>      int i;
>
> -    for (i = 0; i < h->NumberProcessors; i++) {
> +    for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
>          if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
> -                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext64), 1)) {
> +                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) {
>              warn_report("win-dump: failed to restore CPU #%d context", i);
>          }
>      }
> @@ -338,7 +368,7 @@ void create_win_dump(DumpState *s, Error **errp)
>       * should be made from system context.
>       */
>
> -    first_x86_cpu->env.cr[3] = h->DirectoryTableBase;
> +    first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
>
>      check_kdbg(h, &local_err);
>      if (local_err) {
> @@ -348,7 +378,7 @@ void create_win_dump(DumpState *s, Error **errp)
>
>      patch_header(h);
>
> -    saved_ctx = g_new(struct saved_context, h->NumberProcessors);
> +    saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
>
>      /*
>       * Always patch context because there is no way
> @@ -361,7 +391,7 @@ void create_win_dump(DumpState *s, Error **errp)
>          goto out_free;
>      }
>
> -    s->total_size = h->RequiredDumpSpace;
> +    s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
>
>      s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
>      if (s->written_size != sizeof(*h)) {
> --
> 2.35.1
>



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

* Re: [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures
  2022-03-25 19:51 ` [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures Viktor Prutyanov
@ 2022-04-06  7:51   ` Marc-André Lureau
  2022-04-06 15:15     ` Viktor Prutyanov
  0 siblings, 1 reply; 11+ messages in thread
From: Marc-André Lureau @ 2022-04-06  7:51 UTC (permalink / raw)
  To: Viktor Prutyanov
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

Hi

On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
<viktor.prutyanov@redhat.com> wrote:
>
> These structures are required to produce 32-bit guest Windows Complete
> Memory Dump. Add 32-bit Windows dump header, CPU context and physical
> memory descriptor structures along with corresponding definitions.
>
> Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Back when the initial support was introduced, I guess I thought those
structures were defined by the fwcfg driver. I realize they are
actually Windows structures. What's your reference for them? It's hard
to find a good source, it seemed it was reverse-engineered by various
projects.

Otherwise lgtm,
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> ---
>  include/qemu/win_dump_defs.h | 107 +++++++++++++++++++++++++++++++++++
>  1 file changed, 107 insertions(+)
>
> diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h
> index 5a5e5a5e09..73a44e2408 100644
> --- a/include/qemu/win_dump_defs.h
> +++ b/include/qemu/win_dump_defs.h
> @@ -11,11 +11,22 @@
>  #ifndef QEMU_WIN_DUMP_DEFS_H
>  #define QEMU_WIN_DUMP_DEFS_H
>
> +typedef struct WinDumpPhyMemRun32 {
> +    uint32_t BasePage;
> +    uint32_t PageCount;
> +} QEMU_PACKED WinDumpPhyMemRun32;
> +
>  typedef struct WinDumpPhyMemRun64 {
>      uint64_t BasePage;
>      uint64_t PageCount;
>  } QEMU_PACKED WinDumpPhyMemRun64;
>
> +typedef struct WinDumpPhyMemDesc32 {
> +    uint32_t NumberOfRuns;
> +    uint32_t NumberOfPages;
> +    WinDumpPhyMemRun32 Run[86];
> +} QEMU_PACKED WinDumpPhyMemDesc32;
> +
>  typedef struct WinDumpPhyMemDesc64 {
>      uint32_t NumberOfRuns;
>      uint32_t unused;
> @@ -33,6 +44,39 @@ typedef struct WinDumpExceptionRecord {
>      uint64_t ExceptionInformation[15];
>  } QEMU_PACKED WinDumpExceptionRecord;
>
> +typedef struct WinDumpHeader32 {
> +    char Signature[4];
> +    char ValidDump[4];
> +    uint32_t MajorVersion;
> +    uint32_t MinorVersion;
> +    uint32_t DirectoryTableBase;
> +    uint32_t PfnDatabase;
> +    uint32_t PsLoadedModuleList;
> +    uint32_t PsActiveProcessHead;
> +    uint32_t MachineImageType;
> +    uint32_t NumberProcessors;
> +    union {
> +        struct {
> +            uint32_t BugcheckCode;
> +            uint32_t BugcheckParameter1;
> +            uint32_t BugcheckParameter2;
> +            uint32_t BugcheckParameter3;
> +            uint32_t BugcheckParameter4;
> +        };
> +        uint8_t BugcheckData[20];
> +    };
> +    uint8_t VersionUser[32];
> +    uint32_t reserved0;
> +    uint32_t KdDebuggerDataBlock;
> +    union {
> +        WinDumpPhyMemDesc32 PhysicalMemoryBlock;
> +        uint8_t PhysicalMemoryBlockBuffer[700];
> +    };
> +    uint8_t reserved1[3200];
> +    uint32_t RequiredDumpSpace;
> +    uint8_t reserved2[92];
> +} QEMU_PACKED WinDumpHeader32;
> +
>  typedef struct WinDumpHeader64 {
>      char Signature[4];
>      char ValidDump[4];
> @@ -81,25 +125,49 @@ typedef struct WinDumpHeader64 {
>      uint8_t reserved[4018];
>  } QEMU_PACKED WinDumpHeader64;
>
> +typedef union WinDumpHeader {
> +    struct {
> +        char Signature[4];
> +        char ValidDump[4];
> +    };
> +    WinDumpHeader32 x32;
> +    WinDumpHeader64 x64;
> +} WinDumpHeader;
> +
>  #define KDBG_OWNER_TAG_OFFSET64             0x10
>  #define KDBG_MM_PFN_DATABASE_OFFSET64       0xC0
>  #define KDBG_KI_BUGCHECK_DATA_OFFSET64      0x88
>  #define KDBG_KI_PROCESSOR_BLOCK_OFFSET64    0x218
>  #define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64   0x338
>
> +#define KDBG_OWNER_TAG_OFFSET           KDBG_OWNER_TAG_OFFSET64
> +#define KDBG_MM_PFN_DATABASE_OFFSET     KDBG_MM_PFN_DATABASE_OFFSET64
> +#define KDBG_KI_BUGCHECK_DATA_OFFSET    KDBG_KI_BUGCHECK_DATA_OFFSET64
> +#define KDBG_KI_PROCESSOR_BLOCK_OFFSET  KDBG_KI_PROCESSOR_BLOCK_OFFSET64
> +#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET KDBG_OFFSET_PRCB_CONTEXT_OFFSET64
> +
>  #define VMCOREINFO_ELF_NOTE_HDR_SIZE    24
> +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE64 (sizeof(WinDumpHeader64) + \
> +                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
> +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE32 (sizeof(WinDumpHeader32) + \
> +                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
>
>  #define WIN_CTX_X64 0x00100000L
> +#define WIN_CTX_X86 0x00010000L
>
>  #define WIN_CTX_CTL 0x00000001L
>  #define WIN_CTX_INT 0x00000002L
>  #define WIN_CTX_SEG 0x00000004L
>  #define WIN_CTX_FP  0x00000008L
>  #define WIN_CTX_DBG 0x00000010L
> +#define WIN_CTX_EXT 0x00000020L
>
>  #define WIN_CTX64_FULL  (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
>  #define WIN_CTX64_ALL   (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
>
> +#define WIN_CTX32_FULL (WIN_CTX_X86 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_SEG)
> +#define WIN_CTX32_ALL (WIN_CTX32_FULL | WIN_CTX_FP | WIN_CTX_DBG | WIN_CTX_EXT)
> +
>  #define LIVE_SYSTEM_DUMP    0x00000161
>
>  typedef struct WinM128A {
> @@ -107,6 +175,40 @@ typedef struct WinM128A {
>      int64_t high;
>  } QEMU_ALIGNED(16) WinM128A;
>
> +typedef struct WinContext32 {
> +    uint32_t ContextFlags;
> +
> +    uint32_t Dr0;
> +    uint32_t Dr1;
> +    uint32_t Dr2;
> +    uint32_t Dr3;
> +    uint32_t Dr6;
> +    uint32_t Dr7;
> +
> +    uint8_t  FloatSave[112];
> +
> +    uint32_t SegGs;
> +    uint32_t SegFs;
> +    uint32_t SegEs;
> +    uint32_t SegDs;
> +
> +    uint32_t Edi;
> +    uint32_t Esi;
> +    uint32_t Ebx;
> +    uint32_t Edx;
> +    uint32_t Ecx;
> +    uint32_t Eax;
> +
> +    uint32_t Ebp;
> +    uint32_t Eip;
> +    uint32_t SegCs;
> +    uint32_t EFlags;
> +    uint32_t Esp;
> +    uint32_t SegSs;
> +
> +    uint8_t ExtendedRegisters[512];
> +} QEMU_ALIGNED(16) WinContext32;
> +
>  typedef struct WinContext64 {
>      uint64_t PHome[6];
>
> @@ -176,4 +278,9 @@ typedef struct WinContext64 {
>      uint64_t LastExceptionFromRip;
>  } QEMU_ALIGNED(16) WinContext64;
>
> +typedef union WinContext {
> +    WinContext32 x32;
> +    WinContext64 x64;
> +} WinContext;
> +
>  #endif /* QEMU_WIN_DUMP_DEFS_H */
> --
> 2.35.1
>



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

* Re: [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support
  2022-03-25 19:51 ` [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support Viktor Prutyanov
@ 2022-04-06  8:00   ` Marc-André Lureau
  2022-04-06 15:20     ` Viktor Prutyanov
  0 siblings, 1 reply; 11+ messages in thread
From: Marc-André Lureau @ 2022-04-06  8:00 UTC (permalink / raw)
  To: Viktor Prutyanov
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

Hi

On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
<viktor.prutyanov@redhat.com> wrote:
>
> Before this patch, 'dump-guest-memory -w' was accepting only 64-bit
> dump header provided by guest through vmcoreinfo and thus was unable
> to produce 32-bit guest Windows dump. So, add 32-bit guest Windows
> dumping support.
>
> Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

lgtm,
you should update dump-guest-memory doc in hmp-commands.hx

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> ---
>  dump/win_dump.c | 245 +++++++++++++++++++++++++++++-------------------
>  1 file changed, 149 insertions(+), 96 deletions(-)
>
> diff --git a/dump/win_dump.c b/dump/win_dump.c
> index df3b432ca5..fda32da036 100644
> --- a/dump/win_dump.c
> +++ b/dump/win_dump.c
> @@ -24,18 +24,24 @@
>  #include "hw/misc/vmcoreinfo.h"
>  #include "win_dump.h"
>
> -#define WIN_DUMP_PTR_SIZE sizeof(uint64_t)
> +static size_t win_dump_ptr_size(bool x64)
> +{
> +    return x64 ? sizeof(uint64_t) : sizeof(uint32_t);
> +}
>
> -#define _WIN_DUMP_FIELD(f) (h->f)
> +#define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f)
>  #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
>
> -#define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f)
> +#define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f)
>  #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
>
> -#define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f)
> +#define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f))
>  #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
>
> -#define WIN_DUMP_CTX_SIZE sizeof(WinContext64)
> +static size_t win_dump_ctx_size(bool x64)
> +{
> +    return x64 ? sizeof(WinContext64) : sizeof(WinContext32);
> +}
>
>  static size_t write_run(uint64_t base_page, uint64_t page_count,
>          int fd, Error **errp)
> @@ -71,7 +77,7 @@ static size_t write_run(uint64_t base_page, uint64_t page_count,
>      return total;
>  }
>
> -static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
> +static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp)
>  {
>      uint64_t BasePage, PageCount;
>      Error *local_err = NULL;
> @@ -88,22 +94,24 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
>      }
>  }
>
> -static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr)
> +static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr)
>  {
>      int ret;
> +    uint32_t ptr32;
>      uint64_t ptr64;
>
> -    ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0);
> +    ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32,
> +            win_dump_ptr_size(x64), 0);
>
> -    *ptr = ptr64;
> +    *ptr = x64 ? ptr64 : ptr32;
>
>      return ret;
>  }
>
> -static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
> +static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp)
>  {
>      if (cpu_memory_rw_debug(first_cpu,
> -            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64,
> +            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET,
>              WIN_DUMP_FIELD_PTR(PfnDatabase),
>              WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
>          error_setg(errp, "win-dump: failed to read MmPfnDatabase");
> @@ -111,13 +119,12 @@ static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
>      }
>  }
>
> -static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
> +static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp)
>  {
>      uint64_t KiBugcheckData;
>
> -    if (cpu_read_ptr(first_cpu,
> -            WIN_DUMP_FIELD(KdDebuggerDataBlock) +
> -                KDBG_KI_BUGCHECK_DATA_OFFSET64,
> +    if (cpu_read_ptr(x64, first_cpu,
> +            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET,
>              &KiBugcheckData)) {
>          error_setg(errp, "win-dump: failed to read KiBugcheckData");
>          return;
> @@ -142,30 +149,34 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
>  /*
>   * This routine tries to correct mistakes in crashdump header.
>   */
> -static void patch_header(WinDumpHeader64 *h)
> +static void patch_header(WinDumpHeader *h, bool x64)
>  {
>      Error *local_err = NULL;
>
> -    h->RequiredDumpSpace = sizeof(WinDumpHeader64) +
> -            (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> -    h->PhysicalMemoryBlock.unused = 0;
> -    h->unused1 = 0;
> +    if (x64) {
> +        h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) +
> +            (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> +        h->x64.PhysicalMemoryBlock.unused = 0;
> +        h->x64.unused1 = 0;
> +    } else {
> +        h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) +
> +            (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> +    }
>
> -    patch_mm_pfn_database(h, &local_err);
> +    patch_mm_pfn_database(h, x64, &local_err);
>      if (local_err) {
>          warn_report_err(local_err);
>          local_err = NULL;
>      }
> -    patch_bugcheck_data(h, &local_err);
> +    patch_bugcheck_data(h, x64, &local_err);
>      if (local_err) {
>          warn_report_err(local_err);
>      }
>  }
>
> -static void check_header(WinDumpHeader64 *h, Error **errp)
> +static void check_header(WinDumpHeader *h, bool *x64, Error **errp)
>  {
>      const char Signature[] = "PAGE";
> -    const char ValidDump[] = "DU64";
>
>      if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
>          error_setg(errp, "win-dump: invalid header, expected '%.4s',"
> @@ -173,14 +184,17 @@ static void check_header(WinDumpHeader64 *h, Error **errp)
>          return;
>      }
>
> -    if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) {
> -        error_setg(errp, "win-dump: invalid header, expected '%.4s',"
> -                         " got '%.4s'", ValidDump, h->ValidDump);
> -        return;
> +    if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) {
> +        *x64 = false;
> +    } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) {
> +        *x64 = true;
> +    } else {
> +        error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64',"
> +                         " got '%.4s'", h->ValidDump);
>      }
>  }
>
> -static void check_kdbg(WinDumpHeader64 *h, Error **errp)
> +static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp)
>  {
>      const char OwnerTag[] = "KDBG";
>      char read_OwnerTag[4];
> @@ -189,7 +203,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp)
>
>  try_again:
>      if (cpu_memory_rw_debug(first_cpu,
> -            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64,
> +            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET,
>              (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
>          error_setg(errp, "win-dump: failed to read OwnerTag");
>          return;
> @@ -214,15 +228,19 @@ try_again:
>          }
>      }
>
> -    h->KdDebuggerDataBlock = KdDebuggerDataBlock;
> +    if (x64) {
> +        h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock;
> +    } else {
> +        h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock;
> +    }
>  }
>
>  struct saved_context {
> -    WinContext64 ctx;
> +    WinContext ctx;
>      uint64_t addr;
>  };
>
> -static void patch_and_save_context(WinDumpHeader64 *h,
> +static void patch_and_save_context(WinDumpHeader *h, bool x64,
>                                     struct saved_context *saved_ctx,
>                                     Error **errp)
>  {
> @@ -232,15 +250,15 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>      CPUState *cpu;
>      int i = 0;
>
> -    if (cpu_read_ptr(first_cpu,
> -            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
> +    if (cpu_read_ptr(x64, first_cpu,
> +            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET,
>              &KiProcessorBlock)) {
>          error_setg(errp, "win-dump: failed to read KiProcessorBlock");
>          return;
>      }
>
>      if (cpu_memory_rw_debug(first_cpu,
> -            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
> +            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET,
>              (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
>          error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
>          return;
> @@ -251,17 +269,17 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>          CPUX86State *env = &x86_cpu->env;
>          uint64_t Prcb;
>          uint64_t Context;
> -        WinContext64 ctx;
> +        WinContext ctx;
>
> -        if (cpu_read_ptr(first_cpu,
> -                KiProcessorBlock + i * WIN_DUMP_PTR_SIZE,
> +        if (cpu_read_ptr(x64, first_cpu,
> +                KiProcessorBlock + i * win_dump_ptr_size(x64),
>                  &Prcb)) {
>              error_setg(errp, "win-dump: failed to read"
>                               " CPU #%d PRCB location", i);
>              return;
>          }
>
> -        if (cpu_read_ptr(first_cpu,
> +        if (cpu_read_ptr(x64, first_cpu,
>                  Prcb + OffsetPrcbContext,
>                  &Context)) {
>              error_setg(errp, "win-dump: failed to read"
> @@ -271,56 +289,88 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>
>          saved_ctx[i].addr = Context;
>
> -        ctx = (WinContext64){
> -            .ContextFlags = WIN_CTX64_ALL,
> -            .MxCsr = env->mxcsr,
> -
> -            .SegEs = env->segs[0].selector,
> -            .SegCs = env->segs[1].selector,
> -            .SegSs = env->segs[2].selector,
> -            .SegDs = env->segs[3].selector,
> -            .SegFs = env->segs[4].selector,
> -            .SegGs = env->segs[5].selector,
> -            .EFlags = cpu_compute_eflags(env),
> -
> -            .Dr0 = env->dr[0],
> -            .Dr1 = env->dr[1],
> -            .Dr2 = env->dr[2],
> -            .Dr3 = env->dr[3],
> -            .Dr6 = env->dr[6],
> -            .Dr7 = env->dr[7],
> -
> -            .Rax = env->regs[R_EAX],
> -            .Rbx = env->regs[R_EBX],
> -            .Rcx = env->regs[R_ECX],
> -            .Rdx = env->regs[R_EDX],
> -            .Rsp = env->regs[R_ESP],
> -            .Rbp = env->regs[R_EBP],
> -            .Rsi = env->regs[R_ESI],
> -            .Rdi = env->regs[R_EDI],
> -            .R8  = env->regs[8],
> -            .R9  = env->regs[9],
> -            .R10 = env->regs[10],
> -            .R11 = env->regs[11],
> -            .R12 = env->regs[12],
> -            .R13 = env->regs[13],
> -            .R14 = env->regs[14],
> -            .R15 = env->regs[15],
> -
> -            .Rip = env->eip,
> -            .FltSave = {
> +        if (x64) {
> +            ctx.x64 = (WinContext64){
> +                .ContextFlags = WIN_CTX64_ALL,
>                  .MxCsr = env->mxcsr,
> -            },
> -        };
> +
> +                .SegEs = env->segs[0].selector,
> +                .SegCs = env->segs[1].selector,
> +                .SegSs = env->segs[2].selector,
> +                .SegDs = env->segs[3].selector,
> +                .SegFs = env->segs[4].selector,
> +                .SegGs = env->segs[5].selector,
> +                .EFlags = cpu_compute_eflags(env),
> +
> +                .Dr0 = env->dr[0],
> +                .Dr1 = env->dr[1],
> +                .Dr2 = env->dr[2],
> +                .Dr3 = env->dr[3],
> +                .Dr6 = env->dr[6],
> +                .Dr7 = env->dr[7],
> +
> +                .Rax = env->regs[R_EAX],
> +                .Rbx = env->regs[R_EBX],
> +                .Rcx = env->regs[R_ECX],
> +                .Rdx = env->regs[R_EDX],
> +                .Rsp = env->regs[R_ESP],
> +                .Rbp = env->regs[R_EBP],
> +                .Rsi = env->regs[R_ESI],
> +                .Rdi = env->regs[R_EDI],
> +                .R8  = env->regs[8],
> +                .R9  = env->regs[9],
> +                .R10 = env->regs[10],
> +                .R11 = env->regs[11],
> +                .R12 = env->regs[12],
> +                .R13 = env->regs[13],
> +                .R14 = env->regs[14],
> +                .R15 = env->regs[15],
> +
> +                .Rip = env->eip,
> +                .FltSave = {
> +                    .MxCsr = env->mxcsr,
> +                },
> +            };
> +        } else {
> +            ctx.x32 = (WinContext32){
> +                .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG,
> +
> +                .SegEs = env->segs[0].selector,
> +                .SegCs = env->segs[1].selector,
> +                .SegSs = env->segs[2].selector,
> +                .SegDs = env->segs[3].selector,
> +                .SegFs = env->segs[4].selector,
> +                .SegGs = env->segs[5].selector,
> +                .EFlags = cpu_compute_eflags(env),
> +
> +                .Dr0 = env->dr[0],
> +                .Dr1 = env->dr[1],
> +                .Dr2 = env->dr[2],
> +                .Dr3 = env->dr[3],
> +                .Dr6 = env->dr[6],
> +                .Dr7 = env->dr[7],
> +
> +                .Eax = env->regs[R_EAX],
> +                .Ebx = env->regs[R_EBX],
> +                .Ecx = env->regs[R_ECX],
> +                .Edx = env->regs[R_EDX],
> +                .Esp = env->regs[R_ESP],
> +                .Ebp = env->regs[R_EBP],
> +                .Esi = env->regs[R_ESI],
> +                .Edi = env->regs[R_EDI],
> +
> +                .Eip = env->eip,
> +            };
> +        }
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) {
> +                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) {
>              error_setg(errp, "win-dump: failed to save CPU #%d context", i);
>              return;
>          }
>
>          if (cpu_memory_rw_debug(first_cpu, Context,
> -                &ctx, WIN_DUMP_CTX_SIZE, 1)) {
> +                &ctx, win_dump_ctx_size(x64), 1)) {
>              error_setg(errp, "win-dump: failed to write CPU #%d context", i);
>              return;
>          }
> @@ -329,14 +379,14 @@ static void patch_and_save_context(WinDumpHeader64 *h,
>      }
>  }
>
> -static void restore_context(WinDumpHeader64 *h,
> +static void restore_context(WinDumpHeader *h, bool x64,
>                              struct saved_context *saved_ctx)
>  {
>      int i;
>
>      for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
>          if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
> -                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) {
> +                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) {
>              warn_report("win-dump: failed to restore CPU #%d context", i);
>          }
>      }
> @@ -344,25 +394,28 @@ static void restore_context(WinDumpHeader64 *h,
>
>  void create_win_dump(DumpState *s, Error **errp)
>  {
> -    WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
> -            VMCOREINFO_ELF_NOTE_HDR_SIZE);
> +    WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
>      X86CPU *first_x86_cpu = X86_CPU(first_cpu);
>      uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
>      struct saved_context *saved_ctx = NULL;
>      Error *local_err = NULL;
> +    bool x64;
> +    size_t hdr_size;
>
> -    if (s->guest_note_size != sizeof(WinDumpHeader64) +
> -            VMCOREINFO_ELF_NOTE_HDR_SIZE) {
> +    if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 &&
> +            s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) {
>          error_setg(errp, "win-dump: invalid vmcoreinfo note size");
>          return;
>      }
>
> -    check_header(h, &local_err);
> +    check_header(h, &x64, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          return;
>      }
>
> +    hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32);
> +
>      /*
>       * Further access to kernel structures by virtual addresses
>       * should be made from system context.
> @@ -370,13 +423,13 @@ void create_win_dump(DumpState *s, Error **errp)
>
>      first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
>
> -    check_kdbg(h, &local_err);
> +    check_kdbg(h, x64, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          goto out_cr3;
>      }
>
> -    patch_header(h);
> +    patch_header(h, x64);
>
>      saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
>
> @@ -385,7 +438,7 @@ void create_win_dump(DumpState *s, Error **errp)
>       * to determine if the system-saved context is valid
>       */
>
> -    patch_and_save_context(h, saved_ctx, &local_err);
> +    patch_and_save_context(h, x64, saved_ctx, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          goto out_free;
> @@ -393,20 +446,20 @@ void create_win_dump(DumpState *s, Error **errp)
>
>      s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
>
> -    s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
> -    if (s->written_size != sizeof(*h)) {
> +    s->written_size = qemu_write_full(s->fd, h, hdr_size);
> +    if (s->written_size != hdr_size) {
>          error_setg(errp, QERR_IO_ERROR);
>          goto out_restore;
>      }
>
> -    write_runs(s, h, &local_err);
> +    write_runs(s, h, x64, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          goto out_restore;
>      }
>
>  out_restore:
> -    restore_context(h, saved_ctx);
> +    restore_context(h, x64, saved_ctx);
>  out_free:
>      g_free(saved_ctx);
>  out_cr3:
> --
> 2.35.1
>



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

* Re: [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures
  2022-04-06  7:51   ` Marc-André Lureau
@ 2022-04-06 15:15     ` Viktor Prutyanov
  0 siblings, 0 replies; 11+ messages in thread
From: Viktor Prutyanov @ 2022-04-06 15:15 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

Hi

On Wed, Apr 6, 2022 at 10:51 AM Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> Hi
>
> On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
> <viktor.prutyanov@redhat.com> wrote:
> >
> > These structures are required to produce 32-bit guest Windows Complete
> > Memory Dump. Add 32-bit Windows dump header, CPU context and physical
> > memory descriptor structures along with corresponding definitions.
> >
> > Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
> > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>
> Back when the initial support was introduced, I guess I thought those
> structures were defined by the fwcfg driver. I realize they are
> actually Windows structures. What's your reference for them? It's hard
> to find a good source, it seemed it was reverse-engineered by various
> projects.

The various structures presented here have different sources of varying
degrees of completeness.

As for WinContext*, WIN_CTX_* definitions, they are fully available as
I386_CONTEXT, AMD64_CONTEXT, CONTEXT_* definitions in the Wine project:
https://github.com/wine-mirror/wine/blob/master/include/winnt.h

As for the Complete Memory Dump header, the main fully open source of
this structure is the Volatility project:
https://github.com/volatilityfoundation/volatility/blob/master/volatility/plugins/overlays/windows/crash_vtypes.py

Besides of that, this information can be revealed experimentally by
comparing dumps between them and by analyzing manually constructed
dumps in WinDbg and noticing which of the data is available and which
is not. It is also possible because some fields of the header are also
presented as debug symbols provided by Microsoft in PDB and because
WinDbg sometimes provides verbose output on error. For example, this is
how the logic of win_dump.c was made.

So that, no reverse-engineering at least from my side is involved, all
of the information was obtained from scattered but open sources.

>
> Otherwise lgtm,
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>

Best regards,
Viktor Prutyanov

> > ---
> >  include/qemu/win_dump_defs.h | 107 +++++++++++++++++++++++++++++++++++
> >  1 file changed, 107 insertions(+)
> >
> > diff --git a/include/qemu/win_dump_defs.h b/include/qemu/win_dump_defs.h
> > index 5a5e5a5e09..73a44e2408 100644
> > --- a/include/qemu/win_dump_defs.h
> > +++ b/include/qemu/win_dump_defs.h
> > @@ -11,11 +11,22 @@
> >  #ifndef QEMU_WIN_DUMP_DEFS_H
> >  #define QEMU_WIN_DUMP_DEFS_H
> >
> > +typedef struct WinDumpPhyMemRun32 {
> > +    uint32_t BasePage;
> > +    uint32_t PageCount;
> > +} QEMU_PACKED WinDumpPhyMemRun32;
> > +
> >  typedef struct WinDumpPhyMemRun64 {
> >      uint64_t BasePage;
> >      uint64_t PageCount;
> >  } QEMU_PACKED WinDumpPhyMemRun64;
> >
> > +typedef struct WinDumpPhyMemDesc32 {
> > +    uint32_t NumberOfRuns;
> > +    uint32_t NumberOfPages;
> > +    WinDumpPhyMemRun32 Run[86];
> > +} QEMU_PACKED WinDumpPhyMemDesc32;
> > +
> >  typedef struct WinDumpPhyMemDesc64 {
> >      uint32_t NumberOfRuns;
> >      uint32_t unused;
> > @@ -33,6 +44,39 @@ typedef struct WinDumpExceptionRecord {
> >      uint64_t ExceptionInformation[15];
> >  } QEMU_PACKED WinDumpExceptionRecord;
> >
> > +typedef struct WinDumpHeader32 {
> > +    char Signature[4];
> > +    char ValidDump[4];
> > +    uint32_t MajorVersion;
> > +    uint32_t MinorVersion;
> > +    uint32_t DirectoryTableBase;
> > +    uint32_t PfnDatabase;
> > +    uint32_t PsLoadedModuleList;
> > +    uint32_t PsActiveProcessHead;
> > +    uint32_t MachineImageType;
> > +    uint32_t NumberProcessors;
> > +    union {
> > +        struct {
> > +            uint32_t BugcheckCode;
> > +            uint32_t BugcheckParameter1;
> > +            uint32_t BugcheckParameter2;
> > +            uint32_t BugcheckParameter3;
> > +            uint32_t BugcheckParameter4;
> > +        };
> > +        uint8_t BugcheckData[20];
> > +    };
> > +    uint8_t VersionUser[32];
> > +    uint32_t reserved0;
> > +    uint32_t KdDebuggerDataBlock;
> > +    union {
> > +        WinDumpPhyMemDesc32 PhysicalMemoryBlock;
> > +        uint8_t PhysicalMemoryBlockBuffer[700];
> > +    };
> > +    uint8_t reserved1[3200];
> > +    uint32_t RequiredDumpSpace;
> > +    uint8_t reserved2[92];
> > +} QEMU_PACKED WinDumpHeader32;
> > +
> >  typedef struct WinDumpHeader64 {
> >      char Signature[4];
> >      char ValidDump[4];
> > @@ -81,25 +125,49 @@ typedef struct WinDumpHeader64 {
> >      uint8_t reserved[4018];
> >  } QEMU_PACKED WinDumpHeader64;
> >
> > +typedef union WinDumpHeader {
> > +    struct {
> > +        char Signature[4];
> > +        char ValidDump[4];
> > +    };
> > +    WinDumpHeader32 x32;
> > +    WinDumpHeader64 x64;
> > +} WinDumpHeader;
> > +
> >  #define KDBG_OWNER_TAG_OFFSET64             0x10
> >  #define KDBG_MM_PFN_DATABASE_OFFSET64       0xC0
> >  #define KDBG_KI_BUGCHECK_DATA_OFFSET64      0x88
> >  #define KDBG_KI_PROCESSOR_BLOCK_OFFSET64    0x218
> >  #define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64   0x338
> >
> > +#define KDBG_OWNER_TAG_OFFSET           KDBG_OWNER_TAG_OFFSET64
> > +#define KDBG_MM_PFN_DATABASE_OFFSET     KDBG_MM_PFN_DATABASE_OFFSET64
> > +#define KDBG_KI_BUGCHECK_DATA_OFFSET    KDBG_KI_BUGCHECK_DATA_OFFSET64
> > +#define KDBG_KI_PROCESSOR_BLOCK_OFFSET  KDBG_KI_PROCESSOR_BLOCK_OFFSET64
> > +#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET KDBG_OFFSET_PRCB_CONTEXT_OFFSET64
> > +
> >  #define VMCOREINFO_ELF_NOTE_HDR_SIZE    24
> > +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE64 (sizeof(WinDumpHeader64) + \
> > +                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
> > +#define VMCOREINFO_WIN_DUMP_NOTE_SIZE32 (sizeof(WinDumpHeader32) + \
> > +                                         VMCOREINFO_ELF_NOTE_HDR_SIZE)
> >
> >  #define WIN_CTX_X64 0x00100000L
> > +#define WIN_CTX_X86 0x00010000L
> >
> >  #define WIN_CTX_CTL 0x00000001L
> >  #define WIN_CTX_INT 0x00000002L
> >  #define WIN_CTX_SEG 0x00000004L
> >  #define WIN_CTX_FP  0x00000008L
> >  #define WIN_CTX_DBG 0x00000010L
> > +#define WIN_CTX_EXT 0x00000020L
> >
> >  #define WIN_CTX64_FULL  (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
> >  #define WIN_CTX64_ALL   (WIN_CTX64_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
> >
> > +#define WIN_CTX32_FULL (WIN_CTX_X86 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_SEG)
> > +#define WIN_CTX32_ALL (WIN_CTX32_FULL | WIN_CTX_FP | WIN_CTX_DBG | WIN_CTX_EXT)
> > +
> >  #define LIVE_SYSTEM_DUMP    0x00000161
> >
> >  typedef struct WinM128A {
> > @@ -107,6 +175,40 @@ typedef struct WinM128A {
> >      int64_t high;
> >  } QEMU_ALIGNED(16) WinM128A;
> >
> > +typedef struct WinContext32 {
> > +    uint32_t ContextFlags;
> > +
> > +    uint32_t Dr0;
> > +    uint32_t Dr1;
> > +    uint32_t Dr2;
> > +    uint32_t Dr3;
> > +    uint32_t Dr6;
> > +    uint32_t Dr7;
> > +
> > +    uint8_t  FloatSave[112];
> > +
> > +    uint32_t SegGs;
> > +    uint32_t SegFs;
> > +    uint32_t SegEs;
> > +    uint32_t SegDs;
> > +
> > +    uint32_t Edi;
> > +    uint32_t Esi;
> > +    uint32_t Ebx;
> > +    uint32_t Edx;
> > +    uint32_t Ecx;
> > +    uint32_t Eax;
> > +
> > +    uint32_t Ebp;
> > +    uint32_t Eip;
> > +    uint32_t SegCs;
> > +    uint32_t EFlags;
> > +    uint32_t Esp;
> > +    uint32_t SegSs;
> > +
> > +    uint8_t ExtendedRegisters[512];
> > +} QEMU_ALIGNED(16) WinContext32;
> > +
> >  typedef struct WinContext64 {
> >      uint64_t PHome[6];
> >
> > @@ -176,4 +278,9 @@ typedef struct WinContext64 {
> >      uint64_t LastExceptionFromRip;
> >  } QEMU_ALIGNED(16) WinContext64;
> >
> > +typedef union WinContext {
> > +    WinContext32 x32;
> > +    WinContext64 x64;
> > +} WinContext;
> > +
> >  #endif /* QEMU_WIN_DUMP_DEFS_H */
> > --
> > 2.35.1
> >
>



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

* Re: [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support
  2022-04-06  8:00   ` Marc-André Lureau
@ 2022-04-06 15:20     ` Viktor Prutyanov
  0 siblings, 0 replies; 11+ messages in thread
From: Viktor Prutyanov @ 2022-04-06 15:20 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Vugenfirer, Yan, Mathieu-Daudé,
	Philippe, viktor.prutyanov, qemu-devel

Hi

On Wed, Apr 6, 2022 at 11:00 AM Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> Hi
>
> On Fri, Mar 25, 2022 at 11:51 PM Viktor Prutyanov
> <viktor.prutyanov@redhat.com> wrote:
> >
> > Before this patch, 'dump-guest-memory -w' was accepting only 64-bit
> > dump header provided by guest through vmcoreinfo and thus was unable
> > to produce 32-bit guest Windows dump. So, add 32-bit guest Windows
> > dumping support.
> >
> > Signed-off-by: Viktor Prutyanov <viktor.prutyanov@redhat.com>
> > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>
> lgtm,
> you should update dump-guest-memory doc in hmp-commands.hx

Thank you for this note, I will update the doc.

>
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>

Best regards,
Viktor Prutyanov

> > ---
> >  dump/win_dump.c | 245 +++++++++++++++++++++++++++++-------------------
> >  1 file changed, 149 insertions(+), 96 deletions(-)
> >
> > diff --git a/dump/win_dump.c b/dump/win_dump.c
> > index df3b432ca5..fda32da036 100644
> > --- a/dump/win_dump.c
> > +++ b/dump/win_dump.c
> > @@ -24,18 +24,24 @@
> >  #include "hw/misc/vmcoreinfo.h"
> >  #include "win_dump.h"
> >
> > -#define WIN_DUMP_PTR_SIZE sizeof(uint64_t)
> > +static size_t win_dump_ptr_size(bool x64)
> > +{
> > +    return x64 ? sizeof(uint64_t) : sizeof(uint32_t);
> > +}
> >
> > -#define _WIN_DUMP_FIELD(f) (h->f)
> > +#define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f)
> >  #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
> >
> > -#define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f)
> > +#define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f)
> >  #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
> >
> > -#define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f)
> > +#define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f))
> >  #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
> >
> > -#define WIN_DUMP_CTX_SIZE sizeof(WinContext64)
> > +static size_t win_dump_ctx_size(bool x64)
> > +{
> > +    return x64 ? sizeof(WinContext64) : sizeof(WinContext32);
> > +}
> >
> >  static size_t write_run(uint64_t base_page, uint64_t page_count,
> >          int fd, Error **errp)
> > @@ -71,7 +77,7 @@ static size_t write_run(uint64_t base_page, uint64_t page_count,
> >      return total;
> >  }
> >
> > -static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
> > +static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp)
> >  {
> >      uint64_t BasePage, PageCount;
> >      Error *local_err = NULL;
> > @@ -88,22 +94,24 @@ static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
> >      }
> >  }
> >
> > -static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr)
> > +static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr)
> >  {
> >      int ret;
> > +    uint32_t ptr32;
> >      uint64_t ptr64;
> >
> > -    ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0);
> > +    ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32,
> > +            win_dump_ptr_size(x64), 0);
> >
> > -    *ptr = ptr64;
> > +    *ptr = x64 ? ptr64 : ptr32;
> >
> >      return ret;
> >  }
> >
> > -static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
> > +static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp)
> >  {
> >      if (cpu_memory_rw_debug(first_cpu,
> > -            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64,
> > +            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET,
> >              WIN_DUMP_FIELD_PTR(PfnDatabase),
> >              WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
> >          error_setg(errp, "win-dump: failed to read MmPfnDatabase");
> > @@ -111,13 +119,12 @@ static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
> >      }
> >  }
> >
> > -static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
> > +static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp)
> >  {
> >      uint64_t KiBugcheckData;
> >
> > -    if (cpu_read_ptr(first_cpu,
> > -            WIN_DUMP_FIELD(KdDebuggerDataBlock) +
> > -                KDBG_KI_BUGCHECK_DATA_OFFSET64,
> > +    if (cpu_read_ptr(x64, first_cpu,
> > +            WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET,
> >              &KiBugcheckData)) {
> >          error_setg(errp, "win-dump: failed to read KiBugcheckData");
> >          return;
> > @@ -142,30 +149,34 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
> >  /*
> >   * This routine tries to correct mistakes in crashdump header.
> >   */
> > -static void patch_header(WinDumpHeader64 *h)
> > +static void patch_header(WinDumpHeader *h, bool x64)
> >  {
> >      Error *local_err = NULL;
> >
> > -    h->RequiredDumpSpace = sizeof(WinDumpHeader64) +
> > -            (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> > -    h->PhysicalMemoryBlock.unused = 0;
> > -    h->unused1 = 0;
> > +    if (x64) {
> > +        h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) +
> > +            (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> > +        h->x64.PhysicalMemoryBlock.unused = 0;
> > +        h->x64.unused1 = 0;
> > +    } else {
> > +        h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) +
> > +            (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
> > +    }
> >
> > -    patch_mm_pfn_database(h, &local_err);
> > +    patch_mm_pfn_database(h, x64, &local_err);
> >      if (local_err) {
> >          warn_report_err(local_err);
> >          local_err = NULL;
> >      }
> > -    patch_bugcheck_data(h, &local_err);
> > +    patch_bugcheck_data(h, x64, &local_err);
> >      if (local_err) {
> >          warn_report_err(local_err);
> >      }
> >  }
> >
> > -static void check_header(WinDumpHeader64 *h, Error **errp)
> > +static void check_header(WinDumpHeader *h, bool *x64, Error **errp)
> >  {
> >      const char Signature[] = "PAGE";
> > -    const char ValidDump[] = "DU64";
> >
> >      if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
> >          error_setg(errp, "win-dump: invalid header, expected '%.4s',"
> > @@ -173,14 +184,17 @@ static void check_header(WinDumpHeader64 *h, Error **errp)
> >          return;
> >      }
> >
> > -    if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) {
> > -        error_setg(errp, "win-dump: invalid header, expected '%.4s',"
> > -                         " got '%.4s'", ValidDump, h->ValidDump);
> > -        return;
> > +    if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) {
> > +        *x64 = false;
> > +    } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) {
> > +        *x64 = true;
> > +    } else {
> > +        error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64',"
> > +                         " got '%.4s'", h->ValidDump);
> >      }
> >  }
> >
> > -static void check_kdbg(WinDumpHeader64 *h, Error **errp)
> > +static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp)
> >  {
> >      const char OwnerTag[] = "KDBG";
> >      char read_OwnerTag[4];
> > @@ -189,7 +203,7 @@ static void check_kdbg(WinDumpHeader64 *h, Error **errp)
> >
> >  try_again:
> >      if (cpu_memory_rw_debug(first_cpu,
> > -            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64,
> > +            KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET,
> >              (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
> >          error_setg(errp, "win-dump: failed to read OwnerTag");
> >          return;
> > @@ -214,15 +228,19 @@ try_again:
> >          }
> >      }
> >
> > -    h->KdDebuggerDataBlock = KdDebuggerDataBlock;
> > +    if (x64) {
> > +        h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock;
> > +    } else {
> > +        h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock;
> > +    }
> >  }
> >
> >  struct saved_context {
> > -    WinContext64 ctx;
> > +    WinContext ctx;
> >      uint64_t addr;
> >  };
> >
> > -static void patch_and_save_context(WinDumpHeader64 *h,
> > +static void patch_and_save_context(WinDumpHeader *h, bool x64,
> >                                     struct saved_context *saved_ctx,
> >                                     Error **errp)
> >  {
> > @@ -232,15 +250,15 @@ static void patch_and_save_context(WinDumpHeader64 *h,
> >      CPUState *cpu;
> >      int i = 0;
> >
> > -    if (cpu_read_ptr(first_cpu,
> > -            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
> > +    if (cpu_read_ptr(x64, first_cpu,
> > +            KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET,
> >              &KiProcessorBlock)) {
> >          error_setg(errp, "win-dump: failed to read KiProcessorBlock");
> >          return;
> >      }
> >
> >      if (cpu_memory_rw_debug(first_cpu,
> > -            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
> > +            KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET,
> >              (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
> >          error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
> >          return;
> > @@ -251,17 +269,17 @@ static void patch_and_save_context(WinDumpHeader64 *h,
> >          CPUX86State *env = &x86_cpu->env;
> >          uint64_t Prcb;
> >          uint64_t Context;
> > -        WinContext64 ctx;
> > +        WinContext ctx;
> >
> > -        if (cpu_read_ptr(first_cpu,
> > -                KiProcessorBlock + i * WIN_DUMP_PTR_SIZE,
> > +        if (cpu_read_ptr(x64, first_cpu,
> > +                KiProcessorBlock + i * win_dump_ptr_size(x64),
> >                  &Prcb)) {
> >              error_setg(errp, "win-dump: failed to read"
> >                               " CPU #%d PRCB location", i);
> >              return;
> >          }
> >
> > -        if (cpu_read_ptr(first_cpu,
> > +        if (cpu_read_ptr(x64, first_cpu,
> >                  Prcb + OffsetPrcbContext,
> >                  &Context)) {
> >              error_setg(errp, "win-dump: failed to read"
> > @@ -271,56 +289,88 @@ static void patch_and_save_context(WinDumpHeader64 *h,
> >
> >          saved_ctx[i].addr = Context;
> >
> > -        ctx = (WinContext64){
> > -            .ContextFlags = WIN_CTX64_ALL,
> > -            .MxCsr = env->mxcsr,
> > -
> > -            .SegEs = env->segs[0].selector,
> > -            .SegCs = env->segs[1].selector,
> > -            .SegSs = env->segs[2].selector,
> > -            .SegDs = env->segs[3].selector,
> > -            .SegFs = env->segs[4].selector,
> > -            .SegGs = env->segs[5].selector,
> > -            .EFlags = cpu_compute_eflags(env),
> > -
> > -            .Dr0 = env->dr[0],
> > -            .Dr1 = env->dr[1],
> > -            .Dr2 = env->dr[2],
> > -            .Dr3 = env->dr[3],
> > -            .Dr6 = env->dr[6],
> > -            .Dr7 = env->dr[7],
> > -
> > -            .Rax = env->regs[R_EAX],
> > -            .Rbx = env->regs[R_EBX],
> > -            .Rcx = env->regs[R_ECX],
> > -            .Rdx = env->regs[R_EDX],
> > -            .Rsp = env->regs[R_ESP],
> > -            .Rbp = env->regs[R_EBP],
> > -            .Rsi = env->regs[R_ESI],
> > -            .Rdi = env->regs[R_EDI],
> > -            .R8  = env->regs[8],
> > -            .R9  = env->regs[9],
> > -            .R10 = env->regs[10],
> > -            .R11 = env->regs[11],
> > -            .R12 = env->regs[12],
> > -            .R13 = env->regs[13],
> > -            .R14 = env->regs[14],
> > -            .R15 = env->regs[15],
> > -
> > -            .Rip = env->eip,
> > -            .FltSave = {
> > +        if (x64) {
> > +            ctx.x64 = (WinContext64){
> > +                .ContextFlags = WIN_CTX64_ALL,
> >                  .MxCsr = env->mxcsr,
> > -            },
> > -        };
> > +
> > +                .SegEs = env->segs[0].selector,
> > +                .SegCs = env->segs[1].selector,
> > +                .SegSs = env->segs[2].selector,
> > +                .SegDs = env->segs[3].selector,
> > +                .SegFs = env->segs[4].selector,
> > +                .SegGs = env->segs[5].selector,
> > +                .EFlags = cpu_compute_eflags(env),
> > +
> > +                .Dr0 = env->dr[0],
> > +                .Dr1 = env->dr[1],
> > +                .Dr2 = env->dr[2],
> > +                .Dr3 = env->dr[3],
> > +                .Dr6 = env->dr[6],
> > +                .Dr7 = env->dr[7],
> > +
> > +                .Rax = env->regs[R_EAX],
> > +                .Rbx = env->regs[R_EBX],
> > +                .Rcx = env->regs[R_ECX],
> > +                .Rdx = env->regs[R_EDX],
> > +                .Rsp = env->regs[R_ESP],
> > +                .Rbp = env->regs[R_EBP],
> > +                .Rsi = env->regs[R_ESI],
> > +                .Rdi = env->regs[R_EDI],
> > +                .R8  = env->regs[8],
> > +                .R9  = env->regs[9],
> > +                .R10 = env->regs[10],
> > +                .R11 = env->regs[11],
> > +                .R12 = env->regs[12],
> > +                .R13 = env->regs[13],
> > +                .R14 = env->regs[14],
> > +                .R15 = env->regs[15],
> > +
> > +                .Rip = env->eip,
> > +                .FltSave = {
> > +                    .MxCsr = env->mxcsr,
> > +                },
> > +            };
> > +        } else {
> > +            ctx.x32 = (WinContext32){
> > +                .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG,
> > +
> > +                .SegEs = env->segs[0].selector,
> > +                .SegCs = env->segs[1].selector,
> > +                .SegSs = env->segs[2].selector,
> > +                .SegDs = env->segs[3].selector,
> > +                .SegFs = env->segs[4].selector,
> > +                .SegGs = env->segs[5].selector,
> > +                .EFlags = cpu_compute_eflags(env),
> > +
> > +                .Dr0 = env->dr[0],
> > +                .Dr1 = env->dr[1],
> > +                .Dr2 = env->dr[2],
> > +                .Dr3 = env->dr[3],
> > +                .Dr6 = env->dr[6],
> > +                .Dr7 = env->dr[7],
> > +
> > +                .Eax = env->regs[R_EAX],
> > +                .Ebx = env->regs[R_EBX],
> > +                .Ecx = env->regs[R_ECX],
> > +                .Edx = env->regs[R_EDX],
> > +                .Esp = env->regs[R_ESP],
> > +                .Ebp = env->regs[R_EBP],
> > +                .Esi = env->regs[R_ESI],
> > +                .Edi = env->regs[R_EDI],
> > +
> > +                .Eip = env->eip,
> > +            };
> > +        }
> >
> >          if (cpu_memory_rw_debug(first_cpu, Context,
> > -                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) {
> > +                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) {
> >              error_setg(errp, "win-dump: failed to save CPU #%d context", i);
> >              return;
> >          }
> >
> >          if (cpu_memory_rw_debug(first_cpu, Context,
> > -                &ctx, WIN_DUMP_CTX_SIZE, 1)) {
> > +                &ctx, win_dump_ctx_size(x64), 1)) {
> >              error_setg(errp, "win-dump: failed to write CPU #%d context", i);
> >              return;
> >          }
> > @@ -329,14 +379,14 @@ static void patch_and_save_context(WinDumpHeader64 *h,
> >      }
> >  }
> >
> > -static void restore_context(WinDumpHeader64 *h,
> > +static void restore_context(WinDumpHeader *h, bool x64,
> >                              struct saved_context *saved_ctx)
> >  {
> >      int i;
> >
> >      for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
> >          if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
> > -                &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) {
> > +                &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) {
> >              warn_report("win-dump: failed to restore CPU #%d context", i);
> >          }
> >      }
> > @@ -344,25 +394,28 @@ static void restore_context(WinDumpHeader64 *h,
> >
> >  void create_win_dump(DumpState *s, Error **errp)
> >  {
> > -    WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
> > -            VMCOREINFO_ELF_NOTE_HDR_SIZE);
> > +    WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
> >      X86CPU *first_x86_cpu = X86_CPU(first_cpu);
> >      uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
> >      struct saved_context *saved_ctx = NULL;
> >      Error *local_err = NULL;
> > +    bool x64;
> > +    size_t hdr_size;
> >
> > -    if (s->guest_note_size != sizeof(WinDumpHeader64) +
> > -            VMCOREINFO_ELF_NOTE_HDR_SIZE) {
> > +    if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 &&
> > +            s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) {
> >          error_setg(errp, "win-dump: invalid vmcoreinfo note size");
> >          return;
> >      }
> >
> > -    check_header(h, &local_err);
> > +    check_header(h, &x64, &local_err);
> >      if (local_err) {
> >          error_propagate(errp, local_err);
> >          return;
> >      }
> >
> > +    hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32);
> > +
> >      /*
> >       * Further access to kernel structures by virtual addresses
> >       * should be made from system context.
> > @@ -370,13 +423,13 @@ void create_win_dump(DumpState *s, Error **errp)
> >
> >      first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
> >
> > -    check_kdbg(h, &local_err);
> > +    check_kdbg(h, x64, &local_err);
> >      if (local_err) {
> >          error_propagate(errp, local_err);
> >          goto out_cr3;
> >      }
> >
> > -    patch_header(h);
> > +    patch_header(h, x64);
> >
> >      saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
> >
> > @@ -385,7 +438,7 @@ void create_win_dump(DumpState *s, Error **errp)
> >       * to determine if the system-saved context is valid
> >       */
> >
> > -    patch_and_save_context(h, saved_ctx, &local_err);
> > +    patch_and_save_context(h, x64, saved_ctx, &local_err);
> >      if (local_err) {
> >          error_propagate(errp, local_err);
> >          goto out_free;
> > @@ -393,20 +446,20 @@ void create_win_dump(DumpState *s, Error **errp)
> >
> >      s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
> >
> > -    s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
> > -    if (s->written_size != sizeof(*h)) {
> > +    s->written_size = qemu_write_full(s->fd, h, hdr_size);
> > +    if (s->written_size != hdr_size) {
> >          error_setg(errp, QERR_IO_ERROR);
> >          goto out_restore;
> >      }
> >
> > -    write_runs(s, h, &local_err);
> > +    write_runs(s, h, x64, &local_err);
> >      if (local_err) {
> >          error_propagate(errp, local_err);
> >          goto out_restore;
> >      }
> >
> >  out_restore:
> > -    restore_context(h, saved_ctx);
> > +    restore_context(h, x64, saved_ctx);
> >  out_free:
> >      g_free(saved_ctx);
> >  out_cr3:
> > --
> > 2.35.1
> >
>



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

end of thread, other threads:[~2022-04-06 15:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-25 19:51 [PATCH v3 0/4] dump: add 32-bit guest Windows support Viktor Prutyanov
2022-03-25 19:51 ` [PATCH v3 1/4] include/qemu: rename Windows context definitions to expose bitness Viktor Prutyanov
2022-04-06  7:24   ` Marc-André Lureau
2022-03-25 19:51 ` [PATCH v3 2/4] dump/win_dump: add helper macros for Windows dump header access Viktor Prutyanov
2022-04-06  7:24   ` Marc-André Lureau
2022-03-25 19:51 ` [PATCH v3 3/4] include/qemu: add 32-bit Windows dump structures Viktor Prutyanov
2022-04-06  7:51   ` Marc-André Lureau
2022-04-06 15:15     ` Viktor Prutyanov
2022-03-25 19:51 ` [PATCH v3 4/4] dump/win_dump: add 32-bit guest Windows support Viktor Prutyanov
2022-04-06  8:00   ` Marc-André Lureau
2022-04-06 15:20     ` Viktor Prutyanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.