/* * 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 #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; }