mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-07 04:40:43 +08:00
engine: platform: win32: make output similar to libbacktrace-based crashhandler, general improvements and refactoring
This commit is contained in:
@@ -34,23 +34,20 @@ typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
|
||||
|
||||
static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
|
||||
{
|
||||
DWORD_PTR baseAddress = 0;
|
||||
static HMODULE *moduleArray;
|
||||
static unsigned int moduleCount;
|
||||
LPBYTE moduleArrayBytes;
|
||||
DWORD bytesRequired;
|
||||
int i;
|
||||
|
||||
if( len < 3 )
|
||||
return 0;
|
||||
|
||||
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ) )
|
||||
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ))
|
||||
{
|
||||
if ( bytesRequired )
|
||||
if( bytesRequired )
|
||||
{
|
||||
moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
|
||||
LPBYTE moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
|
||||
|
||||
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ) )
|
||||
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ))
|
||||
{
|
||||
moduleCount = bytesRequired / sizeof( HMODULE );
|
||||
moduleArray = (HMODULE *)moduleArrayBytes;
|
||||
@@ -58,139 +55,149 @@ static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < moduleCount; i++ )
|
||||
for( int i = 0; i < moduleCount; i++ )
|
||||
{
|
||||
MODULEINFO info;
|
||||
GetModuleInformation( process, moduleArray[i], &info, sizeof(MODULEINFO) );
|
||||
GetModuleInformation( process, moduleArray[i], &info, sizeof( MODULEINFO ));
|
||||
|
||||
if( ( address > info.lpBaseOfDll ) &&
|
||||
( (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage ) )
|
||||
if( address > info.lpBaseOfDll && (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage )
|
||||
return GetModuleBaseName( process, moduleArray[i], name, len );
|
||||
}
|
||||
|
||||
return Q_snprintf( name, len, "???" );
|
||||
}
|
||||
|
||||
static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
||||
{
|
||||
char message[8192]; // match *nix Sys_Crash
|
||||
int len = 0;
|
||||
size_t i;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
char message[8192]; // match *nix Sys_Crash
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
DWORD dline = 0;
|
||||
DWORD options = SymGetOptions();
|
||||
CONTEXT context = *pInfo->ContextRecord;
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD dline = 0;
|
||||
DWORD options;
|
||||
CONTEXT context;
|
||||
STACKFRAME64 stackframe;
|
||||
DWORD image;
|
||||
|
||||
context = *pInfo->ContextRecord;
|
||||
|
||||
options = SymGetOptions();
|
||||
options |= SYMOPT_DEBUG;
|
||||
options |= SYMOPT_LOAD_LINES;
|
||||
SetBits( options, SYMOPT_DEBUG | SYMOPT_LOAD_LINES );
|
||||
SymSetOptions( options );
|
||||
|
||||
SymInitialize( process, NULL, TRUE );
|
||||
|
||||
ZeroMemory( &stackframe, sizeof( STACKFRAME64 ));
|
||||
|
||||
#ifdef _M_IX86
|
||||
image = IMAGE_FILE_MACHINE_I386;
|
||||
stackframe.AddrPC.Offset = context.Eip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Ebp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Esp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD image = IMAGE_FILE_MACHINE_I386;
|
||||
STACKFRAME64 stackframe =
|
||||
{
|
||||
.AddrPC.Offset = context.Eip,
|
||||
.AddrPC.Mode = AddrModeFlat,
|
||||
.AddrFrame.Offset = context.Ebp,
|
||||
.AddrFrame.Mode = AddrModeFlat,
|
||||
.AddrStack.Offset = context.Esp,
|
||||
.AddrStack.Mode = AddrModeFlat,
|
||||
};
|
||||
#elif _M_X64
|
||||
image = IMAGE_FILE_MACHINE_AMD64;
|
||||
stackframe.AddrPC.Offset = context.Rip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Rsp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Rsp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD image = IMAGE_FILE_MACHINE_AMD64;
|
||||
STACKFRAME64 stackframe =
|
||||
{
|
||||
.AddrPC.Offset = context.Rip,
|
||||
.AddrPC.Mode = AddrModeFlat,
|
||||
.AddrFrame.Offset = context.Rsp,
|
||||
.AddrFrame.Mode = AddrModeFlat,
|
||||
.AddrStack.Offset = context.Rsp,
|
||||
.AddrStack.Mode = AddrModeFlat,
|
||||
};
|
||||
#elif _M_IA64
|
||||
image = IMAGE_FILE_MACHINE_IA64;
|
||||
stackframe.AddrPC.Offset = context.StIIP;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.IntSp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrBStore.Offset = context.RsBSP;
|
||||
stackframe.AddrBStore.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.IntSp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD image = IMAGE_FILE_MACHINE_IA64;
|
||||
STACKFRAME64 stackframe =
|
||||
{
|
||||
.AddrPC.Offset = context.StIIP,
|
||||
.AddrPC.Mode = AddrModeFlat,
|
||||
.AddrFrame.Offset = context.IntSp,
|
||||
.AddrFrame.Mode = AddrModeFlat,
|
||||
.AddrBStore.Offset = context.RsBSP,
|
||||
.AddrBStore.Mode = AddrModeFlat,
|
||||
.AddrStack.Offset = context.IntSp,
|
||||
.AddrStack.Mode = AddrModeFlat,
|
||||
};
|
||||
#elif _M_ARM
|
||||
image = IMAGE_FILE_MACHINE_ARMNT;
|
||||
stackframe.AddrPC.Offset = context.Pc;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.R11;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Sp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD image = IMAGE_FILE_MACHINE_ARMNT;
|
||||
STACKFRAME64 stackframe =
|
||||
{
|
||||
.AddrPC.Offset = context.Pc,
|
||||
.AddrPC.Mode = AddrModeFlat,
|
||||
.AddrFrame.Offset = context.R11,
|
||||
.AddrFrame.Mode = AddrModeFlat,
|
||||
.AddrStack.Offset = context.Sp,
|
||||
.AddrStack.Mode = AddrModeFlat,
|
||||
};
|
||||
#elif _M_ARM64
|
||||
image = IMAGE_FILE_MACHINE_ARM64;
|
||||
stackframe.AddrPC.Offset = context.Pc;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Fp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Sp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD image = IMAGE_FILE_MACHINE_ARM64;
|
||||
STACKFRAME64 stackframe =
|
||||
{
|
||||
.AddrPC.Offset = context.Pc,
|
||||
.AddrPC.Mode = AddrModeFlat,
|
||||
.AddrFrame.Offset = context.Fp,
|
||||
.AddrFrame.Mode = AddrModeFlat,
|
||||
.AddrStack.Offset = context.Sp,
|
||||
.AddrStack.Mode = AddrModeFlat,
|
||||
};
|
||||
#elif
|
||||
#error
|
||||
#endif
|
||||
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
int len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s-%s, %s-%s)\n",
|
||||
Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
|
||||
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
|
||||
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
|
||||
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ) )
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: address %p, code %p\n",
|
||||
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
|
||||
|
||||
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ))
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len, "Exception: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Exception: %s:%d:%d\n",
|
||||
COM_FileWithoutPath((char*)line.FileName ), (int)line.LineNumber, (int)dline );
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
|
||||
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ))
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"PC: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "PC: %s:%d:%d\n",
|
||||
COM_FileWithoutPath((char*)line.FileName ), (int)line.LineNumber, (int)dline );
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ) )
|
||||
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ))
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"Frame: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Frame: %s:%d:%d\n",
|
||||
COM_FileWithoutPath((char*)line.FileName ), (int)line.LineNumber, (int)dline );
|
||||
}
|
||||
for( i = 0; i < 25; i++ )
|
||||
|
||||
for( size_t i = 0; i < 25; i++ )
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
char buffer[sizeof( SYMBOL_INFO ) + MAX_SYM_NAME * sizeof( TCHAR )];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
BOOL result = StackWalk64(
|
||||
image, process, thread,
|
||||
BOOL result = StackWalk64( image, process, thread,
|
||||
&stackframe, &context, NULL,
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, NULL );
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
if( !result )
|
||||
break;
|
||||
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
len += Q_snprintf( message + len, 1024 - len, "% 2d %p",
|
||||
i, (void*)stackframe.AddrPC.Offset );
|
||||
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ) )
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "%2d: %p",
|
||||
i, (void*)stackframe.AddrPC.Offset );
|
||||
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ))
|
||||
{
|
||||
len += Q_snprintf( message + len, 1024 - len, " %s ", symbol->Name );
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, " %s ", symbol->Name );
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
|
||||
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ))
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"(%s:%d:%d) ",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len,"(%s:%d:%d) ",
|
||||
COM_FileWithoutPath((char*)line.FileName ), (int)line.LineNumber, (int)dline );
|
||||
}
|
||||
len += Q_snprintf( message + len, 1024 - len, "(");
|
||||
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, 1024 - len );
|
||||
len += Q_snprintf( message + len, 1024 - len, ")\n");
|
||||
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "(" );
|
||||
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, sizeof( message ) - len );
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, ")\n" );
|
||||
}
|
||||
|
||||
#if XASH_SDL == 2
|
||||
@@ -227,34 +234,34 @@ static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName
|
||||
currentLocalTime->tm_sec );
|
||||
}
|
||||
|
||||
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
|
||||
static qboolean Sys_WriteMinidump( PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType )
|
||||
{
|
||||
HRESULT errorCode;
|
||||
string processName;
|
||||
string mdmpFileName;
|
||||
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
|
||||
|
||||
Sys_GetProcessName( processName, sizeof( processName ));
|
||||
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
|
||||
|
||||
SetLastError( NOERROR );
|
||||
HANDLE fileHandle = CreateFile(
|
||||
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
HANDLE fileHandle = CreateFile( mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
|
||||
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
|
||||
if( !SUCCEEDED( errorCode )) {
|
||||
HRESULT errorCode = HRESULT_FROM_WIN32( GetLastError( ));
|
||||
if( !SUCCEEDED( errorCode ))
|
||||
{
|
||||
CloseHandle( fileHandle );
|
||||
return false;
|
||||
}
|
||||
|
||||
minidumpInfo.ThreadId = GetCurrentThreadId();
|
||||
minidumpInfo.ExceptionPointers = exceptionInfo;
|
||||
minidumpInfo.ClientPointers = FALSE;
|
||||
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo =
|
||||
{
|
||||
.ThreadId = GetCurrentThreadId(),
|
||||
.ExceptionPointers = exceptionInfo,
|
||||
.ClientPointers = FALSE
|
||||
};
|
||||
|
||||
qboolean status = MiniDumpWriteDump(
|
||||
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
|
||||
minidumpType, &minidumpInfo, NULL, NULL);
|
||||
qboolean status = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
|
||||
minidumpType, &minidumpInfo, NULL, NULL);
|
||||
|
||||
CloseHandle( fileHandle );
|
||||
return status;
|
||||
|
||||
Reference in New Issue
Block a user