123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- // 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
- // [email protected]
- //
- // Modified by: Hans Dietrich
- // [email protected]
- //
- // 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;
- }
|