X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fstacktrace.cpp;h=e2d383f5d590bbe9a95b2f04ad07e148b31ff1dd;hb=9dfae1c9b270ee369c6362903a9205b30751b95f;hp=7c75db423597a7afd6b90dc64cc5169264ae9d86;hpb=107765f0e4b543dfc346851ee5b4605cc17eb1c6;p=xonotic%2Fnetradiant.git diff --git a/radiant/stacktrace.cpp b/radiant/stacktrace.cpp index 7c75db42..e2d383f5 100644 --- a/radiant/stacktrace.cpp +++ b/radiant/stacktrace.cpp @@ -1,57 +1,60 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant 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 2 of the License, or -(at your option) any later version. + GtkRadiant 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 2 of the License, or + (at your option) any later version. -GtkRadiant 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. + GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "stacktrace.h" +#include "globaldefs.h" + #include "stream/textstream.h" #include "environment.h" -#ifdef __linux__ +#if GDEF_OS_LINUX + #include -void write_stack_trace(TextOutputStream& outputStream) +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); - } -} -#endif + const unsigned int MAX_SYMBOLS = 256; + void *symbols[MAX_SYMBOLS]; + + // get return addresses + int symbol_count = backtrace(symbols, MAX_SYMBOLS); -#if defined (WIN32) && defined (_MSC_VER) && defined (DEBUG) + 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" #include "winnt.h" @@ -60,259 +63,243 @@ void write_stack_trace(TextOutputStream& outputStream) class Address { public: - void* m_value; - Address(void* value) : m_value(value) - { - } +void* m_value; +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; +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; } class Offset { public: - void* m_value; - Offset(void* value) : m_value(value) - { - } +void* m_value; +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; +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; } /// \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; +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; } 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) -{ +void write_symbol( PSYMBOL_INFO pSym, STACKFRAME64& sf, TextOutputStream& outputStream, std::size_t& count ){ #if 0 - if ( pSym->Flags & SYMFLAG_PARAMETER ) - { + 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 )) - { + DWORD basicType; if ( SymGetTypeInfo( GetCurrentProcess(), pSym->ModBase, pSym->TypeIndex, - TI_GET_BASETYPE, &basicType ) ) - { - int bleh = 0; + 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; - } + 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; + } } - } - else - { - const char* FormatGetLastError(); - const char* error = FormatGetLastError(); - int bleh = 0; - } - } - if(count != 0) - { - outputStream << ", "; + if ( count != 0 ) { + outputStream << ", "; + } + outputStream << pSym->Name; + ++count; } - 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; +void write_stack_trace( PCONTEXT pContext, TextOutputStream& outputStream ){ + 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; + } + + STACKFRAME64 sf; + memset( &sf, 0, sizeof( sf ) ); + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Mode = AddrModeFlat; - // 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; - #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; - - dwMachineType = IMAGE_FILE_MACHINE_I386; -#elif _M_X64 - 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; - - dwMachineType = IMAGE_FILE_MACHINE_AMD64; -#endif + // 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; - 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 << "!"; + dwMachineType = IMAGE_FILE_MACHINE_I386; +#elif _M_X64 + sf.AddrPC.Offset = context.Rip; + sf.AddrStack.Offset = context.Rsp; - if ( SymFromAddr(m_hProcess, sf.AddrPC.Offset, &symDisplacement, pSymbol)) - { - char undecoratedName[max_sym_name]; - UnDecorateSymbolName(pSymbol->Name, undecoratedName, max_sym_name, UNDNAME_COMPLETE); + // 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; - outputStream << undecoratedName; + dwMachineType = IMAGE_FILE_MACHINE_AMD64; +#endif - 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 ); + const unsigned int max_sym_name = 1024; // should be enough - // Enumerate the locals/parameters - EnumerateSymbolsContext context(sf, outputStream); - SymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &context ); - outputStream << ")"; + while ( 1 ) + { + // Get the next stack frame + if ( !StackWalk64( dwMachineType, + m_hProcess, + GetCurrentThread(), + &sf, + &context, + 0, + SymFunctionTableAccess64, + SymGetModuleBase64, + 0 ) ) { + break; + } - outputStream << " + " << Offset(reinterpret_cast(symDisplacement)); + if ( 0 == sf.AddrFrame.Offset ) { // Basic sanity check to make sure + break; // the frame is OK. Bail if not. - // 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)); - } - } + // 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"; - } + outputStream << "\n"; + } - SymCleanup(m_hProcess); + SymCleanup( m_hProcess ); - return; + return; } -void write_stack_trace(TextOutputStream& outputStream) -{ - __try{ RaiseException(0,0,0,0); } __except(write_stack_trace((GetExceptionInformation())->ContextRecord, outputStream), EXCEPTION_CONTINUE_EXECUTION) {} +void write_stack_trace( TextOutputStream& outputStream ){ + __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"; +} #else -#if defined (WIN32) -void write_stack_trace(TextOutputStream& outputStream) -{ - outputStream << "\nStacktrace is disabled in release-builds\n"; +void write_stack_trace( TextOutputStream& outputStream ){ + outputStream << "\nStacktrace is disabled on this platform\n"; } #endif -#endif