aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_crasher/ExceptionHandler.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_crasher/ExceptionHandler.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-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.cpp814
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