From 642402d5817f37c29555ccd01787d0317d640ad1 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 7 Mar 2005 11:03:21 +0000 Subject: [PATCH] Added support for minidump (read & write). --- dlls/dbghelp/dbghelp.spec | 4 +- dlls/dbghelp/elf_module.c | 2 + dlls/dbghelp/minidump.c | 784 +++++++++++++++++++++++++++++++------- include/dbghelp.h | 225 +++++++---- 4 files changed, 800 insertions(+), 215 deletions(-) diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec index 8fdd97c82ae..c3d0c9567e7 100644 --- a/dlls/dbghelp/dbghelp.spec +++ b/dlls/dbghelp/dbghelp.spec @@ -20,8 +20,8 @@ @ stdcall ImagehlpApiVersionEx(ptr) @ stdcall MakeSureDirectoryPathExists(str) @ stdcall MapDebugInformation(long str str long) -@ stub MiniDumpReadDumpStream -@ stub MiniDumpWriteDump +@ stdcall MiniDumpReadDumpStream(ptr long ptr ptr ptr) +@ stdcall MiniDumpWriteDump(ptr long ptr long long long long) @ stdcall SearchTreeForFile(str str str) @ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr) @ stub StackWalk64 diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index bbc07c85762..c3172b12c35 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -1278,9 +1278,11 @@ BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) struct process pcs; struct elf_info elf_info; + memset(&pcs, 0, sizeof(pcs)); pcs.handle = hProc; elf_info.flags = ELF_INFO_DEBUG_HEADER; if (!elf_search_loader(&pcs, &elf_info)) return FALSE; + pcs.dbg_hdr_addr = elf_info.dbg_hdr_addr; return elf_enum_modules_internal(&pcs, cb, user); } diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index 67cb291c2ba..8a3adb0cb0d 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -24,74 +24,415 @@ #define NONAMELESSSTRUCT #include "dbghelp_private.h" +#include "ntstatus.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" +#include "psapi.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); -#if 0 -/* hard to see how we can generate this very easily (how to grab latest exception - * in a process ?) +struct dump_memory +{ + ULONG base; + ULONG size; + ULONG rva; +}; + +struct dump_module +{ + unsigned is_elf; + ULONG base; + ULONG size; + char name[MAX_PATH]; +}; + +struct dump_context +{ + /* process & thread information */ + HANDLE hProcess; + DWORD pid; + void* pcs_buffer; + SYSTEM_PROCESS_INFORMATION* spi; + /* module information */ + struct dump_module* module; + unsigned num_module; + /* exception information */ + /* output information */ + MINIDUMP_TYPE type; + HANDLE hFile; + RVA rva; + struct dump_memory* mem; + unsigned num_mem; + /* callback information */ + MINIDUMP_CALLBACK_INFORMATION* cb; +}; + +/****************************************************************** + * fetch_process_info + * + * reads system wide process information, and make spi point to the record + * for process of id 'pid' */ -static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva) +static BOOL fetch_process_info(struct dump_context* dc) +{ + ULONG buf_size = 0x1000; + NTSTATUS nts; + + dc->pcs_buffer = NULL; + if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE; + for (;;) + { + nts = NtQuerySystemInformation(SystemProcessInformation, + dc->pcs_buffer, buf_size, NULL); + if (nts != STATUS_INFO_LENGTH_MISMATCH) break; + dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer, + buf_size *= 2); + if (!dc->pcs_buffer) return FALSE; + } + + if (nts == STATUS_SUCCESS) + { + dc->spi = dc->pcs_buffer; + for (;;) + { + if (dc->spi->dwProcessID == dc->pid) return TRUE; + if (!dc->spi->dwOffset) break; + dc->spi = (SYSTEM_PROCESS_INFORMATION*) + ((char*)dc->spi + dc->spi->dwOffset); + } + } + HeapFree(GetProcessHeap(), 0, dc->pcs_buffer); + dc->pcs_buffer = NULL; + dc->spi = NULL; + return FALSE; +} + +/****************************************************************** + * fetch_thread_info + * + * fetches some information about thread of id 'tid' + */ +static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, + MINIDUMP_THREAD* mdThd, CONTEXT* ctx) +{ + NT_TIB tib; + DWORD tid = dc->spi->ti[thd_idx].dwThreadID; + HANDLE hThread; + THREAD_BASIC_INFORMATION tbi; + + memset(ctx, 0, sizeof(*ctx)); + + mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID; + mdThd->SuspendCount = 0; + mdThd->Teb = 0; + mdThd->Stack.StartOfMemoryRange = 0; + mdThd->Stack.Memory.DataSize = 0; + mdThd->Stack.Memory.Rva = 0; + mdThd->ThreadContext.DataSize = 0; + mdThd->ThreadContext.Rva = 0; + mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */ + mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority; + + if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL) + { + FIXME("Couldn't open thread %lu (%lu)\n", + dc->spi->ti[thd_idx].dwThreadID, GetLastError()); + return FALSE; + } + + if (NtQueryInformationThread(hThread, ThreadBasicInformation, + &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS) + { + mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress; + if (tbi.ExitStatus == STILL_ACTIVE && tid != GetCurrentThreadId() && + (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1) + { + mdThd->SuspendCount--; + ctx->ContextFlags = CONTEXT_FULL; + if (!GetThreadContext(hThread, ctx)) + memset(ctx, 0, sizeof(*ctx)); + + if (ReadProcessMemory(dc->hProcess, tbi.TebBaseAddress, + &tib, sizeof(tib), NULL)) + { +#ifdef __i386__ + /* limiting the stack dumping to the size actually used */ + if (ctx->Esp) + mdThd->Stack.StartOfMemoryRange = (ctx->Esp - 4); + else + mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; + mdThd->Stack.Memory.DataSize = (ULONG_PTR)tib.StackBase - + mdThd->Stack.StartOfMemoryRange; +#else +#error unsupported CPU +#endif + } + ResumeThread(hThread); + } + } + CloseHandle(hThread); + return TRUE; +} + +/****************************************************************** + * add_module + * + * Add a module to a dump context + */ +static BOOL add_module(struct dump_context* dc, const char* name, + DWORD base, DWORD size, BOOL is_elf) +{ + if (!dc->module) + dc->module = HeapAlloc(GetProcessHeap(), 0, ++dc->num_module * sizeof(*dc->module)); + else + dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module, ++dc->num_module * sizeof(*dc->module)); + if (!dc->module) return FALSE; + if (is_elf || + !GetModuleFileNameExA(dc->hProcess, (HMODULE)base, + dc->module[dc->num_module - 1].name, + sizeof(dc->module[dc->num_module - 1].name))) + lstrcpynA(dc->module[dc->num_module - 1].name, name, + sizeof(dc->module[dc->num_module - 1].name)); + dc->module[dc->num_module - 1].base = base; + dc->module[dc->num_module - 1].size = size; + dc->module[dc->num_module - 1].is_elf = is_elf; + + return TRUE; +} + +/****************************************************************** + * fetch_pe_module_info_cb + * + * Callback for accumulating in dump_context a PE modules set + */ +static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size, + void* user) +{ + return add_module((struct dump_context*)user, name, base, size, FALSE); +} + +/****************************************************************** + * fetch_elf_module_info_cb + * + * Callback for accumulating in dump_context a ELF modules set + */ +static BOOL fetch_elf_module_info_cb(const char* name, unsigned long base, + void* user) +{ + return add_module((struct dump_context*)user, name, + base, 0 /* FIXME */, TRUE); +} + +static void fetch_module_info(struct dump_context* dc) +{ + WINE_FIXME("--> %p\n", dc->hProcess); + EnumerateLoadedModules(dc->hProcess, fetch_pe_module_info_cb, dc); + /* Since we include ELF modules in a separate stream from the regular PE ones, + * we can always include those ELF modules (they don't eat lots of space) + * And it's always a good idea to have a trace of the loaded ELF modules for + * a given application in a post mortem debugging condition. + */ + elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc); +} + +/****************************************************************** + * add_memory_block + * + * Add a memory block to be dumped in a minidump + * If rva is non 0, it's the rva in the minidump where has to be stored + * also the rva of the memory block when written (this allows to reference + * a memory block from outside the list of memory blocks). + */ +static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva) +{ + if (dc->mem) + dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, + ++dc->num_mem * sizeof(*dc->mem)); + else + dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem)); + if (dc->mem) + { + dc->mem[dc->num_mem - 1].base = base; + dc->mem[dc->num_mem - 1].size = size; + dc->mem[dc->num_mem - 1].rva = rva; + } + else dc->num_mem = 0; +} + +/****************************************************************** + * writeat + * + * Writes a chunk of data at a given position in the minidump + */ +static void writeat(struct dump_context* dc, RVA rva, void* data, unsigned size) +{ + DWORD written; + + SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN); + WriteFile(dc->hFile, data, size, &written, NULL); +} + +/****************************************************************** + * append + * + * writes a new chunk of data to the minidump, increasing the current + * rva in dc + */ +static void append(struct dump_context* dc, void* data, unsigned size) +{ + writeat(dc, dc->rva, data, size); + dc->rva += size; +} + +/****************************************************************** + * dump_exception_info + * + * Write in File the exception information from pcs + */ +static void dump_exception_info(struct dump_context* dc, + const MINIDUMP_EXCEPTION_INFORMATION* except) { MINIDUMP_EXCEPTION_STREAM mdExcpt; + EXCEPTION_RECORD rec, *prec; + CONTEXT ctx, *pctx; + int i; - mdExcpt.ThreadId = DEBUG_CurrThread->tid; + mdExcpt.ThreadId = except->ThreadId; mdExcpt.__alignment = 0; - mdExcpt.ExceptionRecord. + if (except->ClientPointers) + { + EXCEPTION_POINTERS ep; - ULONG ExceptionCode; - ULONG ExceptionFlags; - ULONGLONG ExceptionRecord; - ULONGLONG ExceptionAddress; - ULONG NumberParameters; - ULONG __unusedAlignment; - ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + ReadProcessMemory(dc->hProcess, + except->ExceptionPointers, &ep, sizeof(ep), NULL); + ReadProcessMemory(dc->hProcess, + ep.ExceptionRecord, &rec, sizeof(rec), NULL); + ReadProcessMemory(dc->hProcess, + ep.ContextRecord, &ctx, sizeof(ctx), NULL); + prec = &rec; + pctx = &ctx; + + } + else + { + prec = except->ExceptionPointers->ExceptionRecord; + pctx = except->ExceptionPointers->ContextRecord; + } + mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode; + mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags; + mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord; + mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress; + mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters; + mdExcpt.ExceptionRecord.__unusedAlignment = 0; + for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++) + mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i]; + mdExcpt.ThreadContext.DataSize = sizeof(*pctx); + mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt); + + append(dc, &mdExcpt, sizeof(mdExcpt)); + append(dc, pctx, sizeof(*pctx)); } -#endif /****************************************************************** * dump_modules * * Write in File the modules from pcs */ -static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva) +static void dump_modules(struct dump_context* dc, BOOL dump_elf) { MINIDUMP_MODULE mdModule; MINIDUMP_MODULE_LIST mdModuleList; - DWORD written; - struct module* module = NULL; + char tmp[1024]; + MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp; + ULONG i, nmod; + RVA rva_base; + DWORD flags_out; + + for (i = nmod = 0; i < dc->num_module; i++) + { + if ((dc->module[i].is_elf && dump_elf) || (!dc->module[i].is_elf && !dump_elf)) + nmod++; + } mdModuleList.NumberOfModules = 0; - for (module = pcs->lmodules; module; module = module->next) - mdModuleList.NumberOfModules++; - WriteFile(hFile, &mdModuleList.NumberOfModules, - sizeof(mdModuleList.NumberOfModules), &written, NULL); - *rva += sizeof(mdModuleList.NumberOfModules) + - sizeof(mdModule) * mdModuleList.NumberOfModules; - for (module = pcs->lmodules; module; module = module->next) + /* reserve space for mdModuleList + * FIXME: since we don't support 0 length arrays, we cannot use the + * size of mdModuleList + * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file + */ + rva_base = dc->rva; + dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod; + for (i = 0; i < dc->num_module; i++) { - mdModule.BaseOfImage = (DWORD)module->module.BaseOfImage; - mdModule.SizeOfImage = module->module.ImageSize; - mdModule.CheckSum = module->module.CheckSum; - mdModule.TimeDateStamp = module->module.TimeDateStamp; - mdModule.ModuleNameRva = *rva; - *rva += strlen(module->module.ModuleName) + 1; - memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */ - mdModule.CvRecord.DataSize = 0; /* FIXME */ - mdModule.CvRecord.Rva = 0; /* FIXME */ - mdModule.MiscRecord.DataSize = 0; /* FIXME */ - mdModule.MiscRecord.Rva = 0; /* FIXME */ - mdModule.Reserved0 = 0; - mdModule.Reserved1 = 0; - WriteFile(hFile, &mdModule, sizeof(mdModule), &written, NULL); - } - for (module = pcs->lmodules; module; module = module->next) - { - WriteFile(hFile, module->module.ModuleName, - strlen(module->module.ModuleName) + 1, &written, NULL); - FIXME("CV and misc records not written\n"); + if ((dc->module[i].is_elf && !dump_elf) || (!dc->module[i].is_elf && dump_elf)) + continue; + + flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord; + if (dc->type & MiniDumpWithDataSegs) + flags_out |= ModuleWriteDataSeg; + if (dc->type & MiniDumpWithProcessThreadData) + flags_out |= ModuleWriteTlsData; + if (dc->type & MiniDumpWithCodeSegs) + flags_out |= ModuleWriteCodeSegs; + ms->Length = MultiByteToWideChar(CP_ACP, 0, + dc->module[i].name, -1, + NULL, 0) * sizeof(WCHAR); + if (sizeof(ULONG) + ms->Length > sizeof(tmp)) + FIXME("Buffer overflow!!!\n"); + MultiByteToWideChar(CP_ACP, 0, dc->module[i].name, -1, + ms->Buffer, ms->Length); + + if (dc->cb) + { + MINIDUMP_CALLBACK_INPUT cbin; + MINIDUMP_CALLBACK_OUTPUT cbout; + + cbin.ProcessId = dc->pid; + cbin.ProcessHandle = dc->hProcess; + cbin.CallbackType = ModuleCallback; + + cbin.u.Module.FullPath = ms->Buffer; + cbin.u.Module.BaseOfImage = dc->module[i].base; + cbin.u.Module.SizeOfImage = dc->module[i].size; + cbin.u.Module.CheckSum = 0; /* FIXME */ + cbin.u.Module.TimeDateStamp = 0; /* FIXME */ + memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo)); + cbin.u.Module.CvRecord = NULL; + cbin.u.Module.SizeOfCvRecord = 0; + cbin.u.Module.MiscRecord = NULL; + cbin.u.Module.SizeOfMiscRecord = 0; + + cbout.u.ModuleWriteFlags = flags_out; + if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout)) + continue; + flags_out &= cbout.u.ModuleWriteFlags; + } + if (flags_out & ModuleWriteModule) + { + mdModule.BaseOfImage = dc->module[i].base; + mdModule.SizeOfImage = dc->module[i].size; + mdModule.CheckSum = 0; /* FIXME */ + mdModule.TimeDateStamp = 0; /* FIXME */ + mdModule.ModuleNameRva = dc->rva; + ms->Length -= sizeof(WCHAR); + append(dc, ms, sizeof(ULONG) + ms->Length); + memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */ + mdModule.CvRecord.DataSize = 0; /* FIXME */ + mdModule.CvRecord.Rva = 0; /* FIXME */ + mdModule.MiscRecord.DataSize = 0; /* FIXME */ + mdModule.MiscRecord.Rva = 0; /* FIXME */ + mdModule.Reserved0 = 0; /* FIXME */ + mdModule.Reserved1 = 0; /* FIXME */ + writeat(dc, + rva_base + sizeof(mdModuleList.NumberOfModules) + + mdModuleList.NumberOfModules++ * sizeof(mdModule), + &mdModule, sizeof(mdModule)); + } } + writeat(dc, rva_base, &mdModuleList.NumberOfModules, + sizeof(mdModuleList.NumberOfModules)); } /****************************************************************** @@ -99,34 +440,39 @@ static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva) * * Dumps into File the information about the system */ -static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva) +static void dump_system_info(struct dump_context* dc) { MINIDUMP_SYSTEM_INFO mdSysInfo; SYSTEM_INFO sysInfo; - OSVERSIONINFOA osInfo; + OSVERSIONINFOW osInfo; DWORD written; + ULONG slen; GetSystemInfo(&sysInfo); - GetVersionExA(&osInfo); + osInfo.dwOSVersionInfoSize = sizeof(osInfo); + GetVersionExW(&osInfo); mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture; mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel; mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision; - mdSysInfo.Reserved0 = 0; - + mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors; + mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */ mdSysInfo.MajorVersion = osInfo.dwMajorVersion; mdSysInfo.MinorVersion = osInfo.dwMinorVersion; mdSysInfo.BuildNumber = osInfo.dwBuildNumber; mdSysInfo.PlatformId = osInfo.dwPlatformId; - mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo); - mdSysInfo.Reserved1 = 0; + mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo); + mdSysInfo.u1.Reserved1 = 0; - WriteFile(hFile, &mdSysInfo, sizeof(mdSysInfo), &written, NULL); - *rva += sizeof(mdSysInfo); - WriteFile(hFile, osInfo.szCSDVersion, strlen(osInfo.szCSDVersion) + 1, - &written, NULL); - *rva += strlen(osInfo.szCSDVersion) + 1; + memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu)); + + append(dc, &mdSysInfo, sizeof(mdSysInfo)); + + slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR); + WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL); + WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL); + dc->rva += sizeof(ULONG) + slen; } /****************************************************************** @@ -134,36 +480,140 @@ static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva) * * Dumps into File the information about running threads */ -static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva) +static void dump_threads(struct dump_context* dc) { -#if 0 MINIDUMP_THREAD mdThd; MINIDUMP_THREAD_LIST mdThdList; - DWORD written; - DBG_THREAD* thd; + unsigned i; + RVA rva_base; + DWORD flags_out; + CONTEXT ctx; - mdThdList.NumberOfThreads = pcs->num_threads; - WriteFile(hFile, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads), - &written, NULL); - *rva += sizeof(mdThdList.NumberOfThreads) + - mdThdList.NumberOfThreads * sizeof(mdThd); - for (thd = pcs->threads; thd; thd = thd->next) + mdThdList.NumberOfThreads = 0; + + rva_base = dc->rva; + dc->rva += sizeof(mdThdList.NumberOfThreads) + + dc->spi->dwThreadCount * sizeof(mdThd); + + for (i = 0; i < dc->spi->dwThreadCount; i++) { - mdThd.ThreadId = thd->tid; - mdThd.SuspendCount = 0; /* FIXME */ - mdThd.PriorityClass = 0; /* FIXME */ - mdThd.Priority = 0; /* FIXME */ - mdThd.Teb = 0; /* FIXME */ - mdThd.Stack.StartOfMemoryRange = 0; /* FIXME */ - mdThd.Stack.Memory.DataSize = 0; /* FIXME */ - mdThd.Stack.Memory.Rva = 0; /* FIXME */ - mdThd.ThreadContext.DataSize = 0;/* FIXME */ - mdThd.ThreadContext.Rva = 0; /* FIXME */ + fetch_thread_info(dc, i, &mdThd, &ctx); - WriteFile(hFile, &mdThd, sizeof(mdThd), &written, NULL); - FIXME("Stack & thread context not written\n"); + flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext | + ThreadWriteInstructionWindow; + if (dc->type & MiniDumpWithProcessThreadData) + flags_out |= ThreadWriteThreadData; + if (dc->type & MiniDumpWithThreadInfo) + flags_out |= ThreadWriteThreadInfo; + + if (dc->cb) + { + MINIDUMP_CALLBACK_INPUT cbin; + MINIDUMP_CALLBACK_OUTPUT cbout; + + cbin.ProcessId = dc->pid; + cbin.ProcessHandle = dc->hProcess; + cbin.CallbackType = ThreadCallback; + cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID; + cbin.u.Thread.ThreadHandle = 0; /* FIXME */ + memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT)); + cbin.u.Thread.SizeOfContext = sizeof(CONTEXT); + cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange; + cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange + + mdThd.Stack.Memory.DataSize; + + cbout.u.ThreadWriteFlags = flags_out; + if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout)) + continue; + flags_out &= cbout.u.ThreadWriteFlags; + } + if (flags_out & ThreadWriteThread) + { + if (ctx.ContextFlags && (flags_out & ThreadWriteContext)) + { + mdThd.ThreadContext.Rva = dc->rva; + mdThd.ThreadContext.DataSize = sizeof(CONTEXT); + append(dc, &ctx, sizeof(CONTEXT)); + } + if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack)) + { + add_memory_block(dc, mdThd.Stack.StartOfMemoryRange, + mdThd.Stack.Memory.DataSize, + rva_base + sizeof(mdThdList.NumberOfThreads) + + mdThdList.NumberOfThreads * sizeof(mdThd) + + FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva)); + } + writeat(dc, + rva_base + sizeof(mdThdList.NumberOfThreads) + + mdThdList.NumberOfThreads * sizeof(mdThd), + &mdThd, sizeof(mdThd)); + mdThdList.NumberOfThreads++; + } + if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow)) + { + /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP + * - also crop values across module boundaries, + * - and don't make it i386 dependent + */ + /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */ + } } -#endif + writeat(dc, rva_base, + &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads)); +} + +/****************************************************************** + * dump_memory_info + * + * dumps information about the memory of the process (stack of the threads) + */ +static void dump_memory_info(struct dump_context* dc) +{ + MINIDUMP_MEMORY_LIST mdMemList; + MINIDUMP_MEMORY_DESCRIPTOR mdMem; + DWORD written; + unsigned i, pos, len; + RVA rva_base; + char tmp[1024]; + + mdMemList.NumberOfMemoryRanges = dc->num_mem; + append(dc, &mdMemList.NumberOfMemoryRanges, + sizeof(mdMemList.NumberOfMemoryRanges)); + rva_base = dc->rva; + dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem); + + for (i = 0; i < dc->num_mem; i++) + { + mdMem.StartOfMemoryRange = dc->mem[i].base; + mdMem.Memory.Rva = dc->rva; + mdMem.Memory.DataSize = dc->mem[i].size; + SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN); + for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp)) + { + len = min(dc->mem[i].size - pos, sizeof(tmp)); + if (ReadProcessMemory(dc->hProcess, + (void*)(ULONG)(dc->mem[i].base + pos), + tmp, len, NULL)) + WriteFile(dc->hFile, tmp, len, &written, NULL); + } + dc->rva += mdMem.Memory.DataSize; + writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem)); + if (dc->mem[i].rva) + { + writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva)); + } + } +} + +static void dump_misc_info(struct dump_context* dc) +{ + MINIDUMP_MISC_INFO mmi; + + mmi.SizeOfInfo = sizeof(mmi); + mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID; + mmi.ProcessId = dc->pid; + /* FIXME: create/user/kernel time */ + append(dc, &mmi, sizeof(mmi)); } /****************************************************************** @@ -171,28 +621,34 @@ static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva) * * */ -BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, +BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam) { - struct process* pcs; MINIDUMP_HEADER mdHead; MINIDUMP_DIRECTORY mdDir; - DWORD currRva, written; - DWORD i, nStream, addStream; - RVA rva; + DWORD i, nStreams, idx_stream; + struct dump_context dc; - pcs = process_find_by_handle(hProcess); - if (!pcs) return FALSE; /* FIXME: should try to load it ??? */ + dc.hProcess = hProcess; + dc.hFile = hFile; + dc.pid = pid; + dc.module = NULL; + dc.num_module = 0; + dc.cb = CallbackParam; + dc.type = DumpType; + dc.mem = NULL; + dc.num_mem = 0; + dc.rva = 0; + + if (!fetch_process_info(&dc)) return FALSE; + fetch_module_info(&dc); /* 1) init */ - - nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0; - addStream = 0; - if (DumpType & MiniDumpNormal) - addStream += 3; /* sure ? thread stack back trace */ + nStreams = 6 + (ExceptionParam ? 1 : 0) + + (UserStreamParam ? UserStreamParam->UserStreamCount : 0); if (DumpType & MiniDumpWithDataSegs) FIXME("NIY MiniDumpWithDataSegs\n"); @@ -206,61 +662,123 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, FIXME("NIY MiniDumpScanMemory\n"); /* 2) write header */ - rva = sizeof(mdHead); mdHead.Signature = MINIDUMP_SIGNATURE; mdHead.Version = MINIDUMP_VERSION; - mdHead.NumberOfStreams = nStream + addStream; - mdHead.StreamDirectoryRva = rva; + mdHead.NumberOfStreams = nStreams; + mdHead.StreamDirectoryRva = sizeof(mdHead); mdHead.u.TimeDateStamp = time(NULL); mdHead.Flags = DumpType; - WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL); - + append(&dc, &mdHead, sizeof(mdHead)); + /* 3) write stream directories */ - rva += (nStream + addStream) * sizeof(mdDir); + dc.rva += nStreams * sizeof(mdDir); + idx_stream = 0; + /* 3.1) write data stream directories */ - currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - SetFilePointer(hFile, rva, NULL, FILE_BEGIN); - mdDir.StreamType = ModuleListStream; - mdDir.Location.Rva = rva; - dump_modules(pcs, hFile, &rva); - mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva; - SetFilePointer(hFile, currRva, NULL, FILE_BEGIN); - WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL); - currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - SetFilePointer(hFile, rva, NULL, FILE_BEGIN); mdDir.StreamType = ThreadListStream; - mdDir.Location.Rva = rva; - dump_threads(pcs, hFile, &rva); - mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva; - SetFilePointer(hFile, currRva, NULL, FILE_BEGIN); - WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL); + mdDir.Location.Rva = dc.rva; + dump_threads(&dc); + mdDir.Location.DataSize = 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); + mdDir.Location.DataSize = 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); + mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); + + mdDir.StreamType = MemoryListStream; + mdDir.Location.Rva = dc.rva; + dump_memory_info(&dc); + mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); - currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - SetFilePointer(hFile, rva, NULL, FILE_BEGIN); mdDir.StreamType = SystemInfoStream; - mdDir.Location.Rva = rva; - dump_system_info(pcs, hFile, &rva); - mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva; - SetFilePointer(hFile, currRva, NULL, FILE_BEGIN); - WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL); + mdDir.Location.Rva = dc.rva; + dump_system_info(&dc); + mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); - /* 3.2) write user define stream */ - for (i = 0; i < nStream; i++) + mdDir.StreamType = MiscInfoStream; + mdDir.Location.Rva = dc.rva; + dump_misc_info(&dc); + mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); + + /* 3.2) write exception information (if any) */ + if (ExceptionParam) { - mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type; - mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize; - mdDir.Location.Rva = rva; - WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL); - currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - SetFilePointer(hFile, rva, NULL, FILE_BEGIN); - WriteFile(hFile, - UserStreamParam->UserStreamArray[i].Buffer, - UserStreamParam->UserStreamArray[i].BufferSize, - &written, NULL); - rva += UserStreamParam->UserStreamArray[i].BufferSize; - SetFilePointer(hFile, currRva, NULL, FILE_BEGIN); + mdDir.StreamType = ExceptionStream; + mdDir.Location.Rva = dc.rva; + dump_exception_info(&dc, ExceptionParam); + mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); } + /* 3.3) write user defined streams (if any) */ + if (UserStreamParam) + { + for (i = 0; i < UserStreamParam->UserStreamCount; i++) + { + mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type; + mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize; + mdDir.Location.Rva = dc.rva; + writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + &mdDir, sizeof(mdDir)); + append(&dc, UserStreamParam->UserStreamArray[i].Buffer, + UserStreamParam->UserStreamArray[i].BufferSize); + } + } + + HeapFree(GetProcessHeap(), 0, dc.pcs_buffer); + HeapFree(GetProcessHeap(), 0, dc.mem); + HeapFree(GetProcessHeap(), 0, dc.module); + return TRUE; } + +/****************************************************************** + * MiniDumpReadDumpStream (DEBUGHLP.@) + * + * + */ +BOOL WINAPI MiniDumpReadDumpStream(void* base, ULONG str_idx, + PMINIDUMP_DIRECTORY* pdir, + void** stream, ULONG* size) +{ + MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base; + + if (mdHead->Signature == MINIDUMP_SIGNATURE) + { + MINIDUMP_DIRECTORY* dir; + int i; + + dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva); + for (i = 0; i < mdHead->NumberOfStreams; i++, dir++) + { + if (dir->StreamType == str_idx) + { + *pdir = dir; + *stream = (char*)base + dir->Location.Rva; + *size = dir->Location.DataSize; + return TRUE; + } + } + } + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; +} diff --git a/include/dbghelp.h b/include/dbghelp.h index 45c64c90be1..aa7bff3593b 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -250,7 +250,7 @@ typedef struct _DBGHELP_MODLOAD_DATA /* DebugHelp */ -#define MINIDUMP_SIGNATURE 0x4D444D50 /* 'PMDM' */ +#define MINIDUMP_SIGNATURE 0x504D444D /* 'MDMP' */ #define MINIDUMP_VERSION (42899) typedef DWORD RVA; @@ -258,12 +258,21 @@ typedef ULONG64 RVA64; typedef enum _MINIDUMP_TYPE { - MiniDumpNormal = 0x0000, - MiniDumpWithDataSegs = 0x0001, - MiniDumpWithFullMemory = 0x0002, - MiniDumpWithHandleData = 0x0004, - MiniDumpFilterMemory = 0x0008, - MiniDumpScanMemory = 0x0010 + MiniDumpNormal = 0x0000, + MiniDumpWithDataSegs = 0x0001, + MiniDumpWithFullMemory = 0x0002, + MiniDumpWithHandleData = 0x0004, + MiniDumpFilterMemory = 0x0008, + MiniDumpScanMemory = 0x0010, + MiniDumpWithUnloadedModules = 0x0020, + MiniDumpWithIndirectlyReferencedMemory = 0x0040, + MiniDumpFilterModulePaths = 0x0080, + MiniDumpWithProcessThreadData = 0x0100, + MiniDumpWithPrivateReadWriteMemory = 0x0200, + MiniDumpWithoutOptionalData = 0x0400, + MiniDumpWithFullMemoryInfo = 0x0800, + MiniDumpWithThreadInfo = 0x1000, + MiniDumpWithCodeSegs = 0x2000 } MINIDUMP_TYPE; typedef enum _MINIDUMP_CALLBACK_TYPE @@ -273,6 +282,7 @@ typedef enum _MINIDUMP_CALLBACK_TYPE ThreadExCallback, IncludeThreadCallback, IncludeModuleCallback, + MemoryCallback, } MINIDUMP_CALLBACK_TYPE; typedef struct _MINIDUMP_THREAD_CALLBACK @@ -281,7 +291,7 @@ typedef struct _MINIDUMP_THREAD_CALLBACK HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; - ULONGLONG StackBase; + ULONG64 StackBase; ULONG64 StackEnd; } MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK; @@ -291,10 +301,10 @@ typedef struct _MINIDUMP_THREAD_EX_CALLBACK HANDLE ThreadHandle; CONTEXT Context; ULONG SizeOfContext; - ULONGLONG StackBase; - ULONGLONG StackEnd; - ULONGLONG BackingStoreBase; - ULONGLONG BackingStoreEnd; + ULONG64 StackBase; + ULONG64 StackEnd; + ULONG64 BackingStoreBase; + ULONG64 BackingStoreEnd; } MINIDUMP_THREAD_EX_CALLBACK, *PMINIDUMP_THREAD_EX_CALLBACK; typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK @@ -308,13 +318,15 @@ typedef enum _THREAD_WRITE_FLAGS ThreadWriteStack = 0x0002, ThreadWriteContext = 0x0004, ThreadWriteBackingStore = 0x0008, - ThreadWriteInstructionWindow = 0x0010 + ThreadWriteInstructionWindow = 0x0010, + ThreadWriteThreadData = 0x0020, + ThreadWriteThreadInfo = 0x0040 } THREAD_WRITE_FLAGS; typedef struct _MINIDUMP_MODULE_CALLBACK { PWCHAR FullPath; - ULONGLONG BaseOfImage; + ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; @@ -336,7 +348,9 @@ typedef enum _MODULE_WRITE_FLAGS ModuleWriteDataSeg = 0x0002, ModuleWriteMiscRecord = 0x0004, ModuleWriteCvRecord = 0x0008, - ModuleReferencedByMemory = 0x0010 + ModuleReferencedByMemory = 0x0010, + ModuleWriteTlsData = 0x0020, + ModuleWriteCodeSegs = 0x0040, } MODULE_WRITE_FLAGS; typedef struct _MINIDUMP_CALLBACK_INPUT @@ -351,7 +365,7 @@ typedef struct _MINIDUMP_CALLBACK_INPUT MINIDUMP_MODULE_CALLBACK Module; MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; - } u; + } DUMMYUNIONNAME; } MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT; typedef struct _MINIDUMP_CALLBACK_OUTPUT @@ -360,12 +374,15 @@ typedef struct _MINIDUMP_CALLBACK_OUTPUT { ULONG ModuleWriteFlags; ULONG ThreadWriteFlags; - } u; + struct + { + ULONG64 MemoryBase; + ULONG MemorySize; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; } MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT; -typedef BOOL (WINAPI* MINIDUMP_CALLBACK_ROUTINE)(PVOID CallbackParam, - const PMINIDUMP_CALLBACK_INPUT CallbackInput, - PMINIDUMP_CALLBACK_OUTPUT CallbackOutput); +typedef BOOL (WINAPI* MINIDUMP_CALLBACK_ROUTINE)(PVOID, const PMINIDUMP_CALLBACK_INPUT, PMINIDUMP_CALLBACK_OUTPUT); typedef struct _MINIDUMP_CALLBACK_INFORMATION { @@ -389,11 +406,11 @@ typedef struct _MINIDUMP_EXCEPTION { ULONG ExceptionCode; ULONG ExceptionFlags; - ULONGLONG ExceptionRecord; - ULONGLONG ExceptionAddress; + ULONG64 ExceptionRecord; + ULONG64 ExceptionAddress; ULONG NumberParameters; ULONG __unusedAlignment; - ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + ULONG64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } MINIDUMP_EXCEPTION, *PMINIDUMP_EXCEPTION; typedef struct _MINIDUMP_EXCEPTION_INFORMATION @@ -422,19 +439,38 @@ typedef struct _MINIDUMP_HEADER { DWORD Reserved; DWORD TimeDateStamp; - } u; - ULONGLONG Flags; + } DUMMYUNIONNAME; + ULONG64 Flags; } MINIDUMP_HEADER, *PMINIDUMP_HEADER; typedef struct _MINIDUMP_MEMORY_DESCRIPTOR { - ULONGLONG StartOfMemoryRange; + ULONG64 StartOfMemoryRange; MINIDUMP_LOCATION_DESCRIPTOR Memory; } MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR; +typedef struct _MINIDUMP_MEMORY_LIST +{ + ULONG NumberOfMemoryRanges; + MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges[1]; /* FIXME: 0-sized array not supported */ +} MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST; + +#define MINIDUMP_MISC1_PROCESS_ID 0x00000001 +#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002 + +typedef struct _MINIDUMP_MISC_INFO +{ + ULONG SizeOfInfo; + ULONG Flags1; + ULONG ProcessId; + ULONG ProcessCreateTime; + ULONG ProcessUserTime; + ULONG ProcessKernelTime; +} MINIDUMP_MISC_INFO, *PMINIDUMP_MISC_INFO; + typedef struct _MINIDUMP_MODULE { - ULONGLONG BaseOfImage; + ULONG64 BaseOfImage; ULONG SizeOfImage; ULONG CheckSum; ULONG TimeDateStamp; @@ -442,8 +478,8 @@ typedef struct _MINIDUMP_MODULE VS_FIXEDFILEINFO VersionInfo; MINIDUMP_LOCATION_DESCRIPTOR CvRecord; MINIDUMP_LOCATION_DESCRIPTOR MiscRecord; - ULONGLONG Reserved0; - ULONGLONG Reserved1; + ULONG64 Reserved0; + ULONG64 Reserved1; } MINIDUMP_MODULE, *PMINIDUMP_MODULE; typedef struct _MINIDUMP_MODULE_LIST @@ -452,6 +488,76 @@ typedef struct _MINIDUMP_MODULE_LIST MINIDUMP_MODULE Modules[1]; /* FIXME: 0-sized array not supported */ } MINIDUMP_MODULE_LIST, *PMINIDUMP_MODULE_LIST; +typedef struct _MINIDUMP_STRING +{ + ULONG Length; + WCHAR Buffer[1]; /* FIXME: O-sized array not supported */ +} MINIDUMP_STRING, *PMINIDUMP_STRING; + +typedef struct _MINIDUMP_SYSTEM_INFO +{ + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + union + { + USHORT Reserved0; + struct + { + UCHAR NumberOfProcessors; + UCHAR ProductType; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + + ULONG MajorVersion; + ULONG MinorVersion; + ULONG BuildNumber; + ULONG PlatformId; + + RVA CSDVersionRva; + union + { + ULONG Reserved1; + struct + { + USHORT SuiteMask; + USHORT Reserved2; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME1; + union _CPU_INFORMATION + { + struct + { + ULONG VendorId[3]; + ULONG VersionInformation; + ULONG FeatureInformation; + ULONG AMDExtendedCpuFeatures; + } X86CpuInfo; + struct + { + ULONG64 ProcessorFeatures[2]; + } OtherCpuInfo; + } Cpu; + +} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO; + +typedef struct _MINIDUMP_THREAD +{ + ULONG ThreadId; + ULONG SuspendCount; + ULONG PriorityClass; + ULONG Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; +} MINIDUMP_THREAD, *PMINIDUMP_THREAD; + +typedef struct _MINIDUMP_THREAD_LIST +{ + ULONG NumberOfThreads; + MINIDUMP_THREAD Threads[1]; /* FIXME: no support of 0 sized array */ +} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST; + typedef struct _MINIDUMP_USER_STREAM { ULONG Type; @@ -481,61 +587,20 @@ typedef enum _MINIDUMP_STREAM_TYPE CommentStreamW = 11, HandleDataStream = 12, FunctionTableStream = 13, + UnloadedModuleListStream = 14, + MiscInfoStream = 15, + MemoryInfoListStream = 16, + ThreadInfoListStream = 17, LastReservedStream = 0xffff } MINIDUMP_STREAM_TYPE; -typedef struct _MINIDUMP_SYSTEM_INFO -{ - USHORT ProcessorArchitecture; - USHORT ProcessorLevel; - USHORT ProcessorRevision; - USHORT Reserved0; - - ULONG MajorVersion; - ULONG MinorVersion; - ULONG BuildNumber; - ULONG PlatformId; - - RVA CSDVersionRva; - ULONG Reserved1; - union _CPU_INFORMATION - { - struct - { - ULONG VendorId[3]; - ULONG VersionInformation; - ULONG FeatureInformation; - ULONG AMDExtendedCpuFeatures; - } X86CpuInfo; - struct - { - ULONGLONG ProcessorFeatures[2]; - } OtherCpuInfo; - } Cpu; - -} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO; - -typedef struct _MINIDUMP_THREAD -{ - ULONG ThreadId; - ULONG SuspendCount; - ULONG PriorityClass; - ULONG Priority; - ULONGLONG Teb; - MINIDUMP_MEMORY_DESCRIPTOR Stack; - MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; -} MINIDUMP_THREAD, *PMINIDUMP_THREAD; - -typedef struct _MINIDUMP_THREAD_LIST -{ - ULONG NumberOfThreads; - MINIDUMP_THREAD Threads[1]; /* FIXME: no support of 0 sized array */ -} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST; - -BOOL WINAPI MiniDumpWriteDump(HANDLE,DWORD,HANDLE,MINIDUMP_TYPE,const PMINIDUMP_EXCEPTION_INFORMATION, - const PMINIDUMP_USER_STREAM_INFORMATION,const PMINIDUMP_CALLBACK_INFORMATION); -BOOL WINAPI MiniDumpReadDumpStream(PVOID,ULONG,PMINIDUMP_DIRECTORY*,PVOID*,ULONG*); +BOOL WINAPI MiniDumpWriteDump(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, + const PMINIDUMP_EXCEPTION_INFORMATION, + const PMINIDUMP_USER_STREAM_INFORMATION, + const PMINIDUMP_CALLBACK_INFORMATION); +BOOL WINAPI MiniDumpReadDumpStream(PVOID, ULONG, PMINIDUMP_DIRECTORY*, PVOID*, + ULONG*); /*************************