[PATCH] dbghelp: Support full memory dumps.

Eric Bissonnette ebisso.dev at gmail.com
Tue Jan 1 12:29:59 CST 2019


Add support of flag MinidumpWithFullMemory in
function MinidumpWriteDump. A Memory64ListStream is
added to the minidump streams and all memory regions
of the process with MEM_COMMIT state are written to
the last part of the minidump file.

Signed-off-by: Eric Bissonnette <ebisso.dev at gmail.com>
---
 dlls/dbghelp/dbghelp_private.h |   9 +++
 dlls/dbghelp/minidump.c        | 129 ++++++++++++++++++++++++++++++++++++++---
 include/dbghelp.h              |  13 +++++
 3 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h
index ae8bc50..8083408 100644
--- a/dlls/dbghelp/dbghelp_private.h
+++ b/dlls/dbghelp/dbghelp_private.h
@@ -471,6 +471,12 @@ struct dump_memory
     ULONG                               rva;
 };
 
+struct dump_memory64
+{
+    ULONG64                             base;
+    ULONG64                             size;
+};
+
 struct dump_module
 {
     unsigned                            is_elf;
@@ -509,6 +515,9 @@ struct dump_context
     struct dump_memory*                 mem;
     unsigned                            num_mem;
     unsigned                            alloc_mem;
+    struct dump_memory64*               mem64;
+    unsigned                            num_mem64;
+    unsigned                            alloc_mem64;
     /* callback information */
     MINIDUMP_CALLBACK_INFORMATION*      cb;
 };
diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c
index 04dc775..ad69ba5 100644
--- a/dlls/dbghelp/minidump.c
+++ b/dlls/dbghelp/minidump.c
@@ -294,6 +294,49 @@ static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base,
     return TRUE;
 }
 
+void minidump_add_memory64_block(struct dump_context* dc, ULONG64 base, ULONG64 size)
+{
+    if (!dc->mem64)
+    {
+        dc->alloc_mem64 = 32;
+        dc->mem64 = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem64 * sizeof(*dc->mem64));
+    }
+    else if (dc->num_mem64 >= dc->alloc_mem64)
+    {
+        dc->alloc_mem64 *= 2;
+        dc->mem64 = HeapReAlloc(GetProcessHeap(), 0, dc->mem64,
+                                dc->alloc_mem64 * sizeof(*dc->mem64));
+    }
+    if (dc->mem64)
+    {
+        dc->mem64[dc->num_mem64].base = base;
+        dc->mem64[dc->num_mem64].size = size;
+        dc->num_mem64++;
+    }
+    else dc->num_mem64 = dc->alloc_mem64 = 0;
+}
+
+static void fetch_memory64_info(struct dump_context* dc)
+{
+    ULONG_PTR                   addr;
+    MEMORY_BASIC_INFORMATION    mbi;
+
+    addr = 0;
+    while (VirtualQueryEx(dc->hProcess, (LPCVOID)addr, &mbi, sizeof(mbi)) != 0)
+    {
+        /* Memory regions with state MEM_COMMIT will be added to the dump */
+        if (mbi.State == MEM_COMMIT)
+        {
+            minidump_add_memory64_block(dc, (ULONG_PTR)mbi.BaseAddress, mbi.RegionSize);
+        }
+
+        if ((addr + mbi.RegionSize) < addr)
+            break;
+        
+        addr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
+    }
+}
+
 static void fetch_modules_info(struct dump_context* dc)
 {
     EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
@@ -831,6 +874,60 @@ static unsigned         dump_memory_info(struct dump_context* dc)
     return sz;
 }
 
