X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fstacktrace.cpp;h=5e63857428fae5ae54a22ea94ab0a55e965658b8;hb=ed990b29b0790e2a4d798477df8be2965fd80f41;hp=e2d383f5d590bbe9a95b2f04ad07e148b31ff1dd;hpb=02a51890a3d97a0e937fbb11071cf7c41cc00aa9;p=xonotic%2Fnetradiant.git diff --git a/radiant/stacktrace.cpp b/radiant/stacktrace.cpp index e2d383f5..5e638574 100644 --- a/radiant/stacktrace.cpp +++ b/radiant/stacktrace.cpp @@ -27,33 +27,29 @@ #include "environment.h" #if GDEF_OS_LINUX - #include -void write_stack_trace(TextOutputStream &outputStream) -{ - const unsigned int MAX_SYMBOLS = 256; - void *symbols[MAX_SYMBOLS]; - - // get return addresses - int symbol_count = backtrace(symbols, MAX_SYMBOLS); - - if (!symbol_count) { - return; - } - - // resolve and print names - char **symbol_names = backtrace_symbols(symbols, symbol_count); - if (symbol_names) { - for (int i = 0; (i < symbol_count); ++i) { - outputStream << symbol_names[i] << "\n"; - } - - // not a memleak, see www.gnu.org/software/libc/manual (Debugging Support, Backtraces) - free(symbol_names); - } -} +void write_stack_trace( TextOutputStream& outputStream ){ + const unsigned int MAX_SYMBOLS = 256; + void* symbols[MAX_SYMBOLS]; + // get return addresses + int symbol_count = backtrace( symbols, MAX_SYMBOLS ); + + if ( !symbol_count ) { + return; + } + + // resolve and print names + char** symbol_names = backtrace_symbols( symbols, symbol_count ); + if ( symbol_names ) { + for ( int i = 0; ( i < symbol_count ); ++i ) + outputStream << symbol_names[i] << "\n"; + + // not a memleak, see www.gnu.org/software/libc/manual (Debugging Support, Backtraces) + free( symbol_names ); + } +} #elif GDEF_COMPILER_MSVC #include "windows.h" @@ -71,10 +67,10 @@ Address( void* value ) : m_value( value ){ /// \brief Writes an address \p p to \p ostream in hexadecimal form. template inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Address& p ){ - const std::size_t bufferSize = ( sizeof( void* ) * 2 ) + 1; - char buf[bufferSize]; - ostream.write( buf, snprintf( buf, bufferSize, "%0p", p.m_value ) ); - return ostream; + const std::size_t bufferSize = ( sizeof( void* ) * 2 ) + 1; + char buf[bufferSize]; + ostream.write( buf, snprintf( buf, bufferSize, "%0p", p.m_value ) ); + return ostream; } class Offset @@ -88,218 +84,218 @@ Offset( void* value ) : m_value( value ){ /// \brief Writes an address \p p to \p ostream in hexadecimal form. template inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Offset& p ){ - const std::size_t bufferSize = ( sizeof( void* ) * 2 ) + 1; - char buf[bufferSize]; - ostream.write( buf, snprintf( buf, bufferSize, "%X", p.m_value ) ); - return ostream; + const std::size_t bufferSize = ( sizeof( void* ) * 2 ) + 1; + char buf[bufferSize]; + ostream.write( buf, snprintf( buf, bufferSize, "%X", p.m_value ) ); + return ostream; } /// \brief Writes a WCHAR string \p s to \p ostream. template inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const WCHAR* s ){ - const std::size_t bufferSize = 1024; - char buf[bufferSize]; - ostream.write( buf, snprintf( buf, bufferSize, "%ls", s ) ); - return ostream; + const std::size_t bufferSize = 1024; + char buf[bufferSize]; + ostream.write( buf, snprintf( buf, bufferSize, "%ls", s ) ); + return ostream; } struct EnumerateSymbolsContext { - STACKFRAME64& sf; - TextOutputStream& outputStream; - std::size_t count; - EnumerateSymbolsContext( STACKFRAME64& sf, TextOutputStream& outputStream ) : sf( sf ), outputStream( outputStream ), count( 0 ){ - } + STACKFRAME64& sf; + TextOutputStream& outputStream; + std::size_t count; + EnumerateSymbolsContext( STACKFRAME64& sf, TextOutputStream& outputStream ) : sf( sf ), outputStream( outputStream ), count( 0 ){ + } }; void write_symbol( PSYMBOL_INFO pSym, STACKFRAME64& sf, TextOutputStream& outputStream, std::size_t& count ){ #if 0 - if ( pSym->Flags & SYMFLAG_PARAMETER ) { - - DWORD basicType; - if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, - TI_GET_BASETYPE, &basicType ) ) { - int bleh = 0; - } - else - { - DWORD typeId; - if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, - TI_GET_TYPEID, &typeId ) ) { - if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, - TI_GET_BASETYPE, &basicType ) ) { - int bleh = 0; - } - else - { - const char* FormatGetLastError(); - const char* error = FormatGetLastError(); - int bleh = 0; - - WCHAR* name; - if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, typeId, - TI_GET_SYMNAME, &name ) ) { - outputStream << name << " "; - LocalFree( name ); - int bleh = 0; - } - else - { - const char* FormatGetLastError(); - const char* error = FormatGetLastError(); - int bleh = 0; - } - } - } - else - { - const char* FormatGetLastError(); - const char* error = FormatGetLastError(); - int bleh = 0; - } - } - if ( count != 0 ) { - outputStream << ", "; - } - outputStream << pSym->Name; - ++count; - } + if ( pSym->Flags & SYMFLAG_PARAMETER ) { + + DWORD basicType; + if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, + TI_GET_BASETYPE, &basicType ) ) { + int bleh = 0; + } + else + { + DWORD typeId; + if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, + TI_GET_TYPEID, &typeId ) ) { + if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, + TI_GET_BASETYPE, &basicType ) ) { + int bleh = 0; + } + else + { + const char* FormatGetLastError(); + const char* error = FormatGetLastError(); + int bleh = 0; + + WCHAR* name; + if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, typeId, + TI_GET_SYMNAME, &name ) ) { + outputStream << name << " "; + LocalFree( name ); + int bleh = 0; + } + else + { + const char* FormatGetLastError(); + const char* error = FormatGetLastError(); + int bleh = 0; + } + } + } + else + { + const char* FormatGetLastError(); + const char* error = FormatGetLastError(); + int bleh = 0; + } + } + if ( count != 0 ) { + outputStream << ", "; + } + outputStream << pSym->Name; + ++count; + } #endif } BOOL CALLBACK EnumerateSymbolsCallback( - PSYMBOL_INFO pSymInfo, - ULONG SymbolSize, - PVOID UserContext ){ - write_symbol( pSymInfo, ( (EnumerateSymbolsContext*)UserContext )->sf, ( (EnumerateSymbolsContext*)UserContext )->outputStream, ( (EnumerateSymbolsContext*)UserContext )->count ); + PSYMBOL_INFO pSymInfo, + ULONG SymbolSize, + PVOID UserContext ){ + write_symbol( pSymInfo, ( (EnumerateSymbolsContext*)UserContext )->sf, ( (EnumerateSymbolsContext*)UserContext )->outputStream, ( (EnumerateSymbolsContext*)UserContext )->count ); - return TRUE; + return TRUE; } void write_stack_trace( PCONTEXT pContext, TextOutputStream& outputStream ){ - HANDLE m_hProcess = GetCurrentProcess(); - DWORD dwMachineType = 0; + HANDLE m_hProcess = GetCurrentProcess(); + DWORD dwMachineType = 0; - CONTEXT context = *pContext; + CONTEXT context = *pContext; - // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag - if ( !SymInitialize( m_hProcess, (PSTR)environment_get_app_path(), TRUE ) ) { - return; - } + // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag + if ( !SymInitialize( m_hProcess, (PSTR)environment_get_app_path(), TRUE ) ) { + return; + } - STACKFRAME64 sf; - memset( &sf, 0, sizeof( sf ) ); - sf.AddrPC.Mode = AddrModeFlat; - sf.AddrStack.Mode = AddrModeFlat; - sf.AddrFrame.Mode = AddrModeFlat; + STACKFRAME64 sf; + memset( &sf, 0, sizeof( sf ) ); + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Mode = AddrModeFlat; #ifdef _M_IX86 - // Initialize the STACKFRAME structure for the first call. This is only - // necessary for Intel CPUs, and isn't mentioned in the documentation. - sf.AddrPC.Offset = context.Eip; - sf.AddrStack.Offset = context.Esp; - sf.AddrFrame.Offset = context.Ebp; + // Initialize the STACKFRAME structure for the first call. This is only + // necessary for Intel CPUs, and isn't mentioned in the documentation. + sf.AddrPC.Offset = context.Eip; + sf.AddrStack.Offset = context.Esp; + sf.AddrFrame.Offset = context.Ebp; - dwMachineType = IMAGE_FILE_MACHINE_I386; + dwMachineType = IMAGE_FILE_MACHINE_I386; #elif _M_X64 - sf.AddrPC.Offset = context.Rip; - sf.AddrStack.Offset = context.Rsp; + sf.AddrPC.Offset = context.Rip; + sf.AddrStack.Offset = context.Rsp; - // MSDN: x64: The frame pointer is RBP or RDI. This value is not always used. - // very funny, we'll try Rdi for now - sf.AddrFrame.Offset = context.Rdi; + // MSDN: x64: The frame pointer is RBP or RDI. This value is not always used. + // very funny, we'll try Rdi for now + sf.AddrFrame.Offset = context.Rdi; - dwMachineType = IMAGE_FILE_MACHINE_AMD64; + dwMachineType = IMAGE_FILE_MACHINE_AMD64; #endif - const unsigned int max_sym_name = 1024; // should be enough - - while ( 1 ) - { - // Get the next stack frame - if ( !StackWalk64( dwMachineType, - m_hProcess, - GetCurrentThread(), - &sf, - &context, - 0, - SymFunctionTableAccess64, - SymGetModuleBase64, - 0 ) ) { - break; - } - - if ( 0 == sf.AddrFrame.Offset ) { // Basic sanity check to make sure - break; // the frame is OK. Bail if not. - - } - // Get the name of the function for this stack frame entry - BYTE symbolBuffer[ sizeof( SYMBOL_INFO ) + max_sym_name ]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; - pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO ); - pSymbol->MaxNameLen = max_sym_name; - - DWORD64 symDisplacement = 0; // Displacement of the input address, - // relative to the start of the symbol - - IMAGEHLP_MODULE64 module = { sizeof( IMAGEHLP_MODULE64 ) }; - if ( SymGetModuleInfo64( m_hProcess, sf.AddrPC.Offset, &module ) ) { - outputStream << module.ModuleName << "!"; - - if ( SymFromAddr( m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol ) ) { - char undecoratedName[max_sym_name]; - UnDecorateSymbolName( pSymbol->Name, undecoratedName, max_sym_name, UNDNAME_COMPLETE ); - - outputStream << undecoratedName; - - outputStream << "("; - // Use SymSetContext to get just the locals/params for this frame - IMAGEHLP_STACK_FRAME imagehlpStackFrame; - imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; - SymSetContext( m_hProcess, &imagehlpStackFrame, 0 ); - - // Enumerate the locals/parameters - EnumerateSymbolsContext context( sf, outputStream ); - SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context ); - outputStream << ")"; - - outputStream << " + " << Offset( reinterpret_cast( symDisplacement ) ); - - // Get the source line for this stack frame entry - IMAGEHLP_LINE64 lineInfo = { sizeof( IMAGEHLP_LINE64 ) }; - DWORD dwLineDisplacement; - if ( SymGetLineFromAddr64( m_hProcess, sf.AddrPC.Offset, - &dwLineDisplacement, &lineInfo ) ) { - outputStream << " " << lineInfo.FileName << " line " << Unsigned( lineInfo.LineNumber ); - } - } - else - { - outputStream << Address( reinterpret_cast( sf.AddrPC.Offset ) ); - } - } - - outputStream << "\n"; - } - - SymCleanup( m_hProcess ); - - return; + const unsigned int max_sym_name = 1024; // should be enough + + while ( 1 ) + { + // Get the next stack frame + if ( !StackWalk64( dwMachineType, + m_hProcess, + GetCurrentThread(), + &sf, + &context, + 0, + SymFunctionTableAccess64, + SymGetModuleBase64, + 0 ) ) { + break; + } + + if ( 0 == sf.AddrFrame.Offset ) { // Basic sanity check to make sure + break; // the frame is OK. Bail if not. + + } + // Get the name of the function for this stack frame entry + BYTE symbolBuffer[ sizeof( SYMBOL_INFO ) + max_sym_name ]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer; + pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO ); + pSymbol->MaxNameLen = max_sym_name; + + DWORD64 symDisplacement = 0; // Displacement of the input address, + // relative to the start of the symbol + + IMAGEHLP_MODULE64 module = { sizeof( IMAGEHLP_MODULE64 ) }; + if ( SymGetModuleInfo64( m_hProcess, sf.AddrPC.Offset, &module ) ) { + outputStream << module.ModuleName << "!"; + + if ( SymFromAddr( m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol ) ) { + char undecoratedName[max_sym_name]; + UnDecorateSymbolName( pSymbol->Name, undecoratedName, max_sym_name, UNDNAME_COMPLETE ); + + outputStream << undecoratedName; + + outputStream << "("; + // Use SymSetContext to get just the locals/params for this frame + IMAGEHLP_STACK_FRAME imagehlpStackFrame; + imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; + SymSetContext( m_hProcess, &imagehlpStackFrame, 0 ); + + // Enumerate the locals/parameters + EnumerateSymbolsContext context( sf, outputStream ); + SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context ); + outputStream << ")"; + + outputStream << " + " << Offset( reinterpret_cast( symDisplacement ) ); + + // Get the source line for this stack frame entry + IMAGEHLP_LINE64 lineInfo = { sizeof( IMAGEHLP_LINE64 ) }; + DWORD dwLineDisplacement; + if ( SymGetLineFromAddr64( m_hProcess, sf.AddrPC.Offset, + &dwLineDisplacement, &lineInfo ) ) { + outputStream << " " << lineInfo.FileName << " line " << Unsigned( lineInfo.LineNumber ); + } + } + else + { + outputStream << Address( reinterpret_cast( sf.AddrPC.Offset ) ); + } + } + + outputStream << "\n"; + } + + SymCleanup( m_hProcess ); + + return; } void write_stack_trace( TextOutputStream& outputStream ){ - __try { RaiseException( 0,0,0,0 ); } __except( write_stack_trace( ( GetExceptionInformation() )->ContextRecord, outputStream ), EXCEPTION_CONTINUE_EXECUTION ) { - } + __try { RaiseException( 0,0,0,0 ); } __except( write_stack_trace( ( GetExceptionInformation() )->ContextRecord, outputStream ), EXCEPTION_CONTINUE_EXECUTION ) { + } } #elif GDEF_OS_WINDOWS void write_stack_trace( TextOutputStream& outputStream ){ - outputStream << "\nStacktrace is disabled on this compiler\n"; + outputStream << "\nStacktrace is disabled on this compiler\n"; } #else void write_stack_trace( TextOutputStream& outputStream ){ - outputStream << "\nStacktrace is disabled on this platform\n"; + outputStream << "\nStacktrace is disabled on this platform\n"; } #endif