crypt32: Move provider stores to a separate file.
[wine/wine64.git] / dlls / dbghelp / minidump.c
blobe8daedad3b2bd68221316eeb84fc590996489e5c
1 /*
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <time.h>
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "dbghelp_private.h"
29 #include "winternl.h"
30 #include "psapi.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
35 struct dump_memory
37 ULONG base;
38 ULONG size;
39 ULONG rva;
42 struct dump_module
44 unsigned is_elf;
45 ULONG base;
46 ULONG size;
47 DWORD timestamp;
48 DWORD checksum;
49 WCHAR name[MAX_PATH];
52 struct dump_context
54 /* process & thread information */
55 HANDLE hProcess;
56 DWORD pid;
57 void* pcs_buffer;
58 SYSTEM_PROCESS_INFORMATION* spi;
59 /* module information */
60 struct dump_module* module;
61 unsigned num_module;
62 /* exception information */
63 /* output information */
64 MINIDUMP_TYPE type;
65 HANDLE hFile;
66 RVA rva;
67 struct dump_memory* mem;
68 unsigned num_mem;
69 /* callback information */
70 MINIDUMP_CALLBACK_INFORMATION* cb;
73 /******************************************************************
74 * fetch_process_info
76 * reads system wide process information, and make spi point to the record
77 * for process of id 'pid'
79 static BOOL fetch_process_info(struct dump_context* dc)
81 ULONG buf_size = 0x1000;
82 NTSTATUS nts;
84 dc->pcs_buffer = NULL;
85 if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
86 for (;;)
88 nts = NtQuerySystemInformation(SystemProcessInformation,
89 dc->pcs_buffer, buf_size, NULL);
90 if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
91 dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
92 buf_size *= 2);
93 if (!dc->pcs_buffer) return FALSE;
96 if (nts == STATUS_SUCCESS)
98 dc->spi = dc->pcs_buffer;
99 for (;;)
101 if (dc->spi->dwProcessID == dc->pid) return TRUE;
102 if (!dc->spi->dwOffset) break;
103 dc->spi = (SYSTEM_PROCESS_INFORMATION*)
104 ((char*)dc->spi + dc->spi->dwOffset);
107 HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
108 dc->pcs_buffer = NULL;
109 dc->spi = NULL;
110 return FALSE;
113 static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
114 const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
116 NT_TIB tib;
118 if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL))
120 #ifdef __i386__
121 /* limiting the stack dumping to the size actually used */
122 if (ctx->Esp)
123 mmd->StartOfMemoryRange = (ctx->Esp - 4);
124 else
125 mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
126 #elif defined(__powerpc__)
127 if (ctx->Iar)
128 mmd->StartOfMemoryRange = ctx->Iar - 4;
129 else
130 mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
131 #elif defined(__x86_64__)
132 if (ctx->Rsp)
133 mmd->StartOfMemoryRange = (ctx->Rsp - 8);
134 else
135 mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
136 #else
137 #error unsupported CPU
138 #endif
139 mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange;
143 /******************************************************************
144 * fetch_thread_info
146 * fetches some information about thread of id 'tid'
148 static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
149 const MINIDUMP_EXCEPTION_INFORMATION* except,
150 MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
152 DWORD tid = dc->spi->ti[thd_idx].dwThreadID;
153 HANDLE hThread;
154 THREAD_BASIC_INFORMATION tbi;
156 memset(ctx, 0, sizeof(*ctx));
158 mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
159 mdThd->SuspendCount = 0;
160 mdThd->Teb = 0;
161 mdThd->Stack.StartOfMemoryRange = 0;
162 mdThd->Stack.Memory.DataSize = 0;
163 mdThd->Stack.Memory.Rva = 0;
164 mdThd->ThreadContext.DataSize = 0;
165 mdThd->ThreadContext.Rva = 0;
166 mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
167 mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
169 if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
171 FIXME("Couldn't open thread %u (%u)\n",
172 dc->spi->ti[thd_idx].dwThreadID, GetLastError());
173 return FALSE;
176 if (NtQueryInformationThread(hThread, ThreadBasicInformation,
177 &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
179 mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
180 if (tbi.ExitStatus == STILL_ACTIVE)
182 if (tid != GetCurrentThreadId() &&
183 (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
185 mdThd->SuspendCount--;
186 ctx->ContextFlags = CONTEXT_FULL;
187 if (!GetThreadContext(hThread, ctx))
188 memset(ctx, 0, sizeof(*ctx));
190 fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack);
191 ResumeThread(hThread);
193 else if (tid == GetCurrentThreadId() && except)
195 CONTEXT lctx, *pctx;
196 if (except->ClientPointers)
198 EXCEPTION_POINTERS ep;
200 ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
201 &ep, sizeof(ep), NULL);
202 ReadProcessMemory(dc->hProcess, ep.ContextRecord,
203 &ctx, sizeof(ctx), NULL);
204 pctx = &lctx;
206 else pctx = except->ExceptionPointers->ContextRecord;
207 fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack);
211 CloseHandle(hThread);
212 return TRUE;
215 /******************************************************************
216 * add_module
218 * Add a module to a dump context
220 static BOOL add_module(struct dump_context* dc, const WCHAR* name,
221 DWORD base, DWORD size, DWORD timestamp, DWORD checksum,
222 BOOL is_elf)
224 if (!dc->module)
225 dc->module = HeapAlloc(GetProcessHeap(), 0,
226 ++dc->num_module * sizeof(*dc->module));
227 else
228 dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module,
229 ++dc->num_module * sizeof(*dc->module));
230 if (!dc->module) return FALSE;
231 if (is_elf ||
232 !GetModuleFileNameExW(dc->hProcess, (HMODULE)base,
233 dc->module[dc->num_module - 1].name,
234 sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR)))
235 lstrcpynW(dc->module[dc->num_module - 1].name, name,
236 sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR));
237 dc->module[dc->num_module - 1].base = base;
238 dc->module[dc->num_module - 1].size = size;
239 dc->module[dc->num_module - 1].timestamp = timestamp;
240 dc->module[dc->num_module - 1].checksum = checksum;
241 dc->module[dc->num_module - 1].is_elf = is_elf;
243 return TRUE;
246 /******************************************************************
247 * fetch_pe_module_info_cb
249 * Callback for accumulating in dump_context a PE modules set
251 static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size,
252 PVOID user)
254 struct dump_context* dc = (struct dump_context*)user;
255 IMAGE_NT_HEADERS nth;
257 if (!validate_addr64(base)) return FALSE;
259 if (pe_load_nt_header(dc->hProcess, base, &nth))
260 add_module((struct dump_context*)user, name, base, size,
261 nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
262 FALSE);
263 return TRUE;
266 /******************************************************************
267 * fetch_elf_module_info_cb
269 * Callback for accumulating in dump_context an ELF modules set
271 static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
272 void* user)
274 struct dump_context* dc = (struct dump_context*)user;
275 DWORD rbase, size, checksum;
277 /* FIXME: there's no relevant timestamp on ELF modules */
278 /* NB: if we have a non-null base from the live-target use it (whenever
279 * the ELF module is relocatable or not). If we have a null base (ELF
280 * module isn't relocatable) then grab its base address from ELF file
282 if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
283 size = checksum = 0;
284 add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
285 return TRUE;
288 static void fetch_module_info(struct dump_context* dc)
290 EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
291 /* Since we include ELF modules in a separate stream from the regular PE ones,
292 * we can always include those ELF modules (they don't eat lots of space)
293 * And it's always a good idea to have a trace of the loaded ELF modules for
294 * a given application in a post mortem debugging condition.
296 elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
299 /******************************************************************
300 * add_memory_block
302 * Add a memory block to be dumped in a minidump
303 * If rva is non 0, it's the rva in the minidump where has to be stored
304 * also the rva of the memory block when written (this allows to reference
305 * a memory block from outside the list of memory blocks).
307 static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
309 if (dc->mem)
310 dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
311 ++dc->num_mem * sizeof(*dc->mem));
312 else
313 dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
314 if (dc->mem)
316 dc->mem[dc->num_mem - 1].base = base;
317 dc->mem[dc->num_mem - 1].size = size;
318 dc->mem[dc->num_mem - 1].rva = rva;
320 else dc->num_mem = 0;
323 /******************************************************************
324 * writeat
326 * Writes a chunk of data at a given position in the minidump
328 static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size)
330 DWORD written;
332 SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
333 WriteFile(dc->hFile, data, size, &written, NULL);
336 /******************************************************************
337 * append
339 * writes a new chunk of data to the minidump, increasing the current
340 * rva in dc
342 static void append(struct dump_context* dc, void* data, unsigned size)
344 writeat(dc, dc->rva, data, size);
345 dc->rva += size;
348 /******************************************************************
349 * dump_exception_info
351 * Write in File the exception information from pcs
353 static void dump_exception_info(struct dump_context* dc,
354 const MINIDUMP_EXCEPTION_INFORMATION* except)
356 MINIDUMP_EXCEPTION_STREAM mdExcpt;
357 EXCEPTION_RECORD rec, *prec;
358 CONTEXT ctx, *pctx;
359 int i;
361 mdExcpt.ThreadId = except->ThreadId;
362 mdExcpt.__alignment = 0;
363 if (except->ClientPointers)
365 EXCEPTION_POINTERS ep;
367 ReadProcessMemory(dc->hProcess,
368 except->ExceptionPointers, &ep, sizeof(ep), NULL);
369 ReadProcessMemory(dc->hProcess,
370 ep.ExceptionRecord, &rec, sizeof(rec), NULL);
371 ReadProcessMemory(dc->hProcess,
372 ep.ContextRecord, &ctx, sizeof(ctx), NULL);
373 prec = &rec;
374 pctx = &ctx;
376 else
378 prec = except->ExceptionPointers->ExceptionRecord;
379 pctx = except->ExceptionPointers->ContextRecord;
381 mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
382 mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
383 mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
384 mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
385 mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
386 mdExcpt.ExceptionRecord.__unusedAlignment = 0;
387 for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
388 mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
389 mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
390 mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
392 append(dc, &mdExcpt, sizeof(mdExcpt));
393 append(dc, pctx, sizeof(*pctx));
396 /******************************************************************
397 * dump_modules
399 * Write in File the modules from pcs
401 static void dump_modules(struct dump_context* dc, BOOL dump_elf)
403 MINIDUMP_MODULE mdModule;
404 MINIDUMP_MODULE_LIST mdModuleList;
405 char tmp[1024];
406 MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp;
407 ULONG i, nmod;
408 RVA rva_base;
409 DWORD flags_out;
411 for (i = nmod = 0; i < dc->num_module; i++)
413 if ((dc->module[i].is_elf && dump_elf) ||
414 (!dc->module[i].is_elf && !dump_elf))
415 nmod++;
418 mdModuleList.NumberOfModules = 0;
419 /* reserve space for mdModuleList
420 * FIXME: since we don't support 0 length arrays, we cannot use the
421 * size of mdModuleList
422 * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
424 rva_base = dc->rva;
425 dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
426 for (i = 0; i < dc->num_module; i++)
428 if ((dc->module[i].is_elf && !dump_elf) ||
429 (!dc->module[i].is_elf && dump_elf))
430 continue;
432 flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
433 if (dc->type & MiniDumpWithDataSegs)
434 flags_out |= ModuleWriteDataSeg;
435 if (dc->type & MiniDumpWithProcessThreadData)
436 flags_out |= ModuleWriteTlsData;
437 if (dc->type & MiniDumpWithCodeSegs)
438 flags_out |= ModuleWriteCodeSegs;
439 ms->Length = (lstrlenW(dc->module[i].name) + 1) * sizeof(WCHAR);
440 if (sizeof(ULONG) + ms->Length > sizeof(tmp))
441 FIXME("Buffer overflow!!!\n");
442 lstrcpyW(ms->Buffer, dc->module[i].name);
444 if (dc->cb)
446 MINIDUMP_CALLBACK_INPUT cbin;
447 MINIDUMP_CALLBACK_OUTPUT cbout;
449 cbin.ProcessId = dc->pid;
450 cbin.ProcessHandle = dc->hProcess;
451 cbin.CallbackType = ModuleCallback;
453 cbin.u.Module.FullPath = ms->Buffer;
454 cbin.u.Module.BaseOfImage = dc->module[i].base;
455 cbin.u.Module.SizeOfImage = dc->module[i].size;
456 cbin.u.Module.CheckSum = dc->module[i].checksum;
457 cbin.u.Module.TimeDateStamp = dc->module[i].timestamp;
458 memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
459 cbin.u.Module.CvRecord = NULL;
460 cbin.u.Module.SizeOfCvRecord = 0;
461 cbin.u.Module.MiscRecord = NULL;
462 cbin.u.Module.SizeOfMiscRecord = 0;
464 cbout.u.ModuleWriteFlags = flags_out;
465 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
466 continue;
467 flags_out &= cbout.u.ModuleWriteFlags;
469 if (flags_out & ModuleWriteModule)
471 mdModule.BaseOfImage = dc->module[i].base;
472 mdModule.SizeOfImage = dc->module[i].size;
473 mdModule.CheckSum = dc->module[i].checksum;
474 mdModule.TimeDateStamp = dc->module[i].timestamp;
475 mdModule.ModuleNameRva = dc->rva;
476 ms->Length -= sizeof(WCHAR);
477 append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR));
478 memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
479 mdModule.CvRecord.DataSize = 0; /* FIXME */
480 mdModule.CvRecord.Rva = 0; /* FIXME */
481 mdModule.MiscRecord.DataSize = 0; /* FIXME */
482 mdModule.MiscRecord.Rva = 0; /* FIXME */
483 mdModule.Reserved0 = 0; /* FIXME */
484 mdModule.Reserved1 = 0; /* FIXME */
485 writeat(dc,
486 rva_base + sizeof(mdModuleList.NumberOfModules) +
487 mdModuleList.NumberOfModules++ * sizeof(mdModule),
488 &mdModule, sizeof(mdModule));
491 writeat(dc, rva_base, &mdModuleList.NumberOfModules,
492 sizeof(mdModuleList.NumberOfModules));
495 /******************************************************************
496 * dump_system_info
498 * Dumps into File the information about the system
500 static void dump_system_info(struct dump_context* dc)
502 MINIDUMP_SYSTEM_INFO mdSysInfo;
503 SYSTEM_INFO sysInfo;
504 OSVERSIONINFOW osInfo;
505 DWORD written;
506 ULONG slen;
508 GetSystemInfo(&sysInfo);
509 osInfo.dwOSVersionInfoSize = sizeof(osInfo);
510 GetVersionExW(&osInfo);
512 mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
513 mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
514 mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
515 mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
516 mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
517 mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
518 mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
519 mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
520 mdSysInfo.PlatformId = osInfo.dwPlatformId;
522 mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
523 mdSysInfo.u1.Reserved1 = 0;
525 memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));
527 append(dc, &mdSysInfo, sizeof(mdSysInfo));
529 slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
530 WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
531 WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
532 dc->rva += sizeof(ULONG) + slen;
535 /******************************************************************
536 * dump_threads
538 * Dumps into File the information about running threads
540 static void dump_threads(struct dump_context* dc,
541 const MINIDUMP_EXCEPTION_INFORMATION* except)
543 MINIDUMP_THREAD mdThd;
544 MINIDUMP_THREAD_LIST mdThdList;
545 unsigned i;
546 RVA rva_base;
547 DWORD flags_out;
548 CONTEXT ctx;
550 mdThdList.NumberOfThreads = 0;
552 rva_base = dc->rva;
553 dc->rva += sizeof(mdThdList.NumberOfThreads) +
554 dc->spi->dwThreadCount * sizeof(mdThd);
556 for (i = 0; i < dc->spi->dwThreadCount; i++)
558 fetch_thread_info(dc, i, except, &mdThd, &ctx);
560 flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
561 ThreadWriteInstructionWindow;
562 if (dc->type & MiniDumpWithProcessThreadData)
563 flags_out |= ThreadWriteThreadData;
564 if (dc->type & MiniDumpWithThreadInfo)
565 flags_out |= ThreadWriteThreadInfo;
567 if (dc->cb)
569 MINIDUMP_CALLBACK_INPUT cbin;
570 MINIDUMP_CALLBACK_OUTPUT cbout;
572 cbin.ProcessId = dc->pid;
573 cbin.ProcessHandle = dc->hProcess;
574 cbin.CallbackType = ThreadCallback;
575 cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
576 cbin.u.Thread.ThreadHandle = 0; /* FIXME */
577 memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
578 cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
579 cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
580 cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
581 mdThd.Stack.Memory.DataSize;
583 cbout.u.ThreadWriteFlags = flags_out;
584 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
585 continue;
586 flags_out &= cbout.u.ThreadWriteFlags;
588 if (flags_out & ThreadWriteThread)
590 if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
592 mdThd.ThreadContext.Rva = dc->rva;
593 mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
594 append(dc, &ctx, sizeof(CONTEXT));
596 if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
598 add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
599 mdThd.Stack.Memory.DataSize,
600 rva_base + sizeof(mdThdList.NumberOfThreads) +
601 mdThdList.NumberOfThreads * sizeof(mdThd) +
602 FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
604 writeat(dc,
605 rva_base + sizeof(mdThdList.NumberOfThreads) +
606 mdThdList.NumberOfThreads * sizeof(mdThd),
607 &mdThd, sizeof(mdThd));
608 mdThdList.NumberOfThreads++;
610 if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
612 /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
613 * - also crop values across module boundaries,
614 * - and don't make it i386 dependent
616 /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
619 writeat(dc, rva_base,
620 &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
623 /******************************************************************
624 * dump_memory_info
626 * dumps information about the memory of the process (stack of the threads)
628 static void dump_memory_info(struct dump_context* dc)
630 MINIDUMP_MEMORY_LIST mdMemList;
631 MINIDUMP_MEMORY_DESCRIPTOR mdMem;
632 DWORD written;
633 unsigned i, pos, len;
634 RVA rva_base;
635 char tmp[1024];
637 mdMemList.NumberOfMemoryRanges = dc->num_mem;
638 append(dc, &mdMemList.NumberOfMemoryRanges,
639 sizeof(mdMemList.NumberOfMemoryRanges));
640 rva_base = dc->rva;
641 dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
643 for (i = 0; i < dc->num_mem; i++)
645 mdMem.StartOfMemoryRange = dc->mem[i].base;
646 mdMem.Memory.Rva = dc->rva;
647 mdMem.Memory.DataSize = dc->mem[i].size;
648 SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
649 for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
651 len = min(dc->mem[i].size - pos, sizeof(tmp));
652 if (ReadProcessMemory(dc->hProcess,
653 (void*)(ULONG)(dc->mem[i].base + pos),
654 tmp, len, NULL))
655 WriteFile(dc->hFile, tmp, len, &written, NULL);
657 dc->rva += mdMem.Memory.DataSize;
658 writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
659 if (dc->mem[i].rva)
661 writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
666 static void dump_misc_info(struct dump_context* dc)
668 MINIDUMP_MISC_INFO mmi;
670 mmi.SizeOfInfo = sizeof(mmi);
671 mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
672 mmi.ProcessId = dc->pid;
673 /* FIXME: create/user/kernel time */
674 append(dc, &mmi, sizeof(mmi));
677 /******************************************************************
678 * MiniDumpWriteDump (DEBUGHLP.@)
681 BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
682 MINIDUMP_TYPE DumpType,
683 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
684 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
685 PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
687 MINIDUMP_HEADER mdHead;
688 MINIDUMP_DIRECTORY mdDir;
689 DWORD i, nStreams, idx_stream;
690 struct dump_context dc;
692 dc.hProcess = hProcess;
693 dc.hFile = hFile;
694 dc.pid = pid;
695 dc.module = NULL;
696 dc.num_module = 0;
697 dc.cb = CallbackParam;
698 dc.type = DumpType;
699 dc.mem = NULL;
700 dc.num_mem = 0;
701 dc.rva = 0;
703 if (!fetch_process_info(&dc)) return FALSE;
704 fetch_module_info(&dc);
706 /* 1) init */
707 nStreams = 6 + (ExceptionParam ? 1 : 0) +
708 (UserStreamParam ? UserStreamParam->UserStreamCount : 0);
710 if (DumpType & MiniDumpWithDataSegs)
711 FIXME("NIY MiniDumpWithDataSegs\n");
712 if (DumpType & MiniDumpWithFullMemory)
713 FIXME("NIY MiniDumpWithFullMemory\n");
714 if (DumpType & MiniDumpWithHandleData)
715 FIXME("NIY MiniDumpWithHandleData\n");
716 if (DumpType & MiniDumpFilterMemory)
717 FIXME("NIY MiniDumpFilterMemory\n");
718 if (DumpType & MiniDumpScanMemory)
719 FIXME("NIY MiniDumpScanMemory\n");
721 /* 2) write header */
722 mdHead.Signature = MINIDUMP_SIGNATURE;
723 mdHead.Version = MINIDUMP_VERSION;
724 mdHead.NumberOfStreams = nStreams;
725 mdHead.StreamDirectoryRva = sizeof(mdHead);
726 mdHead.u.TimeDateStamp = time(NULL);
727 mdHead.Flags = DumpType;
728 append(&dc, &mdHead, sizeof(mdHead));
730 /* 3) write stream directories */
731 dc.rva += nStreams * sizeof(mdDir);
732 idx_stream = 0;
734 /* 3.1) write data stream directories */
736 mdDir.StreamType = ThreadListStream;
737 mdDir.Location.Rva = dc.rva;
738 dump_threads(&dc, ExceptionParam);
739 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
740 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
741 &mdDir, sizeof(mdDir));
743 mdDir.StreamType = ModuleListStream;
744 mdDir.Location.Rva = dc.rva;
745 dump_modules(&dc, FALSE);
746 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
747 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
748 &mdDir, sizeof(mdDir));
750 mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
751 mdDir.Location.Rva = dc.rva;
752 dump_modules(&dc, TRUE);
753 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
754 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
755 &mdDir, sizeof(mdDir));
757 mdDir.StreamType = MemoryListStream;
758 mdDir.Location.Rva = dc.rva;
759 dump_memory_info(&dc);
760 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
761 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
762 &mdDir, sizeof(mdDir));
764 mdDir.StreamType = SystemInfoStream;
765 mdDir.Location.Rva = dc.rva;
766 dump_system_info(&dc);
767 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
768 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
769 &mdDir, sizeof(mdDir));
771 mdDir.StreamType = MiscInfoStream;
772 mdDir.Location.Rva = dc.rva;
773 dump_misc_info(&dc);
774 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
775 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
776 &mdDir, sizeof(mdDir));
778 /* 3.2) write exception information (if any) */
779 if (ExceptionParam)
781 mdDir.StreamType = ExceptionStream;
782 mdDir.Location.Rva = dc.rva;
783 dump_exception_info(&dc, ExceptionParam);
784 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
785 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
786 &mdDir, sizeof(mdDir));
789 /* 3.3) write user defined streams (if any) */
790 if (UserStreamParam)
792 for (i = 0; i < UserStreamParam->UserStreamCount; i++)
794 mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
795 mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
796 mdDir.Location.Rva = dc.rva;
797 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
798 &mdDir, sizeof(mdDir));
799 append(&dc, UserStreamParam->UserStreamArray[i].Buffer,
800 UserStreamParam->UserStreamArray[i].BufferSize);
804 HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
805 HeapFree(GetProcessHeap(), 0, dc.mem);
806 HeapFree(GetProcessHeap(), 0, dc.module);
808 return TRUE;
811 /******************************************************************
812 * MiniDumpReadDumpStream (DEBUGHLP.@)
816 BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
817 PMINIDUMP_DIRECTORY* pdir,
818 PVOID* stream, ULONG* size)
820 MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
822 if (mdHead->Signature == MINIDUMP_SIGNATURE)
824 MINIDUMP_DIRECTORY* dir;
825 int i;
827 dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
828 for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
830 if (dir->StreamType == str_idx)
832 *pdir = dir;
833 *stream = (char*)base + dir->Location.Rva;
834 *size = dir->Location.DataSize;
835 return TRUE;
839 SetLastError(ERROR_INVALID_PARAMETER);
840 return FALSE;