OpenWalnut
1.2.5
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #if ( defined( __linux__ ) && defined( __GNUC__ ) ) 00026 // This is highly platform dependent. Used for backtrace functionality. 00027 #include <execinfo.h> 00028 #include <cxxabi.h> 00029 #endif 00030 00031 #include <iostream> 00032 #include <list> 00033 #include <sstream> 00034 #include <stdexcept> 00035 #include <string> 00036 00037 #include <boost/algorithm/string.hpp> 00038 00039 #include "WException.h" 00040 00041 /** 00042 * initialize static member. 00043 */ 00044 bool WException::noBacktrace = false; 00045 00046 WException::WException( const std::string& msg ): 00047 exception(), 00048 m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ), 00049 m_functionColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGBlue ) ), 00050 m_symbolColor( WTerminalColor() ), 00051 m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) ) 00052 { 00053 // initialize members 00054 m_msg = msg; 00055 00056 // print stacktrace and message 00057 // no backtrace? 00058 if( !noBacktrace ) 00059 { 00060 std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl; 00061 } 00062 } 00063 00064 WException::WException( const std::exception& e ): 00065 exception( e ), 00066 m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ), 00067 m_functionColor( WTerminalColor( WTerminalColor::Off, WTerminalColor::FGBlue ) ), 00068 m_symbolColor( WTerminalColor() ), 00069 m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) ) 00070 { 00071 m_msg = e.what(); 00072 00073 // print stacktrace and message 00074 // no backtrace? 00075 if( !noBacktrace ) 00076 { 00077 std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl; 00078 } 00079 } 00080 00081 WException::~WException() throw() 00082 { 00083 // cleanup 00084 } 00085 00086 const char* WException::what() const throw() 00087 { 00088 // return it 00089 return m_msg.c_str(); 00090 } 00091 00092 std::string WException::getTrace() const 00093 { 00094 std::string result( what() ); 00095 result += "\n\n"; 00096 std::list< std::string >::const_iterator citer; 00097 for( citer = m_trace.begin(); citer != m_trace.end(); ++citer ) 00098 result += "trace: " + *citer + "\n"; 00099 boost::trim( result ); 00100 return result; 00101 } 00102 00103 std::string WException::getBacktrace() const 00104 { 00105 // print trace here 00106 std::ostringstream o; 00107 00108 #if ( defined( __linux__ ) && defined( __GNUC__ ) ) 00109 // This is highly platform dependent. It MIGHT also work on BSD and other unix. 00110 00111 // Automatic callstack backtrace 00112 const size_t maxDepth = 100; 00113 size_t stackDepth; 00114 void* stackAddrs[maxDepth]; 00115 char** stackSymbols; 00116 00117 // acquire stacktrace 00118 stackDepth = backtrace( stackAddrs, maxDepth ); 00119 stackSymbols = backtrace_symbols( stackAddrs, stackDepth ); 00120 00121 // for each stack element -> demangle and print 00122 for( size_t i = 1; i < stackDepth; ++i ) 00123 { 00124 // need some space for function name 00125 // just a guess, especially template names might be even longer 00126 size_t functionLength = 512; 00127 char* function = new char[functionLength]; 00128 00129 // find mangled function name in stackSymbols[i] 00130 char* begin = 0; 00131 char* end = 0; 00132 00133 // find the parentheses and address offset surrounding the mangled name 00134 for( char* j = stackSymbols[i]; *j; ++j ) 00135 { 00136 if( *j == '(' ) 00137 { 00138 begin = j; 00139 } 00140 else if( *j == '+' ) 00141 { 00142 end = j; 00143 } 00144 } 00145 00146 // found? 00147 if( begin && end ) 00148 { 00149 *begin++ = '('; 00150 *end = '\0'; // temporarily end string there (since \0 is string delimiter) 00151 00152 // found our mangled name, now in [begin, end) 00153 int status; 00154 char* ret = abi::__cxa_demangle( begin, function, &functionLength, &status ); 00155 00156 if( ret ) 00157 { 00158 // return value may be a realloc() of the input 00159 function = ret; 00160 } 00161 else 00162 { 00163 // demangling failed, just pretend it's a C function with no args 00164 std::strncpy( function, begin, functionLength ); 00165 std::strncat( function, "()", functionLength ); 00166 function[functionLength-1] = '\0'; 00167 } 00168 *end = '+'; 00169 o << m_labelColor( std::string( "trace: " ) ) 00170 << m_functionColor( function ) 00171 << "\t->\t" 00172 << m_symbolColor( stackSymbols[i] ) << std::endl; 00173 } 00174 else 00175 { 00176 // didn't find the mangled name, just print the whole line 00177 o << m_labelColor( std::string( "trace: " ) ) 00178 << m_functionColor( std::string( "??? " ) ) 00179 << "\t->\t" 00180 << m_symbolColor( stackSymbols[i] ) << std::endl; 00181 } 00182 00183 delete[] function; 00184 } 00185 00186 // backtrace_symbols malloc()ed some mem -> we NEED to use free() 00187 free( stackSymbols ); 00188 #else 00189 o << "Backtrace not supported on your platform. Currently just works on Linux with GCC. Sorry!"; 00190 #endif 00191 00192 return o.str(); 00193 } 00194 00195 void WException::disableBacktrace() 00196 { 00197 noBacktrace = true; 00198 } 00199