2 * File minidump.c - management of dumps (read & write)
4 * Copyright (C) 2004, 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
);
53 /* process & thread information */
57 SYSTEM_PROCESS_INFORMATION
* spi
;
58 /* module information */
59 struct dump_module
* module
;
61 /* exception information */
62 /* output information */
66 struct dump_memory
* mem
;
68 /* callback information */
69 MINIDUMP_CALLBACK_INFORMATION
* cb
;
72 /******************************************************************
75 * reads system wide process information, and make spi point to the record
76 * for process of id 'pid'
78 static BOOL
fetch_process_info(struct dump_context
* dc
)
80 ULONG buf_size
= 0x1000;
83 dc
->pcs_buffer
= NULL
;
84 if (!(dc
->pcs_buffer
= HeapAlloc(GetProcessHeap(), 0, buf_size
))) return FALSE
;
87 nts
= NtQuerySystemInformation(SystemProcessInformation
,
88 dc
->pcs_buffer
, buf_size
, NULL
);
89 if (nts
!= STATUS_INFO_LENGTH_MISMATCH
) break;
90 dc
->pcs_buffer
= HeapReAlloc(GetProcessHeap(), 0, dc
->pcs_buffer
,
92 if (!dc
->pcs_buffer
) return FALSE
;
95 if (nts
== STATUS_SUCCESS
)
97 dc
->spi
= dc
->pcs_buffer
;
100 if (dc
->spi
->dwProcessID
== dc
->pid
) return TRUE
;
101 if (!dc
->spi
->dwOffset
) break;
102 dc
->spi
= (SYSTEM_PROCESS_INFORMATION
*)
103 ((char*)dc
->spi
+ dc
->spi
->dwOffset
);
106 HeapFree(GetProcessHeap(), 0, dc
->pcs_buffer
);
107 dc
->pcs_buffer
= NULL
;
112 /******************************************************************
115 * fetches some information about thread of id 'tid'
117 static BOOL
fetch_thread_info(struct dump_context
* dc
, int thd_idx
,
118 MINIDUMP_THREAD
* mdThd
, CONTEXT
* ctx
)
121 DWORD tid
= dc
->spi
->ti
[thd_idx
].dwThreadID
;
123 THREAD_BASIC_INFORMATION tbi
;
125 memset(ctx
, 0, sizeof(*ctx
));
127 mdThd
->ThreadId
= dc
->spi
->ti
[thd_idx
].dwThreadID
;
128 mdThd
->SuspendCount
= 0;
130 mdThd
->Stack
.StartOfMemoryRange
= 0;
131 mdThd
->Stack
.Memory
.DataSize
= 0;
132 mdThd
->Stack
.Memory
.Rva
= 0;
133 mdThd
->ThreadContext
.DataSize
= 0;
134 mdThd
->ThreadContext
.Rva
= 0;
135 mdThd
->PriorityClass
= dc
->spi
->ti
[thd_idx
].dwBasePriority
; /* FIXME */
136 mdThd
->Priority
= dc
->spi
->ti
[thd_idx
].dwCurrentPriority
;
138 if ((hThread
= OpenThread(THREAD_ALL_ACCESS
, FALSE
, tid
)) == NULL
)
140 FIXME("Couldn't open thread %lu (%lu)\n",
141 dc
->spi
->ti
[thd_idx
].dwThreadID
, GetLastError());
145 if (NtQueryInformationThread(hThread
, ThreadBasicInformation
,
146 &tbi
, sizeof(tbi
), NULL
) == STATUS_SUCCESS
)
148 mdThd
->Teb
= (ULONG_PTR
)tbi
.TebBaseAddress
;
149 if (tbi
.ExitStatus
== STILL_ACTIVE
&& tid
!= GetCurrentThreadId() &&
150 (mdThd
->SuspendCount
= SuspendThread(hThread
)) != (DWORD
)-1)
152 mdThd
->SuspendCount
--;
153 ctx
->ContextFlags
= CONTEXT_FULL
;
154 if (!GetThreadContext(hThread
, ctx
))
155 memset(ctx
, 0, sizeof(*ctx
));
157 if (ReadProcessMemory(dc
->hProcess
, tbi
.TebBaseAddress
,
158 &tib
, sizeof(tib
), NULL
))
161 /* limiting the stack dumping to the size actually used */
163 mdThd
->Stack
.StartOfMemoryRange
= (ctx
->Esp
- 4);
165 mdThd
->Stack
.StartOfMemoryRange
= (ULONG_PTR
)tib
.StackLimit
;
166 mdThd
->Stack
.Memory
.DataSize
= (ULONG_PTR
)tib
.StackBase
-
167 mdThd
->Stack
.StartOfMemoryRange
;
169 #error unsupported CPU
172 ResumeThread(hThread
);
175 CloseHandle(hThread
);
179 /******************************************************************
182 * Add a module to a dump context
184 static BOOL
add_module(struct dump_context
* dc
, const char* name
,
185 DWORD base
, DWORD size
, BOOL is_elf
)
188 dc
->module
= HeapAlloc(GetProcessHeap(), 0, ++dc
->num_module
* sizeof(*dc
->module
));
190 dc
->module
= HeapReAlloc(GetProcessHeap(), 0, dc
->module
, ++dc
->num_module
* sizeof(*dc
->module
));
191 if (!dc
->module
) return FALSE
;
193 !GetModuleFileNameExA(dc
->hProcess
, (HMODULE
)base
,
194 dc
->module
[dc
->num_module
- 1].name
,
195 sizeof(dc
->module
[dc
->num_module
- 1].name
)))
196 lstrcpynA(dc
->module
[dc
->num_module
- 1].name
, name
,
197 sizeof(dc
->module
[dc
->num_module
- 1].name
));
198 dc
->module
[dc
->num_module
- 1].base
= base
;
199 dc
->module
[dc
->num_module
- 1].size
= size
;
200 dc
->module
[dc
->num_module
- 1].is_elf
= is_elf
;
205 /******************************************************************
206 * fetch_pe_module_info_cb
208 * Callback for accumulating in dump_context a PE modules set
210 static BOOL WINAPI
fetch_pe_module_info_cb(char* name
, DWORD base
, DWORD size
,
213 return add_module((struct dump_context
*)user
, name
, base
, size
, FALSE
);
216 /******************************************************************
217 * fetch_elf_module_info_cb
219 * Callback for accumulating in dump_context a ELF modules set
221 static BOOL
fetch_elf_module_info_cb(const char* name
, unsigned long base
,
224 return add_module((struct dump_context
*)user
, name
,
225 base
, 0 /* FIXME */, TRUE
);
228 static void fetch_module_info(struct dump_context
* dc
)
230 WINE_FIXME("--> %p\n", dc
->hProcess
);
231 EnumerateLoadedModules(dc
->hProcess
, fetch_pe_module_info_cb
, dc
);
232 /* Since we include ELF modules in a separate stream from the regular PE ones,
233 * we can always include those ELF modules (they don't eat lots of space)
234 * And it's always a good idea to have a trace of the loaded ELF modules for
235 * a given application in a post mortem debugging condition.
237 elf_enum_modules(dc
->hProcess
, fetch_elf_module_info_cb
, dc
);
240 /******************************************************************
243 * Add a memory block to be dumped in a minidump
244 * If rva is non 0, it's the rva in the minidump where has to be stored
245 * also the rva of the memory block when written (this allows to reference
246 * a memory block from outside the list of memory blocks).
248 static void add_memory_block(struct dump_context
* dc
, ULONG64 base
, ULONG size
, ULONG rva
)
251 dc
->mem
= HeapReAlloc(GetProcessHeap(), 0, dc
->mem
,
252 ++dc
->num_mem
* sizeof(*dc
->mem
));
254 dc
->mem
= HeapAlloc(GetProcessHeap(), 0, ++dc
->num_mem
* sizeof(*dc
->mem
));
257 dc
->mem
[dc
->num_mem
- 1].base
= base
;
258 dc
->mem
[dc
->num_mem
- 1].size
= size
;
259 dc
->mem
[dc
->num_mem
- 1].rva
= rva
;
261 else dc
->num_mem
= 0;
264 /******************************************************************
267 * Writes a chunk of data at a given position in the minidump
269 static void writeat(struct dump_context
* dc
, RVA rva
, void* data
, unsigned size
)
273 SetFilePointer(dc
->hFile
, rva
, NULL
, FILE_BEGIN
);
274 WriteFile(dc
->hFile
, data
, size
, &written
, NULL
);
277 /******************************************************************
280 * writes a new chunk of data to the minidump, increasing the current
283 static void append(struct dump_context
* dc
, void* data
, unsigned size
)
285 writeat(dc
, dc
->rva
, data
, size
);
289 /******************************************************************
290 * dump_exception_info
292 * Write in File the exception information from pcs
294 static void dump_exception_info(struct dump_context
* dc
,
295 const MINIDUMP_EXCEPTION_INFORMATION
* except
)
297 MINIDUMP_EXCEPTION_STREAM mdExcpt
;
298 EXCEPTION_RECORD rec
, *prec
;
302 mdExcpt
.ThreadId
= except
->ThreadId
;
303 mdExcpt
.__alignment
= 0;
304 if (except
->ClientPointers
)
306 EXCEPTION_POINTERS ep
;
308 ReadProcessMemory(dc
->hProcess
,
309 except
->ExceptionPointers
, &ep
, sizeof(ep
), NULL
);
310 ReadProcessMemory(dc
->hProcess
,
311 ep
.ExceptionRecord
, &rec
, sizeof(rec
), NULL
);
312 ReadProcessMemory(dc
->hProcess
,
313 ep
.ContextRecord
, &ctx
, sizeof(ctx
), NULL
);
320 prec
= except
->ExceptionPointers
->ExceptionRecord
;
321 pctx
= except
->ExceptionPointers
->ContextRecord
;
323 mdExcpt
.ExceptionRecord
.ExceptionCode
= prec
->ExceptionCode
;
324 mdExcpt
.ExceptionRecord
.ExceptionFlags
= prec
->ExceptionFlags
;
325 mdExcpt
.ExceptionRecord
.ExceptionRecord
= (DWORD_PTR
)prec
->ExceptionRecord
;
326 mdExcpt
.ExceptionRecord
.ExceptionAddress
= (DWORD_PTR
)prec
->ExceptionAddress
;
327 mdExcpt
.ExceptionRecord
.NumberParameters
= prec
->NumberParameters
;
328 mdExcpt
.ExceptionRecord
.__unusedAlignment
= 0;
329 for (i
= 0; i
< mdExcpt
.ExceptionRecord
.NumberParameters
; i
++)
330 mdExcpt
.ExceptionRecord
.ExceptionInformation
[i
] = (DWORD_PTR
)prec
->ExceptionInformation
[i
];
331 mdExcpt
.ThreadContext
.DataSize
= sizeof(*pctx
);
332 mdExcpt
.ThreadContext
.Rva
= dc
->rva
+ sizeof(mdExcpt
);
334 append(dc
, &mdExcpt
, sizeof(mdExcpt
));
335 append(dc
, pctx
, sizeof(*pctx
));
338 /******************************************************************
341 * Write in File the modules from pcs
343 static void dump_modules(struct dump_context
* dc
, BOOL dump_elf
)
345 MINIDUMP_MODULE mdModule
;
346 MINIDUMP_MODULE_LIST mdModuleList
;
348 MINIDUMP_STRING
* ms
= (MINIDUMP_STRING
*)tmp
;
353 for (i
= nmod
= 0; i
< dc
->num_module
; i
++)
355 if ((dc
->module
[i
].is_elf
&& dump_elf
) || (!dc
->module
[i
].is_elf
&& !dump_elf
))
359 mdModuleList
.NumberOfModules
= 0;
360 /* reserve space for mdModuleList
361 * FIXME: since we don't support 0 length arrays, we cannot use the
362 * size of mdModuleList
363 * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
366 dc
->rva
+= sizeof(mdModuleList
.NumberOfModules
) + sizeof(mdModule
) * nmod
;
367 for (i
= 0; i
< dc
->num_module
; i
++)
369 if ((dc
->module
[i
].is_elf
&& !dump_elf
) || (!dc
->module
[i
].is_elf
&& dump_elf
))
372 flags_out
= ModuleWriteModule
| ModuleWriteMiscRecord
| ModuleWriteCvRecord
;
373 if (dc
->type
& MiniDumpWithDataSegs
)
374 flags_out
|= ModuleWriteDataSeg
;
375 if (dc
->type
& MiniDumpWithProcessThreadData
)
376 flags_out
|= ModuleWriteTlsData
;
377 if (dc
->type
& MiniDumpWithCodeSegs
)
378 flags_out
|= ModuleWriteCodeSegs
;
379 ms
->Length
= MultiByteToWideChar(CP_ACP
, 0,
380 dc
->module
[i
].name
, -1,
381 NULL
, 0) * sizeof(WCHAR
);
382 if (sizeof(ULONG
) + ms
->Length
> sizeof(tmp
))
383 FIXME("Buffer overflow!!!\n");
384 MultiByteToWideChar(CP_ACP
, 0, dc
->module
[i
].name
, -1,
385 ms
->Buffer
, ms
->Length
);
389 MINIDUMP_CALLBACK_INPUT cbin
;
390 MINIDUMP_CALLBACK_OUTPUT cbout
;
392 cbin
.ProcessId
= dc
->pid
;
393 cbin
.ProcessHandle
= dc
->hProcess
;
394 cbin
.CallbackType
= ModuleCallback
;
396 cbin
.u
.Module
.FullPath
= ms
->Buffer
;
397 cbin
.u
.Module
.BaseOfImage
= dc
->module
[i
].base
;
398 cbin
.u
.Module
.SizeOfImage
= dc
->module
[i
].size
;
399 cbin
.u
.Module
.CheckSum
= 0; /* FIXME */
400 cbin
.u
.Module
.TimeDateStamp
= 0; /* FIXME */
401 memset(&cbin
.u
.Module
.VersionInfo
, 0, sizeof(cbin
.u
.Module
.VersionInfo
));
402 cbin
.u
.Module
.CvRecord
= NULL
;
403 cbin
.u
.Module
.SizeOfCvRecord
= 0;
404 cbin
.u
.Module
.MiscRecord
= NULL
;
405 cbin
.u
.Module
.SizeOfMiscRecord
= 0;
407 cbout
.u
.ModuleWriteFlags
= flags_out
;
408 if (!dc
->cb
->CallbackRoutine(dc
->cb
->CallbackParam
, &cbin
, &cbout
))
410 flags_out
&= cbout
.u
.ModuleWriteFlags
;
412 if (flags_out
& ModuleWriteModule
)
414 mdModule
.BaseOfImage
= dc
->module
[i
].base
;
415 mdModule
.SizeOfImage
= dc
->module
[i
].size
;
416 mdModule
.CheckSum
= 0; /* FIXME */
417 mdModule
.TimeDateStamp
= 0; /* FIXME */
418 mdModule
.ModuleNameRva
= dc
->rva
;
419 ms
->Length
-= sizeof(WCHAR
);
420 append(dc
, ms
, sizeof(ULONG
) + ms
->Length
);
421 memset(&mdModule
.VersionInfo
, 0, sizeof(mdModule
.VersionInfo
)); /* FIXME */
422 mdModule
.CvRecord
.DataSize
= 0; /* FIXME */
423 mdModule
.CvRecord
.Rva
= 0; /* FIXME */
424 mdModule
.MiscRecord
.DataSize
= 0; /* FIXME */
425 mdModule
.MiscRecord
.Rva
= 0; /* FIXME */
426 mdModule
.Reserved0
= 0; /* FIXME */
427 mdModule
.Reserved1
= 0; /* FIXME */
429 rva_base
+ sizeof(mdModuleList
.NumberOfModules
) +
430 mdModuleList
.NumberOfModules
++ * sizeof(mdModule
),
431 &mdModule
, sizeof(mdModule
));
434 writeat(dc
, rva_base
, &mdModuleList
.NumberOfModules
,
435 sizeof(mdModuleList
.NumberOfModules
));
438 /******************************************************************
441 * Dumps into File the information about the system
443 static void dump_system_info(struct dump_context
* dc
)
445 MINIDUMP_SYSTEM_INFO mdSysInfo
;
447 OSVERSIONINFOW osInfo
;
451 GetSystemInfo(&sysInfo
);
452 osInfo
.dwOSVersionInfoSize
= sizeof(osInfo
);
453 GetVersionExW(&osInfo
);
455 mdSysInfo
.ProcessorArchitecture
= sysInfo
.u
.s
.wProcessorArchitecture
;
456 mdSysInfo
.ProcessorLevel
= sysInfo
.wProcessorLevel
;
457 mdSysInfo
.ProcessorRevision
= sysInfo
.wProcessorRevision
;
458 mdSysInfo
.u
.s
.NumberOfProcessors
= sysInfo
.dwNumberOfProcessors
;
459 mdSysInfo
.u
.s
.ProductType
= VER_NT_WORKSTATION
; /* FIXME */
460 mdSysInfo
.MajorVersion
= osInfo
.dwMajorVersion
;
461 mdSysInfo
.MinorVersion
= osInfo
.dwMinorVersion
;
462 mdSysInfo
.BuildNumber
= osInfo
.dwBuildNumber
;
463 mdSysInfo
.PlatformId
= osInfo
.dwPlatformId
;
465 mdSysInfo
.CSDVersionRva
= dc
->rva
+ sizeof(mdSysInfo
);
466 mdSysInfo
.u1
.Reserved1
= 0;
468 memset(&mdSysInfo
.Cpu
, 0, sizeof(mdSysInfo
.Cpu
));
470 append(dc
, &mdSysInfo
, sizeof(mdSysInfo
));
472 slen
= lstrlenW(osInfo
.szCSDVersion
) * sizeof(WCHAR
);
473 WriteFile(dc
->hFile
, &slen
, sizeof(slen
), &written
, NULL
);
474 WriteFile(dc
->hFile
, osInfo
.szCSDVersion
, slen
, &written
, NULL
);
475 dc
->rva
+= sizeof(ULONG
) + slen
;
478 /******************************************************************
481 * Dumps into File the information about running threads
483 static void dump_threads(struct dump_context
* dc
)
485 MINIDUMP_THREAD mdThd
;
486 MINIDUMP_THREAD_LIST mdThdList
;
492 mdThdList
.NumberOfThreads
= 0;
495 dc
->rva
+= sizeof(mdThdList
.NumberOfThreads
) +
496 dc
->spi
->dwThreadCount
* sizeof(mdThd
);
498 for (i
= 0; i
< dc
->spi
->dwThreadCount
; i
++)
500 fetch_thread_info(dc
, i
, &mdThd
, &ctx
);
502 flags_out
= ThreadWriteThread
| ThreadWriteStack
| ThreadWriteContext
|
503 ThreadWriteInstructionWindow
;
504 if (dc
->type
& MiniDumpWithProcessThreadData
)
505 flags_out
|= ThreadWriteThreadData
;
506 if (dc
->type
& MiniDumpWithThreadInfo
)
507 flags_out
|= ThreadWriteThreadInfo
;
511 MINIDUMP_CALLBACK_INPUT cbin
;
512 MINIDUMP_CALLBACK_OUTPUT cbout
;
514 cbin
.ProcessId
= dc
->pid
;
515 cbin
.ProcessHandle
= dc
->hProcess
;
516 cbin
.CallbackType
= ThreadCallback
;
517 cbin
.u
.Thread
.ThreadId
= dc
->spi
->ti
[i
].dwThreadID
;
518 cbin
.u
.Thread
.ThreadHandle
= 0; /* FIXME */
519 memcpy(&cbin
.u
.Thread
.Context
, &ctx
, sizeof(CONTEXT
));
520 cbin
.u
.Thread
.SizeOfContext
= sizeof(CONTEXT
);
521 cbin
.u
.Thread
.StackBase
= mdThd
.Stack
.StartOfMemoryRange
;
522 cbin
.u
.Thread
.StackEnd
= mdThd
.Stack
.StartOfMemoryRange
+
523 mdThd
.Stack
.Memory
.DataSize
;
525 cbout
.u
.ThreadWriteFlags
= flags_out
;
526 if (!dc
->cb
->CallbackRoutine(dc
->cb
->CallbackParam
, &cbin
, &cbout
))
528 flags_out
&= cbout
.u
.ThreadWriteFlags
;
530 if (flags_out
& ThreadWriteThread
)
532 if (ctx
.ContextFlags
&& (flags_out
& ThreadWriteContext
))
534 mdThd
.ThreadContext
.Rva
= dc
->rva
;
535 mdThd
.ThreadContext
.DataSize
= sizeof(CONTEXT
);
536 append(dc
, &ctx
, sizeof(CONTEXT
));
538 if (mdThd
.Stack
.Memory
.DataSize
&& (flags_out
& ThreadWriteStack
))
540 add_memory_block(dc
, mdThd
.Stack
.StartOfMemoryRange
,
541 mdThd
.Stack
.Memory
.DataSize
,
542 rva_base
+ sizeof(mdThdList
.NumberOfThreads
) +
543 mdThdList
.NumberOfThreads
* sizeof(mdThd
) +
544 FIELD_OFFSET(MINIDUMP_THREAD
, Stack
.Memory
.Rva
));
547 rva_base
+ sizeof(mdThdList
.NumberOfThreads
) +
548 mdThdList
.NumberOfThreads
* sizeof(mdThd
),
549 &mdThd
, sizeof(mdThd
));
550 mdThdList
.NumberOfThreads
++;
552 if (ctx
.ContextFlags
&& (flags_out
& ThreadWriteInstructionWindow
))
554 /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
555 * - also crop values across module boundaries,
556 * - and don't make it i386 dependent
558 /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
561 writeat(dc
, rva_base
,
562 &mdThdList
.NumberOfThreads
, sizeof(mdThdList
.NumberOfThreads
));
565 /******************************************************************
568 * dumps information about the memory of the process (stack of the threads)
570 static void dump_memory_info(struct dump_context
* dc
)
572 MINIDUMP_MEMORY_LIST mdMemList
;
573 MINIDUMP_MEMORY_DESCRIPTOR mdMem
;
575 unsigned i
, pos
, len
;
579 mdMemList
.NumberOfMemoryRanges
= dc
->num_mem
;
580 append(dc
, &mdMemList
.NumberOfMemoryRanges
,
581 sizeof(mdMemList
.NumberOfMemoryRanges
));
583 dc
->rva
+= mdMemList
.NumberOfMemoryRanges
* sizeof(mdMem
);
585 for (i
= 0; i
< dc
->num_mem
; i
++)
587 mdMem
.StartOfMemoryRange
= dc
->mem
[i
].base
;
588 mdMem
.Memory
.Rva
= dc
->rva
;
589 mdMem
.Memory
.DataSize
= dc
->mem
[i
].size
;
590 SetFilePointer(dc
->hFile
, dc
->rva
, NULL
, FILE_BEGIN
);
591 for (pos
= 0; pos
< dc
->mem
[i
].size
; pos
+= sizeof(tmp
))
593 len
= min(dc
->mem
[i
].size
- pos
, sizeof(tmp
));
594 if (ReadProcessMemory(dc
->hProcess
,
595 (void*)(ULONG
)(dc
->mem
[i
].base
+ pos
),
597 WriteFile(dc
->hFile
, tmp
, len
, &written
, NULL
);
599 dc
->rva
+= mdMem
.Memory
.DataSize
;
600 writeat(dc
, rva_base
+ i
* sizeof(mdMem
), &mdMem
, sizeof(mdMem
));
603 writeat(dc
, dc
->mem
[i
].rva
, &mdMem
.Memory
.Rva
, sizeof(mdMem
.Memory
.Rva
));
608 static void dump_misc_info(struct dump_context
* dc
)
610 MINIDUMP_MISC_INFO mmi
;
612 mmi
.SizeOfInfo
= sizeof(mmi
);
613 mmi
.Flags1
= MINIDUMP_MISC1_PROCESS_ID
;
614 mmi
.ProcessId
= dc
->pid
;
615 /* FIXME: create/user/kernel time */
616 append(dc
, &mmi
, sizeof(mmi
));
619 /******************************************************************
620 * MiniDumpWriteDump (DEBUGHLP.@)
624 BOOL WINAPI
MiniDumpWriteDump(HANDLE hProcess
, DWORD pid
, HANDLE hFile
,
625 MINIDUMP_TYPE DumpType
,
626 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam
,
627 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam
,
628 PMINIDUMP_CALLBACK_INFORMATION CallbackParam
)
630 MINIDUMP_HEADER mdHead
;
631 MINIDUMP_DIRECTORY mdDir
;
632 DWORD i
, nStreams
, idx_stream
;
633 struct dump_context dc
;
635 dc
.hProcess
= hProcess
;
640 dc
.cb
= CallbackParam
;
646 if (!fetch_process_info(&dc
)) return FALSE
;
647 fetch_module_info(&dc
);
650 nStreams
= 6 + (ExceptionParam
? 1 : 0) +
651 (UserStreamParam
? UserStreamParam
->UserStreamCount
: 0);
653 if (DumpType
& MiniDumpWithDataSegs
)
654 FIXME("NIY MiniDumpWithDataSegs\n");
655 if (DumpType
& MiniDumpWithFullMemory
)
656 FIXME("NIY MiniDumpWithFullMemory\n");
657 if (DumpType
& MiniDumpWithHandleData
)
658 FIXME("NIY MiniDumpWithHandleData\n");
659 if (DumpType
& MiniDumpFilterMemory
)
660 FIXME("NIY MiniDumpFilterMemory\n");
661 if (DumpType
& MiniDumpScanMemory
)
662 FIXME("NIY MiniDumpScanMemory\n");
664 /* 2) write header */
665 mdHead
.Signature
= MINIDUMP_SIGNATURE
;
666 mdHead
.Version
= MINIDUMP_VERSION
;
667 mdHead
.NumberOfStreams
= nStreams
;
668 mdHead
.StreamDirectoryRva
= sizeof(mdHead
);
669 mdHead
.u
.TimeDateStamp
= time(NULL
);
670 mdHead
.Flags
= DumpType
;
671 append(&dc
, &mdHead
, sizeof(mdHead
));
673 /* 3) write stream directories */
674 dc
.rva
+= nStreams
* sizeof(mdDir
);
677 /* 3.1) write data stream directories */
679 mdDir
.StreamType
= ThreadListStream
;
680 mdDir
.Location
.Rva
= dc
.rva
;
682 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
683 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
684 &mdDir
, sizeof(mdDir
));
686 mdDir
.StreamType
= ModuleListStream
;
687 mdDir
.Location
.Rva
= dc
.rva
;
688 dump_modules(&dc
, FALSE
);
689 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
690 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
691 &mdDir
, sizeof(mdDir
));
693 mdDir
.StreamType
= 0xfff0; /* FIXME: this is part of MS reserved streams */
694 mdDir
.Location
.Rva
= dc
.rva
;
695 dump_modules(&dc
, TRUE
);
696 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
697 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
698 &mdDir
, sizeof(mdDir
));
700 mdDir
.StreamType
= MemoryListStream
;
701 mdDir
.Location
.Rva
= dc
.rva
;
702 dump_memory_info(&dc
);
703 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
704 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
705 &mdDir
, sizeof(mdDir
));
707 mdDir
.StreamType
= SystemInfoStream
;
708 mdDir
.Location
.Rva
= dc
.rva
;
709 dump_system_info(&dc
);
710 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
711 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
712 &mdDir
, sizeof(mdDir
));
714 mdDir
.StreamType
= MiscInfoStream
;
715 mdDir
.Location
.Rva
= dc
.rva
;
717 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
718 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
719 &mdDir
, sizeof(mdDir
));
721 /* 3.2) write exception information (if any) */
724 mdDir
.StreamType
= ExceptionStream
;
725 mdDir
.Location
.Rva
= dc
.rva
;
726 dump_exception_info(&dc
, ExceptionParam
);
727 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
728 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
729 &mdDir
, sizeof(mdDir
));
732 /* 3.3) write user defined streams (if any) */
735 for (i
= 0; i
< UserStreamParam
->UserStreamCount
; i
++)
737 mdDir
.StreamType
= UserStreamParam
->UserStreamArray
[i
].Type
;
738 mdDir
.Location
.DataSize
= UserStreamParam
->UserStreamArray
[i
].BufferSize
;
739 mdDir
.Location
.Rva
= dc
.rva
;
740 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
741 &mdDir
, sizeof(mdDir
));
742 append(&dc
, UserStreamParam
->UserStreamArray
[i
].Buffer
,
743 UserStreamParam
->UserStreamArray
[i
].BufferSize
);
747 HeapFree(GetProcessHeap(), 0, dc
.pcs_buffer
);
748 HeapFree(GetProcessHeap(), 0, dc
.mem
);
749 HeapFree(GetProcessHeap(), 0, dc
.module
);
754 /******************************************************************
755 * MiniDumpReadDumpStream (DEBUGHLP.@)
759 BOOL WINAPI
MiniDumpReadDumpStream(void* base
, ULONG str_idx
,
760 PMINIDUMP_DIRECTORY
* pdir
,
761 void** stream
, ULONG
* size
)
763 MINIDUMP_HEADER
* mdHead
= (MINIDUMP_HEADER
*)base
;
765 if (mdHead
->Signature
== MINIDUMP_SIGNATURE
)
767 MINIDUMP_DIRECTORY
* dir
;
770 dir
= (MINIDUMP_DIRECTORY
*)((char*)base
+ mdHead
->StreamDirectoryRva
);
771 for (i
= 0; i
< mdHead
->NumberOfStreams
; i
++, dir
++)
773 if (dir
->StreamType
== str_idx
)
776 *stream
= (char*)base
+ dir
->Location
.Rva
;
777 *size
= dir
->Location
.DataSize
;
782 SetLastError(ERROR_INVALID_PARAMETER
);