backtrace.cpp
Go to the documentation of this file.
1 //
2 // backtrace.cpp
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
29 
30 #include <cstring>
31 #include <iterator>
32 #include <sstream>
33 
34 #include <madness/madness_config.h>
35 #ifdef MADNESS_HAS_LIBUNWIND
36 #define UNW_LOCAL_ONLY
37 #include <libunwind.h>
38 #else
39 #if __has_include(<execinfo.h>)
40 #define HAVE_BACKTRACE
41 #include <execinfo.h>
42 #endif
43 #endif
44 
45 #if __has_include(<cxxabi.h>)
46 #include <cxxabi.h>
47 #define HAVE_CXA_DEMANGLE
48 #endif
49 
50 namespace TiledArray {
51 namespace detail {
52 Backtrace::Backtrace(const std::string &prefix) : prefix_(prefix) {
53 #ifdef MADNESS_HAS_LIBUNWIND
54  {
55  unw_cursor_t cursor;
56  unw_context_t uc;
57  unw_word_t ip, sp, offp;
58  int frame = 0;
59 
60  unw_getcontext(&uc);
61  unw_init_local(&cursor, &uc);
62  while (unw_step(&cursor) > 0) {
63  unw_get_reg(&cursor, UNW_REG_IP, &ip);
64  unw_get_reg(&cursor, UNW_REG_SP, &sp);
65  char name[32768];
66  unw_get_proc_name(&cursor, name, 32768, &offp);
67  std::ostringstream oss;
68  oss << prefix_ << "frame " << frame << ": "
69  << "ip = 0x" << (long)ip << " sp = 0x" << (long)sp
70  << " symbol = " << __demangle(name);
71  frames_.push_back(oss.str());
72  ++frame;
73  }
74  }
75 #elif defined(HAVE_BACKTRACE) // !MADNESS_HAS_LIBUNWIND
76  void *stack_addrs[1024];
77  const int naddrs = backtrace(stack_addrs, 1024);
78  char **frame_symbols = backtrace_symbols(stack_addrs, naddrs);
79  // starting @ 1 to skip this function
80  for (int i = 1; i < naddrs; ++i) {
81  // extract (mangled) function name
82  // parsing frame_symbols[i] is OS-specific
83  // for unknown OS ... just return the whole string
84  std::string mangled_function_name = frame_symbols[i];
85 #if defined(__APPLE__)
86  {
87  // "frame_id /path/to/exec address symbol"
88  std::istringstream iss(std::string(frame_symbols[i]),
89  std::istringstream::in);
90  std::string frame, file, address;
91  iss >> frame >> file >> address >> mangled_function_name;
92  }
93 #elif defined(__linux__)
94  {
95  // "/path/to/exec(symbol+0x...) [address]"
96  // parse from the back to avoid dealing with parentheses in the path
97  const auto last_right_bracket = mangled_function_name.rfind(']');
98  const auto last_left_bracket =
99  mangled_function_name.rfind('[', last_right_bracket);
100  const auto last_right_parens =
101  mangled_function_name.rfind(')', last_left_bracket);
102  const auto offset = mangled_function_name.rfind("+0x", last_right_parens);
103  const auto last_left_parens =
104  mangled_function_name.rfind('(', last_right_parens);
105  if (last_left_parens + 1 < mangled_function_name.size()) {
106  mangled_function_name = mangled_function_name.substr(
107  last_left_parens + 1, offset - last_left_parens - 1);
108  }
109  }
110 #endif
111 
112  std::ostringstream oss;
113  oss << prefix_ << "frame " << i << ": return address = " << stack_addrs[i]
114  << std::endl
115  << " symbol = " << __demangle(mangled_function_name);
116  frames_.push_back(oss.str());
117  }
118  free(frame_symbols);
119 #else // !MADNESS_HAS_LIBUNWIND && !HAVE_BACKTRACE
120 #if defined(SIMPLE_STACK)
121  int bottom = 0x1234;
122  void **topstack = (void **)0xffffffffL;
123  void **botstack = (void **)0x70000000L;
124  // signal handlers can put weird things in the return address slot,
125  // so it is usually best to keep toptext large.
126  void **toptext = (void **)0xffffffffL;
127  void **bottext = (void **)0x00010000L;
128 #endif // SIMPLE_STACK
129 
130 #if (defined(linux) && defined(i386))
131  topstack = (void **)0xc0000000;
132  botstack = (void **)0xb0000000;
133 #endif
134 #if (defined(__OSF1__) && defined(i860))
135  topstack = (void **)0x80000000;
136  botstack = (void **)0x70000000;
137 #endif
138 
139 #if defined(SIMPLE_STACK)
140  // This will go through the stack assuming a simple linked list
141  // of pointers to the previous frame followed by the return address.
142  // It trys to be careful and avoid creating new exceptions, but there
143  // are no guarantees.
144  void **stack = (void **)&bottom;
145 
146  void **frame_pointer = (void **)stack[3];
147  while (frame_pointer >= botstack && frame_pointer < topstack &&
148  frame_pointer[1] >= bottext && frame_pointer[1] < toptext) {
149  std::ostringstream oss;
150  oss << prefix_ << "frame: " << (void *)frame_pointer;
151  oss << " retaddr: " << frame_pointer[1];
152  frames_.push_back(oss.str());
153 
154  frame_pointer = (void **)*frame_pointer;
155  }
156 #endif // SIMPLE_STACK
157 #endif // HAVE_BACKTRACE
158 }
159 
161  : frames_(other.frames_), prefix_(other.prefix_) {}
162 
163 std::string Backtrace::str(size_t nframes_to_skip) const {
164  std::ostringstream oss;
165  std::copy(frames_.begin() + nframes_to_skip, frames_.end(),
166  std::ostream_iterator<std::string>(oss, "\n"));
167  return oss.str();
168 }
169 
170 std::string Backtrace::__demangle(const std::string &symbol) {
171  std::string dsymbol;
172 #ifdef HAVE_CXA_DEMANGLE
173  {
174  int status;
175  char *dsymbol_char = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
176  if (status == 0) { // success
177  dsymbol = dsymbol_char;
178  free(dsymbol_char);
179  } else // fail
180  dsymbol = symbol;
181  }
182 #else
183  dsymbol = symbol;
184 #endif
185  return dsymbol;
186 }
187 
188 } // namespace detail
189 } // namespace TiledArray
std::string str(const size_t nframes_to_skip=0) const
Definition: backtrace.cpp:163
Backtrace(const std::string &prefix=std::string(""))
Definition: backtrace.cpp:52