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