Added support for minidump (read & write).
This commit is contained in:
parent
9f81a801c2
commit
642402d581
|
@ -20,8 +20,8 @@
|
||||||
@ stdcall ImagehlpApiVersionEx(ptr)
|
@ stdcall ImagehlpApiVersionEx(ptr)
|
||||||
@ stdcall MakeSureDirectoryPathExists(str)
|
@ stdcall MakeSureDirectoryPathExists(str)
|
||||||
@ stdcall MapDebugInformation(long str str long)
|
@ stdcall MapDebugInformation(long str str long)
|
||||||
@ stub MiniDumpReadDumpStream
|
@ stdcall MiniDumpReadDumpStream(ptr long ptr ptr ptr)
|
||||||
@ stub MiniDumpWriteDump
|
@ stdcall MiniDumpWriteDump(ptr long ptr long long long long)
|
||||||
@ stdcall SearchTreeForFile(str str str)
|
@ stdcall SearchTreeForFile(str str str)
|
||||||
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
|
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
|
||||||
@ stub StackWalk64
|
@ stub StackWalk64
|
||||||
|
|
|
@ -1278,9 +1278,11 @@ BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user)
|
||||||
struct process pcs;
|
struct process pcs;
|
||||||
struct elf_info elf_info;
|
struct elf_info elf_info;
|
||||||
|
|
||||||
|
memset(&pcs, 0, sizeof(pcs));
|
||||||
pcs.handle = hProc;
|
pcs.handle = hProc;
|
||||||
elf_info.flags = ELF_INFO_DEBUG_HEADER;
|
elf_info.flags = ELF_INFO_DEBUG_HEADER;
|
||||||
if (!elf_search_loader(&pcs, &elf_info)) return FALSE;
|
if (!elf_search_loader(&pcs, &elf_info)) return FALSE;
|
||||||
|
pcs.dbg_hdr_addr = elf_info.dbg_hdr_addr;
|
||||||
return elf_enum_modules_internal(&pcs, cb, user);
|
return elf_enum_modules_internal(&pcs, cb, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,74 +24,415 @@
|
||||||
#define NONAMELESSSTRUCT
|
#define NONAMELESSSTRUCT
|
||||||
|
|
||||||
#include "dbghelp_private.h"
|
#include "dbghelp_private.h"
|
||||||
|
#include "ntstatus.h"
|
||||||
|
#include "winnls.h"
|
||||||
|
#include "winreg.h"
|
||||||
|
#include "winternl.h"
|
||||||
|
#include "psapi.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
||||||
|
|
||||||
#if 0
|
struct dump_memory
|
||||||
/* hard to see how we can generate this very easily (how to grab latest exception
|
{
|
||||||
* in a process ?)
|
ULONG base;
|
||||||
|
ULONG size;
|
||||||
|
ULONG rva;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dump_module
|
||||||
|
{
|
||||||
|
unsigned is_elf;
|
||||||
|
ULONG base;
|
||||||
|
ULONG size;
|
||||||
|
char name[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dump_context
|
||||||
|
{
|
||||||
|
/* process & thread information */
|
||||||
|
HANDLE hProcess;
|
||||||
|
DWORD pid;
|
||||||
|
void* pcs_buffer;
|
||||||
|
SYSTEM_PROCESS_INFORMATION* spi;
|
||||||
|
/* module information */
|
||||||
|
struct dump_module* module;
|
||||||
|
unsigned num_module;
|
||||||
|
/* exception information */
|
||||||
|
/* output information */
|
||||||
|
MINIDUMP_TYPE type;
|
||||||
|
HANDLE hFile;
|
||||||
|
RVA rva;
|
||||||
|
struct dump_memory* mem;
|
||||||
|
unsigned num_mem;
|
||||||
|
/* callback information */
|
||||||
|
MINIDUMP_CALLBACK_INFORMATION* cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* fetch_process_info
|
||||||
|
*
|
||||||
|
* reads system wide process information, and make spi point to the record
|
||||||
|
* for process of id 'pid'
|
||||||
*/
|
*/
|
||||||
static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva)
|
static BOOL fetch_process_info(struct dump_context* dc)
|
||||||
|
{
|
||||||
|
ULONG buf_size = 0x1000;
|
||||||
|
NTSTATUS nts;
|
||||||
|
|
||||||
|
dc->pcs_buffer = NULL;
|
||||||
|
if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
nts = NtQuerySystemInformation(SystemProcessInformation,
|
||||||
|
dc->pcs_buffer, buf_size, NULL);
|
||||||
|
if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
|
||||||
|
dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer,
|
||||||
|
buf_size *= 2);
|
||||||
|
if (!dc->pcs_buffer) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nts == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
dc->spi = dc->pcs_buffer;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (dc->spi->dwProcessID == dc->pid) return TRUE;
|
||||||
|
if (!dc->spi->dwOffset) break;
|
||||||
|
dc->spi = (SYSTEM_PROCESS_INFORMATION*)
|
||||||
|
((char*)dc->spi + dc->spi->dwOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
|
||||||
|
dc->pcs_buffer = NULL;
|
||||||
|
dc->spi = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* fetch_thread_info
|
||||||
|
*
|
||||||
|
* fetches some information about thread of id 'tid'
|
||||||
|
*/
|
||||||
|
static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
|
||||||
|
MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
|
||||||
|
{
|
||||||
|
NT_TIB tib;
|
||||||
|
DWORD tid = dc->spi->ti[thd_idx].dwThreadID;
|
||||||
|
HANDLE hThread;
|
||||||
|
THREAD_BASIC_INFORMATION tbi;
|
||||||
|
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
|
||||||
|
mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
|
||||||
|
mdThd->SuspendCount = 0;
|
||||||
|
mdThd->Teb = 0;
|
||||||
|
mdThd->Stack.StartOfMemoryRange = 0;
|
||||||
|
mdThd->Stack.Memory.DataSize = 0;
|
||||||
|
mdThd->Stack.Memory.Rva = 0;
|
||||||
|
mdThd->ThreadContext.DataSize = 0;
|
||||||
|
mdThd->ThreadContext.Rva = 0;
|
||||||
|
mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
|
||||||
|
mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
|
||||||
|
|
||||||
|
if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
|
||||||
|
{
|
||||||
|
FIXME("Couldn't open thread %lu (%lu)\n",
|
||||||
|
dc->spi->ti[thd_idx].dwThreadID, GetLastError());
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NtQueryInformationThread(hThread, ThreadBasicInformation,
|
||||||
|
&tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
|
||||||
|
if (tbi.ExitStatus == STILL_ACTIVE && tid != GetCurrentThreadId() &&
|
||||||
|
(mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
|
||||||
|
{
|
||||||
|
mdThd->SuspendCount--;
|
||||||
|
ctx->ContextFlags = CONTEXT_FULL;
|
||||||
|
if (!GetThreadContext(hThread, ctx))
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
|
||||||
|
if (ReadProcessMemory(dc->hProcess, tbi.TebBaseAddress,
|
||||||
|
&tib, sizeof(tib), NULL))
|
||||||
|
{
|
||||||
|
#ifdef __i386__
|
||||||
|
/* limiting the stack dumping to the size actually used */
|
||||||
|
if (ctx->Esp)
|
||||||
|
mdThd->Stack.StartOfMemoryRange = (ctx->Esp - 4);
|
||||||
|
else
|
||||||
|
mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
|
||||||
|
mdThd->Stack.Memory.DataSize = (ULONG_PTR)tib.StackBase -
|
||||||
|
mdThd->Stack.StartOfMemoryRange;
|
||||||
|
#else
|
||||||
|
#error unsupported CPU
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
ResumeThread(hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(hThread);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* add_module
|
||||||
|
*
|
||||||
|
* Add a module to a dump context
|
||||||
|
*/
|
||||||
|
static BOOL add_module(struct dump_context* dc, const char* name,
|
||||||
|
DWORD base, DWORD size, BOOL is_elf)
|
||||||
|
{
|
||||||
|
if (!dc->module)
|
||||||
|
dc->module = HeapAlloc(GetProcessHeap(), 0, ++dc->num_module * sizeof(*dc->module));
|
||||||
|
else
|
||||||
|
dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module, ++dc->num_module * sizeof(*dc->module));
|
||||||
|
if (!dc->module) return FALSE;
|
||||||
|
if (is_elf ||
|
||||||
|
!GetModuleFileNameExA(dc->hProcess, (HMODULE)base,
|
||||||
|
dc->module[dc->num_module - 1].name,
|
||||||
|
sizeof(dc->module[dc->num_module - 1].name)))
|
||||||
|
lstrcpynA(dc->module[dc->num_module - 1].name, name,
|
||||||
|
sizeof(dc->module[dc->num_module - 1].name));
|
||||||
|
dc->module[dc->num_module - 1].base = base;
|
||||||
|
dc->module[dc->num_module - 1].size = size;
|
||||||
|
dc->module[dc->num_module - 1].is_elf = is_elf;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* fetch_pe_module_info_cb
|
||||||
|
*
|
||||||
|
* Callback for accumulating in dump_context a PE modules set
|
||||||
|
*/
|
||||||
|
static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size,
|
||||||
|
void* user)
|
||||||
|
{
|
||||||
|
return add_module((struct dump_context*)user, name, base, size, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* fetch_elf_module_info_cb
|
||||||
|
*
|
||||||
|
* Callback for accumulating in dump_context a ELF modules set
|
||||||
|
*/
|
||||||
|
static BOOL fetch_elf_module_info_cb(const char* name, unsigned long base,
|
||||||
|
void* user)
|
||||||
|
{
|
||||||
|
return add_module((struct dump_context*)user, name,
|
||||||
|
base, 0 /* FIXME */, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fetch_module_info(struct dump_context* dc)
|
||||||
|
{
|
||||||
|
WINE_FIXME("--> %p\n", dc->hProcess);
|
||||||
|
EnumerateLoadedModules(dc->hProcess, fetch_pe_module_info_cb, dc);
|
||||||
|
/* Since we include ELF modules in a separate stream from the regular PE ones,
|
||||||
|
* we can always include those ELF modules (they don't eat lots of space)
|
||||||
|
* And it's always a good idea to have a trace of the loaded ELF modules for
|
||||||
|
* a given application in a post mortem debugging condition.
|
||||||
|
*/
|
||||||
|
elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* add_memory_block
|
||||||
|
*
|
||||||
|
* Add a memory block to be dumped in a minidump
|
||||||
|
* If rva is non 0, it's the rva in the minidump where has to be stored
|
||||||
|
* also the rva of the memory block when written (this allows to reference
|
||||||
|
* a memory block from outside the list of memory blocks).
|
||||||
|
*/
|
||||||
|
static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
|
||||||
|
{
|
||||||
|
if (dc->mem)
|
||||||
|
dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
|
||||||
|
++dc->num_mem * sizeof(*dc->mem));
|
||||||
|
else
|
||||||
|
dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
|
||||||
|
if (dc->mem)
|
||||||
|
{
|
||||||
|
dc->mem[dc->num_mem - 1].base = base;
|
||||||
|
dc->mem[dc->num_mem - 1].size = size;
|
||||||
|
dc->mem[dc->num_mem - 1].rva = rva;
|
||||||
|
}
|
||||||
|
else dc->num_mem = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* writeat
|
||||||
|
*
|
||||||
|
* Writes a chunk of data at a given position in the minidump
|
||||||
|
*/
|
||||||
|
static void writeat(struct dump_context* dc, RVA rva, void* data, unsigned size)
|
||||||
|
{
|
||||||
|
DWORD written;
|
||||||
|
|
||||||
|
SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
|
||||||
|
WriteFile(dc->hFile, data, size, &written, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* append
|
||||||
|
*
|
||||||
|
* writes a new chunk of data to the minidump, increasing the current
|
||||||
|
* rva in dc
|
||||||
|
*/
|
||||||
|
static void append(struct dump_context* dc, void* data, unsigned size)
|
||||||
|
{
|
||||||
|
writeat(dc, dc->rva, data, size);
|
||||||
|
dc->rva += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* dump_exception_info
|
||||||
|
*
|
||||||
|
* Write in File the exception information from pcs
|
||||||
|
*/
|
||||||
|
static void dump_exception_info(struct dump_context* dc,
|
||||||
|
const MINIDUMP_EXCEPTION_INFORMATION* except)
|
||||||
{
|
{
|
||||||
MINIDUMP_EXCEPTION_STREAM mdExcpt;
|
MINIDUMP_EXCEPTION_STREAM mdExcpt;
|
||||||
|
EXCEPTION_RECORD rec, *prec;
|
||||||
|
CONTEXT ctx, *pctx;
|
||||||
|
int i;
|
||||||
|
|
||||||
mdExcpt.ThreadId = DEBUG_CurrThread->tid;
|
mdExcpt.ThreadId = except->ThreadId;
|
||||||
mdExcpt.__alignment = 0;
|
mdExcpt.__alignment = 0;
|
||||||
mdExcpt.ExceptionRecord.
|
if (except->ClientPointers)
|
||||||
|
{
|
||||||
|
EXCEPTION_POINTERS ep;
|
||||||
|
|
||||||
ULONG ExceptionCode;
|
ReadProcessMemory(dc->hProcess,
|
||||||
ULONG ExceptionFlags;
|
except->ExceptionPointers, &ep, sizeof(ep), NULL);
|
||||||
ULONGLONG ExceptionRecord;
|
ReadProcessMemory(dc->hProcess,
|
||||||
ULONGLONG ExceptionAddress;
|
ep.ExceptionRecord, &rec, sizeof(rec), NULL);
|
||||||
ULONG NumberParameters;
|
ReadProcessMemory(dc->hProcess,
|
||||||
ULONG __unusedAlignment;
|
ep.ContextRecord, &ctx, sizeof(ctx), NULL);
|
||||||
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
prec = &rec;
|
||||||
|
pctx = &ctx;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prec = except->ExceptionPointers->ExceptionRecord;
|
||||||
|
pctx = except->ExceptionPointers->ContextRecord;
|
||||||
|
}
|
||||||
|
mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
|
||||||
|
mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
|
||||||
|
mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
|
||||||
|
mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
|
||||||
|
mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
|
||||||
|
mdExcpt.ExceptionRecord.__unusedAlignment = 0;
|
||||||
|
for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
|
||||||
|
mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
|
||||||
|
mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
|
||||||
|
mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
|
||||||
|
|
||||||
|
append(dc, &mdExcpt, sizeof(mdExcpt));
|
||||||
|
append(dc, pctx, sizeof(*pctx));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* dump_modules
|
* dump_modules
|
||||||
*
|
*
|
||||||
* Write in File the modules from pcs
|
* Write in File the modules from pcs
|
||||||
*/
|
*/
|
||||||
static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
|
static void dump_modules(struct dump_context* dc, BOOL dump_elf)
|
||||||
{
|
{
|
||||||
MINIDUMP_MODULE mdModule;
|
MINIDUMP_MODULE mdModule;
|
||||||
MINIDUMP_MODULE_LIST mdModuleList;
|
MINIDUMP_MODULE_LIST mdModuleList;
|
||||||
DWORD written;
|
char tmp[1024];
|
||||||
struct module* module = NULL;
|
MINIDUMP_STRING* ms = (MINIDUMP_STRING*)tmp;
|
||||||
|
ULONG i, nmod;
|
||||||
|
RVA rva_base;
|
||||||
|
DWORD flags_out;
|
||||||
|
|
||||||
|
for (i = nmod = 0; i < dc->num_module; i++)
|
||||||
|
{
|
||||||
|
if ((dc->module[i].is_elf && dump_elf) || (!dc->module[i].is_elf && !dump_elf))
|
||||||
|
nmod++;
|
||||||
|
}
|
||||||
|
|
||||||
mdModuleList.NumberOfModules = 0;
|
mdModuleList.NumberOfModules = 0;
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
/* reserve space for mdModuleList
|
||||||
mdModuleList.NumberOfModules++;
|
* FIXME: since we don't support 0 length arrays, we cannot use the
|
||||||
WriteFile(hFile, &mdModuleList.NumberOfModules,
|
* size of mdModuleList
|
||||||
sizeof(mdModuleList.NumberOfModules), &written, NULL);
|
* FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
|
||||||
*rva += sizeof(mdModuleList.NumberOfModules) +
|
*/
|
||||||
sizeof(mdModule) * mdModuleList.NumberOfModules;
|
rva_base = dc->rva;
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
|
||||||
|
for (i = 0; i < dc->num_module; i++)
|
||||||
{
|
{
|
||||||
mdModule.BaseOfImage = (DWORD)module->module.BaseOfImage;
|
if ((dc->module[i].is_elf && !dump_elf) || (!dc->module[i].is_elf && dump_elf))
|
||||||
mdModule.SizeOfImage = module->module.ImageSize;
|
continue;
|
||||||
mdModule.CheckSum = module->module.CheckSum;
|
|
||||||
mdModule.TimeDateStamp = module->module.TimeDateStamp;
|
flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
|
||||||
mdModule.ModuleNameRva = *rva;
|
if (dc->type & MiniDumpWithDataSegs)
|
||||||
*rva += strlen(module->module.ModuleName) + 1;
|
flags_out |= ModuleWriteDataSeg;
|
||||||
memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
|
if (dc->type & MiniDumpWithProcessThreadData)
|
||||||
mdModule.CvRecord.DataSize = 0; /* FIXME */
|
flags_out |= ModuleWriteTlsData;
|
||||||
mdModule.CvRecord.Rva = 0; /* FIXME */
|
if (dc->type & MiniDumpWithCodeSegs)
|
||||||
mdModule.MiscRecord.DataSize = 0; /* FIXME */
|
flags_out |= ModuleWriteCodeSegs;
|
||||||
mdModule.MiscRecord.Rva = 0; /* FIXME */
|
ms->Length = MultiByteToWideChar(CP_ACP, 0,
|
||||||
mdModule.Reserved0 = 0;
|
dc->module[i].name, -1,
|
||||||
mdModule.Reserved1 = 0;
|
NULL, 0) * sizeof(WCHAR);
|
||||||
WriteFile(hFile, &mdModule, sizeof(mdModule), &written, NULL);
|
if (sizeof(ULONG) + ms->Length > sizeof(tmp))
|
||||||
}
|
FIXME("Buffer overflow!!!\n");
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
MultiByteToWideChar(CP_ACP, 0, dc->module[i].name, -1,
|
||||||
{
|
ms->Buffer, ms->Length);
|
||||||
WriteFile(hFile, module->module.ModuleName,
|
|
||||||
strlen(module->module.ModuleName) + 1, &written, NULL);
|
if (dc->cb)
|
||||||
FIXME("CV and misc records not written\n");
|
{
|
||||||
|
MINIDUMP_CALLBACK_INPUT cbin;
|
||||||
|
MINIDUMP_CALLBACK_OUTPUT cbout;
|
||||||
|
|
||||||
|
cbin.ProcessId = dc->pid;
|
||||||
|
cbin.ProcessHandle = dc->hProcess;
|
||||||
|
cbin.CallbackType = ModuleCallback;
|
||||||
|
|
||||||
|
cbin.u.Module.FullPath = ms->Buffer;
|
||||||
|
cbin.u.Module.BaseOfImage = dc->module[i].base;
|
||||||
|
cbin.u.Module.SizeOfImage = dc->module[i].size;
|
||||||
|
cbin.u.Module.CheckSum = 0; /* FIXME */
|
||||||
|
cbin.u.Module.TimeDateStamp = 0; /* FIXME */
|
||||||
|
memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
|
||||||
|
cbin.u.Module.CvRecord = NULL;
|
||||||
|
cbin.u.Module.SizeOfCvRecord = 0;
|
||||||
|
cbin.u.Module.MiscRecord = NULL;
|
||||||
|
cbin.u.Module.SizeOfMiscRecord = 0;
|
||||||
|
|
||||||
|
cbout.u.ModuleWriteFlags = flags_out;
|
||||||
|
if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
|
||||||
|
continue;
|
||||||
|
flags_out &= cbout.u.ModuleWriteFlags;
|
||||||
|
}
|
||||||
|
if (flags_out & ModuleWriteModule)
|
||||||
|
{
|
||||||
|
mdModule.BaseOfImage = dc->module[i].base;
|
||||||
|
mdModule.SizeOfImage = dc->module[i].size;
|
||||||
|
mdModule.CheckSum = 0; /* FIXME */
|
||||||
|
mdModule.TimeDateStamp = 0; /* FIXME */
|
||||||
|
mdModule.ModuleNameRva = dc->rva;
|
||||||
|
ms->Length -= sizeof(WCHAR);
|
||||||
|
append(dc, ms, sizeof(ULONG) + ms->Length);
|
||||||
|
memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
|
||||||
|
mdModule.CvRecord.DataSize = 0; /* FIXME */
|
||||||
|
mdModule.CvRecord.Rva = 0; /* FIXME */
|
||||||
|
mdModule.MiscRecord.DataSize = 0; /* FIXME */
|
||||||
|
mdModule.MiscRecord.Rva = 0; /* FIXME */
|
||||||
|
mdModule.Reserved0 = 0; /* FIXME */
|
||||||
|
mdModule.Reserved1 = 0; /* FIXME */
|
||||||
|
writeat(dc,
|
||||||
|
rva_base + sizeof(mdModuleList.NumberOfModules) +
|
||||||
|
mdModuleList.NumberOfModules++ * sizeof(mdModule),
|
||||||
|
&mdModule, sizeof(mdModule));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
writeat(dc, rva_base, &mdModuleList.NumberOfModules,
|
||||||
|
sizeof(mdModuleList.NumberOfModules));
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -99,34 +440,39 @@ static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||||
*
|
*
|
||||||
* Dumps into File the information about the system
|
* Dumps into File the information about the system
|
||||||
*/
|
*/
|
||||||
static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
|
static void dump_system_info(struct dump_context* dc)
|
||||||
{
|
{
|
||||||
MINIDUMP_SYSTEM_INFO mdSysInfo;
|
MINIDUMP_SYSTEM_INFO mdSysInfo;
|
||||||
SYSTEM_INFO sysInfo;
|
SYSTEM_INFO sysInfo;
|
||||||
OSVERSIONINFOA osInfo;
|
OSVERSIONINFOW osInfo;
|
||||||
DWORD written;
|
DWORD written;
|
||||||
|
ULONG slen;
|
||||||
|
|
||||||
GetSystemInfo(&sysInfo);
|
GetSystemInfo(&sysInfo);
|
||||||
GetVersionExA(&osInfo);
|
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
||||||
|
GetVersionExW(&osInfo);
|
||||||
|
|
||||||
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
|
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
|
||||||
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
|
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
|
||||||
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
|
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
|
||||||
mdSysInfo.Reserved0 = 0;
|
mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
|
||||||
|
mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
|
||||||
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
|
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
|
||||||
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
|
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
|
||||||
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
|
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
|
||||||
mdSysInfo.PlatformId = osInfo.dwPlatformId;
|
mdSysInfo.PlatformId = osInfo.dwPlatformId;
|
||||||
|
|
||||||
mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo);
|
mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
|
||||||
mdSysInfo.Reserved1 = 0;
|
mdSysInfo.u1.Reserved1 = 0;
|
||||||
|
|
||||||
WriteFile(hFile, &mdSysInfo, sizeof(mdSysInfo), &written, NULL);
|
memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));
|
||||||
*rva += sizeof(mdSysInfo);
|
|
||||||
WriteFile(hFile, osInfo.szCSDVersion, strlen(osInfo.szCSDVersion) + 1,
|
append(dc, &mdSysInfo, sizeof(mdSysInfo));
|
||||||
&written, NULL);
|
|
||||||
*rva += strlen(osInfo.szCSDVersion) + 1;
|
slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
|
||||||
|
WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
|
||||||
|
WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
|
||||||
|
dc->rva += sizeof(ULONG) + slen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -134,36 +480,140 @@ static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||||
*
|
*
|
||||||
* Dumps into File the information about running threads
|
* Dumps into File the information about running threads
|
||||||
*/
|
*/
|
||||||
static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
|
static void dump_threads(struct dump_context* dc)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
MINIDUMP_THREAD mdThd;
|
MINIDUMP_THREAD mdThd;
|
||||||
MINIDUMP_THREAD_LIST mdThdList;
|
MINIDUMP_THREAD_LIST mdThdList;
|
||||||
DWORD written;
|
unsigned i;
|
||||||
DBG_THREAD* thd;
|
RVA rva_base;
|
||||||
|
DWORD flags_out;
|
||||||
|
CONTEXT ctx;
|
||||||
|
|
||||||
mdThdList.NumberOfThreads = pcs->num_threads;
|
mdThdList.NumberOfThreads = 0;
|
||||||
WriteFile(hFile, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads),
|
|
||||||
&written, NULL);
|
rva_base = dc->rva;
|
||||||
*rva += sizeof(mdThdList.NumberOfThreads) +
|
dc->rva += sizeof(mdThdList.NumberOfThreads) +
|
||||||
mdThdList.NumberOfThreads * sizeof(mdThd);
|
dc->spi->dwThreadCount * sizeof(mdThd);
|
||||||
for (thd = pcs->threads; thd; thd = thd->next)
|
|
||||||
|
for (i = 0; i < dc->spi->dwThreadCount; i++)
|
||||||
{
|
{
|
||||||
mdThd.ThreadId = thd->tid;
|
fetch_thread_info(dc, i, &mdThd, &ctx);
|
||||||
mdThd.SuspendCount = 0; /* FIXME */
|
|
||||||
mdThd.PriorityClass = 0; /* FIXME */
|
|
||||||
mdThd.Priority = 0; /* FIXME */
|
|
||||||
mdThd.Teb = 0; /* FIXME */
|
|
||||||
mdThd.Stack.StartOfMemoryRange = 0; /* FIXME */
|
|
||||||
mdThd.Stack.Memory.DataSize = 0; /* FIXME */
|
|
||||||
mdThd.Stack.Memory.Rva = 0; /* FIXME */
|
|
||||||
mdThd.ThreadContext.DataSize = 0;/* FIXME */
|
|
||||||
mdThd.ThreadContext.Rva = 0; /* FIXME */
|
|
||||||
|
|
||||||
WriteFile(hFile, &mdThd, sizeof(mdThd), &written, NULL);
|
flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
|
||||||
FIXME("Stack & thread context not written\n");
|
ThreadWriteInstructionWindow;
|
||||||
|
if (dc->type & MiniDumpWithProcessThreadData)
|
||||||
|
flags_out |= ThreadWriteThreadData;
|
||||||
|
if (dc->type & MiniDumpWithThreadInfo)
|
||||||
|
flags_out |= ThreadWriteThreadInfo;
|
||||||
|
|
||||||
|
if (dc->cb)
|
||||||
|
{
|
||||||
|
MINIDUMP_CALLBACK_INPUT cbin;
|
||||||
|
MINIDUMP_CALLBACK_OUTPUT cbout;
|
||||||
|
|
||||||
|
cbin.ProcessId = dc->pid;
|
||||||
|
cbin.ProcessHandle = dc->hProcess;
|
||||||
|
cbin.CallbackType = ThreadCallback;
|
||||||
|
cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
|
||||||
|
cbin.u.Thread.ThreadHandle = 0; /* FIXME */
|
||||||
|
memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
|
||||||
|
cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
|
||||||
|
cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
|
||||||
|
cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
|
||||||
|
mdThd.Stack.Memory.DataSize;
|
||||||
|
|
||||||
|
cbout.u.ThreadWriteFlags = flags_out;
|
||||||
|
if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
|
||||||
|
continue;
|
||||||
|
flags_out &= cbout.u.ThreadWriteFlags;
|
||||||
|
}
|
||||||
|
if (flags_out & ThreadWriteThread)
|
||||||
|
{
|
||||||
|
if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
|
||||||
|
{
|
||||||
|
mdThd.ThreadContext.Rva = dc->rva;
|
||||||
|
mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
|
||||||
|
append(dc, &ctx, sizeof(CONTEXT));
|
||||||
|
}
|
||||||
|
if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
|
||||||
|
{
|
||||||
|
add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
|
||||||
|
mdThd.Stack.Memory.DataSize,
|
||||||
|
rva_base + sizeof(mdThdList.NumberOfThreads) +
|
||||||
|
mdThdList.NumberOfThreads * sizeof(mdThd) +
|
||||||
|
FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
|
||||||
|
}
|
||||||
|
writeat(dc,
|
||||||
|
rva_base + sizeof(mdThdList.NumberOfThreads) +
|
||||||
|
mdThdList.NumberOfThreads * sizeof(mdThd),
|
||||||
|
&mdThd, sizeof(mdThd));
|
||||||
|
mdThdList.NumberOfThreads++;
|
||||||
|
}
|
||||||
|
if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
|
||||||
|
{
|
||||||
|
/* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
|
||||||
|
* - also crop values across module boundaries,
|
||||||
|
* - and don't make it i386 dependent
|
||||||
|
*/
|
||||||
|
/* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
writeat(dc, rva_base,
|
||||||
|
&mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* dump_memory_info
|
||||||
|
*
|
||||||
|
* dumps information about the memory of the process (stack of the threads)
|
||||||
|
*/
|
||||||
|
static void dump_memory_info(struct dump_context* dc)
|
||||||
|
{
|
||||||
|
MINIDUMP_MEMORY_LIST mdMemList;
|
||||||
|
MINIDUMP_MEMORY_DESCRIPTOR mdMem;
|
||||||
|
DWORD written;
|
||||||
|
unsigned i, pos, len;
|
||||||
|
RVA rva_base;
|
||||||
|
char tmp[1024];
|
||||||
|
|
||||||
|
mdMemList.NumberOfMemoryRanges = dc->num_mem;
|
||||||
|
append(dc, &mdMemList.NumberOfMemoryRanges,
|
||||||
|
sizeof(mdMemList.NumberOfMemoryRanges));
|
||||||
|
rva_base = dc->rva;
|
||||||
|
dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
|
||||||
|
|
||||||
|
for (i = 0; i < dc->num_mem; i++)
|
||||||
|
{
|
||||||
|
mdMem.StartOfMemoryRange = dc->mem[i].base;
|
||||||
|
mdMem.Memory.Rva = dc->rva;
|
||||||
|
mdMem.Memory.DataSize = dc->mem[i].size;
|
||||||
|
SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
|
||||||
|
for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
|
||||||
|
{
|
||||||
|
len = min(dc->mem[i].size - pos, sizeof(tmp));
|
||||||
|
if (ReadProcessMemory(dc->hProcess,
|
||||||
|
(void*)(ULONG)(dc->mem[i].base + pos),
|
||||||
|
tmp, len, NULL))
|
||||||
|
WriteFile(dc->hFile, tmp, len, &written, NULL);
|
||||||
|
}
|
||||||
|
dc->rva += mdMem.Memory.DataSize;
|
||||||
|
writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
|
||||||
|
if (dc->mem[i].rva)
|
||||||
|
{
|
||||||
|
writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_misc_info(struct dump_context* dc)
|
||||||
|
{
|
||||||
|
MINIDUMP_MISC_INFO mmi;
|
||||||
|
|
||||||
|
mmi.SizeOfInfo = sizeof(mmi);
|
||||||
|
mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
|
||||||
|
mmi.ProcessId = dc->pid;
|
||||||
|
/* FIXME: create/user/kernel time */
|
||||||
|
append(dc, &mmi, sizeof(mmi));
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -171,28 +621,34 @@ static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
|
||||||
MINIDUMP_TYPE DumpType,
|
MINIDUMP_TYPE DumpType,
|
||||||
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
|
PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
|
||||||
{
|
{
|
||||||
struct process* pcs;
|
|
||||||
MINIDUMP_HEADER mdHead;
|
MINIDUMP_HEADER mdHead;
|
||||||
MINIDUMP_DIRECTORY mdDir;
|
MINIDUMP_DIRECTORY mdDir;
|
||||||
DWORD currRva, written;
|
DWORD i, nStreams, idx_stream;
|
||||||
DWORD i, nStream, addStream;
|
struct dump_context dc;
|
||||||
RVA rva;
|
|
||||||
|
|
||||||
pcs = process_find_by_handle(hProcess);
|
dc.hProcess = hProcess;
|
||||||
if (!pcs) return FALSE; /* FIXME: should try to load it ??? */
|
dc.hFile = hFile;
|
||||||
|
dc.pid = pid;
|
||||||
|
dc.module = NULL;
|
||||||
|
dc.num_module = 0;
|
||||||
|
dc.cb = CallbackParam;
|
||||||
|
dc.type = DumpType;
|
||||||
|
dc.mem = NULL;
|
||||||
|
dc.num_mem = 0;
|
||||||
|
dc.rva = 0;
|
||||||
|
|
||||||
|
if (!fetch_process_info(&dc)) return FALSE;
|
||||||
|
fetch_module_info(&dc);
|
||||||
|
|
||||||
/* 1) init */
|
/* 1) init */
|
||||||
|
nStreams = 6 + (ExceptionParam ? 1 : 0) +
|
||||||
nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0;
|
(UserStreamParam ? UserStreamParam->UserStreamCount : 0);
|
||||||
addStream = 0;
|
|
||||||
if (DumpType & MiniDumpNormal)
|
|
||||||
addStream += 3; /* sure ? thread stack back trace */
|
|
||||||
|
|
||||||
if (DumpType & MiniDumpWithDataSegs)
|
if (DumpType & MiniDumpWithDataSegs)
|
||||||
FIXME("NIY MiniDumpWithDataSegs\n");
|
FIXME("NIY MiniDumpWithDataSegs\n");
|
||||||
|
@ -206,61 +662,123 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
||||||
FIXME("NIY MiniDumpScanMemory\n");
|
FIXME("NIY MiniDumpScanMemory\n");
|
||||||
|
|
||||||
/* 2) write header */
|
/* 2) write header */
|
||||||
rva = sizeof(mdHead);
|
|
||||||
mdHead.Signature = MINIDUMP_SIGNATURE;
|
mdHead.Signature = MINIDUMP_SIGNATURE;
|
||||||
mdHead.Version = MINIDUMP_VERSION;
|
mdHead.Version = MINIDUMP_VERSION;
|
||||||
mdHead.NumberOfStreams = nStream + addStream;
|
mdHead.NumberOfStreams = nStreams;
|
||||||
mdHead.StreamDirectoryRva = rva;
|
mdHead.StreamDirectoryRva = sizeof(mdHead);
|
||||||
mdHead.u.TimeDateStamp = time(NULL);
|
mdHead.u.TimeDateStamp = time(NULL);
|
||||||
mdHead.Flags = DumpType;
|
mdHead.Flags = DumpType;
|
||||||
WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL);
|
append(&dc, &mdHead, sizeof(mdHead));
|
||||||
|
|
||||||
/* 3) write stream directories */
|
/* 3) write stream directories */
|
||||||
rva += (nStream + addStream) * sizeof(mdDir);
|
dc.rva += nStreams * sizeof(mdDir);
|
||||||
|
idx_stream = 0;
|
||||||
|
|
||||||
/* 3.1) write data stream directories */
|
/* 3.1) write data stream directories */
|
||||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
||||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
|
||||||
mdDir.StreamType = ModuleListStream;
|
|
||||||
mdDir.Location.Rva = rva;
|
|
||||||
dump_modules(pcs, hFile, &rva);
|
|
||||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
|
||||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
|
||||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
|
||||||
|
|
||||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
||||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
|
||||||
mdDir.StreamType = ThreadListStream;
|
mdDir.StreamType = ThreadListStream;
|
||||||
mdDir.Location.Rva = rva;
|
mdDir.Location.Rva = dc.rva;
|
||||||
dump_threads(pcs, hFile, &rva);
|
dump_threads(&dc);
|
||||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
|
mdDir.StreamType = ModuleListStream;
|
||||||
|
mdDir.Location.Rva = dc.rva;
|
||||||
|
dump_modules(&dc, FALSE);
|
||||||
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
|
mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
|
||||||
|
mdDir.Location.Rva = dc.rva;
|
||||||
|
dump_modules(&dc, TRUE);
|
||||||
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
|
mdDir.StreamType = MemoryListStream;
|
||||||
|
mdDir.Location.Rva = dc.rva;
|
||||||
|
dump_memory_info(&dc);
|
||||||
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
||||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
|
||||||
mdDir.StreamType = SystemInfoStream;
|
mdDir.StreamType = SystemInfoStream;
|
||||||
mdDir.Location.Rva = rva;
|
mdDir.Location.Rva = dc.rva;
|
||||||
dump_system_info(pcs, hFile, &rva);
|
dump_system_info(&dc);
|
||||||
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
/* 3.2) write user define stream */
|
mdDir.StreamType = MiscInfoStream;
|
||||||
for (i = 0; i < nStream; i++)
|
mdDir.Location.Rva = dc.rva;
|
||||||
|
dump_misc_info(&dc);
|
||||||
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
|
&mdDir, sizeof(mdDir));
|
||||||
|
|
||||||
|
/* 3.2) write exception information (if any) */
|
||||||
|
if (ExceptionParam)
|
||||||
{
|
{
|
||||||
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
|
mdDir.StreamType = ExceptionStream;
|
||||||
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
|
mdDir.Location.Rva = dc.rva;
|
||||||
mdDir.Location.Rva = rva;
|
dump_exception_info(&dc, ExceptionParam);
|
||||||
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
|
||||||
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
&mdDir, sizeof(mdDir));
|
||||||
WriteFile(hFile,
|
|
||||||
UserStreamParam->UserStreamArray[i].Buffer,
|
|
||||||
UserStreamParam->UserStreamArray[i].BufferSize,
|
|
||||||
&written, NULL);
|
|
||||||
rva += UserStreamParam->UserStreamArray[i].BufferSize;
|
|
||||||
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 3.3) write user defined streams (if any) */
|
||||||
|
if (UserStreamParam)
|
||||||
|
{
|
||||||
|
for (i = 0; i < UserStreamParam->UserStreamCount; i++)
|
||||||
|
{
|
||||||
|
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
|
||||||
|
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
|
||||||
|
mdDir.Location.Rva = dc.rva;
|
||||||
|
writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
|
||||||
|
&mdDir, sizeof(mdDir));
|
||||||
|
append(&dc, UserStreamParam->UserStreamArray[i].Buffer,
|
||||||
|
UserStreamParam->UserStreamArray[i].BufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
|
||||||
|
HeapFree(GetProcessHeap(), 0, dc.mem);
|
||||||
|
HeapFree(GetProcessHeap(), 0, dc.module);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* MiniDumpReadDumpStream (DEBUGHLP.@)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
BOOL WINAPI MiniDumpReadDumpStream(void* base, ULONG str_idx,
|
||||||
|
PMINIDUMP_DIRECTORY* pdir,
|
||||||
|
void** stream, ULONG* size)
|
||||||
|
{
|
||||||
|
MINIDUMP_HEADER* mdHead = (MINIDUMP_HEADER*)base;
|
||||||
|
|
||||||
|
if (mdHead->Signature == MINIDUMP_SIGNATURE)
|
||||||
|
{
|
||||||
|
MINIDUMP_DIRECTORY* dir;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
|
||||||
|
for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
|
||||||
|
{
|
||||||
|
if (dir->StreamType == str_idx)
|
||||||
|
{
|
||||||
|
*pdir = dir;
|
||||||
|
*stream = (char*)base + dir->Location.Rva;
|
||||||
|
*size = dir->Location.DataSize;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
|
@ -250,7 +250,7 @@ typedef struct _DBGHELP_MODLOAD_DATA
|
||||||
|
|
||||||
/* DebugHelp */
|
/* DebugHelp */
|
||||||
|
|
||||||
#define MINIDUMP_SIGNATURE 0x4D444D50 /* 'PMDM' */
|
#define MINIDUMP_SIGNATURE 0x504D444D /* 'MDMP' */
|
||||||
#define MINIDUMP_VERSION (42899)
|
#define MINIDUMP_VERSION (42899)
|
||||||
|
|
||||||
typedef DWORD RVA;
|
typedef DWORD RVA;
|
||||||
|
@ -258,12 +258,21 @@ typedef ULONG64 RVA64;
|
||||||
|
|
||||||
typedef enum _MINIDUMP_TYPE
|
typedef enum _MINIDUMP_TYPE
|
||||||
{
|
{
|
||||||
MiniDumpNormal = 0x0000,
|
MiniDumpNormal = 0x0000,
|
||||||
MiniDumpWithDataSegs = 0x0001,
|
MiniDumpWithDataSegs = 0x0001,
|
||||||
MiniDumpWithFullMemory = 0x0002,
|
MiniDumpWithFullMemory = 0x0002,
|
||||||
MiniDumpWithHandleData = 0x0004,
|
MiniDumpWithHandleData = 0x0004,
|
||||||
MiniDumpFilterMemory = 0x0008,
|
MiniDumpFilterMemory = 0x0008,
|
||||||
MiniDumpScanMemory = 0x0010
|
MiniDumpScanMemory = 0x0010,
|
||||||
|
MiniDumpWithUnloadedModules = 0x0020,
|
||||||
|
MiniDumpWithIndirectlyReferencedMemory = 0x0040,
|
||||||
|
MiniDumpFilterModulePaths = 0x0080,
|
||||||
|
MiniDumpWithProcessThreadData = 0x0100,
|
||||||
|
MiniDumpWithPrivateReadWriteMemory = 0x0200,
|
||||||
|
MiniDumpWithoutOptionalData = 0x0400,
|
||||||
|
MiniDumpWithFullMemoryInfo = 0x0800,
|
||||||
|
MiniDumpWithThreadInfo = 0x1000,
|
||||||
|
MiniDumpWithCodeSegs = 0x2000
|
||||||
} MINIDUMP_TYPE;
|
} MINIDUMP_TYPE;
|
||||||
|
|
||||||
typedef enum _MINIDUMP_CALLBACK_TYPE
|
typedef enum _MINIDUMP_CALLBACK_TYPE
|
||||||
|
@ -273,6 +282,7 @@ typedef enum _MINIDUMP_CALLBACK_TYPE
|
||||||
ThreadExCallback,
|
ThreadExCallback,
|
||||||
IncludeThreadCallback,
|
IncludeThreadCallback,
|
||||||
IncludeModuleCallback,
|
IncludeModuleCallback,
|
||||||
|
MemoryCallback,
|
||||||
} MINIDUMP_CALLBACK_TYPE;
|
} MINIDUMP_CALLBACK_TYPE;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_THREAD_CALLBACK
|
typedef struct _MINIDUMP_THREAD_CALLBACK
|
||||||
|
@ -281,7 +291,7 @@ typedef struct _MINIDUMP_THREAD_CALLBACK
|
||||||
HANDLE ThreadHandle;
|
HANDLE ThreadHandle;
|
||||||
CONTEXT Context;
|
CONTEXT Context;
|
||||||
ULONG SizeOfContext;
|
ULONG SizeOfContext;
|
||||||
ULONGLONG StackBase;
|
ULONG64 StackBase;
|
||||||
ULONG64 StackEnd;
|
ULONG64 StackEnd;
|
||||||
} MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK;
|
} MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK;
|
||||||
|
|
||||||
|
@ -291,10 +301,10 @@ typedef struct _MINIDUMP_THREAD_EX_CALLBACK
|
||||||
HANDLE ThreadHandle;
|
HANDLE ThreadHandle;
|
||||||
CONTEXT Context;
|
CONTEXT Context;
|
||||||
ULONG SizeOfContext;
|
ULONG SizeOfContext;
|
||||||
ULONGLONG StackBase;
|
ULONG64 StackBase;
|
||||||
ULONGLONG StackEnd;
|
ULONG64 StackEnd;
|
||||||
ULONGLONG BackingStoreBase;
|
ULONG64 BackingStoreBase;
|
||||||
ULONGLONG BackingStoreEnd;
|
ULONG64 BackingStoreEnd;
|
||||||
} MINIDUMP_THREAD_EX_CALLBACK, *PMINIDUMP_THREAD_EX_CALLBACK;
|
} MINIDUMP_THREAD_EX_CALLBACK, *PMINIDUMP_THREAD_EX_CALLBACK;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK
|
typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK
|
||||||
|
@ -308,13 +318,15 @@ typedef enum _THREAD_WRITE_FLAGS
|
||||||
ThreadWriteStack = 0x0002,
|
ThreadWriteStack = 0x0002,
|
||||||
ThreadWriteContext = 0x0004,
|
ThreadWriteContext = 0x0004,
|
||||||
ThreadWriteBackingStore = 0x0008,
|
ThreadWriteBackingStore = 0x0008,
|
||||||
ThreadWriteInstructionWindow = 0x0010
|
ThreadWriteInstructionWindow = 0x0010,
|
||||||
|
ThreadWriteThreadData = 0x0020,
|
||||||
|
ThreadWriteThreadInfo = 0x0040
|
||||||
} THREAD_WRITE_FLAGS;
|
} THREAD_WRITE_FLAGS;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_MODULE_CALLBACK
|
typedef struct _MINIDUMP_MODULE_CALLBACK
|
||||||
{
|
{
|
||||||
PWCHAR FullPath;
|
PWCHAR FullPath;
|
||||||
ULONGLONG BaseOfImage;
|
ULONG64 BaseOfImage;
|
||||||
ULONG SizeOfImage;
|
ULONG SizeOfImage;
|
||||||
ULONG CheckSum;
|
ULONG CheckSum;
|
||||||
ULONG TimeDateStamp;
|
ULONG TimeDateStamp;
|
||||||
|
@ -336,7 +348,9 @@ typedef enum _MODULE_WRITE_FLAGS
|
||||||
ModuleWriteDataSeg = 0x0002,
|
ModuleWriteDataSeg = 0x0002,
|
||||||
ModuleWriteMiscRecord = 0x0004,
|
ModuleWriteMiscRecord = 0x0004,
|
||||||
ModuleWriteCvRecord = 0x0008,
|
ModuleWriteCvRecord = 0x0008,
|
||||||
ModuleReferencedByMemory = 0x0010
|
ModuleReferencedByMemory = 0x0010,
|
||||||
|
ModuleWriteTlsData = 0x0020,
|
||||||
|
ModuleWriteCodeSegs = 0x0040,
|
||||||
} MODULE_WRITE_FLAGS;
|
} MODULE_WRITE_FLAGS;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_CALLBACK_INPUT
|
typedef struct _MINIDUMP_CALLBACK_INPUT
|
||||||
|
@ -351,7 +365,7 @@ typedef struct _MINIDUMP_CALLBACK_INPUT
|
||||||
MINIDUMP_MODULE_CALLBACK Module;
|
MINIDUMP_MODULE_CALLBACK Module;
|
||||||
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
|
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
|
||||||
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
|
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
|
||||||
} u;
|
} DUMMYUNIONNAME;
|
||||||
} MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT;
|
} MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_CALLBACK_OUTPUT
|
typedef struct _MINIDUMP_CALLBACK_OUTPUT
|
||||||
|
@ -360,12 +374,15 @@ typedef struct _MINIDUMP_CALLBACK_OUTPUT
|
||||||
{
|
{
|
||||||
ULONG ModuleWriteFlags;
|
ULONG ModuleWriteFlags;
|
||||||
ULONG ThreadWriteFlags;
|
ULONG ThreadWriteFlags;
|
||||||
} u;
|
struct
|
||||||
|
{
|
||||||
|
ULONG64 MemoryBase;
|
||||||
|
ULONG MemorySize;
|
||||||
|
} DUMMYSTRUCTNAME;
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
} MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT;
|
} MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT;
|
||||||
|
|
||||||
typedef BOOL (WINAPI* MINIDUMP_CALLBACK_ROUTINE)(PVOID CallbackParam,
|
typedef BOOL (WINAPI* MINIDUMP_CALLBACK_ROUTINE)(PVOID, const PMINIDUMP_CALLBACK_INPUT, PMINIDUMP_CALLBACK_OUTPUT);
|
||||||
const PMINIDUMP_CALLBACK_INPUT CallbackInput,
|
|
||||||
PMINIDUMP_CALLBACK_OUTPUT CallbackOutput);
|
|
||||||
|
|
||||||
typedef struct _MINIDUMP_CALLBACK_INFORMATION
|
typedef struct _MINIDUMP_CALLBACK_INFORMATION
|
||||||
{
|
{
|
||||||
|
@ -389,11 +406,11 @@ typedef struct _MINIDUMP_EXCEPTION
|
||||||
{
|
{
|
||||||
ULONG ExceptionCode;
|
ULONG ExceptionCode;
|
||||||
ULONG ExceptionFlags;
|
ULONG ExceptionFlags;
|
||||||
ULONGLONG ExceptionRecord;
|
ULONG64 ExceptionRecord;
|
||||||
ULONGLONG ExceptionAddress;
|
ULONG64 ExceptionAddress;
|
||||||
ULONG NumberParameters;
|
ULONG NumberParameters;
|
||||||
ULONG __unusedAlignment;
|
ULONG __unusedAlignment;
|
||||||
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
ULONG64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
||||||
} MINIDUMP_EXCEPTION, *PMINIDUMP_EXCEPTION;
|
} MINIDUMP_EXCEPTION, *PMINIDUMP_EXCEPTION;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_EXCEPTION_INFORMATION
|
typedef struct _MINIDUMP_EXCEPTION_INFORMATION
|
||||||
|
@ -422,19 +439,38 @@ typedef struct _MINIDUMP_HEADER
|
||||||
{
|
{
|
||||||
DWORD Reserved;
|
DWORD Reserved;
|
||||||
DWORD TimeDateStamp;
|
DWORD TimeDateStamp;
|
||||||
} u;
|
} DUMMYUNIONNAME;
|
||||||
ULONGLONG Flags;
|
ULONG64 Flags;
|
||||||
} MINIDUMP_HEADER, *PMINIDUMP_HEADER;
|
} MINIDUMP_HEADER, *PMINIDUMP_HEADER;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_MEMORY_DESCRIPTOR
|
typedef struct _MINIDUMP_MEMORY_DESCRIPTOR
|
||||||
{
|
{
|
||||||
ULONGLONG StartOfMemoryRange;
|
ULONG64 StartOfMemoryRange;
|
||||||
MINIDUMP_LOCATION_DESCRIPTOR Memory;
|
MINIDUMP_LOCATION_DESCRIPTOR Memory;
|
||||||
} MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR;
|
} MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR;
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_MEMORY_LIST
|
||||||
|
{
|
||||||
|
ULONG NumberOfMemoryRanges;
|
||||||
|
MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges[1]; /* FIXME: 0-sized array not supported */
|
||||||
|
} MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST;
|
||||||
|
|
||||||
|
#define MINIDUMP_MISC1_PROCESS_ID 0x00000001
|
||||||
|
#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_MISC_INFO
|
||||||
|
{
|
||||||
|
ULONG SizeOfInfo;
|
||||||
|
ULONG Flags1;
|
||||||
|
ULONG ProcessId;
|
||||||
|
ULONG ProcessCreateTime;
|
||||||
|
ULONG ProcessUserTime;
|
||||||
|
ULONG ProcessKernelTime;
|
||||||
|
} MINIDUMP_MISC_INFO, *PMINIDUMP_MISC_INFO;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_MODULE
|
typedef struct _MINIDUMP_MODULE
|
||||||
{
|
{
|
||||||
ULONGLONG BaseOfImage;
|
ULONG64 BaseOfImage;
|
||||||
ULONG SizeOfImage;
|
ULONG SizeOfImage;
|
||||||
ULONG CheckSum;
|
ULONG CheckSum;
|
||||||
ULONG TimeDateStamp;
|
ULONG TimeDateStamp;
|
||||||
|
@ -442,8 +478,8 @@ typedef struct _MINIDUMP_MODULE
|
||||||
VS_FIXEDFILEINFO VersionInfo;
|
VS_FIXEDFILEINFO VersionInfo;
|
||||||
MINIDUMP_LOCATION_DESCRIPTOR CvRecord;
|
MINIDUMP_LOCATION_DESCRIPTOR CvRecord;
|
||||||
MINIDUMP_LOCATION_DESCRIPTOR MiscRecord;
|
MINIDUMP_LOCATION_DESCRIPTOR MiscRecord;
|
||||||
ULONGLONG Reserved0;
|
ULONG64 Reserved0;
|
||||||
ULONGLONG Reserved1;
|
ULONG64 Reserved1;
|
||||||
} MINIDUMP_MODULE, *PMINIDUMP_MODULE;
|
} MINIDUMP_MODULE, *PMINIDUMP_MODULE;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_MODULE_LIST
|
typedef struct _MINIDUMP_MODULE_LIST
|
||||||
|
@ -452,6 +488,76 @@ typedef struct _MINIDUMP_MODULE_LIST
|
||||||
MINIDUMP_MODULE Modules[1]; /* FIXME: 0-sized array not supported */
|
MINIDUMP_MODULE Modules[1]; /* FIXME: 0-sized array not supported */
|
||||||
} MINIDUMP_MODULE_LIST, *PMINIDUMP_MODULE_LIST;
|
} MINIDUMP_MODULE_LIST, *PMINIDUMP_MODULE_LIST;
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_STRING
|
||||||
|
{
|
||||||
|
ULONG Length;
|
||||||
|
WCHAR Buffer[1]; /* FIXME: O-sized array not supported */
|
||||||
|
} MINIDUMP_STRING, *PMINIDUMP_STRING;
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_SYSTEM_INFO
|
||||||
|
{
|
||||||
|
USHORT ProcessorArchitecture;
|
||||||
|
USHORT ProcessorLevel;
|
||||||
|
USHORT ProcessorRevision;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
USHORT Reserved0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UCHAR NumberOfProcessors;
|
||||||
|
UCHAR ProductType;
|
||||||
|
} DUMMYSTRUCTNAME;
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
|
|
||||||
|
ULONG MajorVersion;
|
||||||
|
ULONG MinorVersion;
|
||||||
|
ULONG BuildNumber;
|
||||||
|
ULONG PlatformId;
|
||||||
|
|
||||||
|
RVA CSDVersionRva;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ULONG Reserved1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SuiteMask;
|
||||||
|
USHORT Reserved2;
|
||||||
|
} DUMMYSTRUCTNAME;
|
||||||
|
} DUMMYUNIONNAME1;
|
||||||
|
union _CPU_INFORMATION
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ULONG VendorId[3];
|
||||||
|
ULONG VersionInformation;
|
||||||
|
ULONG FeatureInformation;
|
||||||
|
ULONG AMDExtendedCpuFeatures;
|
||||||
|
} X86CpuInfo;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ULONG64 ProcessorFeatures[2];
|
||||||
|
} OtherCpuInfo;
|
||||||
|
} Cpu;
|
||||||
|
|
||||||
|
} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO;
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_THREAD
|
||||||
|
{
|
||||||
|
ULONG ThreadId;
|
||||||
|
ULONG SuspendCount;
|
||||||
|
ULONG PriorityClass;
|
||||||
|
ULONG Priority;
|
||||||
|
ULONG64 Teb;
|
||||||
|
MINIDUMP_MEMORY_DESCRIPTOR Stack;
|
||||||
|
MINIDUMP_LOCATION_DESCRIPTOR ThreadContext;
|
||||||
|
} MINIDUMP_THREAD, *PMINIDUMP_THREAD;
|
||||||
|
|
||||||
|
typedef struct _MINIDUMP_THREAD_LIST
|
||||||
|
{
|
||||||
|
ULONG NumberOfThreads;
|
||||||
|
MINIDUMP_THREAD Threads[1]; /* FIXME: no support of 0 sized array */
|
||||||
|
} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_USER_STREAM
|
typedef struct _MINIDUMP_USER_STREAM
|
||||||
{
|
{
|
||||||
ULONG Type;
|
ULONG Type;
|
||||||
|
@ -481,61 +587,20 @@ typedef enum _MINIDUMP_STREAM_TYPE
|
||||||
CommentStreamW = 11,
|
CommentStreamW = 11,
|
||||||
HandleDataStream = 12,
|
HandleDataStream = 12,
|
||||||
FunctionTableStream = 13,
|
FunctionTableStream = 13,
|
||||||
|
UnloadedModuleListStream = 14,
|
||||||
|
MiscInfoStream = 15,
|
||||||
|
MemoryInfoListStream = 16,
|
||||||
|
ThreadInfoListStream = 17,
|
||||||
|
|
||||||
LastReservedStream = 0xffff
|
LastReservedStream = 0xffff
|
||||||
} MINIDUMP_STREAM_TYPE;
|
} MINIDUMP_STREAM_TYPE;
|
||||||
|
|
||||||
typedef struct _MINIDUMP_SYSTEM_INFO
|
BOOL WINAPI MiniDumpWriteDump(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
|
||||||
{
|
const PMINIDUMP_EXCEPTION_INFORMATION,
|
||||||
USHORT ProcessorArchitecture;
|
const PMINIDUMP_USER_STREAM_INFORMATION,
|
||||||
USHORT ProcessorLevel;
|
const PMINIDUMP_CALLBACK_INFORMATION);
|
||||||
USHORT ProcessorRevision;
|
BOOL WINAPI MiniDumpReadDumpStream(PVOID, ULONG, PMINIDUMP_DIRECTORY*, PVOID*,
|
||||||
USHORT Reserved0;
|
ULONG*);
|
||||||
|
|
||||||
ULONG MajorVersion;
|
|
||||||
ULONG MinorVersion;
|
|
||||||
ULONG BuildNumber;
|
|
||||||
ULONG PlatformId;
|
|
||||||
|
|
||||||
RVA CSDVersionRva;
|
|
||||||
ULONG Reserved1;
|
|
||||||
union _CPU_INFORMATION
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG VendorId[3];
|
|
||||||
ULONG VersionInformation;
|
|
||||||
ULONG FeatureInformation;
|
|
||||||
ULONG AMDExtendedCpuFeatures;
|
|
||||||
} X86CpuInfo;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONGLONG ProcessorFeatures[2];
|
|
||||||
} OtherCpuInfo;
|
|
||||||
} Cpu;
|
|
||||||
|
|
||||||
} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO;
|
|
||||||
|
|
||||||
typedef struct _MINIDUMP_THREAD
|
|
||||||
{
|
|
||||||
ULONG ThreadId;
|
|
||||||
ULONG SuspendCount;
|
|
||||||
ULONG PriorityClass;
|
|
||||||
ULONG Priority;
|
|
||||||
ULONGLONG Teb;
|
|
||||||
MINIDUMP_MEMORY_DESCRIPTOR Stack;
|
|
||||||
MINIDUMP_LOCATION_DESCRIPTOR ThreadContext;
|
|
||||||
} MINIDUMP_THREAD, *PMINIDUMP_THREAD;
|
|
||||||
|
|
||||||
typedef struct _MINIDUMP_THREAD_LIST
|
|
||||||
{
|
|
||||||
ULONG NumberOfThreads;
|
|
||||||
MINIDUMP_THREAD Threads[1]; /* FIXME: no support of 0 sized array */
|
|
||||||
} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST;
|
|
||||||
|
|
||||||
BOOL WINAPI MiniDumpWriteDump(HANDLE,DWORD,HANDLE,MINIDUMP_TYPE,const PMINIDUMP_EXCEPTION_INFORMATION,
|
|
||||||
const PMINIDUMP_USER_STREAM_INFORMATION,const PMINIDUMP_CALLBACK_INFORMATION);
|
|
||||||
BOOL WINAPI MiniDumpReadDumpStream(PVOID,ULONG,PMINIDUMP_DIRECTORY*,PVOID*,ULONG*);
|
|
||||||
|
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
|
|
Loading…
Reference in New Issue