From 2c02fa6378627555b2b6dc4ebcb46c6fab0faff4 Mon Sep 17 00:00:00 2001 From: Jason Green Date: Wed, 21 Nov 2007 10:09:41 -0500 Subject: [PATCH] Clamp minidump memory blocks to 928KB and improve TRACEs WinDbg can't read minidumps with memory blocks larger than this. --- dlls/dbghelp/minidump.c | 84 +++++++++++++++++++++++++++++++++++++--------- 1 files changed, 67 insertions(+), 17 deletions(-) diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index 44a88f1..17106c1 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -32,6 +32,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); + +/* windbg isn't able to open minidump files if they contain a single memory block larger + than 928KB. If a larger block is found, it simply reports that all following streams + could not be loaded. This is as of WinDbg version 6.7.0005.1. */ +#define MINIDUMP_MEMORY_BLOCK_MAX (928 * 1024) + + struct dump_memory { ULONG64 base; @@ -654,8 +661,32 @@ static void dump_threads(struct dump_context* dc, } if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack)) { - add_memory_block(dc, mdThd.Stack.StartOfMemoryRange, - mdThd.Stack.Memory.DataSize, + ULONG size; + ULONG64 base; + + + /* windbg only supports memory blocks up to 928KB in size. Not sure where that + specific amount comes from, but in testing it will completely fail to load + all minidump streams that follow a memory block that is larger than 928KB. + Because of this, we'll clamp all of the memory blocks that we add to the + file. */ + if (mdThd.Stack.Memory.DataSize > MINIDUMP_MEMORY_BLOCK_MAX){ + size = MINIDUMP_MEMORY_BLOCK_MAX; + + /* since this is the thread stack we'll want to save this block top-down + instead of just clamping the buffer size */ + base = mdThd.Stack.StartOfMemoryRange + (mdThd.Stack.Memory.DataSize - MINIDUMP_MEMORY_BLOCK_MAX); + + TRACE(" clamping the stack block starting at 0x%08llx {oldSize = %u bytes, newSize = %u bytes, newBase = 0x%08llx}\n", + mdThd.Stack.StartOfMemoryRange, mdThd.Stack.Memory.DataSize, size, base); + } + + else{ + size = mdThd.Stack.Memory.DataSize; + base = mdThd.Stack.StartOfMemoryRange; + } + + add_memory_block(dc, base, size, rva_base + sizeof(mdThdList.NumberOfThreads) + mdThdList.NumberOfThreads * sizeof(mdThd) + FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva)); @@ -714,9 +745,11 @@ static void dump_memory_info(struct dump_context* dc, ULONG64 *streamSize) safely be stored starting at the end of this stream. */ *streamSize = sizeof(mdMemList.NumberOfMemoryRanges) + mdMemList.NumberOfMemoryRanges * sizeof(mdMem); + TRACE("writing %d memory blocks streams\n", dc->num_mem); for (i = 0; i < dc->num_mem; i++) { + TRACE(" writing memory block %d {addr = 0x%08llx, size = %u bytes, RVA = 0x%x}\n", i, dc->mem[i].base, dc->mem[i].size, dc->rva); mdMem.StartOfMemoryRange = dc->mem[i].base; mdMem.Memory.Rva = dc->rva; mdMem.Memory.DataSize = dc->mem[i].size; @@ -837,62 +870,77 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, /* 3.1) write data stream directories */ + TRACE("dumping thread list stream\n"); mdDir.StreamType = ThreadListStream; mdDir.Location.Rva = dc.rva; dump_threads(&dc, ExceptionParam, &streamSize); mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); - - mdDir.StreamType = ModuleListStream; - mdDir.Location.Rva = dc.rva; - dump_modules(&dc, FALSE, &streamSize); - mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), - &mdDir, sizeof(mdDir)); - - mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */ - mdDir.Location.Rva = dc.rva; - dump_modules(&dc, TRUE, &streamSize); - mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), - &mdDir, sizeof(mdDir)); - + TRACE(" wrote thread list at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); + + TRACE("dumping module list stream\n"); + mdDir.StreamType = ModuleListStream; + mdDir.Location.Rva = dc.rva; + dump_modules(&dc, FALSE, &streamSize); + mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); + TRACE(" wrote module list at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); + + TRACE("dumping cider module list stream\n"); + mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */ + mdDir.Location.Rva = dc.rva; + dump_modules(&dc, TRUE, &streamSize); + mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); + TRACE(" wrote cider module list at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); + + TRACE("dumping memory list stream\n"); mdDir.StreamType = MemoryListStream; mdDir.Location.Rva = dc.rva; dump_memory_info(&dc, &streamSize); mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); + TRACE(" wrote memory list at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); + TRACE("dumping system info stream\n"); mdDir.StreamType = SystemInfoStream; mdDir.Location.Rva = dc.rva; dump_system_info(&dc, &streamSize); mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); + TRACE(" wrote system info at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); + TRACE("dumping misc info stream\n"); mdDir.StreamType = MiscInfoStream; mdDir.Location.Rva = dc.rva; dump_misc_info(&dc, &streamSize); mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); + TRACE(" wrote misc info at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); /* 3.2) write exception information (if any) */ if (ExceptionParam) { + TRACE("dumping exception info stream\n"); mdDir.StreamType = ExceptionStream; mdDir.Location.Rva = dc.rva; dump_exception_info(&dc, ExceptionParam, &streamSize); mdDir.Location.DataSize = (ULONG32)streamSize; /*dc.rva - mdDir.Location.Rva;*/ writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); + TRACE(" wrote exception info at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); } /* 3.3) write user defined streams (if any) */ if (UserStreamParam) { + TRACE("dumping %u user info streams\n", UserStreamParam->UserStreamCount); for (i = 0; i < UserStreamParam->UserStreamCount; i++) { mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type; @@ -902,10 +950,12 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, &mdDir, sizeof(mdDir)); append(&dc, UserStreamParam->UserStreamArray[i].Buffer, UserStreamParam->UserStreamArray[i].BufferSize); + TRACE(" wrote user stream %d at 0x%08x {streamType = %u, dataSize = %d bytes, dirEntry = 0x%08x}\n", i, mdDir.Location.Rva, mdDir.StreamType, mdDir.Location.DataSize, (mdHead.StreamDirectoryRva + (idx_stream - 1) * sizeof(mdDir))); } } + TRACE("writing header info\n"); /* 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++) -- 1.4.4.2