dbghelp: Support full memory dumps.

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@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Eric Bissonnette 2019-01-25 21:12:02 -05:00 committed by Alexandre Julliard
parent 18ac7e15aa
commit b90bbcbe75
3 changed files with 144 additions and 7 deletions

View File

@ -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;
};

View File

@ -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);

View File

@ -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