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
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
27 #define WIN32_NO_STATUS
28 #include "dbghelp_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
56 /* process & thread information */
60 SYSTEM_PROCESS_INFORMATION
* spi
;
61 /* module information */
62 struct dump_module
* module
;
64 /* exception information */
65 /* output information */
69 struct dump_memory
* mem
;
71 /* callback information */
72 MINIDUMP_CALLBACK_INFORMATION
* cb
;
75 /******************************************************************
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;
86 dc
->pcs_buffer
= NULL
;
87 if (!(dc
->pcs_buffer
= HeapAlloc(GetProcessHeap(), 0, buf_size
))) return FALSE
;
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
,
95 if (!dc
->pcs_buffer
) return FALSE
;
98 if (nts
== STATUS_SUCCESS
)
100 dc
->spi
= dc
->pcs_buffer
;
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
;
115 static void fetch_thread_stack(struct dump_context
* dc
, void* teb_addr
,
116 const CONTEXT
* ctx
, MINIDUMP_MEMORY_DESCRIPTOR
* mmd
)
120 if (ReadProcessMemory(dc
->hProcess
, teb_addr
, &tib
, sizeof(tib
), NULL
))
123 /* limiting the stack dumping to the size actually used */
125 mmd
->StartOfMemoryRange
= (ctx
->Esp
- 4);
127 mmd
->StartOfMemoryRange
= (ULONG_PTR
)tib
.StackLimit
;
128 #elif defined(__powerpc__)
130 mmd
->StartOfMemoryRange
= ctx
->Iar
- 4;
132 mmd
->StartOfMemoryRange
= (ULONG_PTR
)tib
.StackLimit
;
133 #elif defined(__x86_64__)
135 mmd
->StartOfMemoryRange
= (ctx
->Rsp
- 8);
137 mmd
->StartOfMemoryRange
= (ULONG_PTR
)tib
.StackLimit
;
139 #error unsupported CPU
141 mmd
->Memory
.DataSize
= (ULONG_PTR
)tib
.StackBase
- mmd
->StartOfMemoryRange
;
145 /******************************************************************
148 * fetches some information about thread of id 'tid'
150 static BOOL
fetch_thread_info(struct dump_context
* dc
, int thd_idx
,
151 const MINIDUMP_EXCEPTION_INFORMATION
* except
,
152 MINIDUMP_THREAD
* mdThd
, CONTEXT
* ctx
)
154 DWORD tid
= dc
->spi
->ti
[thd_idx
].dwThreadID
;
156 THREAD_BASIC_INFORMATION tbi
;
158 memset(ctx
, 0, sizeof(*ctx
));
160 mdThd
->ThreadId
= dc
->spi
->ti
[thd_idx
].dwThreadID
;
161 mdThd
->SuspendCount
= 0;
163 mdThd
->Stack
.StartOfMemoryRange
= 0;
164 mdThd
->Stack
.Memory
.DataSize
= 0;
165 mdThd
->Stack
.Memory
.Rva
= 0;
166 mdThd
->ThreadContext
.DataSize
= 0;
167 mdThd
->ThreadContext
.Rva
= 0;
168 mdThd
->PriorityClass
= dc
->spi
->ti
[thd_idx
].dwBasePriority
; /* FIXME */
169 mdThd
->Priority
= dc
->spi
->ti
[thd_idx
].dwCurrentPriority
;
171 if ((hThread
= OpenThread(THREAD_ALL_ACCESS
, FALSE
, tid
)) == NULL
)
173 FIXME("Couldn't open thread %u (%u)\n",
174 dc
->spi
->ti
[thd_idx
].dwThreadID
, GetLastError());
178 if (NtQueryInformationThread(hThread
, ThreadBasicInformation
,
179 &tbi
, sizeof(tbi
), NULL
) == STATUS_SUCCESS
)
181 mdThd
->Teb
= (ULONG_PTR
)tbi
.TebBaseAddress
;
182 if (tbi
.ExitStatus
== STILL_ACTIVE
)
184 if (tid
!= GetCurrentThreadId() &&
185 (mdThd
->SuspendCount
= SuspendThread(hThread
)) != (DWORD
)-1)
187 mdThd
->SuspendCount
--;
188 ctx
->ContextFlags
= CONTEXT_FULL
;
189 if (!GetThreadContext(hThread
, ctx
))
190 memset(ctx
, 0, sizeof(*ctx
));
192 fetch_thread_stack(dc
, tbi
.TebBaseAddress
, ctx
, &mdThd
->Stack
);
193 ResumeThread(hThread
);
195 else if (tid
== GetCurrentThreadId() && except
)
198 if (except
->ClientPointers
)
200 EXCEPTION_POINTERS ep
;
202 ReadProcessMemory(dc
->hProcess
, except
->ExceptionPointers
,
203 &ep
, sizeof(ep
), NULL
);
204 ReadProcessMemory(dc
->hProcess
, ep
.ContextRecord
,
205 &ctx
, sizeof(ctx
), NULL
);
208 else pctx
= except
->ExceptionPointers
->ContextRecord
;
209 fetch_thread_stack(dc
, tbi
.TebBaseAddress
, pctx
, &mdThd
->Stack
);
213 CloseHandle(hThread
);
217 /******************************************************************
220 * Add a module to a dump context
222 static BOOL
add_module(struct dump_context
* dc
, const WCHAR
* name
,
223 DWORD base
, DWORD size
, DWORD timestamp
, DWORD checksum
,
227 dc
->module
= HeapAlloc(GetProcessHeap(), 0,
228 ++dc
->num_module
* sizeof(*dc
->module
));
230 dc
->module
= HeapReAlloc(GetProcessHeap(), 0, dc
->module
,
231 ++dc
->num_module
* sizeof(*dc
->module
));
232 if (!dc
->module
) return FALSE
;
234 !GetModuleFileNameExW(dc
->hProcess
, (HMODULE
)base
,
235 dc
->module
[dc
->num_module
- 1].name
,
236 sizeof(dc
->module
[dc
->num_module
- 1].name
) / sizeof(WCHAR
)))
237 lstrcpynW(dc
->module
[dc
->num_module
- 1].name
, name
,
238 sizeof(dc
->module
[dc
->num_module
- 1].name
) / sizeof(WCHAR
));
239 dc
->module
[dc
->num_module
- 1].base
= base
;
240 dc
->module
[dc
->num_module
- 1].size
= size
;
241 dc
->module
[dc
->num_module
- 1].timestamp
= timestamp
;
242 dc
->module
[dc
->num_module
- 1].checksum
= checksum
;
243 dc
->module
[dc
->num_module
- 1].is_elf
= is_elf
;
248 /******************************************************************
249 * fetch_pe_module_info_cb
251 * Callback for accumulating in dump_context a PE modules set
253 static BOOL WINAPI
fetch_pe_module_info_cb(WCHAR
* name
, DWORD64 base
, DWORD size
,
256 struct dump_context
* dc
= (struct dump_context
*)user
;
257 IMAGE_NT_HEADERS nth
;
259 if (!validate_addr64(base
)) return FALSE
;
261 if (pe_load_nt_header(dc
->hProcess
, base
, &nth
))
262 add_module((struct dump_context
*)user
, name
, base
, size
,
263 nth
.FileHeader
.TimeDateStamp
, nth
.OptionalHeader
.CheckSum
,
268 /******************************************************************
269 * fetch_elf_module_info_cb
271 * Callback for accumulating in dump_context an ELF modules set
273 static BOOL
fetch_elf_module_info_cb(const WCHAR
* name
, unsigned long base
,
276 struct dump_context
* dc
= (struct dump_context
*)user
;
277 DWORD rbase
, size
, checksum
;
280 /* FIXME: there's no relevant timestamp on ELF modules */
281 /* NB: if we have a non-null base from the live-target use it (whenever
282 * the ELF module is relocatable or not). If we have a null base (ELF
283 * module isn't relocatable) then grab its base address from ELF file
285 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, tmp
, sizeof(tmp
), 0, 0);
286 if (!elf_fetch_file_info(tmp
, &rbase
, &size
, &checksum
))
288 add_module(dc
, name
, base
? base
: rbase
, size
, 0 /* FIXME */, checksum
, TRUE
);
292 static void fetch_module_info(struct dump_context
* dc
)
294 EnumerateLoadedModulesW64(dc
->hProcess
, fetch_pe_module_info_cb
, dc
);
295 /* Since we include ELF modules in a separate stream from the regular PE ones,
296 * we can always include those ELF modules (they don't eat lots of space)
297 * And it's always a good idea to have a trace of the loaded ELF modules for
298 * a given application in a post mortem debugging condition.
300 elf_enum_modules(dc
->hProcess
, fetch_elf_module_info_cb
, dc
);
303 /******************************************************************
306 * Add a memory block to be dumped in a minidump
307 * If rva is non 0, it's the rva in the minidump where has to be stored
308 * also the rva of the memory block when written (this allows to reference
309 * a memory block from outside the list of memory blocks).
311 static void add_memory_block(struct dump_context
* dc
, ULONG64 base
, ULONG size
, ULONG rva
)
314 dc
->mem
= HeapReAlloc(GetProcessHeap(), 0, dc
->mem
,
315 ++dc
->num_mem
* sizeof(*dc
->mem
));
317 dc
->mem
= HeapAlloc(GetProcessHeap(), 0, ++dc
->num_mem
* sizeof(*dc
->mem
));
320 dc
->mem
[dc
->num_mem
- 1].base
= base
;
321 dc
->mem
[dc
->num_mem
- 1].size
= size
;
322 dc
->mem
[dc
->num_mem
- 1].rva
= rva
;
324 else dc
->num_mem
= 0;
327 /******************************************************************
330 * Writes a chunk of data at a given position in the minidump
332 static void writeat(struct dump_context
* dc
, RVA rva
, void* data
, unsigned size
)
336 SetFilePointer(dc
->hFile
, rva
, NULL
, FILE_BEGIN
);
337 WriteFile(dc
->hFile
, data
, size
, &written
, NULL
);
340 /******************************************************************
343 * writes a new chunk of data to the minidump, increasing the current
346 static void append(struct dump_context
* dc
, void* data
, unsigned size
)
348 writeat(dc
, dc
->rva
, data
, size
);
352 /******************************************************************
353 * dump_exception_info
355 * Write in File the exception information from pcs
357 static void dump_exception_info(struct dump_context
* dc
,
358 const MINIDUMP_EXCEPTION_INFORMATION
* except
)
360 MINIDUMP_EXCEPTION_STREAM mdExcpt
;
361 EXCEPTION_RECORD rec
, *prec
;
365 mdExcpt
.ThreadId
= except
->ThreadId
;
366 mdExcpt
.__alignment
= 0;
367 if (except
->ClientPointers
)
369 EXCEPTION_POINTERS ep
;
371 ReadProcessMemory(dc
->hProcess
,
372 except
->ExceptionPointers
, &ep
, sizeof(ep
), NULL
);
373 ReadProcessMemory(dc
->hProcess
,
374 ep
.ExceptionRecord
, &rec
, sizeof(rec
), NULL
);
375 ReadProcessMemory(dc
->hProcess
,
376 ep
.ContextRecord
, &ctx
, sizeof(ctx
), NULL
);
382 prec
= except
->ExceptionPointers
->ExceptionRecord
;
383 pctx
= except
->ExceptionPointers
->ContextRecord
;
385 mdExcpt
.ExceptionRecord
.ExceptionCode
= prec
->ExceptionCode
;
386 mdExcpt
.ExceptionRecord
.ExceptionFlags
= prec
->ExceptionFlags
;
387 mdExcpt
.ExceptionRecord
.ExceptionRecord
= (DWORD_PTR
)prec
->ExceptionRecord
;
388 mdExcpt
.ExceptionRecord
.ExceptionAddress
= (DWORD_PTR
)prec
->ExceptionAddress
;
389 mdExcpt
.ExceptionRecord
.NumberParameters
= prec
->NumberParameters
;
390 mdExcpt
.ExceptionRecord
.__unusedAlignment
= 0;
391 for (i
= 0; i
< mdExcpt
.ExceptionRecord
.NumberParameters
; i
++)
392 mdExcpt
.ExceptionRecord
.ExceptionInformation
[i
] = (DWORD_PTR
)prec
->ExceptionInformation
[i
];
393 mdExcpt
.ThreadContext
.DataSize
= sizeof(*pctx
);
394 mdExcpt
.ThreadContext
.Rva
= dc
->rva
+ sizeof(mdExcpt
);
396 append(dc
, &mdExcpt
, sizeof(mdExcpt
));
397 append(dc
, pctx
, sizeof(*pctx
));
400 /******************************************************************
403 * Write in File the modules from pcs
405 static void dump_modules(struct dump_context
* dc
, BOOL dump_elf
)
407 MINIDUMP_MODULE mdModule
;
408 MINIDUMP_MODULE_LIST mdModuleList
;
410 MINIDUMP_STRING
* ms
= (MINIDUMP_STRING
*)tmp
;
415 for (i
= nmod
= 0; i
< dc
->num_module
; i
++)
417 if ((dc
->module
[i
].is_elf
&& dump_elf
) ||
418 (!dc
->module
[i
].is_elf
&& !dump_elf
))
422 mdModuleList
.NumberOfModules
= 0;
423 /* reserve space for mdModuleList
424 * FIXME: since we don't support 0 length arrays, we cannot use the
425 * size of mdModuleList
426 * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
429 dc
->rva
+= sizeof(mdModuleList
.NumberOfModules
) + sizeof(mdModule
) * nmod
;
430 for (i
= 0; i
< dc
->num_module
; i
++)
432 if ((dc
->module
[i
].is_elf
&& !dump_elf
) ||
433 (!dc
->module
[i
].is_elf
&& dump_elf
))
436 flags_out
= ModuleWriteModule
| ModuleWriteMiscRecord
| ModuleWriteCvRecord
;
437 if (dc
->type
& MiniDumpWithDataSegs
)
438 flags_out
|= ModuleWriteDataSeg
;
439 if (dc
->type
& MiniDumpWithProcessThreadData
)
440 flags_out
|= ModuleWriteTlsData
;
441 if (dc
->type
& MiniDumpWithCodeSegs
)
442 flags_out
|= ModuleWriteCodeSegs
;
443 ms
->Length
= (lstrlenW(dc
->module
[i
].name
) + 1) * sizeof(WCHAR
);
444 if (sizeof(ULONG
) + ms
->Length
> sizeof(tmp
))
445 FIXME("Buffer overflow!!!\n");
446 lstrcpyW(ms
->Buffer
, dc
->module
[i
].name
);
450 MINIDUMP_CALLBACK_INPUT cbin
;
451 MINIDUMP_CALLBACK_OUTPUT cbout
;
453 cbin
.ProcessId
= dc
->pid
;
454 cbin
.ProcessHandle
= dc
->hProcess
;
455 cbin
.CallbackType
= ModuleCallback
;
457 cbin
.u
.Module
.FullPath
= ms
->Buffer
;
458 cbin
.u
.Module
.BaseOfImage
= dc
->module
[i
].base
;
459 cbin
.u
.Module
.SizeOfImage
= dc
->module
[i
].size
;
460 cbin
.u
.Module
.CheckSum
= dc
->module
[i
].checksum
;
461 cbin
.u
.Module
.TimeDateStamp
= dc
->module
[i
].timestamp
;
462 memset(&cbin
.u
.Module
.VersionInfo
, 0, sizeof(cbin
.u
.Module
.VersionInfo
));
463 cbin
.u
.Module
.CvRecord
= NULL
;
464 cbin
.u
.Module
.SizeOfCvRecord
= 0;
465 cbin
.u
.Module
.MiscRecord
= NULL
;
466 cbin
.u
.Module
.SizeOfMiscRecord
= 0;
468 cbout
.u
.ModuleWriteFlags
= flags_out
;
469 if (!dc
->cb
->CallbackRoutine(dc
->cb
->CallbackParam
, &cbin
, &cbout
))
471 flags_out
&= cbout
.u
.ModuleWriteFlags
;
473 if (flags_out
& ModuleWriteModule
)
475 mdModule
.BaseOfImage
= dc
->module
[i
].base
;
476 mdModule
.SizeOfImage
= dc
->module
[i
].size
;
477 mdModule
.CheckSum
= dc
->module
[i
].checksum
;
478 mdModule
.TimeDateStamp
= dc
->module
[i
].timestamp
;
479 mdModule
.ModuleNameRva
= dc
->rva
;
480 ms
->Length
-= sizeof(WCHAR
);
481 append(dc
, ms
, sizeof(ULONG
) + ms
->Length
);
482 memset(&mdModule
.VersionInfo
, 0, sizeof(mdModule
.VersionInfo
)); /* FIXME */
483 mdModule
.CvRecord
.DataSize
= 0; /* FIXME */
484 mdModule
.CvRecord
.Rva
= 0; /* FIXME */
485 mdModule
.MiscRecord
.DataSize
= 0; /* FIXME */
486 mdModule
.MiscRecord
.Rva
= 0; /* FIXME */
487 mdModule
.Reserved0
= 0; /* FIXME */
488 mdModule
.Reserved1
= 0; /* FIXME */
490 rva_base
+ sizeof(mdModuleList
.NumberOfModules
) +
491 mdModuleList
.NumberOfModules
++ * sizeof(mdModule
),
492 &mdModule
, sizeof(mdModule
));
495 writeat(dc
, rva_base
, &mdModuleList
.NumberOfModules
,
496 sizeof(mdModuleList
.NumberOfModules
));
499 /******************************************************************
502 * Dumps into File the information about the system
504 static void dump_system_info(struct dump_context
* dc
)
506 MINIDUMP_SYSTEM_INFO mdSysInfo
;
508 OSVERSIONINFOW osInfo
;
512 GetSystemInfo(&sysInfo
);
513 osInfo
.dwOSVersionInfoSize
= sizeof(osInfo
);
514 GetVersionExW(&osInfo
);
516 mdSysInfo
.ProcessorArchitecture
= sysInfo
.u
.s
.wProcessorArchitecture
;
517 mdSysInfo
.ProcessorLevel
= sysInfo
.wProcessorLevel
;
518 mdSysInfo
.ProcessorRevision
= sysInfo
.wProcessorRevision
;
519 mdSysInfo
.u
.s
.NumberOfProcessors
= sysInfo
.dwNumberOfProcessors
;
520 mdSysInfo
.u
.s
.ProductType
= VER_NT_WORKSTATION
; /* FIXME */
521 mdSysInfo
.MajorVersion
= osInfo
.dwMajorVersion
;
522 mdSysInfo
.MinorVersion
= osInfo
.dwMinorVersion
;
523 mdSysInfo
.BuildNumber
= osInfo
.dwBuildNumber
;
524 mdSysInfo
.PlatformId
= osInfo
.dwPlatformId
;
526 mdSysInfo
.CSDVersionRva
= dc
->rva
+ sizeof(mdSysInfo
);
527 mdSysInfo
.u1
.Reserved1
= 0;
529 memset(&mdSysInfo
.Cpu
, 0, sizeof(mdSysInfo
.Cpu
));
531 append(dc
, &mdSysInfo
, sizeof(mdSysInfo
));
533 slen
= lstrlenW(osInfo
.szCSDVersion
) * sizeof(WCHAR
);
534 WriteFile(dc
->hFile
, &slen
, sizeof(slen
), &written
, NULL
);
535 WriteFile(dc
->hFile
, osInfo
.szCSDVersion
, slen
, &written
, NULL
);
536 dc
->rva
+= sizeof(ULONG
) + slen
;
539 /******************************************************************
542 * Dumps into File the information about running threads
544 static void dump_threads(struct dump_context
* dc
,
545 const MINIDUMP_EXCEPTION_INFORMATION
* except
)
547 MINIDUMP_THREAD mdThd
;
548 MINIDUMP_THREAD_LIST mdThdList
;
554 mdThdList
.NumberOfThreads
= 0;
557 dc
->rva
+= sizeof(mdThdList
.NumberOfThreads
) +
558 dc
->spi
->dwThreadCount
* sizeof(mdThd
);
560 for (i
= 0; i
< dc
->spi
->dwThreadCount
; i
++)
562 fetch_thread_info(dc
, i
, except
, &mdThd
, &ctx
);
564 flags_out
= ThreadWriteThread
| ThreadWriteStack
| ThreadWriteContext
|
565 ThreadWriteInstructionWindow
;
566 if (dc
->type
& MiniDumpWithProcessThreadData
)
567 flags_out
|= ThreadWriteThreadData
;
568 if (dc
->type
& MiniDumpWithThreadInfo
)
569 flags_out
|= ThreadWriteThreadInfo
;
573 MINIDUMP_CALLBACK_INPUT cbin
;
574 MINIDUMP_CALLBACK_OUTPUT cbout
;
576 cbin
.ProcessId
= dc
->pid
;
577 cbin
.ProcessHandle
= dc
->hProcess
;
578 cbin
.CallbackType
= ThreadCallback
;
579 cbin
.u
.Thread
.ThreadId
= dc
->spi
->ti
[i
].dwThreadID
;
580 cbin
.u
.Thread
.ThreadHandle
= 0; /* FIXME */
581 memcpy(&cbin
.u
.Thread
.Context
, &ctx
, sizeof(CONTEXT
));
582 cbin
.u
.Thread
.SizeOfContext
= sizeof(CONTEXT
);
583 cbin
.u
.Thread
.StackBase
= mdThd
.Stack
.StartOfMemoryRange
;
584 cbin
.u
.Thread
.StackEnd
= mdThd
.Stack
.StartOfMemoryRange
+
585 mdThd
.Stack
.Memory
.DataSize
;
587 cbout
.u
.ThreadWriteFlags
= flags_out
;
588 if (!dc
->cb
->CallbackRoutine(dc
->cb
->CallbackParam
, &cbin
, &cbout
))
590 flags_out
&= cbout
.u
.ThreadWriteFlags
;
592 if (flags_out
& ThreadWriteThread
)
594 if (ctx
.ContextFlags
&& (flags_out
& ThreadWriteContext
))
596 mdThd
.ThreadContext
.Rva
= dc
->rva
;
597 mdThd
.ThreadContext
.DataSize
= sizeof(CONTEXT
);
598 append(dc
, &ctx
, sizeof(CONTEXT
));
600 if (mdThd
.Stack
.Memory
.DataSize
&& (flags_out
& ThreadWriteStack
))
602 add_memory_block(dc
, mdThd
.Stack
.StartOfMemoryRange
,
603 mdThd
.Stack
.Memory
.DataSize
,
604 rva_base
+ sizeof(mdThdList
.NumberOfThreads
) +
605 mdThdList
.NumberOfThreads
* sizeof(mdThd
) +
606 FIELD_OFFSET(MINIDUMP_THREAD
, Stack
.Memory
.Rva
));
609 rva_base
+ sizeof(mdThdList
.NumberOfThreads
) +
610 mdThdList
.NumberOfThreads
* sizeof(mdThd
),
611 &mdThd
, sizeof(mdThd
));
612 mdThdList
.NumberOfThreads
++;
614 if (ctx
.ContextFlags
&& (flags_out
& ThreadWriteInstructionWindow
))
616 /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
617 * - also crop values across module boundaries,
618 * - and don't make it i386 dependent
620 /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
623 writeat(dc
, rva_base
,
624 &mdThdList
.NumberOfThreads
, sizeof(mdThdList
.NumberOfThreads
));
627 /******************************************************************
630 * dumps information about the memory of the process (stack of the threads)
632 static void dump_memory_info(struct dump_context
* dc
)
634 MINIDUMP_MEMORY_LIST mdMemList
;
635 MINIDUMP_MEMORY_DESCRIPTOR mdMem
;
637 unsigned i
, pos
, len
;
641 mdMemList
.NumberOfMemoryRanges
= dc
->num_mem
;
642 append(dc
, &mdMemList
.NumberOfMemoryRanges
,
643 sizeof(mdMemList
.NumberOfMemoryRanges
));
645 dc
->rva
+= mdMemList
.NumberOfMemoryRanges
* sizeof(mdMem
);
647 for (i
= 0; i
< dc
->num_mem
; i
++)
649 mdMem
.StartOfMemoryRange
= dc
->mem
[i
].base
;
650 mdMem
.Memory
.Rva
= dc
->rva
;
651 mdMem
.Memory
.DataSize
= dc
->mem
[i
].size
;
652 SetFilePointer(dc
->hFile
, dc
->rva
, NULL
, FILE_BEGIN
);
653 for (pos
= 0; pos
< dc
->mem
[i
].size
; pos
+= sizeof(tmp
))
655 len
= min(dc
->mem
[i
].size
- pos
, sizeof(tmp
));
656 if (ReadProcessMemory(dc
->hProcess
,
657 (void*)(ULONG
)(dc
->mem
[i
].base
+ pos
),
659 WriteFile(dc
->hFile
, tmp
, len
, &written
, NULL
);
661 dc
->rva
+= mdMem
.Memory
.DataSize
;
662 writeat(dc
, rva_base
+ i
* sizeof(mdMem
), &mdMem
, sizeof(mdMem
));
665 writeat(dc
, dc
->mem
[i
].rva
, &mdMem
.Memory
.Rva
, sizeof(mdMem
.Memory
.Rva
));
670 static void dump_misc_info(struct dump_context
* dc
)
672 MINIDUMP_MISC_INFO mmi
;
674 mmi
.SizeOfInfo
= sizeof(mmi
);
675 mmi
.Flags1
= MINIDUMP_MISC1_PROCESS_ID
;
676 mmi
.ProcessId
= dc
->pid
;
677 /* FIXME: create/user/kernel time */
678 append(dc
, &mmi
, sizeof(mmi
));
681 /******************************************************************
682 * MiniDumpWriteDump (DEBUGHLP.@)
685 BOOL WINAPI
MiniDumpWriteDump(HANDLE hProcess
, DWORD pid
, HANDLE hFile
,
686 MINIDUMP_TYPE DumpType
,
687 PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam
,
688 PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam
,
689 PMINIDUMP_CALLBACK_INFORMATION CallbackParam
)
691 MINIDUMP_HEADER mdHead
;
692 MINIDUMP_DIRECTORY mdDir
;
693 DWORD i
, nStreams
, idx_stream
;
694 struct dump_context dc
;
696 dc
.hProcess
= hProcess
;
701 dc
.cb
= CallbackParam
;
707 if (!fetch_process_info(&dc
)) return FALSE
;
708 fetch_module_info(&dc
);
711 nStreams
= 6 + (ExceptionParam
? 1 : 0) +
712 (UserStreamParam
? UserStreamParam
->UserStreamCount
: 0);
714 if (DumpType
& MiniDumpWithDataSegs
)
715 FIXME("NIY MiniDumpWithDataSegs\n");
716 if (DumpType
& MiniDumpWithFullMemory
)
717 FIXME("NIY MiniDumpWithFullMemory\n");
718 if (DumpType
& MiniDumpWithHandleData
)
719 FIXME("NIY MiniDumpWithHandleData\n");
720 if (DumpType
& MiniDumpFilterMemory
)
721 FIXME("NIY MiniDumpFilterMemory\n");
722 if (DumpType
& MiniDumpScanMemory
)
723 FIXME("NIY MiniDumpScanMemory\n");
725 /* 2) write header */
726 mdHead
.Signature
= MINIDUMP_SIGNATURE
;
727 mdHead
.Version
= MINIDUMP_VERSION
;
728 mdHead
.NumberOfStreams
= nStreams
;
729 mdHead
.StreamDirectoryRva
= sizeof(mdHead
);
730 mdHead
.u
.TimeDateStamp
= time(NULL
);
731 mdHead
.Flags
= DumpType
;
732 append(&dc
, &mdHead
, sizeof(mdHead
));
734 /* 3) write stream directories */
735 dc
.rva
+= nStreams
* sizeof(mdDir
);
738 /* 3.1) write data stream directories */
740 mdDir
.StreamType
= ThreadListStream
;
741 mdDir
.Location
.Rva
= dc
.rva
;
742 dump_threads(&dc
, ExceptionParam
);
743 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
744 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
745 &mdDir
, sizeof(mdDir
));
747 mdDir
.StreamType
= ModuleListStream
;
748 mdDir
.Location
.Rva
= dc
.rva
;
749 dump_modules(&dc
, FALSE
);
750 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
751 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
752 &mdDir
, sizeof(mdDir
));
754 mdDir
.StreamType
= 0xfff0; /* FIXME: this is part of MS reserved streams */
755 mdDir
.Location
.Rva
= dc
.rva
;
756 dump_modules(&dc
, TRUE
);
757 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
758 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
759 &mdDir
, sizeof(mdDir
));
761 mdDir
.StreamType
= MemoryListStream
;
762 mdDir
.Location
.Rva
= dc
.rva
;
763 dump_memory_info(&dc
);
764 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
765 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
766 &mdDir
, sizeof(mdDir
));
768 mdDir
.StreamType
= SystemInfoStream
;
769 mdDir
.Location
.Rva
= dc
.rva
;
770 dump_system_info(&dc
);
771 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
772 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
773 &mdDir
, sizeof(mdDir
));
775 mdDir
.StreamType
= MiscInfoStream
;
776 mdDir
.Location
.Rva
= dc
.rva
;
778 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
779 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
780 &mdDir
, sizeof(mdDir
));
782 /* 3.2) write exception information (if any) */
785 mdDir
.StreamType
= ExceptionStream
;
786 mdDir
.Location
.Rva
= dc
.rva
;
787 dump_exception_info(&dc
, ExceptionParam
);
788 mdDir
.Location
.DataSize
= dc
.rva
- mdDir
.Location
.Rva
;
789 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
790 &mdDir
, sizeof(mdDir
));
793 /* 3.3) write user defined streams (if any) */
796 for (i
= 0; i
< UserStreamParam
->UserStreamCount
; i
++)
798 mdDir
.StreamType
= UserStreamParam
->UserStreamArray
[i
].Type
;
799 mdDir
.Location
.DataSize
= UserStreamParam
->UserStreamArray
[i
].BufferSize
;
800 mdDir
.Location
.Rva
= dc
.rva
;
801 writeat(&dc
, mdHead
.StreamDirectoryRva
+ idx_stream
++ * sizeof(mdDir
),
802 &mdDir
, sizeof(mdDir
));
803 append(&dc
, UserStreamParam
->UserStreamArray
[i
].Buffer
,
804 UserStreamParam
->UserStreamArray
[i
].BufferSize
);
808 HeapFree(GetProcessHeap(), 0, dc
.pcs_buffer
);
809 HeapFree(GetProcessHeap(), 0, dc
.mem
);
810 HeapFree(GetProcessHeap(), 0, dc
.module
);
815 /******************************************************************
816 * MiniDumpReadDumpStream (DEBUGHLP.@)
820 BOOL WINAPI
MiniDumpReadDumpStream(void* base
, ULONG str_idx
,
821 PMINIDUMP_DIRECTORY
* pdir
,
822 void** stream
, ULONG
* size
)
824 MINIDUMP_HEADER
* mdHead
= (MINIDUMP_HEADER
*)base
;
826 if (mdHead
->Signature
== MINIDUMP_SIGNATURE
)
828 MINIDUMP_DIRECTORY
* dir
;
831 dir
= (MINIDUMP_DIRECTORY
*)((char*)base
+ mdHead
->StreamDirectoryRva
);
832 for (i
= 0; i
< mdHead
->NumberOfStreams
; i
++, dir
++)
834 if (dir
->StreamType
== str_idx
)
837 *stream
= (char*)base
+ dir
->Location
.Rva
;
838 *size
= dir
->Location
.DataSize
;
843 SetLastError(ERROR_INVALID_PARAMETER
);