diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_crasher/ExceptionHandler.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/General/gen_crasher/ExceptionHandler.cpp')
-rw-r--r-- | Src/Plugins/General/gen_crasher/ExceptionHandler.cpp | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_crasher/ExceptionHandler.cpp b/Src/Plugins/General/gen_crasher/ExceptionHandler.cpp new file mode 100644 index 00000000..ae1c2399 --- /dev/null +++ b/Src/Plugins/General/gen_crasher/ExceptionHandler.cpp @@ -0,0 +1,814 @@ +// ExceptionHandler.cpp Version 1.4 +// +// Copyright © 1998 Bruce Dawson +// +// This source file contains the exception handler for recording error +// information after crashes. See ExceptionHandler.h for information +// on how to hook it in. +// +// Author: Bruce Dawson +// brucedawson@cygnus-software.com +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.4: - Added invocation of XCrashReport.exe +// +// Version 1.3: - Added minidump output +// +// Version 1.1: - reformatted output for XP-like error report +// - added ascii output to stack dump +// +// A paper by the original author can be found at: +// http://www.cygnus-software.com/papers/release_debugging.html +// +/////////////////////////////////////////////////////////////////////////////// + +// Disable warnings generated by the Windows header files. +#pragma warning(disable : 4514) +#pragma warning(disable : 4201) + +#define _WIN32_WINDOWS 0x0500 // for IsDebuggerPresent + +#include "windows.h" +#include <tchar.h> +#include "GetWinVer.h" +#include "miniversion.h" +#include "../nu/ns_wc.h" + +#include "minidump.h" +#include ".\settings.h" +#include "api__gen_crasher.h" + +extern char *winampVersion; +extern Settings settings; + +#ifndef _countof +#define _countof(array) (sizeof(array)/sizeof(array[0])) +#endif + +const int NumCodeBytes = 16; // Number of code bytes to record. +const int MaxStackDump = 3072; // Maximum number of DWORDS in stack dumps. +const int StackColumns = 4; // Number of columns in stack dump. + +#define ONEK 1024 +#define SIXTYFOURK (64*ONEK) +#define ONEM (ONEK*ONEK) +#define ONEG (ONEK*ONEK*ONEK) + + +/////////////////////////////////////////////////////////////////////////////// +// lstrrchr (avoid the C Runtime ) +static TCHAR * lstrrchr(LPCTSTR string, int ch) +{ + TCHAR *start = (TCHAR *)string; + + while (string && *string++) /* find end of string */ + ; + /* search towards front */ + while (--string != start && *string != (TCHAR) ch) + ; + + if (*string == (TCHAR) ch) /* char found ? */ + return (TCHAR *)string; + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// hprintf behaves similarly to printf, with a few vital differences. +// It uses wvsprintf to do the formatting, which is a system routine, +// thus avoiding C run time interactions. For similar reasons it +// uses WriteFile rather than fwrite. +// The one limitation that this imposes is that wvsprintf, and +// therefore hprintf, cannot handle floating point numbers. + +// Too many calls to WriteFile can take a long time, causing +// confusing delays when programs crash. Therefore I implemented +// a simple buffering scheme for hprintf + +#define HPRINTF_BUFFER_SIZE (8*1024) // must be at least 2048 +static wchar_t hprintf_buffer[HPRINTF_BUFFER_SIZE]; // wvsprintf never prints more than one K. +static int hprintf_index = 0; + +/////////////////////////////////////////////////////////////////////////////// +// hflush +static void hflush(HANDLE LogFile) +{ + if (hprintf_index > 0) + { + DWORD NumBytes = 0; + WriteFile(LogFile, hprintf_buffer, lstrlenW(hprintf_buffer)*2, &NumBytes, 0); + hprintf_index = 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// hprintf +static void hprintf(HANDLE LogFile, const wchar_t *Format, ...) +{ + if (hprintf_index > (HPRINTF_BUFFER_SIZE-1024)) + { + DWORD NumBytes = 0; + WriteFile(LogFile, hprintf_buffer, lstrlen(hprintf_buffer)*2, &NumBytes, 0); + hprintf_index = 0; + } + + va_list arglist; + va_start( arglist, Format); + hprintf_index += vswprintf(&hprintf_buffer[hprintf_index], Format, arglist); + va_end( arglist); +} + +#include <strsafe.h> + +/////////////////////////////////////////////////////////////////////////////// +// DumpMiniDump +static BOOL DumpMiniDump(HANDLE hFile, PEXCEPTION_POINTERS excpInfo) +{ + if (excpInfo == NULL) + { + // Generate exception to get proper context in dump + __try + { + //OutputDebugString(_T("raising exception\r\n")); + RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL); + } + __except(DumpMiniDump(hFile, GetExceptionInformation()), EXCEPTION_CONTINUE_EXECUTION) + { + } + } + else + { + //OutputDebugString(_T("writing minidump\r\n")); + MINIDUMP_EXCEPTION_INFORMATION eInfo = {0}; + eInfo.ThreadId = GetCurrentThreadId(); + eInfo.ExceptionPointers = excpInfo; + eInfo.ClientPointers = FALSE; + + // try to load dbghelpdll + HMODULE hm = NULL; + // first from app folder + wchar_t szDbgHelpPath[_MAX_PATH] = {0}; + + if (GetModuleFileNameW( NULL, szDbgHelpPath, _MAX_PATH )) + { + wchar_t *pSlash = wcsrchr( szDbgHelpPath, L'\\' ); + if (pSlash) + { + StringCchCopy( pSlash+1, _MAX_PATH, L"dbghelp.dll"); + hm = LoadLibraryW( szDbgHelpPath ); + } + } + if (!hm) + { + // load any version we can + hm = LoadLibraryW(L"dbghelp.dll"); + } + + if (hm) + { + 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 + ) = NULL; + //OutputDebugString(_T("Found dbghelp.dll, searching for MiniDumpWriteDump\r\n")); + *(FARPROC*)&MiniDumpWriteDump = GetProcAddress(hm, "MiniDumpWriteDump"); + if (MiniDumpWriteDump) + { + //OutputDebugString(_T("Calling MiniDumpWriteDump\r\n")); + BOOL ret = MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + (MINIDUMP_TYPE)settings.dumpType, + excpInfo ? &eInfo : NULL, + NULL, + NULL); + //OutputDebugString(_T("MiniDumpWriteDump finished\r\n")); + if (!ret) + { + DWORD le = GetLastError(); + wchar_t tmp[256] = {0}; + StringCchPrintfW(tmp, 256, L"call failed with error code: %d", le); + //OutputDebugString(tmp); + } + return ret; + } + } + } + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// +// FormatTime +// +// Format the specified FILETIME to output in a human readable format, +// without using the C run time. +static void FormatTime(LPTSTR output, FILETIME TimeToPrint) +{ + output[0] = _T('\0'); + WORD Date, Time; + if (FileTimeToLocalFileTime(&TimeToPrint, &TimeToPrint) && + FileTimeToDosDateTime(&TimeToPrint, &Date, &Time)) + { + StringCchPrintf(output, 100, _T("%d/%d/%d %02d:%02d:%02d"), + (Date / 32) & 15, Date & 31, (Date / 512) + 1980, + (Time >> 11), (Time >> 5) & 0x3F, (Time & 0x1F) * 2); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// DumpModuleInfo +// +// Print information about a code module (DLL or EXE) such as its size, +// location, time stamp, etc. +static bool DumpModuleInfo(HANDLE LogFile, HINSTANCE ModuleHandle, int nModuleNo) +{ + bool rc = false; + wchar_t szModName[MAX_PATH*2] = {0}; + __try + { + if (GetModuleFileName(ModuleHandle, szModName, MAX_PATH*2) > 0) + { + // If GetModuleFileName returns greater than zero then this must + // be a valid code module address. Therefore we can try to walk + // our way through its structures to find the link time stamp. + IMAGE_DOS_HEADER *DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle; + if (IMAGE_DOS_SIGNATURE != DosHeader->e_magic) + return false; + + IMAGE_NT_HEADERS *NTHeader = (IMAGE_NT_HEADERS*)((char *)DosHeader + + DosHeader->e_lfanew); + if (IMAGE_NT_SIGNATURE != NTHeader->Signature) + return false; + + // open the code module file so that we can get its file date and size + HANDLE ModuleFile = CreateFile(szModName, GENERIC_READ, + FILE_SHARE_READ, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + + TCHAR TimeBuffer[100] = {0}; + DWORD FileSize = 0; + if (ModuleFile != INVALID_HANDLE_VALUE) + { + FileSize = GetFileSize(ModuleFile, 0); + FILETIME LastWriteTime; + if (GetFileTime(ModuleFile, 0, 0, &LastWriteTime)) + { + FormatTime(TimeBuffer, LastWriteTime); + } + CloseHandle(ModuleFile); + } + hprintf(LogFile, _T("Module %d\r\n"), nModuleNo); + hprintf(LogFile, _T("%s\r\n"), szModName); + hprintf(LogFile, _T("Image Base: 0x%08x Image Size: 0x%08x\r\n"), + NTHeader->OptionalHeader.ImageBase, + NTHeader->OptionalHeader.SizeOfImage), + + hprintf(LogFile, _T("Checksum: 0x%08x Time Stamp: 0x%08x\r\n"), + NTHeader->OptionalHeader.CheckSum, + NTHeader->FileHeader.TimeDateStamp); + + hprintf(LogFile, _T("File Size: %-10d File Time: %s\r\n"), + FileSize, TimeBuffer); + + hprintf(LogFile, _T("Version Information:\r\n")); + + CMiniVersion ver(szModName); + TCHAR szBuf[200] = {0}; + WORD dwBuf[4] = {0}; + + ver.GetCompanyName(szBuf, _countof(szBuf)-1); + hprintf(LogFile, _T(" Company: %s\r\n"), szBuf); + + ver.GetProductName(szBuf, _countof(szBuf)-1); + hprintf(LogFile, _T(" Product: %s\r\n"), szBuf); + + ver.GetFileDescription(szBuf, _countof(szBuf)-1); + hprintf(LogFile, _T(" FileDesc: %s\r\n"), szBuf); + + ver.GetFileVersion(dwBuf); + hprintf(LogFile, _T(" FileVer: %d.%d.%d.%d\r\n"), + dwBuf[0], dwBuf[1], dwBuf[2], dwBuf[3]); + + ver.GetProductVersion(dwBuf); + hprintf(LogFile, _T(" ProdVer: %d.%d.%d.%d\r\n"), + dwBuf[0], dwBuf[1], dwBuf[2], dwBuf[3]); + + ver.Release(); + + hprintf(LogFile, _T("\r\n")); + + rc = true; + } + } + // Handle any exceptions by continuing from this point. + __except(EXCEPTION_EXECUTE_HANDLER) + { + //OutputDebugString(L"DumpModuleInfo exception"); + } + return rc; +} + +/////////////////////////////////////////////////////////////////////////////// +// DumpModuleList +// +// Scan memory looking for code modules (DLLs or EXEs). VirtualQuery is used +// to find all the blocks of address space that were reserved or committed, +// and ShowModuleInfo will display module information if they are code +// modules. +static void DumpModuleList(HANDLE LogFile) +{ + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + + //OutputDebugString(L"Dumping modules list"); + const size_t PageSize = SystemInfo.dwPageSize; + + // Set NumPages to the number of pages in the 4GByte address space, + // while being careful to avoid overflowing ints + const size_t NumPages = 4 * size_t(ONEG / PageSize); + size_t pageNum = 0; + void *LastAllocationBase = 0; + + int nModuleNo = 1; + + while (pageNum < NumPages) + { + MEMORY_BASIC_INFORMATION MemInfo; + if (VirtualQuery((void *)(pageNum * PageSize), &MemInfo, sizeof(MemInfo))) + { + if (MemInfo.RegionSize > 0) + { + // Adjust the page number to skip over this block of memory + pageNum += MemInfo.RegionSize / PageSize; + if (MemInfo.State == MEM_COMMIT && MemInfo.AllocationBase > LastAllocationBase) + { + // Look for new blocks of committed memory, and try + // recording their module names - this will fail + // gracefully if they aren't code modules + LastAllocationBase = MemInfo.AllocationBase; + + if (DumpModuleInfo(LogFile, (HINSTANCE)LastAllocationBase, nModuleNo)) + { + nModuleNo++; + } + } + } + else + pageNum += SIXTYFOURK / PageSize; + } + else + pageNum += SIXTYFOURK / PageSize; + + // If VirtualQuery fails we advance by 64K because that is the + // granularity of address space doled out by VirtualAlloc() + } +} + +/////////////////////////////////////////////////////////////////////////////// +// DumpSystemInformation +// +// Record information about the user's system, such as processor type, amount +// of memory, etc. +static void DumpSystemInformation(HANDLE LogFile) +{ + FILETIME CurrentTime; + GetSystemTimeAsFileTime(&CurrentTime); + TCHAR szTimeBuffer[100] = {0}; + FormatTime(szTimeBuffer, CurrentTime); + + hprintf(LogFile, _T("Error occurred at %s.\r\n"), szTimeBuffer); + + TCHAR szModuleName[MAX_PATH*2] = {0}; + if (GetModuleFileName(0, szModuleName, _countof(szModuleName)-2) <= 0) + StringCbCopy(szModuleName, sizeof(szModuleName), _T("Unknown")); + + TCHAR szUserName[200] = {0}; + DWORD UserNameSize = _countof(szUserName)-2; + if (!GetUserName(szUserName, &UserNameSize)) + StringCbCopy(szUserName, sizeof(szUserName), _T("Unknown")); + + hprintf(LogFile, _T("%s, run by %s.\r\n"), szModuleName, szUserName); + + // print out operating system + TCHAR szWinVer[50] = {0}, szMajorMinorBuild[50] = {0}; + int nWinVer = 0; + GetWinVer(szWinVer, &nWinVer, szMajorMinorBuild); + hprintf(LogFile, _T("Operating system: %s (%s).\r\n"), + szWinVer, szMajorMinorBuild); + + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + hprintf(LogFile, _T("%d processor(s), type %d.\r\n"), + SystemInfo.dwNumberOfProcessors, SystemInfo.dwProcessorType); + + MEMORYSTATUS MemInfo; + MemInfo.dwLength = sizeof(MemInfo); + GlobalMemoryStatus(&MemInfo); + + // Print out info on memory, rounded up. + hprintf(LogFile, _T("%d%% memory in use.\r\n"), MemInfo.dwMemoryLoad); + hprintf(LogFile, _T("%d MBytes physical memory.\r\n"), (MemInfo.dwTotalPhys + + ONEM - 1) / ONEM); + hprintf(LogFile, _T("%d MBytes physical memory free.\r\n"), + (MemInfo.dwAvailPhys + ONEM - 1) / ONEM); + hprintf(LogFile, _T("%d MBytes paging file.\r\n"), (MemInfo.dwTotalPageFile + + ONEM - 1) / ONEM); + hprintf(LogFile, _T("%d MBytes paging file free.\r\n"), + (MemInfo.dwAvailPageFile + ONEM - 1) / ONEM); + hprintf(LogFile, _T("%d MBytes user address space.\r\n"), + (MemInfo.dwTotalVirtual + ONEM - 1) / ONEM); + hprintf(LogFile, _T("%d MBytes user address space free.\r\n"), + (MemInfo.dwAvailVirtual + ONEM - 1) / ONEM); +} + +/////////////////////////////////////////////////////////////////////////////// +// GetExceptionDescription +// +// Translate the exception code into something human readable +static const TCHAR *GetExceptionDescription(DWORD ExceptionCode) +{ + struct ExceptionNames + { + DWORD ExceptionCode; + TCHAR * ExceptionName; + }; + +#if 0 // from winnt.h +#define STATUS_WAIT_0 ((DWORD )0x00000000L) +#define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) +#define STATUS_USER_APC ((DWORD )0x000000C0L) +#define STATUS_TIMEOUT ((DWORD )0x00000102L) +#define STATUS_PENDING ((DWORD )0x00000103L) +#define STATUS_SEGMENT_NOTIFICATION ((DWORD )0x40000005L) +#define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L) +#define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L) +#define STATUS_BREAKPOINT ((DWORD )0x80000003L) +#define STATUS_SINGLE_STEP ((DWORD )0x80000004L) +#define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L) +#define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L) +#define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L) +#define STATUS_NO_MEMORY ((DWORD )0xC0000017L) +#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL) +#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L) +#define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L) +#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL) +#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL) +#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL) +#define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL) +#define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L) +#define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L) +#define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L) +#define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L) +#define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L) +#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L) +#define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL) +#define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL) +#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD )0xC00002B4L) +#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD )0xC00002B5L) +#define STATUS_ILLEGAL_VLM_REFERENCE ((DWORD )0xC00002C0L) +#endif + + ExceptionNames ExceptionMap[] = + { + {0x40010005, _T("a Control-C")}, + {0x40010008, _T("a Control-Break")}, + {0x80000002, _T("a Datatype Misalignment")}, + {0x80000003, _T("a Breakpoint")}, + {0xc0000005, _T("an Access Violation")}, + {0xc0000006, _T("an In Page Error")}, + {0xc0000017, _T("a No Memory")}, + {0xc000001d, _T("an Illegal Instruction")}, + {0xc0000025, _T("a Noncontinuable Exception")}, + {0xc0000026, _T("an Invalid Disposition")}, + {0xc000008c, _T("a Array Bounds Exceeded")}, + {0xc000008d, _T("a Float Denormal Operand")}, + {0xc000008e, _T("a Float Divide by Zero")}, + {0xc000008f, _T("a Float Inexact Result")}, + {0xc0000090, _T("a Float Invalid Operation")}, + {0xc0000091, _T("a Float Overflow")}, + {0xc0000092, _T("a Float Stack Check")}, + {0xc0000093, _T("a Float Underflow")}, + {0xc0000094, _T("an Integer Divide by Zero")}, + {0xc0000095, _T("an Integer Overflow")}, + {0xc0000096, _T("a Privileged Instruction")}, + {0xc00000fD, _T("a Stack Overflow")}, + {0xc0000142, _T("a DLL Initialization Failed")}, + {0xe06d7363, _T("a Microsoft C++ Exception")}, + }; + + for (int i = 0; i < _countof(ExceptionMap); i++) + if (ExceptionCode == ExceptionMap[i].ExceptionCode) + return ExceptionMap[i].ExceptionName; + + return _T("an Unknown exception type"); +} + +/////////////////////////////////////////////////////////////////////////////// +// GetFilePart +static TCHAR * GetFilePart(LPCTSTR source) +{ + TCHAR *result = lstrrchr(source, _T('\\')); + if (result) + result++; + else + result = (TCHAR *)source; + return result; +} + +#ifdef _M_IX86 +/////////////////////////////////////////////////////////////////////////////// +// DumpStack +static void DumpStack(HANDLE LogFile, DWORD *pStack) +{ + hprintf(LogFile, _T("\r\n\r\nStack:\r\n")); + + __try + { + // Esp contains the bottom of the stack, or at least the bottom of + // the currently used area. + DWORD* pStackTop; + + __asm + { + // Load the top (highest address) of the stack from the + // thread information block. It will be found there in + // Win9x and Windows NT. + mov eax, fs:[4] + mov pStackTop, eax + } + + if (pStackTop > pStack + MaxStackDump) + pStackTop = pStack + MaxStackDump; + + int Count = 0; + + DWORD* pStackStart = pStack; + + int nDwordsPrinted = 0; + + while (pStack + 1 <= pStackTop) + { + if ((Count % StackColumns) == 0) + { + pStackStart = pStack; + nDwordsPrinted = 0; + hprintf(LogFile, _T("0x%08x: "), pStack); + } + hprintf(LogFile, _T("%08x "), pStack); + if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop) + { + nDwordsPrinted++; + int n = nDwordsPrinted; + while (n < 4) + { + hprintf(LogFile, _T(" ")); + n++; + } + + for (int i = 0; i < nDwordsPrinted; i++) + { + DWORD dwStack = *pStackStart; + for (int j = 0; j < 4; j++) + { + char c = (char)(dwStack & 0xFF); + if (c < 0x20 || c > 0x7E) + c = '.'; +#ifdef _UNICODE + WCHAR w = (WCHAR)c; + hprintf(LogFile, _T("%c"), w); +#else + hprintf(LogFile, _T("%c"), c); +#endif + dwStack = dwStack >> 8; + } + pStackStart++; + } + + hprintf(LogFile, _T("\r\n")); + } + else + { + // hprintf(LogFile, _T("%08x "), *pStack); + nDwordsPrinted++; + } + pStack++; + } + hprintf(LogFile, _T("\r\n")); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + hprintf(LogFile, _T("Exception encountered during stack dump.\r\n")); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// DumpRegisters +static void DumpRegisters(HANDLE LogFile, PCONTEXT Context) +{ + // Print out the register values in an XP error window compatible format. + hprintf(LogFile, _T("\r\n")); + hprintf(LogFile, _T("Context:\r\n")); + hprintf(LogFile, _T("EDI: 0x%08x ESI: 0x%08x EAX: 0x%08x\r\n"), + Context->Edi, Context->Esi, Context->Eax); + hprintf(LogFile, _T("EBX: 0x%08x ECX: 0x%08x EDX: 0x%08x\r\n"), + Context->Ebx, Context->Ecx, Context->Edx); + hprintf(LogFile, _T("EIP: 0x%08x EBP: 0x%08x SegCs: 0x%08x\r\n"), + Context->Eip, Context->Ebp, Context->SegCs); + hprintf(LogFile, _T("EFlags: 0x%08x ESP: 0x%08x SegSs: 0x%08x\r\n"), + Context->EFlags, Context->Esp, Context->SegSs); +} + +#endif + +BOOL CreateLog(PEXCEPTION_POINTERS pExceptPtrs, LPCWSTR lpszMessage) +{ + HANDLE hLogFile = CreateFile(settings.logPath, GENERIC_WRITE, 0, 0, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0); + + if (hLogFile == INVALID_HANDLE_VALUE) + { + //OutputDebugString(_T("Error creating exception report\r\n")); + return FALSE; + } + + // add BOM + WORD wBOM = 0xFEFF; + DWORD num = 0; + WriteFile(hLogFile, &wBOM, sizeof(WORD), &num, NULL); + // Append to the error log + SetFilePointer(hLogFile, 0, 0, FILE_END); + + wchar_t line[1024] = {0}; + wchar_t msgBody[4*1024] = {0}; + wchar_t winampVersionWide[1024] = {0}; + MultiByteToWideCharSZ(CP_ACP, 0, winampVersion, -1, winampVersionWide, 1024); + StringCchPrintf(line, 1024, L"Winamp client version: %s\r\n", winampVersionWide); + StringCchCopy(msgBody, 4*1024, line); + + PEXCEPTION_RECORD Exception = pExceptPtrs->ExceptionRecord; + PCONTEXT Context = pExceptPtrs->ContextRecord; + + TCHAR szCrashModulePathName[MAX_PATH*2] = {0}; + + TCHAR *pszCrashModuleFileName = _T("Unknown"); + + #ifdef _M_IX86 + MEMORY_BASIC_INFORMATION MemInfo; + + // VirtualQuery can be used to get the allocation base associated with a + // code address, which is the same as the ModuleHandle. This can be used + // to get the filename of the module that the crash happened in. + + if (VirtualQuery((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) && + (GetModuleFileName((HINSTANCE)MemInfo.AllocationBase, + szCrashModulePathName, + sizeof(szCrashModulePathName)-2) > 0)) + { + //OutputDebugString(szCrashModulePathName); + pszCrashModuleFileName = GetFilePart(szCrashModulePathName); + } + #endif + + // Print out the beginning of the error log in a Win95 error window + // compatible format. + TCHAR szModuleName[MAX_PATH*2] = {0}; + if (GetModuleFileName(0, szModuleName, _countof(szModuleName)-2) <= 0) + StringCbCopy(szModuleName, sizeof(szModuleName), _T("Unknown")); + + TCHAR *pszFilePart = GetFilePart(szModuleName); + + // Extract the file name portion and remove it's file extension + TCHAR szFileName[MAX_PATH*2] = {0}; + StringCbCopy(szFileName, sizeof(szFileName), pszFilePart); + TCHAR *lastperiod = lstrrchr(szFileName, _T('.')); + if (lastperiod) + lastperiod[0] = 0; + + #ifdef _M_IX86 + StringCchPrintf(line, 1024, L"%s caused %s (0x%08x) \r\nin module %s at %04x:%08x.\r\n\r\n", + szFileName, GetExceptionDescription(Exception->ExceptionCode), + Exception->ExceptionCode, + pszCrashModuleFileName, Context->SegCs, Context->Eip); + #endif + StringCchCat(msgBody, 4*1024, line); + + StringCchPrintf(line, 1024, L"Exception handler called in %s.\r\n", lpszMessage); + StringCchCat(msgBody, 4*1024, line); + + hprintf(hLogFile, L"%s", msgBody); + wchar_t *p = msgBody, *end = msgBody + wcslen(msgBody); + while(p != end) + { + if (*p == L'\r') *p = 1; + if (*p == L'\n') *p = 2; + p++; + + } + settings.WriteBody(msgBody); + + if (settings.logSystem) + { + DumpSystemInformation(hLogFile); + + // If the exception was an access violation, print out some additional + // information, to the error log and the debugger. + if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION && + Exception->NumberParameters >= 2) + { + TCHAR szDebugMessage[1000] = {0}; + const TCHAR* readwrite = _T("Read from"); + if (Exception->ExceptionInformation[0]) + readwrite = _T("Write to"); + StringCchPrintf(szDebugMessage, 1000, _T("%s location %08x caused an access violation.\r\n"), + readwrite, Exception->ExceptionInformation[1]); + hprintf(hLogFile, _T("%s"), szDebugMessage); + } + } + if (settings.logRegistry) + { + #ifdef _M_IX86 + DumpRegisters(hLogFile, Context); + #endif + + // Print out the bytes of code at the instruction pointer. Since the + // crash may have been caused by an instruction pointer that was bad, + // this code needs to be wrapped in an exception handler, in case there + // is no memory to read. If the dereferencing of code[] fails, the + // exception handler will print '??'. + #ifdef _M_IX86 + hprintf(hLogFile, _T("\r\nBytes at CS:EIP:\r\n")); + BYTE * code = (BYTE *)Context->Eip; + for (int codebyte = 0; codebyte < NumCodeBytes; codebyte++) + { + __try + { + hprintf(hLogFile, _T("%02x "), code[codebyte]); + + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + hprintf(hLogFile, _T("?? ")); + } + } + #endif + } + if (settings.logStack) + { + // Time to print part or all of the stack to the error log. This allows + // us to figure out the call stack, parameters, local variables, etc. + + // Esp contains the bottom of the stack, or at least the bottom of + // the currently used area + + #ifdef _M_IX86 + DWORD* pStack = (DWORD *)Context->Esp; + DumpStack(hLogFile, pStack); + #endif + } + if (settings.logModule) + { + DumpModuleList(hLogFile); + } + + hprintf(hLogFile, _T("\r\n===== [end of log file] =====\r\n")); + hflush(hLogFile); + CloseHandle(hLogFile); + return TRUE; +} + +BOOL CreateDump(PEXCEPTION_POINTERS pExceptPtrs) +{ + BOOL retCode = FALSE; + + // Create the file + //OutputDebugString(_T("CreateFile: ")); + //OutputDebugString(settings.dumpPath); + HANDLE hMiniDumpFile = CreateFile( + settings.dumpPath, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, + NULL); + + // Write the minidump to the file + if (hMiniDumpFile != INVALID_HANDLE_VALUE) + { + retCode = DumpMiniDump(hMiniDumpFile, pExceptPtrs); + // Close file + CloseHandle(hMiniDumpFile); + if (!retCode) DeleteFile(settings.dumpPath); + } + return retCode; +}
\ No newline at end of file |