OpenWalnut  1.5.0dev
WException.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #if( ( defined( __linux__ ) && defined( __GNUC__ ) ) && !defined( __ANDROID__ ) || defined( __APPLE__ ) )
26  #define BACKTRACE_SUPPORTED
27 #endif
28 
29 #ifdef BACKTRACE_SUPPORTED
30 // This is highly platform dependent. Used for backtrace functionality.
31 #include <execinfo.h>
32 #include <cxxabi.h>
33 #endif
34 
35 #include <iostream>
36 #include <list>
37 #include <sstream>
38 #include <stdexcept>
39 #include <string>
40 
41 #include <boost/algorithm/string.hpp>
42 
43 #include "WException.h"
44 
45 /**
46  * initialize static member.
47  */
48 bool WException::noBacktrace = false;
49 
50 WException::WException( const std::string& msg ):
51  exception(),
52  m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
53  m_functionColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGBlue ) ),
54  m_symbolColor( WTerminalColor() ),
55  m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
56 {
57  // initialize members
58  m_msg = msg;
59 
60  // print stacktrace and message
61  // no backtrace?
62  if( !noBacktrace )
63  {
64  std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
65  }
66 }
67 
68 WException::WException( const std::exception& e ):
69  exception( e ),
70  m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
71  m_functionColor( WTerminalColor( WTerminalColor::Off, WTerminalColor::FGBlue ) ),
72  m_symbolColor( WTerminalColor() ),
73  m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
74 {
75  m_msg = e.what();
76 
77  // print stacktrace and message
78  // no backtrace?
79  if( !noBacktrace )
80  {
81  std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
82  }
83 }
84 
86 {
87  // cleanup
88 }
89 
90 const char* WException::what() const throw()
91 {
92  // return it
93  return m_msg.c_str();
94 }
95 
96 std::string WException::getTrace() const
97 {
98  std::string result( what() );
99  result += "\n\n";
100  std::list< std::string >::const_iterator citer;
101  for( citer = m_trace.begin(); citer != m_trace.end(); ++citer )
102  result += "trace: " + *citer + "\n";
103  boost::trim( result );
104  return result;
105 }
106 
107 std::string WException::getBacktrace() const
108 {
109  // print trace here
110  std::ostringstream o;
111 
112 #ifdef BACKTRACE_SUPPORTED
113  // This is highly platform dependent. It MIGHT also work on BSD and other unix.
114 
115  // Automatic callstack backtrace
116  const size_t maxDepth = 100;
117  size_t stackDepth;
118  void* stackAddrs[maxDepth];
119  char** stackSymbols;
120 
121  // acquire stacktrace
122  stackDepth = backtrace( stackAddrs, maxDepth );
123  stackSymbols = backtrace_symbols( stackAddrs, stackDepth );
124 
125  // for each stack element -> demangle and print
126  for( size_t i = 1; i < stackDepth; ++i )
127  {
128  // need some space for function name
129  // just a guess, especially template names might be even longer
130  size_t functionLength = 512;
131  char* function = new char[functionLength];
132 
133  // find mangled function name in stackSymbols[i]
134  char* begin = 0;
135  char* end = 0;
136 
137  // find the parentheses and address offset surrounding the mangled name
138  for( char* j = stackSymbols[i]; *j; ++j )
139  {
140  if( *j == '(' )
141  {
142  begin = j;
143  }
144  else if( *j == '+' )
145  {
146  end = j;
147  }
148  }
149 
150  // found?
151  if( begin && end )
152  {
153  *begin++ = '(';
154  *end = '\0'; // temporarily end string there (since \0 is string delimiter)
155 
156  // found our mangled name, now in [begin, end)
157  int status;
158  char* ret = abi::__cxa_demangle( begin, function, &functionLength, &status );
159 
160  if( ret )
161  {
162  // return value may be a realloc() of the input
163  function = ret;
164  }
165  else
166  {
167  // demangling failed, just pretend it's a C function with no args
168  std::strncpy( function, begin, functionLength );
169  std::strncat( function, "()", functionLength );
170  function[functionLength-1] = '\0';
171  }
172  *end = '+';
173  o << m_labelColor( std::string( "trace: " ) )
174  << m_functionColor( function )
175  << "\t->\t"
176  << m_symbolColor( stackSymbols[i] ) << std::endl;
177  }
178  else
179  {
180  // didn't find the mangled name, just print the whole line
181  o << m_labelColor( std::string( "trace: " ) )
182  << m_functionColor( std::string( "??? " ) )
183  << "\t->\t"
184  << m_symbolColor( stackSymbols[i] ) << std::endl;
185  }
186 
187  delete[] function;
188  }
189 
190  // backtrace_symbols malloc()ed some mem -> we NEED to use free()
191  free( stackSymbols );
192 #else
193  o << "Backtrace not supported on your platform. Currently just works on Linux and MacOS with GCC. Sorry!" << std::endl
194  << "Message was: " << what();
195 #endif
196 
197  return o.str();
198 }
199 
201 {
202  noBacktrace = true;
203 }
204 
static bool noBacktrace
True if the backtrace should NOT be printed.
Definition: WException.h:104
WTerminalColor m_headlineColor
Color used for exception headline.
Definition: WException.h:124
std::list< std::string > m_trace
Stack trace for identifying the source where this exception came from.
Definition: WException.h:99
static void disableBacktrace()
Function disables backtraces.
Definition: WException.cpp:200
WException(const std::string &msg=std::string())
Default constructor.
Definition: WException.cpp:50
std::string m_msg
Message given during throw.
Definition: WException.h:93
std::string getBacktrace() const
Returns a call stacktrace.
Definition: WException.cpp:107
WTerminalColor m_functionColor
Color used for function name.
Definition: WException.h:114
virtual ~WException()
Destructor.
Definition: WException.cpp:85
virtual const char * what() const
Returns the message string set on throw.
Definition: WException.cpp:90
WTerminalColor m_symbolColor
Color used for symbols.
Definition: WException.h:119
WTerminalColor m_labelColor
Color used for the "trace:" label.
Definition: WException.h:109
std::string getTrace() const
Prints the trace of the call chain which caused this exception.
Definition: WException.cpp:96
Helper class to provide a convenient way to colorize output on the console.