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(a)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