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__ ) )
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 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends