OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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__ ) )
26 // This is highly platform dependent. Used for backtrace functionality.
27 #include <execinfo.h>
28 #include <cxxabi.h>
29 #endif
30 
31 #include <iostream>
32 #include <list>
33 #include <sstream>
34 #include <stdexcept>
35 #include <string>
36 
37 #include <boost/algorithm/string.hpp>
38 
39 #include "WException.h"
40 
41 /**
42  * initialize static member.
43  */
44 bool WException::noBacktrace = false;
45 
46 WException::WException( const std::string& msg ):
47  exception(),
48  m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
49  m_functionColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGBlue ) ),
50  m_symbolColor( WTerminalColor() ),
51  m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
52 {
53  // initialize members
54  m_msg = msg;
55 
56  // print stacktrace and message
57  // no backtrace?
58  if( !noBacktrace )
59  {
60  std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
61  }
62 }
63 
64 WException::WException( const std::exception& e ):
65  exception( e ),
66  m_labelColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGRed ) ),
67  m_functionColor( WTerminalColor( WTerminalColor::Off, WTerminalColor::FGBlue ) ),
68  m_symbolColor( WTerminalColor() ),
69  m_headlineColor( WTerminalColor( WTerminalColor::Bold, WTerminalColor::FGYellow ) )
70 {
71  m_msg = e.what();
72 
73  // print stacktrace and message
74  // no backtrace?
75  if( !noBacktrace )
76  {
77  std::cerr << m_headlineColor( std::string( "Exception thrown! Callstack's backtrace:" ) ) << std::endl << getBacktrace() << std::endl;
78  }
79 }
80 
82 {
83  // cleanup
84 }
85 
86 const char* WException::what() const throw()
87 {
88  // return it
89  return m_msg.c_str();
90 }
91 
92 std::string WException::getTrace() const
93 {
94  std::string result( what() );
95  result += "\n\n";
96  std::list< std::string >::const_iterator citer;
97  for( citer = m_trace.begin(); citer != m_trace.end(); ++citer )
98  result += "trace: " + *citer + "\n";
99  boost::trim( result );
100  return result;
101 }
102 
103 std::string WException::getBacktrace() const
104 {
105  // print trace here
106  std::ostringstream o;
107 
108 #if ( defined( __linux__ ) && defined( __GNUC__ ) )
109  // This is highly platform dependent. It MIGHT also work on BSD and other unix.
110 
111  // Automatic callstack backtrace
112  const size_t maxDepth = 100;
113  size_t stackDepth;
114  void* stackAddrs[maxDepth];
115  char** stackSymbols;
116 
117  // acquire stacktrace
118  stackDepth = backtrace( stackAddrs, maxDepth );
119  stackSymbols = backtrace_symbols( stackAddrs, stackDepth );
120 
121  // for each stack element -> demangle and print
122  for( size_t i = 1; i < stackDepth; ++i )
123  {
124  // need some space for function name
125  // just a guess, especially template names might be even longer
126  size_t functionLength = 512;
127  char* function = new char[functionLength];
128 
129  // find mangled function name in stackSymbols[i]
130  char* begin = 0;
131  char* end = 0;
132 
133  // find the parentheses and address offset surrounding the mangled name
134  for( char* j = stackSymbols[i]; *j; ++j )
135  {
136  if( *j == '(' )
137  {
138  begin = j;
139  }
140  else if( *j == '+' )
141  {
142  end = j;
143  }
144  }
145 
146  // found?
147  if( begin && end )
148  {
149  *begin++ = '(';
150  *end = '\0'; // temporarily end string there (since \0 is string delimiter)
151 
152  // found our mangled name, now in [begin, end)
153  int status;
154  char* ret = abi::__cxa_demangle( begin, function, &functionLength, &status );
155 
156  if( ret )
157  {
158  // return value may be a realloc() of the input
159  function = ret;
160  }
161  else
162  {
163  // demangling failed, just pretend it's a C function with no args
164  std::strncpy( function, begin, functionLength );
165  std::strncat( function, "()", functionLength );
166  function[functionLength-1] = '\0';
167  }
168  *end = '+';
169  o << m_labelColor( std::string( "trace: " ) )
170  << m_functionColor( function )
171  << "\t->\t"
172  << m_symbolColor( stackSymbols[i] ) << std::endl;
173  }
174  else
175  {
176  // didn't find the mangled name, just print the whole line
177  o << m_labelColor( std::string( "trace: " ) )
178  << m_functionColor( std::string( "??? " ) )
179  << "\t->\t"
180  << m_symbolColor( stackSymbols[i] ) << std::endl;
181  }
182 
183  delete[] function;
184  }
185 
186  // backtrace_symbols malloc()ed some mem -> we NEED to use free()
187  free( stackSymbols );
188 #else
189  o << "Backtrace not supported on your platform. Currently just works on Linux with GCC. Sorry!";
190 #endif
191 
192  return o.str();
193 }
194 
196 {
197  noBacktrace = true;
198 }
199