/* =========================================================================== Wolfenstein: Enemy Territory GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Wolfenstein: Enemy Territory GPL Source Code (“Wolf ET Source Code”). Wolf ET Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Wolf ET Source Code 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wolf ET Source Code. If not, see . In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include #include #include #include #include #define MAX_STACK_TRACE_LINES 32 HWND g_hWnd = NULL; const char* g_Version = NULL; typedef int fileHandle_t; typedef enum { FS_READ, FS_WRITE, FS_APPEND, FS_APPEND_SYNC } fsMode_t; extern "C" { void Com_Frame( void ); void Q_strcat( char *dest, int size, const char *src ); void __cdecl Com_sprintf( char *dest, int size, const char *fmt, ... ); int FS_FOpenFileByMode( const char *qpath, fileHandle_t * f, fsMode_t mode ); int FS_Write( const void *buffer, int len, fileHandle_t h ); void FS_FCloseFile( fileHandle_t f ); } #define CASE( seCode ) case EXCEPTION_ ## seCode: \ Com_sprintf( minibuffer, sizeof( minibuffer ), "Exception %s (0x%.8x) at address 0x%.8x.", # seCode, EXCEPTION_ ## seCode, m_exPointers->ExceptionRecord->ExceptionAddress ); \ break; class CWolfException { public: CWolfException( UINT nSeCode, _EXCEPTION_POINTERS* pExcPointers ) { m_seCode = nSeCode; m_exPointers = pExcPointers; } ~CWolfException() { } void BuildErrorMessage( char* buffer, int size ) { char minibuffer[256]; switch ( m_seCode ) { case EXCEPTION_ACCESS_VIOLATION: Com_sprintf( minibuffer, sizeof( minibuffer ), "Exception ACCESS_VIOLATION (0x%.8x) at address 0x%.8x trying to %s address 0x%.8x.", EXCEPTION_ACCESS_VIOLATION, m_exPointers->ExceptionRecord->ExceptionAddress, m_exPointers->ExceptionRecord->ExceptionInformation[0] ? "write" : "read", m_exPointers->ExceptionRecord->ExceptionInformation[1] ); break; CASE( DATATYPE_MISALIGNMENT ); CASE( BREAKPOINT ); CASE( SINGLE_STEP ); CASE( ARRAY_BOUNDS_EXCEEDED ); CASE( FLT_DENORMAL_OPERAND ); CASE( FLT_DIVIDE_BY_ZERO ); CASE( FLT_INEXACT_RESULT ); CASE( FLT_INVALID_OPERATION ); CASE( FLT_OVERFLOW ); CASE( FLT_STACK_CHECK ); CASE( FLT_UNDERFLOW ); CASE( INT_DIVIDE_BY_ZERO ); CASE( INT_OVERFLOW ); CASE( PRIV_INSTRUCTION ); CASE( IN_PAGE_ERROR ); CASE( ILLEGAL_INSTRUCTION ); CASE( NONCONTINUABLE_EXCEPTION ); CASE( STACK_OVERFLOW ); CASE( INVALID_DISPOSITION ); CASE( GUARD_PAGE ); CASE( INVALID_HANDLE ); default: Com_sprintf( minibuffer, sizeof( minibuffer ), "Unknown exception." ); break; } Q_strcat( buffer, size, minibuffer ); } void BuildDump( char* buffer, int size ) { char minibuffer[256]; Com_sprintf( minibuffer, sizeof( minibuffer ), "Exception : %.8x\r\n" "Address : %.8x\r\n" "Access Type : %s\r\n" "Access Address : %.8x\r\n", m_exPointers->ExceptionRecord->ExceptionCode, m_exPointers->ExceptionRecord->ExceptionAddress, m_exPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ? m_exPointers->ExceptionRecord->ExceptionInformation[0] ? "write" : "read" : "NA", m_exPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ? m_exPointers->ExceptionRecord->ExceptionInformation[1] : 0 ); Q_strcat( buffer, size, minibuffer ); } void BuildRegisters( char* buffer, int size ) { char minibuffer[256]; Com_sprintf( minibuffer, sizeof( minibuffer ), "Registers : EAX=%.8x CS=%.4x EIP=%.8x EFLGS=%.8x\r\n" " : EBX=%.8x SS=%.4x ESP=%.8x EBP=%.8x\r\n" " : ECX=%.8x DS=%.4x ESI=%.8x FS=%.4x\r\n" " : EDX=%.8x ES=%.4x EDI=%.8x GS=%.4x\r\n", m_exPointers->ContextRecord->Eax, m_exPointers->ContextRecord->SegCs, m_exPointers->ContextRecord->Eip, m_exPointers->ContextRecord->EFlags, m_exPointers->ContextRecord->Ebx, m_exPointers->ContextRecord->SegSs, m_exPointers->ContextRecord->Esp, m_exPointers->ContextRecord->Ebp, m_exPointers->ContextRecord->Ecx, m_exPointers->ContextRecord->SegDs, m_exPointers->ContextRecord->Esi, m_exPointers->ContextRecord->SegFs, m_exPointers->ContextRecord->Edx, m_exPointers->ContextRecord->SegEs, m_exPointers->ContextRecord->Edi, m_exPointers->ContextRecord->SegGs ); Q_strcat( buffer, size, minibuffer ); } void BuildStackTrace( char* buffer, int size ) { int i, j; DWORD* sp; DWORD stackTrace[MAX_STACK_TRACE_LINES]; sp = ( DWORD * )( m_exPointers->ContextRecord->Ebp ); for ( i = 0; i < MAX_STACK_TRACE_LINES; i++ ) { if ( !IsBadReadPtr( sp, sizeof( DWORD ) ) && *sp ) { DWORD* np = (DWORD*)*sp; stackTrace[i] = *( sp + 1 ); sp = np; } else { stackTrace[i] = 0; } } for ( i = 0; i < MAX_STACK_TRACE_LINES; i++ ) { if ( i == 0 ) { Q_strcat( buffer, size, "Stack Trace : " ); } else { Q_strcat( buffer, size, " : " ); } for ( j = 0; j < 4 && i < MAX_STACK_TRACE_LINES; i++, j++ ) { char minibuffer[16]; Com_sprintf( minibuffer, sizeof( minibuffer ), "%.8x ", stackTrace[i] ); Q_strcat( buffer, size, minibuffer ); } Q_strcat( buffer, size, "\r\n" ); } // MessageBox( g_hWnd, buffer, "Arf!", MB_OK ); } private: UINT m_seCode; _EXCEPTION_POINTERS* m_exPointers; }; void WinExceptionHandler( UINT nSeCode, _EXCEPTION_POINTERS* pExcPointers ) { CWolfException* we = new CWolfException( nSeCode, pExcPointers ); throw we; } void RunFrame( void ) { try { // run the game Com_Frame(); } catch ( CWolfException* we ) { char buffer[2048]; fileHandle_t handle; /* *buffer = '\0'; we->BuildErrorMessage( buffer, sizeof( buffer ) ); MessageBox( g_hWnd, buffer, "Error!", MB_OK | MB_ICONEXCLAMATION );*/ *buffer = '\0'; Q_strcat( buffer, sizeof( buffer ), g_Version ); Q_strcat( buffer, sizeof( buffer ), "\r\n" ); we->BuildDump( buffer, sizeof( buffer ) ); we->BuildRegisters( buffer, sizeof( buffer ) ); we->BuildStackTrace( buffer, sizeof( buffer ) ); Q_strcat( buffer, sizeof( buffer ), "\r\n" ); FS_FOpenFileByMode( "crash.log", &handle, FS_APPEND ); if ( handle ) { FS_Write( buffer, strlen( buffer ), handle ); FS_FCloseFile( handle ); } delete we; throw; } } extern "C" { void WinSetExceptionWnd( HWND wnd ) { if ( wnd ) { _set_se_translator( WinExceptionHandler ); } else { _set_se_translator( NULL ); } g_hWnd = wnd; } void Com_FrameExt( void ) { RunFrame(); } void WinSetExceptionVersion( const char* version ) { g_Version = version; } }