2 * File minidump.c - management of dumps (read & write)
4 * Copyright (C) 2004-2005, Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
26 #include "dbghelp_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
55 /* process & thread information */
59 SYSTEM_PROCESS_INFORMATION* spi;
60 /* module information */
61 struct dump_module* module;
63 /* exception information */
64 /* output information */
68 struct dump_memory* mem;
70 /* callback information */
71 MINIDUMP_CALLBACK_INFORMATION* cb;
74 /******************************************************************
77 * reads system wide process information, and make spi point to the record
78 * for process of id 'pid'
80 static BOOL fetch_process_info(struct dump_context* dc)
82 ULONG buf_size = 0x1000;
85 dc->pcs_buffer = NULL;
86 if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
89 nts = NtQuerySystemInformation(SystemProcessInformation,
90 dc->pcs_buffer, buf_size, NULL);
91 if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
92 dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
94 if (!dc->pcs_buffer) return FALSE;
97 if (nts == STATUS_SUCCESS)
99 dc->spi = dc->pcs_buffer;
102 if (dc->spi->dwProcessID == dc->pid) return TRUE;
103 if (!dc->spi->dwOffset) break;
104 dc->spi = (SYSTEM_PROCESS_INFORMATION*)
105 ((char*)dc->spi + dc->spi->dwOffset);
108 HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
109 dc->pcs_buffer = NULL;
114 /******************************************************************
117 * fetches some information about thread of id 'tid'
119 static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
120 MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
123 DWORD tid = dc->spi->ti[thd_idx].dwThreadID;
125 THREAD_BASIC_INFORMATION tbi;
127 memset(ctx, 0, sizeof(*ctx));
129 mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
130 mdThd->SuspendCount = 0;
132 mdThd->Stack.StartOfMemoryRange = 0;
133 mdThd->Stack.Memory.DataSize = 0;
134 mdThd->Stack.Memory.Rva = 0;
135 mdThd->ThreadContext.DataSize = 0;
136 mdThd->ThreadContext.Rva = 0;
137 mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
138 mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
140 if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
142 FIXME("Couldn't open thread %lu (%lu)\n",
143 dc->spi->ti[thd_idx].dwThreadID, GetLastError());
147 if (NtQueryInformationThread(hThread, ThreadBasicInformation,
148 &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
150 mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
151 if (tbi.ExitStatus == STILL_ACTIVE && tid != GetCurrentThreadId() &&
152 (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
154 mdThd->SuspendCount--;
155 ctx->ContextFlags = CONTEXT_FULL;
156 if (!GetThreadContext(hThread, ctx))
157 memset(ctx, 0, sizeof(*ctx));
159 if (ReadProcessMemory(dc->hProcess, tbi.TebBaseAddress,
160 &tib, sizeof(tib), NULL))
163 /* limiting the stack dumping to the size actually used */
165 mdThd->Stack.StartOfMemoryRange = (ctx->Esp - 4);
167 mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
168 mdThd->Stack.Memory.DataSize = (ULONG_PTR)tib.StackBase -
169 mdThd->Stack.StartOfMemoryRange;
171 #error unsupported CPU
174 ResumeThread(hThread);
177 CloseHandle(hThread);
181 /******************************************************************
184 * Add a module to a dump context
186 static BOOL add_module(struct dump_context* dc, const char* name,
187 DWORD base, DWORD size, DWORD timestamp, DWORD checksum,
191 dc->module = HeapAlloc(GetProcessHeap(), 0,
192 ++dc->num_module * sizeof(*dc->module));
194 dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module,
195 ++dc->num_module * sizeof(*dc->module));
196 if (!dc->module) return FALSE;
198 !GetModuleFileNameExA(dc->hProcess, (HMODULE)base,
199 dc->module[dc->num_module - 1].name,
200 sizeof(dc->module[dc->num_module - 1].name)))
201 lstrcpynA(dc->module[dc->num_module - 1].name, name,
202 sizeof(dc->module[dc->num_module - 1].name));
203 dc->module[dc->num_module - 1].base = base;
204 dc->module[dc->num_module - 1].size = size;
205 dc->module[dc->num_module - 1].timestamp = timestamp;
206 dc->module[dc->num_module - 1].checksum = checksum;
207 dc->module[dc->num_module - 1].is_elf = is_elf;
212 /******************************************************************
213 * fetch_pe_module_info_cb
215 * Callback for accumulating in dump_context a PE modules set
217 static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size,
220 struct dump_context* dc = (struct dump_context*)user;
221 IMAGE_NT_HEADERS nth;
223 if (pe_load_nt_header(dc->hProcess, base, &nth))
224 add_module((struct dump_context*)user, name, base, size,
225 nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
230 /******************************************************************
231 * fetch_elf_module_info_cb
233 * Callback for accumulating in dump_context an ELF modules set
235 static BOOL fetch_elf_module_info_cb(const char* name, unsigned long base,
238 struct dump_context* dc = (struct dump_context*)user;
239 DWORD size, checksum;
241 /* FIXME: there's no relevant timestamp on ELF modules */
242 /* NB: if we have a non-null base from the live-target use it (whenever
243 * the ELF module is relocatable or not). If we have a null base (ELF
244 * module isn't relocatable) then grab its base address from ELF file
246 if (!elf_fetch_file_info(name, base ? NULL : &base, &size, &checksum))
248 add_module(dc, name, base, size, 0 /* FIXME */, checksum, TRUE);
252 static void fetch_module_info(struct dump_context* dc)
254 EnumerateLoadedModules(dc->hProcess, fetch_pe_module_info_cb, dc);
255 /* Since we include ELF modules in a separate stream from the regular PE ones,
256 * we can always include those ELF modules (they don't eat lots of space)
257 * And it's always a good idea to have a trace of the loaded ELF modules for
258 * a given application in a post mortem debugging condition.
260 elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
263 /******************************************************************
266 * Add a memory block to be dumped in a minidump
267 * If rva is non 0, it's the rva in the minidump where has to be stored
268 * also the rva of the memory block when written (this allows to reference
269 * a memory block from outside the list of memory blocks).
271 static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
274 dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
275 ++dc->num_mem * sizeof(*dc->mem));
277 dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
280 dc->mem[dc->num_mem - 1].base = base;
281 dc->mem[dc->num_mem - 1].size = size;
282 dc->mem[dc->num_mem - 1].rva = rva;
284 else dc->num_mem = 0;
287 /******************************************************************
290 * Writes a chunk of data at a given position in the minidump
292 static void writeat(struct dump_context* dc, RVA rva, void* data, unsigned size)
296 SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
297 WriteFile(dc->hFile, data, size, &written, NULL);
300 /******************************************************************
303 * writes a new chunk of data to the minidump, increasing the current
306 static void append(struct dump_context* dc, void* data, unsigned size)
308 writeat(dc, dc->rva, data, size);
312 /******************************************************************
313 * dump_exception_info
315 * Write in File the exception information from pcs
317 static void dump_exception_info(struct dump_context* dc,
318 const MINIDUMP_EXCEPTION_INFORMATION* except)
320 MINIDUMP_EXCEPTION_STREAM mdExcpt;
321 EXCEPTION_RECORD rec, *prec;
325 mdExcpt.ThreadId = except->ThreadId;
326 mdExcpt.__alignment = 0;
327 if (except->ClientPointers)
329 EXCEPTION_POINTERS ep;
331 ReadProcessMemory(dc->hProcess,
332 except->ExceptionPointers, &ep, sizeof(ep), NULL);
333 ReadProcessMemory(dc->hProcess,
334 ep.ExceptionRecord, &rec, sizeof(rec), NULL);
335 ReadProcessMemory(dc->hProcess,
336 ep.ContextRecord, &ctx, sizeof(ctx), NULL);
343 prec = except->ExceptionPointers->ExceptionRecord;
344 pctx = except->ExceptionPointers->ContextRecord;
346 mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
347 mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
348 mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
349 mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
350 mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
351 mdExcpt.ExceptionRecord.__unusedAlignment = 0;
352 for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
353 mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
354 mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
355 mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
357 append(dc, &mdExcpt, sizeof(mdExcpt));
358 append(dc, pctx, sizeof(*pctx));
361 /******************************************************************
364 * Write in File the modules from pcs
366 static void dump_modules(struct dump_context* dc, BOOL dump_elf)
368 MINIDUMP_MODULE mdModule;
369 MINIDUMP_MODULE_LIST mdModuleList;
371 MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp;
376 for (i = nmod = 0; i < dc->num_module; i++)
378 if ((dc->module[i].is_elf && dump_elf) ||
379 (!dc->module[i].is_elf && !dump_elf))
383 mdModuleList.NumberOfModules = 0;
384 /* reserve space for mdModuleList
385 * FIXME: since we don't support 0 length arrays, we cannot use the
386 * size of mdModuleList
387 * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
390 dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
391 for (i = 0; i < dc->num_module; i++)
393 if ((dc->module[i].is_elf && !dump_elf) ||
394 (!dc->module[i].is_elf && dump_elf))
397 flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
398 if (dc->type & MiniDumpWithDataSegs)
399 flags_out |= ModuleWriteDataSeg;
400 if (dc->type & MiniDumpWithProcessThreadData)
401 flags_out |= ModuleWriteTlsData;
402 if (dc->type & MiniDumpWithCodeSegs)
403 flags_out |= ModuleWriteCodeSegs;
404 ms->Length = MultiByteToWideChar(CP_ACP, 0,
405 dc->module[i].name, -1,
406 NULL, 0) * sizeof(WCHAR);
407 if (sizeof(ULONG) + ms->Length > sizeof(tmp))
408 FIXME("Buffer overflow!!!\n");
409 MultiByteToWideChar(CP_ACP, 0, dc->module[i].name, -1,
410 ms->Buffer, ms->Length);
414 MINIDUMP_CALLBACK_INPUT cbin;
415 MINIDUMP_CALLBACK_OUTPUT cbout;
417 cbin.ProcessId = dc->pid;
418 cbin.ProcessHandle = dc->hProcess;
419 cbin.CallbackType = ModuleCallback;
421 cbin.u.Module.FullPath = ms->Buffer;
422 cbin.u.Module.BaseOfImage = dc->module[i].base;
423 cbin.u.Module.SizeOfImage = dc->module[i].size;
424 cbin.u.Module.CheckSum = dc->module[i].checksum;
425 cbin.u.Module.TimeDateStamp = dc->module[i].timestamp;
426 memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
427 cbin.u.Module.CvRecord = NULL;
428 cbin.u.Module.SizeOfCvRecord = 0;
429 cbin.u.Module.MiscRecord = NULL;
430 cbin.u.Module.SizeOfMiscRecord = 0;
432 cbout.u.ModuleWriteFlags = flags_out;
433 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
435 flags_out &= cbout.u.ModuleWriteFlags;
437 if (flags_out & ModuleWriteModule)
439 mdModule.BaseOfImage = dc->module[i].base;
440 mdModule.SizeOfImage = dc->module[i].size;
441 mdModule.CheckSum = dc->module[i].checksum;
442 mdModule.TimeDateStamp = dc->module[i].timestamp;
443 mdModule.ModuleNameRva = dc->rva;
444 ms->Length -= sizeof(WCHAR);
445 append(dc, ms, sizeof(ULONG) + ms->Length);
446 memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
447 mdModule.CvRecord.DataSize = 0; /* FIXME */
448 mdModule.CvRecord.Rva = 0; /* FIXME */
449 mdModule.MiscRecord.DataSize = 0; /* FIXME */
450 mdModule.MiscRecord.Rva = 0; /* FIXME */
451 mdModule.Reserved0 = 0; /* FIXME */
452 mdModule.Reserved1 = 0; /* FIXME */
454 rva_base + sizeof(mdModuleList.NumberOfModules) +
455 mdModuleList.NumberOfModules++ * sizeof(mdModule),
456 &mdModule, sizeof(mdModule));
459 writeat(dc, rva_base, &mdModuleList.NumberOfModules,
460 sizeof(mdModuleList.NumberOfModules));
463 /******************************************************************
466 * Dumps into File the information about the system
468 static void dump_system_info(struct dump_context* dc)
470 MINIDUMP_SYSTEM_INFO mdSysInfo;
472 OSVERSIONINFOW osInfo;
476 GetSystemInfo(&sysInfo);
477 osInfo.dwOSVersionInfoSize = sizeof(osInfo);
478 GetVersionExW(&osInfo);
480 mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
481 mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
482 mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
483 mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
484 mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
485 mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
486 mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
487 mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
488 mdSysInfo.PlatformId = osInfo.dwPlatformId;
490 mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
491 mdSysInfo.u1.Reserved1 = 0;
493 memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));
495 append(dc, &mdSysInfo, sizeof(mdSysInfo));
497 slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
498 WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
499 WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
500 dc->rva += sizeof(ULONG) + slen;
503 /******************************************************************
506 * Dumps into File the information about running threads
508 static void dump_threads(struct dump_context* dc)
510 MINIDUMP_THREAD mdThd;
511 MINIDUMP_THREAD_LIST mdThdList;
517 mdThdList.NumberOfThreads = 0;
520 dc->rva += sizeof(mdThdList.NumberOfThreads) +
521 dc->spi->dwThreadCount * sizeof(mdThd);
523 for (i = 0; i < dc->spi->dwThreadCount; i++)
525 fetch_thread_info(dc, i, &mdThd, &ctx);
527 flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
528 ThreadWriteInstructionWindow;
529 if (dc->type & MiniDumpWithProcessThreadData)
530 flags_out |= ThreadWriteThreadData;
531 if (dc->type & MiniDumpWithThreadInfo)
532 flags_out |= ThreadWriteThreadInfo;
536 MINIDUMP_CALLBACK_INPUT cbin;
537 MINIDUMP_CALLBACK_OUTPUT cbout;
539 cbin.ProcessId = dc->pid;
540 cbin.ProcessHandle = dc->hProcess;
541 cbin.CallbackType = ThreadCallback;
542 cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
543 cbin.u.Thread.ThreadHandle = 0; /* FIXME */
544 memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
545 cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
546 cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
547 cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
548 mdThd.Stack.Memory.DataSize;
550 cbout.u.ThreadWriteFlags = flags_out;
551 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
553 flags_out &= cbout.u.ThreadWriteFlags;
555 if (flags_out & ThreadWriteThread)
557 if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
559 mdThd.ThreadContext.Rva = dc->rva;
560 mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
561 append(dc, &ctx, sizeof(CONTEXT));
563 if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
565 add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
566 mdThd.Stack.Memory.DataSize,
567 rva_base + sizeof(mdThdList.NumberOfThreads) +
568 mdThdList.NumberOfThreads * sizeof(mdThd) +
569 FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
572 rva_base + sizeof(mdThdList.NumberOfThreads) +
573 mdThdList.NumberOfThreads * sizeof(mdThd),
574 &mdThd, sizeof(mdThd));
575 mdThdList.NumberOfThreads++;
577 if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
579 /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
580 * - also crop values across module boundaries,
581 * - and don't make it i386 dependent
583 /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
586 writeat(dc, rva_base,
587 &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
590 /******************************************************************
593 * dumps information about the memory of the process (stack of the threads)
595 static void dump_memory_info(struct dump_context* dc)
597 MINIDUMP_MEMORY_LIST mdMemList;
598 MINIDUMP_MEMORY_DESCRIPTOR mdMem;
600 unsigned i, pos, len;
604 mdMemList.NumberOfMemoryRanges = dc->num_mem;
605 append(dc, &mdMemList.NumberOfMemoryRanges,
606 sizeof(mdMemList.NumberOfMemoryRanges));
608 dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
610 for (i = 0; i < dc->num_mem; i++)
612 mdMem.StartOfMemoryRange = dc->mem[i].base;
613 mdMem.Memory.Rva = dc->rva;
614 mdMem.Memory.DataSize = dc->mem[i].size;
615 SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
616 for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
618 len = min(dc->mem[i].size - pos, sizeof(tmp));
619 if (ReadProcessMemory(dc->hProcess,
620 (void*)(ULONG)(dc->mem[i].base + pos),
622 WriteFile(dc->hFile, tmp, len, &written, NULL);
624 dc->rva += mdMem.Memory.DataSize;
625 writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
628 writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
633 static void dump_misc_info(struct dump_context* dc)
635 MINIDUMP_MISC_INFO mmi;
637 mmi.SizeOfInfo = sizeof(mmi);
638 mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
639 mmi.ProcessId = dc->pid;
640 /* FIXME: create/user/kernel time */
641 append(dc, &mmi, sizeof(mmi));
644 /******************************************************************
645 * MiniDumpWriteDump (DEBUGHLP.@)
648 BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
649 MINIDUMP_TYPE DumpType,
650 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
651 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
652 PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
654 MINIDUMP_HEADER mdHead;
655 MINIDUMP_DIRECTORY mdDir;
656 DWORD i, nStreams, idx_stream;
657 struct dump_context dc;
659 dc.hProcess = hProcess;
664 dc.cb = CallbackParam;
670 if (!fetch_process_info(&dc)) return FALSE;
671 fetch_module_info(&dc);
674 nStreams = 6 + (ExceptionParam ? 1 : 0) +
675 (UserStreamParam ? UserStreamParam->UserStreamCount : 0);
677 if (DumpType & MiniDumpWithDataSegs)
678 FIXME("NIY MiniDumpWithDataSegs\n");
679 if (DumpType & MiniDumpWithFullMemory)
680 FIXME("NIY MiniDumpWithFullMemory\n");
681 if (DumpType & MiniDumpWithHandleData)
682 FIXME("NIY MiniDumpWithHandleData\n");
683 if (DumpType & MiniDumpFilterMemory)
684 FIXME("NIY MiniDumpFilterMemory\n");
685 if (DumpType & MiniDumpScanMemory)
686 FIXME("NIY MiniDumpScanMemory\n");
688 /* 2) write header */
689 mdHead.Signature = MINIDUMP_SIGNATURE;
690 mdHead.Version = MINIDUMP_VERSION;
691 mdHead.NumberOfStreams = nStreams;
692 mdHead.StreamDirectoryRva = sizeof(mdHead);
693 mdHead.u.TimeDateStamp = time(NULL);
694 mdHead.Flags = DumpType;
695 append(&dc, &mdHead, sizeof(mdHead));
697 /* 3) write stream directories */
698 dc.rva += nStreams * sizeof(mdDir);
701 /* 3.1) write data stream directories */
703 mdDir.StreamType = ThreadListStream;
704 mdDir.Location.Rva = dc.rva;
706 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
707 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
708 &mdDir, sizeof(mdDir));
710 mdDir.StreamType = ModuleListStream;
711 mdDir.Location.Rva = dc.rva;
712 dump_modules(&dc, FALSE);
713 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
714 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
715 &mdDir, sizeof(mdDir));
717 mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
718 mdDir.Location.Rva = dc.rva;
719 dump_modules(&dc, TRUE);
720 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
721 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
722 &mdDir, sizeof(mdDir));
724 mdDir.StreamType = MemoryListStream;
725 mdDir.Location.Rva = dc.rva;
726 dump_memory_info(&dc);
727 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
728 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
729 &mdDir, sizeof(mdDir));
731 mdDir.StreamType = SystemInfoStream;
732 mdDir.Location.Rva = dc.rva;
733 dump_system_info(&dc);
734 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
735 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
736 &mdDir, sizeof(mdDir));
738 mdDir.StreamType = MiscInfoStream;
739 mdDir.Location.Rva = dc.rva;
741 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
742 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
743 &mdDir, sizeof(mdDir));
745 /* 3.2) write exception information (if any) */
748 mdDir.StreamType = ExceptionStream;
749 mdDir.Location.Rva = dc.rva;
750 dump_exception_info(&dc, ExceptionParam);
751 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
752 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
753 &mdDir, sizeof(mdDir));
756 /* 3.3) write user defined streams (if any) */
759 for (i = 0; i < UserStreamParam->UserStreamCount; i++)
761 mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
762 mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
763 mdDir.Location.Rva = dc.rva;
764 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
765 &mdDir, sizeof(mdDir));
766 append(&dc, UserStreamParam->UserStreamArray[i].Buffer,
767 UserStreamParam->UserStreamArray[i].BufferSize);
771 HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
772 HeapFree(GetProcessHeap(), 0, dc.mem);
773 HeapFree(GetProcessHeap(), 0, dc.module);
778 /******************************************************************
779 * MiniDumpReadDumpStream (DEBUGHLP.@)
783 BOOL WINAPI MiniDumpReadDumpStream(void* base, ULONG str_idx,
784 PMINIDUMP_DIRECTORY* pdir,
785 void** stream, ULONG* size)
787 MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
789 if (mdHead->Signature == MINIDUMP_SIGNATURE)
791 MINIDUMP_DIRECTORY* dir;
794 dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
795 for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
797 if (dir->StreamType == str_idx)
800 *stream = (char*)base + dir->Location.Rva;
801 *size = dir->Location.DataSize;
806 SetLastError(ERROR_INVALID_PARAMETER);