+/******************************************************************
+ *		dump_memory64_info
+ *
+ * dumps information about the memory of the process (virtual memory)
+ */
+static unsigned         dump_memory64_info(struct dump_context* dc)
+{
+    MINIDUMP_MEMORY64_LIST          mdMem64List;
+    MINIDUMP_MEMORY_DESCRIPTOR64    mdMem64;
+    DWORD                           written;
+    unsigned                        i, len, sz;
+    RVA                             rva_base;
+    char                            tmp[1024];
+    ULONG64                         pos;
+    LARGE_INTEGER                   filepos;
+
+    sz = sizeof(mdMem64List.NumberOfMemoryRanges) +
+            sizeof(mdMem64List.BaseRva) +
+            dc->num_mem64 * sizeof(mdMem64);
+
+    mdMem64List.NumberOfMemoryRanges = dc->num_mem64;    
+    mdMem64List.BaseRva = dc->rva + sz;           
+
+    append(dc, &mdMem64List.NumberOfMemoryRanges,
+           sizeof(mdMem64List.NumberOfMemoryRanges));
+    append(dc, &mdMem64List.BaseRva,
+           sizeof(mdMem64List.BaseRva));
+    
+    rva_base = dc->rva;
+    dc->rva += dc->num_mem64 * sizeof(mdMem64);
+    
+    /* dc->rva is not updated past this point. The end of the dump
+     * is just the full memory data. */
+    filepos.QuadPart = dc->rva;
+    for (i = 0; i < dc->num_mem64; i++)
+    {
+        mdMem64.StartOfMemoryRange = dc->mem64[i].base;
+        mdMem64.DataSize = dc->mem64[i].size;
+        SetFilePointerEx(dc->hFile, filepos, NULL, FILE_BEGIN);
+        for (pos = 0; pos < dc->mem64[i].size; pos += sizeof(tmp))
+        {
+            len = min(dc->mem64[i].size - pos, sizeof(tmp));
+            if (ReadProcessMemory(dc->hProcess, 
+                                  (void*)(ULONG_PTR)(dc->mem64[i].base + pos),
+                                  tmp, len, NULL))
+                WriteFile(dc->hFile, tmp, len, &written, NULL);
+        }
+        filepos.QuadPart += mdMem64.DataSize;
+        writeat(dc, rva_base + i * sizeof(mdMem64), &mdMem64, sizeof(mdMem64));
+    }
+    
+    return sz;
+}
+
 static unsigned         dump_misc_info(struct dump_context* dc)
 {
     MINIDUMP_MISC_INFO  mmi;
@@ -876,6 +973,9 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
     dc.mem = NULL;
     dc.num_mem = 0;
     dc.alloc_mem = 0;
+    dc.mem64 = NULL;
+    dc.num_mem64 = 0;
+    dc.alloc_mem64 = 0;
     dc.rva = 0;
 
     if (!fetch_process_info(&dc)) return FALSE;
@@ -890,8 +990,6 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
 
     if (DumpType & MiniDumpWithDataSegs)
         FIXME("NIY MiniDumpWithDataSegs\n");
-    if (DumpType & MiniDumpWithFullMemory)
-        FIXME("NIY MiniDumpWithFullMemory\n");
     if (DumpType & MiniDumpWithHandleData)
         FIXME("NIY MiniDumpWithHandleData\n");
     if (DumpType & MiniDumpFilterMemory)
@@ -940,11 +1038,15 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
             &mdDir, sizeof(mdDir));
 
-    mdDir.StreamType = MemoryListStream;
-    mdDir.Location.Rva = dc.rva;
-    mdDir.Location.DataSize = dump_memory_info(&dc);
-    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
-            &mdDir, sizeof(mdDir));
+    
+    if (!(DumpType & MiniDumpWithFullMemory))
+    {
+        mdDir.StreamType = MemoryListStream;
+        mdDir.Location.Rva = dc.rva;
+        mdDir.Location.DataSize = dump_memory_info(&dc);
+        writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
+                &mdDir, sizeof(mdDir));
+    }
 
     mdDir.StreamType = MiscInfoStream;
     mdDir.Location.Rva = dc.rva;
@@ -977,12 +1079,25 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
         }
     }
 
+    /* 3.4) write full memory (if requested) */
+    if (DumpType & MiniDumpWithFullMemory)
+    {
+        fetch_memory64_info(&dc);
+
+        mdDir.StreamType = Memory64ListStream;
+        mdDir.Location.Rva = dc.rva;
+        mdDir.Location.DataSize = dump_memory64_info(&dc);
+        writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
+                &mdDir, sizeof(mdDir));
+    }
+
     /* fill the remaining directory entries with 0's (unused stream types) */
     /* NOTE: this should always come last in the dump! */
     for (i = idx_stream; i < nStreams; i++)
         writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
 
     HeapFree(GetProcessHeap(), 0, dc.mem);
+    HeapFree(GetProcessHeap(), 0, dc.mem64);
     HeapFree(GetProcessHeap(), 0, dc.modules);
     HeapFree(GetProcessHeap(), 0, dc.threads);
 
diff --git a/include/dbghelp.h b/include/dbghelp.h
index 6e8d375..4210616 100644
--- a/include/dbghelp.h
+++ b/include/dbghelp.h
@@ -747,6 +747,19 @@ typedef struct _MINIDUMP_MEMORY_LIST
     MINIDUMP_MEMORY_DESCRIPTOR  MemoryRanges[1]; /* FIXME: 0-sized array not supported */
 } MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST;
 
+typedef struct _MINIDUMP_MEMORY_DESCRIPTOR64
+{
+    ULONG64                     StartOfMemoryRange;
+    ULONG64                     DataSize;
+} MINIDUMP_MEMORY_DESCRIPTOR64, *PMINIDUMP_MEMORY_DESCRIPTOR64;
+
+typedef struct _MINIDUMP_MEMORY64_LIST
+{
+    ULONG64                     NumberOfMemoryRanges;
+    RVA64                       BaseRva;
+    MINIDUMP_MEMORY_DESCRIPTOR64 MemoryRanges[1]; /* FIXME: 0-sized array not supported */
+} MINIDUMP_MEMORY64_LIST, *PMINIDUMP_MEMORY64_LIST;
+
 #define MINIDUMP_MISC1_PROCESS_ID       0x00000001
 #define MINIDUMP_MISC1_PROCESS_TIMES    0x00000002
 
-- 
1.8.3.1




More information about the wine-devel mailing list