267 lines
9.9 KiB
C
267 lines
9.9 KiB
C
/*
|
|
* File minidump.c - management of dumps (read & write)
|
|
*
|
|
* Copyright (C) 2004, Eric Pouech
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <time.h>
|
|
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
|
|
#include "dbghelp_private.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|
|
|
#if 0
|
|
/* hard to see how we can generate this very easily (how to grab latest exception
|
|
* in a process ?)
|
|
*/
|
|
static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva)
|
|
{
|
|
MINIDUMP_EXCEPTION_STREAM mdExcpt;
|
|
|
|
mdExcpt.ThreadId = DEBUG_CurrThread->tid;
|
|
mdExcpt.__alignment = 0;
|
|
mdExcpt.ExceptionRecord.
|
|
|
|
ULONG ExceptionCode;
|
|
ULONG ExceptionFlags;
|
|
ULONGLONG ExceptionRecord;
|
|
ULONGLONG ExceptionAddress;
|
|
ULONG NumberParameters;
|
|
ULONG __unusedAlignment;
|
|
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************
|
|
* dump_modules
|
|
*
|
|
* Write in File the modules from pcs
|
|
*/
|
|
static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
|
|
{
|
|
MINIDUMP_MODULE mdModule;
|
|
MINIDUMP_MODULE_LIST mdModuleList;
|
|
DWORD written;
|
|
struct module* module = NULL;
|
|
|
|
mdModuleList.NumberOfModules = 0;
|
|
for (module = pcs->lmodules; module; module = module->next)
|
|
mdModuleList.NumberOfModules++;
|
|
WriteFile(hFile, &mdModuleList.NumberOfModules,
|
|
sizeof(mdModuleList.NumberOfModules), &written, NULL);
|
|
*rva += sizeof(mdModuleList.NumberOfModules) +
|
|
sizeof(mdModule) * mdModuleList.NumberOfModules;
|
|
for (module = pcs->lmodules; module; module = module->next)
|
|
{
|
|
mdModule.BaseOfImage = (DWORD)module->module.BaseOfImage;
|
|
mdModule.SizeOfImage = module->module.ImageSize;
|
|
mdModule.CheckSum = module->module.CheckSum;
|
|
mdModule.TimeDateStamp = module->module.TimeDateStamp;
|
|
mdModule.ModuleNameRva = *rva;
|
|
*rva += strlen(module->module.ModuleName) + 1;
|
|
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;
|
|
mdModule.Reserved1 = 0;
|
|
WriteFile(hFile, &mdModule, sizeof(mdModule), &written, NULL);
|
|
}
|
|
for (module = pcs->lmodules; module; module = module->next)
|
|
{
|
|
WriteFile(hFile, module->module.ModuleName,
|
|
strlen(module->module.ModuleName) + 1, &written, NULL);
|
|
FIXME("CV and misc records not written\n");
|
|
}
|
|
}
|
|
|
|
/******************************************************************
|
|
* dump_system_info
|
|
*
|
|
* Dumps into File the information about the system
|
|
*/
|
|
static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
|
|
{
|
|
MINIDUMP_SYSTEM_INFO mdSysInfo;
|
|
SYSTEM_INFO sysInfo;
|
|
OSVERSIONINFOA osInfo;
|
|
DWORD written;
|
|
|
|
GetSystemInfo(&sysInfo);
|
|
GetVersionExA(&osInfo);
|
|
|
|
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
|
|
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
|
|
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
|
|
mdSysInfo.Reserved0 = 0;
|
|
|
|
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
|
|
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
|
|
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
|
|
mdSysInfo.PlatformId = osInfo.dwPlatformId;
|
|
|
|
mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo);
|
|
mdSysInfo.Reserved1 = 0;
|
|
|
|
WriteFile(hFile, &mdSysInfo, sizeof(mdSysInfo), &written, NULL);
|
|
*rva += sizeof(mdSysInfo);
|
|
WriteFile(hFile, osInfo.szCSDVersion, strlen(osInfo.szCSDVersion) + 1,
|
|
&written, NULL);
|
|
*rva += strlen(osInfo.szCSDVersion) + 1;
|
|
}
|
|
|
|
/******************************************************************
|
|
* dump_threads
|
|
*
|
|
* Dumps into File the information about running threads
|
|
*/
|
|
static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
|
|
{
|
|
#if 0
|
|
MINIDUMP_THREAD mdThd;
|
|
MINIDUMP_THREAD_LIST mdThdList;
|
|
DWORD written;
|
|
DBG_THREAD* thd;
|
|
|
|
mdThdList.NumberOfThreads = pcs->num_threads;
|
|
WriteFile(hFile, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads),
|
|
&written, NULL);
|
|
*rva += sizeof(mdThdList.NumberOfThreads) +
|
|
mdThdList.NumberOfThreads * sizeof(mdThd);
|
|
for (thd = pcs->threads; thd; thd = thd->next)
|
|
{
|
|
mdThd.ThreadId = thd->tid;
|
|
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);
|
|
FIXME("Stack & thread context not written\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************************************************
|
|
* MiniDumpWriteDump (DEBUGHLP.@)
|
|
*
|
|
*
|
|
*/
|
|
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
|
MINIDUMP_TYPE DumpType,
|
|
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
|
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
|
PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
|
|
{
|
|
struct process* pcs;
|
|
MINIDUMP_HEADER mdHead;
|
|
MINIDUMP_DIRECTORY mdDir;
|
|
DWORD currRva, written;
|
|
DWORD i, nStream, addStream;
|
|
RVA rva;
|
|
|
|
pcs = process_find_by_handle(hProcess);
|
|
if (!pcs) return FALSE; /* FIXME: should try to load it ??? */
|
|
|
|
/* 1) init */
|
|
|
|
nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0;
|
|
addStream = 0;
|
|
if (DumpType & MiniDumpNormal)
|
|
addStream += 3; /* sure ? thread stack back trace */
|
|
|
|
if (DumpType & MiniDumpWithDataSegs)
|
|
FIXME("NIY MiniDumpWithDataSegs\n");
|
|
if (DumpType & MiniDumpWithFullMemory)
|
|
FIXME("NIY MiniDumpWithFullMemory\n");
|
|
if (DumpType & MiniDumpWithHandleData)
|
|
FIXME("NIY MiniDumpWithHandleData\n");
|
|
if (DumpType & MiniDumpFilterMemory)
|
|
FIXME("NIY MiniDumpFilterMemory\n");
|
|
if (DumpType & MiniDumpScanMemory)
|
|
FIXME("NIY MiniDumpScanMemory\n");
|
|
|
|
/* 2) write header */
|
|
rva = sizeof(mdHead);
|
|
mdHead.Signature = MINIDUMP_SIGNATURE;
|
|
mdHead.Version = MINIDUMP_VERSION;
|
|
mdHead.NumberOfStreams = nStream + addStream;
|
|
mdHead.StreamDirectoryRva = rva;
|
|
mdHead.u.TimeDateStamp = time(NULL);
|
|
mdHead.Flags = DumpType;
|
|
WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL);
|
|
|
|
/* 3) write stream directories */
|
|
rva += (nStream + addStream) * sizeof(mdDir);
|
|
/* 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.Location.Rva = rva;
|
|
dump_threads(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 = SystemInfoStream;
|
|
mdDir.Location.Rva = rva;
|
|
dump_system_info(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);
|
|
|
|
/* 3.2) write user define stream */
|
|
for (i = 0; i < nStream; i++)
|
|
{
|
|
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
|
|
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
|
|
mdDir.Location.Rva = rva;
|
|
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
|
|
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
|
|
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
|
|
WriteFile(hFile,
|
|
UserStreamParam->UserStreamArray[i].Buffer,
|
|
UserStreamParam->UserStreamArray[i].BufferSize,
|
|
&written, NULL);
|
|
rva += UserStreamParam->UserStreamArray[i].BufferSize;
|
|
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|