Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
backtrace.hh
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file utility/backtrace.hh
11 /// @brief Programmatic backtrace whenever you want it.
12 /// @author Rhiju Das
13 
14 
15 #ifndef INCLUDED_utility_backtrace_hh
16 #define INCLUDED_utility_backtrace_hh
17 
18 //////////////////////////////////////////////////////////////////
19 //////////////////////////////////////////////////////////////////
20 // Note to devs -- if your build is failing to compile because
21 // of unrecognized functions backtrace() or backtrace_symbols(),
22 // then just expand the
23 //
24 // #ifdef _WIN32
25 //
26 // to include some tag that goes with your build.
27 //////////////////////////////////////////////////////////////////
28 //////////////////////////////////////////////////////////////////
29 
30 #include <cassert>
31 
32 // Provide workaround for modern compiler feature, if missing
33 #ifdef __has_include
34 #define MY__has_include( x ) __has_include( x )
35 #else
36 #define MY__has_include( x ) 1
37 #endif
38 
39 // C++ headers
40 #if defined(__GNUC__) && !defined(WIN32) && !defined(__CYGWIN__) && MY__has_include( <cxxabi.h> )
41 
42 #include <execinfo.h>
43 #include <cxxabi.h>
44 #include <string>
45 #include <cstdio>
46 #include <stdlib.h>
47 #include <iostream>
48 
49 #include <utility/CSI_Sequence.hh>
50 
51 //////////////////////////////////////////////////////////////////////
52 //
53 // See note above if this is causing your build to not compile.
54 //
55 // from user 'john' in stackoverflow, but adapted to work on a Mac.
56 // and then also re-adapted to work on linux.
57 // -- rhiju, 2014
58 //////////////////////////////////////////////////////////////////////
59 inline
60 std::string
61 demangle( std::string trace ) {
62 
63  std::string::size_type begin, end;
64 
65  // find the beginning and the end of the useful part of the trace
66 
67  // On a Mac, part to be demangled starts with underscore, and then is followed by "+" increment,
68  // separated by spaces from surrounding.
69  begin = trace.find(" _") + 1;
70  end = trace.find(" +",begin);
71 
72  //How it looks for Linux, with parentheses around part to be demangled.
73  // /home/rhiju/src/rosetta/main/source/cmake/build_release/libutility.so(_Z15print_backtracev+0x23) [0x7fb75e08c1a3]
74  if ( begin == std::string::npos || end == std::string::npos ) {
75  begin = trace.find("(_") + 1;
76  end = trace.find("+",begin);
77  }
78 
79  // if begina and end were found, we'll go ahead and demangle
80  if ( begin != std::string::npos && end != std::string::npos ) {
81  std::string mangled_trace = trace.substr(begin, end - begin);
82  size_t maxName = 1024;
83  int demangleStatus;
84 
85  char* demangledName = (char*) malloc(maxName);
86  if ( (demangledName = abi::__cxa_demangle(mangled_trace.c_str(), demangledName, &maxName,
87  &demangleStatus)) && demangleStatus == 0 ) {
88  trace = trace.substr(0,begin) + demangledName + trace.substr(end ); // the demangled name is now in our trace string
89  }
90  free(demangledName);
91  }
92  return trace;
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 //
97 // See note above if this is causing your build to not compile.
98 //
99 // stolen directly from
100 //
101 // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/backtrace.3.html
102 //
103 // see also:
104 //
105 // http://man7.org/linux/man-pages/man3/backtrace.3.html#NOTES
106 //
107 // -- rhiju, 2014.
108 ////////////////////////////////////////////////////////////////////
109 
110 inline
111 bool
112 print_backtrace() {
113 
114  size_t const callstack_size = 128;
115  void* callstack[callstack_size];
116  int i, frames = backtrace(callstack, callstack_size);
117  char** strs = backtrace_symbols(callstack, frames);
118  std::cerr << utility::CSI_Magenta; // set color of cerr to magenta
119  for ( i = 0; i < frames; ++i ) {
120  std::cerr << demangle( strs[i] ).c_str() << std::endl;
121  }
122  std::cerr << utility::CSI_Reset; // reset color of cerr
123  free(strs);
124  return false; // allows use in debug_assert
125 }
126 
127 #define debug_assert(condition) {assert( ( condition ) || print_backtrace() ); }
128 
129 #else
130 // _WIN32, etc.
131 #include <assert.h>
132 
133 inline
134 void
136  // no op
137  // if someone cares, should be possible to code up a backtrace for Windows!
138 }
139 
140 #define debug_assert(condition) {assert( condition ); }
141 
142 #endif
143 
144 #endif // INCLUDED_utility_backtrace_HH
ocstream cerr(std::cerr)
Wrapper around std::cerr.
Definition: ocstream.hh:290
void print_backtrace()
Definition: backtrace.hh:135
utility::keys::lookup::end< KeyType > const end
Terminal ASCII codes.
static THREAD_LOCAL basic::Tracer trace("fragment_picker")
static CSI_Sequence const CSI_Reset("\x1b[0m")
utility::keys::lookup::begin< KeyType > const begin
static CSI_Sequence const CSI_Magenta("\x1b[35m")