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;
|
ULONG rva;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dump_memory64
|
||||||
|
{
|
||||||
|
ULONG64 base;
|
||||||
|
ULONG64 size;
|
||||||
|
};
|
||||||
|
|
||||||
struct dump_module
|
struct dump_module
|
||||||
{
|
{
|
||||||
unsigned is_elf;
|
unsigned is_elf;
|
||||||
|
@ -509,6 +515,9 @@ struct dump_context
|
||||||
struct dump_memory* mem;
|
struct dump_memory* mem;
|
||||||
unsigned num_mem;
|
unsigned num_mem;
|
||||||
unsigned alloc_mem;
|
unsigned alloc_mem;
|
||||||
|
struct dump_memory64* mem64;
|
||||||
|
unsigned num_mem64;
|
||||||
|
unsigned alloc_mem64;
|
||||||
/* callback information */
|
/* callback information */
|
||||||
MINIDUMP_CALLBACK_INFORMATION* cb;
|
MINIDUMP_CALLBACK_INFORMATION* cb;
|
||||||
};
|
};
|
||||||
|
|
|
@ -294,6 +294,49 @@ static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base,
|
||||||
return TRUE;
|
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)
|
static void fetch_modules_info(struct dump_context* dc)
|
||||||
{
|
{
|
||||||
EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, 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;
|
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)
|
static unsigned dump_misc_info(struct dump_context* dc)
|
||||||
{
|
{
|
||||||
MINIDUMP_MISC_INFO mmi;
|
MINIDUMP_MISC_INFO mmi;
|
||||||
|
@ -876,6 +973,9 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
|
||||||
dc.mem = NULL;
|
dc.mem = NULL;
|
||||||
dc.num_mem = 0;
|
dc.num_mem = 0;
|
||||||
dc.alloc_mem = 0;
|
dc.alloc_mem = 0;
|
||||||
|
dc.mem64 = NULL;
|
||||||
|
dc.num_mem64 = 0;
|
||||||
|
dc.alloc_mem64 = 0;
|
||||||
dc.rva = 0;
|
dc.rva = 0;
|
||||||
|
|
||||||
if (!fetch_process_info(&dc)) return FALSE;
|
if (!fetch_process_info(&dc)) return FALSE;
|
||||||
|
@ -890,8 +990,6 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
|
||||||
|
|
||||||
if (DumpType & MiniDumpWithDataSegs)
|
if (DumpType & MiniDumpWithDataSegs)
|
||||||
FIXME("NIY MiniDumpWithDataSegs\n");
|
FIXME("NIY MiniDumpWithDataSegs\n");
|
||||||
if (DumpType & MiniDumpWithFullMemory)
|
|
||||||
FIXME("NIY MiniDumpWithFullMemory\n");
|
|
||||||
if (DumpType & MiniDumpWithHandleData)
|
if (DumpType & MiniDumpWithHandleData)
|
||||||
FIXME("NIY MiniDumpWithHandleData\n");
|
FIXME("NIY MiniDumpWithHandleData\n");
|
||||||
if (DumpType & MiniDumpFilterMemory)
|
if (DumpType & MiniDumpFilterMemory)
|
||||||
|
@ -940,11 +1038,15 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
|
||||||
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
&mdDir, sizeof(mdDir));
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
|
|
||||||
|
if (!(DumpType & MiniDumpWithFullMemory))
|
||||||
|
{
|
||||||
mdDir.StreamType = MemoryListStream;
|
mdDir.StreamType = MemoryListStream;
|
||||||
mdDir.Location.Rva = dc.rva;
|
mdDir.Location.Rva = dc.rva;
|
||||||
mdDir.Location.DataSize = dump_memory_info(&dc);
|
mdDir.Location.DataSize = dump_memory_info(&dc);
|
||||||
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
&mdDir, sizeof(mdDir));
|
&mdDir, sizeof(mdDir));
|
||||||
|
}
|
||||||
|
|
||||||
mdDir.StreamType = MiscInfoStream;
|
mdDir.StreamType = MiscInfoStream;
|
||||||
mdDir.Location.Rva = dc.rva;
|
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) */
|
/* fill the remaining directory entries with 0's (unused stream types) */
|
||||||
/* NOTE: this should always come last in the dump! */
|
/* NOTE: this should always come last in the dump! */
|
||||||
for (i = idx_stream; i < nStreams; i++)
|
for (i = idx_stream; i < nStreams; i++)
|
||||||
writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
|
writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, dc.mem);
|
HeapFree(GetProcessHeap(), 0, dc.mem);
|
||||||
|
HeapFree(GetProcessHeap(), 0, dc.mem64);
|
||||||
HeapFree(GetProcessHeap(), 0, dc.modules);
|
HeapFree(GetProcessHeap(), 0, dc.modules);
|
||||||
HeapFree(GetProcessHeap(), 0, dc.threads);
|
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_DESCRIPTOR MemoryRanges[1]; /* FIXME: 0-sized array not supported */
|
||||||
} MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST;
|
} 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_ID 0x00000001
|
||||||
#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002
|
#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue