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:
parent
18ac7e15aa
commit
b90bbcbe75
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue