wined3d: Move WINED3DRS_STIPPLEDALPHA to the state table.
[wine/multimedia.git] / dlls / dbghelp / minidump.c
blobc1b44b0b082e5dfa8020aefa232d1ca82f6f78ed
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 "winnls.h"
30 #include "winreg.h"
31 #include "winternl.h"
32 #include "psapi.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
37 struct dump_memory
39 ULONG base;
40 ULONG size;
41 ULONG rva;
44 struct dump_module
46 unsigned is_elf;
47 ULONG base;
48 ULONG size;
49 DWORD timestamp;
50 DWORD checksum;
51 char name[MAX_PATH];
54 struct dump_context
56 /* process & thread information */
57 HANDLE hProcess;
58 DWORD pid;
59 void* pcs_buffer;
60 SYSTEM_PROCESS_INFORMATION* spi;
61 /* module information */
62 struct dump_module* module;
63 unsigned num_module;
64 /* exception information */
65 /* output information */
66 MINIDUMP_TYPE type;
67 HANDLE hFile;
68 RVA rva;
69 struct dump_memory* mem;
70 unsigned num_mem;
71 /* callback information */
72 MINIDUMP_CALLBACK_INFORMATION* cb;
75 /******************************************************************
76 * fetch_process_info
78 * reads system wide process information, and make spi point to the record
79 * for process of id 'pid'
81 static BOOL fetch_process_info(struct dump_context* dc)
83 ULONG buf_size = 0x1000;
84 NTSTATUS nts;
86 dc->pcs_buffer = NULL;
87 if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
88 for (;;)
90 nts = NtQuerySystemInformation(SystemProcessInformation,
91 dc->pcs_buffer, buf_size, NULL);
92 if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
93 dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
94 buf_size *= 2);
95 if (!dc->pcs_buffer) return FALSE;
98 if (nts == STATUS_SUCCESS)
100 dc->spi = dc->pcs_buffer;
101 for (;;)
103 if (dc->spi->dwProcessID == dc->pid) return TRUE;
104 if (!dc->spi->dwOffset) break;
105 dc->spi = (SYSTEM_PROCESS_INFORMATION*)
106 ((char*)dc->spi + dc->spi->dwOffset);
109 HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
110 dc->pcs_buffer = NULL;
111 dc->spi = NULL;
112 return FALSE;
115 /******************************************************************
116 * fetch_thread_info
118 * fetches some information about thread of id 'tid'
120 static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
121 MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
123 NT_TIB tib;
124 DWORD tid = dc->spi->ti[thd_idx].dwThreadID;
125 HANDLE hThread;
126 THREAD_BASIC_INFORMATION tbi;
128 memset(ctx, 0, sizeof(*ctx));
130 mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
131 mdThd->SuspendCount = 0;
132 mdThd->Teb = 0;
133 mdThd->Stack.StartOfMemoryRange = 0;
134 mdThd->Stack.Memory.DataSize = 0;
135 mdThd->Stack.Memory.Rva = 0;
136 mdThd->ThreadContext.DataSize = 0;
137 mdThd->ThreadContext.Rva = 0;
138 mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
139 mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
141 if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
143 FIXME("Couldn't open thread %u (%u)\n",
144 dc->spi->ti[thd_idx].dwThreadID, GetLastError());
145 return FALSE;
148 if (NtQueryInformationThread(hThread, ThreadBasicInformation,
149 &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
151 mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
152 if (tbi.ExitStatus == STILL_ACTIVE && tid != GetCurrentThreadId() &&
153 (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
155 mdThd->SuspendCount--;
156 ctx->ContextFlags = CONTEXT_FULL;
157 if (!GetThreadContext(hThread, ctx))
158 memset(ctx, 0, sizeof(*ctx));
160 if (ReadProcessMemory(dc->hProcess, tbi.TebBaseAddress,
161 &tib, sizeof(tib), NULL))
163 #ifdef __i386__
164 /* limiting the stack dumping to the size actually used */
165 if (ctx->Esp)
166 mdThd->Stack.StartOfMemoryRange = (ctx->Esp - 4);
167 else
168 mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
169 #elif defined(__powerpc__)
170 if (ctx->Iar)
171 mdThd->Stack.StartOfMemoryRange = ctx->Iar - 4;
172 else
173 mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
174 #elif defined(__x86_64__)
175 if (ctx->Rsp)
176 mdThd->Stack.StartOfMemoryRange = (ctx->Rsp - 8);
177 else
178 mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
179 #else
180 #error unsupported CPU
181 #endif
182 mdThd->Stack.Memory.DataSize = (ULONG_PTR)tib.StackBase -
183 mdThd->Stack.StartOfMemoryRange;
185 ResumeThread(hThread);
188 CloseHandle(hThread);
189 return TRUE;
192 /******************************************************************
193 * add_module
195 * Add a module to a dump context
197 static BOOL add_module(struct dump_context* dc, const char* name,
198 DWORD base, DWORD size, DWORD timestamp, DWORD checksum,
199 BOOL is_elf)
201 if (!dc->module)
202 dc->module = HeapAlloc(GetProcessHeap(), 0,
203 ++dc->num_module * sizeof(*dc->module));
204 else
205 dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module,
206 ++dc->num_module * sizeof(*dc->module));
207 if (!dc->module) return FALSE;
208 if (is_elf ||
209 !GetModuleFileNameExA(dc->hProcess, (HMODULE)base,
210 dc->module[dc->num_module - 1].name,
211 sizeof(dc->module[dc->num_module - 1].name)))
212 lstrcpynA(dc->module[dc->num_module - 1].name, name,
213 sizeof(dc->module[dc->num_module - 1].name));
214 dc->module[dc->num_module - 1].base = base;
215 dc->module[dc->num_module - 1].size = size;
216 dc->module[dc->num_module - 1].timestamp = timestamp;
217 dc->module[dc->num_module - 1].checksum = checksum;
218 dc->module[dc->num_module - 1].is_elf = is_elf;
220 return TRUE;
223 /******************************************************************
224 * fetch_pe_module_info_cb
226 * Callback for accumulating in dump_context a PE modules set
228 static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size,
229 void* user)
231 struct dump_context* dc = (struct dump_context*)user;
232 IMAGE_NT_HEADERS nth;
234 if (pe_load_nt_header(dc->hProcess, base, &nth))
235 add_module((struct dump_context*)user, name, base, size,
236 nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
237 FALSE);
238 return TRUE;
241 /******************************************************************
242 * fetch_elf_module_info_cb
244 * Callback for accumulating in dump_context an ELF modules set
246 static BOOL fetch_elf_module_info_cb(const char* name, unsigned long base,
247 void* user)
249 struct dump_context* dc = (struct dump_context*)user;
250 DWORD rbase, size, checksum;
252 /* FIXME: there's no relevant timestamp on ELF modules */
253 /* NB: if we have a non-null base from the live-target use it (whenever
254 * the ELF module is relocatable or not). If we have a null base (ELF
255 * module isn't relocatable) then grab its base address from ELF file
257 if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
258 size = checksum = 0;
259 add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
260 return TRUE;
263 static void fetch_module_info(struct dump_context* dc)
265 EnumerateLoadedModules(dc->hProcess, fetch_pe_module_info_cb, dc);
266 /* Since we include ELF modules in a separate stream from the regular PE ones,
267 * we can always include those ELF modules (they don't eat lots of space)
268 * And it's always a good idea to have a trace of the loaded ELF modules for
269 * a given application in a post mortem debugging condition.
271 elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
274 /******************************************************************
275 * add_memory_block
277 * Add a memory block to be dumped in a minidump
278 * If rva is non 0, it's the rva in the minidump where has to be stored
279 * also the rva of the memory block when written (this allows to reference
280 * a memory block from outside the list of memory blocks).
282 static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
284 if (dc->mem)
285 dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
286 ++dc->num_mem * sizeof(*dc->mem));
287 else
288 dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
289 if (dc->mem)
291 dc->mem[dc->num_mem - 1].base = base;
292 dc->mem[dc->num_mem - 1].size = size;
293 dc->mem[dc->num_mem - 1].rva = rva;
295 else dc->num_mem = 0;
298 /******************************************************************
299 * writeat
301 * Writes a chunk of data at a given position in the minidump
303 static void writeat(struct dump_context* dc, RVA rva, void* data, unsigned size)
305 DWORD written;
307 SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
308 WriteFile(dc->hFile, data, size, &written, NULL);
311 /******************************************************************
312 * append
314 * writes a new chunk of data to the minidump, increasing the current
315 * rva in dc
317 static void append(struct dump_context* dc, void* data, unsigned size)
319 writeat(dc, dc->rva, data, size);
320 dc->rva += size;
323 /******************************************************************
324 * dump_exception_info
326 * Write in File the exception information from pcs
328 static void dump_exception_info(struct dump_context* dc,
329 const MINIDUMP_EXCEPTION_INFORMATION* except)
331 MINIDUMP_EXCEPTION_STREAM mdExcpt;
332 EXCEPTION_RECORD rec, *prec;
333 CONTEXT ctx, *pctx;
334 int i;
336 mdExcpt.ThreadId = except->ThreadId;
337 mdExcpt.__alignment = 0;
338 if (except->ClientPointers)
340 EXCEPTION_POINTERS ep;
342 ReadProcessMemory(dc->hProcess,
343 except->ExceptionPointers, &ep, sizeof(ep), NULL);
344 ReadProcessMemory(dc->hProcess,
345 ep.ExceptionRecord, &rec, sizeof(rec), NULL);
346 ReadProcessMemory(dc->hProcess,
347 ep.ContextRecord, &ctx, sizeof(ctx), NULL);
348 prec = &rec;
349 pctx = &ctx;
352 else
354 prec = except->ExceptionPointers->ExceptionRecord;
355 pctx = except->ExceptionPointers->ContextRecord;
357 mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
358 mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
359 mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
360 mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
361 mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
362 mdExcpt.ExceptionRecord.__unusedAlignment = 0;
363 for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
364 mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
365 mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
366 mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
368 append(dc, &mdExcpt, sizeof(mdExcpt));
369 append(dc, pctx, sizeof(*pctx));
372 /******************************************************************
373 * dump_modules
375 * Write in File the modules from pcs
377 static void dump_modules(struct dump_context* dc, BOOL dump_elf)
379 MINIDUMP_MODULE mdModule;
380 MINIDUMP_MODULE_LIST mdModuleList;
381 char tmp[1024];
382 MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp;
383 ULONG i, nmod;
384 RVA rva_base;
385 DWORD flags_out;
387 for (i = nmod = 0; i < dc->num_module; i++)
389 if ((dc->module[i].is_elf && dump_elf) ||
390 (!dc->module[i].is_elf && !dump_elf))
391 nmod++;
394 mdModuleList.NumberOfModules = 0;
395 /* reserve space for mdModuleList
396 * FIXME: since we don't support 0 length arrays, we cannot use the
397 * size of mdModuleList
398 * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
400 rva_base = dc->rva;
401 dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
402 for (i = 0; i < dc->num_module; i++)
404 if ((dc->module[i].is_elf && !dump_elf) ||
405 (!dc->module[i].is_elf && dump_elf))
406 continue;
408 flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
409 if (dc->type & MiniDumpWithDataSegs)
410 flags_out |= ModuleWriteDataSeg;
411 if (dc->type & MiniDumpWithProcessThreadData)
412 flags_out |= ModuleWriteTlsData;
413 if (dc->type & MiniDumpWithCodeSegs)
414 flags_out |= ModuleWriteCodeSegs;
415 ms->Length = MultiByteToWideChar(CP_ACP, 0,
416 dc->module[i].name, -1,
417 NULL, 0) * sizeof(WCHAR);
418 if (sizeof(ULONG) + ms->Length > sizeof(tmp))
419 FIXME("Buffer overflow!!!\n");
420 MultiByteToWideChar(CP_ACP, 0, dc->module[i].name, -1,
421 ms->Buffer, ms->Length/sizeof(WCHAR));
423 if (dc->cb)
425 MINIDUMP_CALLBACK_INPUT cbin;
426 MINIDUMP_CALLBACK_OUTPUT cbout;
428 cbin.ProcessId = dc->pid;
429 cbin.ProcessHandle = dc->hProcess;
430 cbin.CallbackType = ModuleCallback;
432 cbin.u.Module.FullPath = ms->Buffer;
433 cbin.u.Module.BaseOfImage = dc->module[i].base;
434 cbin.u.Module.SizeOfImage = dc->module[i].size;
435 cbin.u.Module.CheckSum = dc->module[i].checksum;
436 cbin.u.Module.TimeDateStamp = dc->module[i].timestamp;
437 memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
438 cbin.u.Module.CvRecord = NULL;
439 cbin.u.Module.SizeOfCvRecord = 0;
440 cbin.u.Module.MiscRecord = NULL;
441 cbin.u.Module.SizeOfMiscRecord = 0;
443 cbout.u.ModuleWriteFlags = flags_out;
444 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
445 continue;
446 flags_out &= cbout.u.ModuleWriteFlags;
448 if (flags_out & ModuleWriteModule)
450 mdModule.BaseOfImage = dc->module[i].base;
451 mdModule.SizeOfImage = dc->module[i].size;
452 mdModule.CheckSum = dc->module[i].checksum;
453 mdModule.TimeDateStamp = dc->module[i].timestamp;
454 mdModule.ModuleNameRva = dc->rva;
455 ms->Length -= sizeof(WCHAR);
456 append(dc, ms, sizeof(ULONG) + ms->Length);
457 memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
458 mdModule.CvRecord.DataSize = 0; /* FIXME */
459 mdModule.CvRecord.Rva = 0; /* FIXME */
460 mdModule.MiscRecord.DataSize = 0; /* FIXME */
461 mdModule.MiscRecord.Rva = 0; /* FIXME */
462 mdModule.Reserved0 = 0; /* FIXME */
463 mdModule.Reserved1 = 0; /* FIXME */
464 writeat(dc,
465 rva_base + sizeof(mdModuleList.NumberOfModules) +
466 mdModuleList.NumberOfModules++ * sizeof(mdModule),
467 &mdModule, sizeof(mdModule));
470 writeat(dc, rva_base, &mdModuleList.NumberOfModules,
471 sizeof(mdModuleList.NumberOfModules));
474 /******************************************************************
475 * dump_system_info
477 * Dumps into File the information about the system
479 static void dump_system_info(struct dump_context* dc)
481 MINIDUMP_SYSTEM_INFO mdSysInfo;
482 SYSTEM_INFO sysInfo;
483 OSVERSIONINFOW osInfo;
484 DWORD written;
485 ULONG slen;
487 GetSystemInfo(&sysInfo);
488 osInfo.dwOSVersionInfoSize = sizeof(osInfo);
489 GetVersionExW(&osInfo);
491 mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
492 mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
493 mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
494 mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
495 mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
496 mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
497 mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
498 mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
499 mdSysInfo.PlatformId = osInfo.dwPlatformId;
501 mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
502 mdSysInfo.u1.Reserved1 = 0;
504 memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));
506 append(dc, &mdSysInfo, sizeof(mdSysInfo));
508 slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
509 WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
510 WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
511 dc->rva += sizeof(ULONG) + slen;
514 /******************************************************************
515 * dump_threads
517 * Dumps into File the information about running threads
519 static void dump_threads(struct dump_context* dc)
521 MINIDUMP_THREAD mdThd;
522 MINIDUMP_THREAD_LIST mdThdList;
523 unsigned i;
524 RVA rva_base;
525 DWORD flags_out;
526 CONTEXT ctx;
528 mdThdList.NumberOfThreads = 0;
530 rva_base = dc->rva;
531 dc->rva += sizeof(mdThdList.NumberOfThreads) +
532 dc->spi->dwThreadCount * sizeof(mdThd);
534 for (i = 0; i < dc->spi->dwThreadCount; i++)
536 fetch_thread_info(dc, i, &mdThd, &ctx);
538 flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
539 ThreadWriteInstructionWindow;
540 if (dc->type & MiniDumpWithProcessThreadData)
541 flags_out |= ThreadWriteThreadData;
542 if (dc->type & MiniDumpWithThreadInfo)
543 flags_out |= ThreadWriteThreadInfo;
545 if (dc->cb)
547 MINIDUMP_CALLBACK_INPUT cbin;
548 MINIDUMP_CALLBACK_OUTPUT cbout;
550 cbin.ProcessId = dc->pid;
551 cbin.ProcessHandle = dc->hProcess;
552 cbin.CallbackType = ThreadCallback;
553 cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
554 cbin.u.Thread.ThreadHandle = 0; /* FIXME */
555 memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
556 cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
557 cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
558 cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
559 mdThd.Stack.Memory.DataSize;
561 cbout.u.ThreadWriteFlags = flags_out;
562 if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
563 continue;
564 flags_out &= cbout.u.ThreadWriteFlags;
566 if (flags_out & ThreadWriteThread)
568 if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
570 mdThd.ThreadContext.Rva = dc->rva;
571 mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
572 append(dc, &ctx, sizeof(CONTEXT));
574 if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
576 add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
577 mdThd.Stack.Memory.DataSize,
578 rva_base + sizeof(mdThdList.NumberOfThreads) +
579 mdThdList.NumberOfThreads * sizeof(mdThd) +
580 FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
582 writeat(dc,
583 rva_base + sizeof(mdThdList.NumberOfThreads) +
584 mdThdList.NumberOfThreads * sizeof(mdThd),
585 &mdThd, sizeof(mdThd));
586 mdThdList.NumberOfThreads++;
588 if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
590 /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
591 * - also crop values across module boundaries,
592 * - and don't make it i386 dependent
594 /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
597 writeat(dc, rva_base,
598 &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
601 /******************************************************************
602 * dump_memory_info
604 * dumps information about the memory of the process (stack of the threads)
606 static void dump_memory_info(struct dump_context* dc)
608 MINIDUMP_MEMORY_LIST mdMemList;
609 MINIDUMP_MEMORY_DESCRIPTOR mdMem;
610 DWORD written;
611 unsigned i, pos, len;
612 RVA rva_base;
613 char tmp[1024];
615 mdMemList.NumberOfMemoryRanges = dc->num_mem;
616 append(dc, &mdMemList.NumberOfMemoryRanges,
617 sizeof(mdMemList.NumberOfMemoryRanges));
618 rva_base = dc->rva;
619 dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
621 for (i = 0; i < dc->num_mem; i++)
623 mdMem.StartOfMemoryRange = dc->mem[i].base;
624 mdMem.Memory.Rva = dc->rva;
625 mdMem.Memory.DataSize = dc->mem[i].size;
626 SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
627 for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
629 len = min(dc->mem[i].size - pos, sizeof(tmp));
630 if (ReadProcessMemory(dc->hProcess,
631 (void*)(ULONG)(dc->mem[i].base + pos),
632 tmp, len, NULL))
633 WriteFile(dc->hFile, tmp, len, &written, NULL);
635 dc->rva += mdMem.Memory.DataSize;
636 writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
637 if (dc->mem[i].rva)
639 writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
644 static void dump_misc_info(struct dump_context* dc)
646 MINIDUMP_MISC_INFO mmi;
648 mmi.SizeOfInfo = sizeof(mmi);
649 mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
650 mmi.ProcessId = dc->pid;
651 /* FIXME: create/user/kernel time */
652 append(dc, &mmi, sizeof(mmi));
655 /******************************************************************
656 * MiniDumpWriteDump (DEBUGHLP.@)
659 BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
660 MINIDUMP_TYPE DumpType,
661 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
662 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
663 PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
665 MINIDUMP_HEADER mdHead;
666 MINIDUMP_DIRECTORY mdDir;
667 DWORD i, nStreams, idx_stream;
668 struct dump_context dc;
670 dc.hProcess = hProcess;
671 dc.hFile = hFile;
672 dc.pid = pid;
673 dc.module = NULL;
674 dc.num_module = 0;
675 dc.cb = CallbackParam;
676 dc.type = DumpType;
677 dc.mem = NULL;
678 dc.num_mem = 0;
679 dc.rva = 0;
681 if (!fetch_process_info(&dc)) return FALSE;
682 fetch_module_info(&dc);
684 /* 1) init */
685 nStreams = 6 + (ExceptionParam ? 1 : 0) +
686 (UserStreamParam ? UserStreamParam->UserStreamCount : 0);
688 if (DumpType & MiniDumpWithDataSegs)
689 FIXME("NIY MiniDumpWithDataSegs\n");
690 if (DumpType & MiniDumpWithFullMemory)
691 FIXME("NIY MiniDumpWithFullMemory\n");
692 if (DumpType & MiniDumpWithHandleData)
693 FIXME("NIY MiniDumpWithHandleData\n");
694 if (DumpType & MiniDumpFilterMemory)
695 FIXME("NIY MiniDumpFilterMemory\n");
696 if (DumpType & MiniDumpScanMemory)
697 FIXME("NIY MiniDumpScanMemory\n");
699 /* 2) write header */
700 mdHead.Signature = MINIDUMP_SIGNATURE;
701 mdHead.Version = MINIDUMP_VERSION;
702 mdHead.NumberOfStreams = nStreams;
703 mdHead.StreamDirectoryRva = sizeof(mdHead);
704 mdHead.u.TimeDateStamp = time(NULL);
705 mdHead.Flags = DumpType;
706 append(&dc, &mdHead, sizeof(mdHead));
708 /* 3) write stream directories */
709 dc.rva += nStreams * sizeof(mdDir);
710 idx_stream = 0;
712 /* 3.1) write data stream directories */
714 mdDir.StreamType = ThreadListStream;
715 mdDir.Location.Rva = dc.rva;
716 dump_threads(&dc);
717 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
718 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
719 &mdDir, sizeof(mdDir));
721 mdDir.StreamType = ModuleListStream;
722 mdDir.Location.Rva = dc.rva;
723 dump_modules(&dc, FALSE);
724 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
725 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
726 &mdDir, sizeof(mdDir));
728 mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
729 mdDir.Location.Rva = dc.rva;
730 dump_modules(&dc, TRUE);
731 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
732 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
733 &mdDir, sizeof(mdDir));
735 mdDir.StreamType = MemoryListStream;
736 mdDir.Location.Rva = dc.rva;
737 dump_memory_info(&dc);
738 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
739 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
740 &mdDir, sizeof(mdDir));
742 mdDir.StreamType = SystemInfoStream;
743 mdDir.Location.Rva = dc.rva;
744 dump_system_info(&dc);
745 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
746 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
747 &mdDir, sizeof(mdDir));
749 mdDir.StreamType = MiscInfoStream;
750 mdDir.Location.Rva = dc.rva;
751 dump_misc_info(&dc);
752 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
753 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
754 &mdDir, sizeof(mdDir));
756 /* 3.2) write exception information (if any) */
757 if (ExceptionParam)
759 mdDir.StreamType = ExceptionStream;
760 mdDir.Location.Rva = dc.rva;
761 dump_exception_info(&dc, ExceptionParam);
762 mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
763 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
764 &mdDir, sizeof(mdDir));
767 /* 3.3) write user defined streams (if any) */
768 if (UserStreamParam)
770 for (i = 0; i < UserStreamParam->UserStreamCount; i++)
772 mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
773 mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
774 mdDir.Location.Rva = dc.rva;
775 writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
776 &mdDir, sizeof(mdDir));
777 append(&dc, UserStreamParam->UserStreamArray[i].Buffer,
778 UserStreamParam->UserStreamArray[i].BufferSize);
782 HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
783 HeapFree(GetProcessHeap(), 0, dc.mem);
784 HeapFree(GetProcessHeap(), 0, dc.module);
786 return TRUE;
789 /******************************************************************
790 * MiniDumpReadDumpStream (DEBUGHLP.@)
794 BOOL WINAPI MiniDumpReadDumpStream(void* base, ULONG str_idx,
795 PMINIDUMP_DIRECTORY* pdir,
796 void** stream, ULONG* size)
798 MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
800 if (mdHead->Signature == MINIDUMP_SIGNATURE)
802 MINIDUMP_DIRECTORY* dir;
803 int i;
805 dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
806 for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
808 if (dir->StreamType == str_idx)
810 *pdir = dir;
811 *stream = (char*)base + dir->Location.Rva;
812 *size = dir->Location.DataSize;
813 return TRUE;
817 SetLastError(ERROR_INVALID_PARAMETER);
818 return FALSE;