OpenWalnut  1.4.0
WException.cpp
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__ )) && !defined( __ANDROID__) || defined ( __APPLE__ ))
00026     #define BACKTRACE_SUPPORTED
00027 #endif
00028 
00029 #ifdef BACKTRACE_SUPPORTED
00030 // This is highly platform dependent. Used for backtrace functionality.
00031 #include <execinfo.h>
00032 #include <cxxabi.h>
00033 #endif
00034 
00035 #include <iostream>
00036 #include <list>
00037 #include <sstream>
00038 #include <stdexcept>
00039 #include <string>
00040 
00041 #include <boost/algorithm/string.hpp>
00042 
00043 #include "WException.h"
00044 
00045 /**
00046  * initialize static member.
00047  */
00048 bool WException::noBacktrace = false;
00049 
00050 WException::WException( const std::string& msg ):
00051     exception(),
00052     m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
00053     m_functionColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGBlue ) ),
00054     m_symbolColor( WTerminalColor() ),
00055     m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
00056 {
00057     // initialize members
00058     m_msg = msg;
00059 
00060     // print stacktrace and message
00061     // no backtrace?
00062     if( !noBacktrace )
00063     {
00064         std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
00065     }
00066 }
00067 
00068 WException::WException( const std::exception& e ):
00069     exception( e ),
00070     m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
00071     m_functionColor( WTerminalColor( WTerminalColor::Off, WTerminalColor::FGBlue ) ),
00072     m_symbolColor( WTerminalColor() ),
00073     m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
00074 {
00075     m_msg = e.what();
00076 
00077     // print stacktrace and message
00078     // no backtrace?
00079     if( !noBacktrace )
00080     {
00081         std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
00082     }
00083 }
00084 
00085 WException::~WException() throw()
00086 {
00087     // cleanup
00088 }
00089 
00090 const char* WException::what() const throw()
00091 {
00092     // return it
00093     return m_msg.c_str();
00094 }
00095 
00096 std::string WException::getTrace() const
00097 {
00098     std::string result( what() );
00099     result += "\n\n";
00100     std::list< std::string >::const_iterator citer;
00101     for( citer = m_trace.begin(); citer != m_trace.end(); ++citer )
00102         result += "trace: " + *citer + "\n";
00103     boost::trim( result );
00104     return result;
00105 }
00106 
00107 std::string WException::getBacktrace() const
00108 {
00109     // print trace here
00110     std::ostringstream o;
00111 
00112 #ifdef BACKTRACE_SUPPORTED
00113     // This is highly platform dependent. It MIGHT also work on BSD and other unix.
00114 
00115     // Automatic callstack backtrace
00116     const size_t maxDepth = 100;
00117     size_t stackDepth;
00118     void* stackAddrs[maxDepth];
00119     char** stackSymbols;
00120 
00121     // acquire stacktrace
00122     stackDepth = backtrace( stackAddrs, maxDepth );
00123     stackSymbols = backtrace_symbols( stackAddrs, stackDepth );
00124 
00125     // for each stack element -> demangle and print
00126     for( size_t i = 1; i < stackDepth; ++i )
00127     {
00128         // need some space for function name
00129         // just a guess, especially template names might be even longer
00130         size_t functionLength = 512;
00131         char* function = new char[functionLength];
00132 
00133         // find mangled function name in stackSymbols[i]
00134         char* begin = 0;
00135         char* end = 0;
00136 
00137         // find the parentheses and address offset surrounding the mangled name
00138         for( char* j = stackSymbols[i]; *j; ++j )
00139         {
00140             if( *j == '(' )
00141             {
00142                 begin = j;
00143             }
00144             else if( *j == '+' )
00145             {
00146                 end = j;
00147             }
00148         }
00149 
00150         // found?
00151         if( begin && end )
00152         {
00153             *begin++ = '(';
00154             *end = '\0';    // temporarily end string there (since \0 is string delimiter)
00155 
00156             // found our mangled name, now in [begin, end)
00157             int status;
00158             char* ret = abi::__cxa_demangle( begin, function, &functionLength, &status );
00159 
00160             if( ret )
00161             {
00162                 // return value may be a realloc() of the input
00163                 function = ret;
00164             }
00165             else
00166             {
00167                 // demangling failed, just pretend it's a C function with no args
00168                 std::strncpy( function, begin, functionLength );
00169                 std::strncat( function, "()", functionLength );
00170                 function[functionLength-1] = '\0';
00171             }
00172             *end = '+';
00173             o << m_labelColor( std::string( "trace: " ) )
00174               << m_functionColor( function )
00175               << "\t->\t"
00176               << m_symbolColor( stackSymbols[i] ) << std::endl;
00177         }
00178         else
00179         {
00180             // didn't find the mangled name, just print the whole line
00181             o << m_labelColor( std::string( "trace: " ) )
00182               << m_functionColor( std::string( "??? " ) )
00183               << "\t->\t"
00184               << m_symbolColor( stackSymbols[i] ) << std::endl;
00185         }
00186 
00187         delete[] function;
00188     }
00189 
00190     // backtrace_symbols malloc()ed some mem -> we NEED to use free()
00191     free( stackSymbols );
00192 #else
00193     o << "Backtrace not supported on your platform. Currently just works on Linux and MacOS with GCC. Sorry!" << std::endl
00194       << "Message was: " << what();
00195 #endif
00196 
00197     return o.str();
00198 }
00199 
00200 void WException::disableBacktrace()
00201 {
00202     noBacktrace = true;
00203 }
00204