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 
28 #include "backtrace.h"
29 
30 #include <cstring>
31 #include <iterator>
32 #include <sstream>
33 
34 #if defined(TTG_HAS_LIBUNWIND)
35 #define UNW_LOCAL_ONLY
36 #include <libunwind.h>
37 #else
38 #if __has_include(<execinfo.h>)
39 #define TTG_HAS_BACKTRACE
40 #include <execinfo.h>
41 #endif
42 #endif
43 
44 #if __has_include(<cxxabi.h>)
45 #include <cxxabi.h>
46 #define TTG_HAS_CXA_DEMANGLE
47 #endif
48 
49 namespace ttg {
50  namespace detail {
51  Backtrace::Backtrace(const std::string &prefix) : prefix_(prefix) {
52 #ifdef TTG_HAS_LIBUNWIND
53  {
54  unw_cursor_t cursor;
55  unw_context_t uc;
56  unw_word_t ip, sp, offp;
57  int frame = 0;
58 
59  unw_getcontext(&uc);
60  unw_init_local(&cursor, &uc);
61  while (unw_step(&cursor) > 0) {
62  unw_get_reg(&cursor, UNW_REG_IP, &ip);
63  unw_get_reg(&cursor, UNW_REG_SP, &sp);
64  char name[32768];
65  unw_get_proc_name(&cursor, name, 32768, &offp);
66  std::ostringstream oss;
67  oss << prefix_ << "frame " << frame << ": "
68  << "ip = 0x" << (long)ip << " sp = 0x" << (long)sp << " symbol = " << __demangle(name);
69  frames_.push_back(oss.str());
70  ++frame;
71  }
72  }
73 #elif defined(TTG_HAS_BACKTRACE) // !TTG_HAS_LIBUNWIND
74  void *stack_addrs[1024];
75  const int naddrs = backtrace(stack_addrs, 1024);
76  char **frame_symbols = backtrace_symbols(stack_addrs, naddrs);
77  // starting @ 1 to skip this function
78  for (int i = 1; i < naddrs; ++i) {
79  // extract (mangled) function name
80  // parsing frame_symbols[i] is OS-specific
81  // for unknown OS ... just return the whole string
82  std::string mangled_function_name = frame_symbols[i];
83 #if defined(__APPLE__)
84  {
85  // "frame_id /path/to/exec address symbol"
86  std::istringstream iss(std::string(frame_symbols[i]), std::istringstream::in);
87  std::string frame, file, address;
88  iss >> frame >> file >> address >> mangled_function_name;
89  }
90 #elif defined(__linux__)
91  {
92  // "/path/to/exec(symbol+0x...) [address]"
93  // parse from the back to avoid dealing with parentheses in the path
94  const auto last_right_bracket = mangled_function_name.rfind(']');
95  const auto last_left_bracket = mangled_function_name.rfind('[', last_right_bracket);
96  const auto last_right_parens = mangled_function_name.rfind(')', last_left_bracket);
97  const auto offset = mangled_function_name.rfind("+0x", last_right_parens);
98  const auto last_left_parens = mangled_function_name.rfind('(', last_right_parens);
99  if (last_left_parens + 1 < mangled_function_name.size()) {
100  mangled_function_name = mangled_function_name.substr(last_left_parens + 1, offset - last_left_parens - 1);
101  }
102  }
103 #endif
104 
105  std::ostringstream oss;
106  oss << prefix_ << "frame " << i << ": return address = " << stack_addrs[i] << std::endl
107  << " symbol = " << __demangle(mangled_function_name);
108  frames_.push_back(oss.str());
109  }
110  free(frame_symbols);
111 #else // !TTG_HAS_LIBUNWIND && !TTG_HAS_BACKTRACE
112 #if defined(SIMPLE_STACK)
113  int bottom = 0x1234;
114  void **topstack = (void **)0xffffffffL;
115  void **botstack = (void **)0x70000000L;
116  // signal handlers can put weird things in the return address slot,
117  // so it is usually best to keep toptext large.
118  void **toptext = (void **)0xffffffffL;
119  void **bottext = (void **)0x00010000L;
120 #endif // SIMPLE_STACK
121 
122 #if (defined(linux) && defined(i386))
123  topstack = (void **)0xc0000000;
124  botstack = (void **)0xb0000000;
125 #endif
126 #if (defined(__OSF1__) && defined(i860))
127  topstack = (void **)0x80000000;
128  botstack = (void **)0x70000000;
129 #endif
130 
131 #if defined(SIMPLE_STACK)
132  // This will go through the stack assuming a simple linked list
133  // of pointers to the previous frame followed by the return address.
134  // It trys to be careful and avoid creating new exceptions, but there
135  // are no guarantees.
136  void **stack = (void **)&bottom;
137 
138  void **frame_pointer = (void **)stack[3];
139  while (frame_pointer >= botstack && frame_pointer < topstack && frame_pointer[1] >= bottext &&
140  frame_pointer[1] < toptext) {
141  std::ostringstream oss;
142  oss << prefix_ << "frame: " << (void *)frame_pointer;
143  oss << " retaddr: " << frame_pointer[1];
144  frames_.push_back(oss.str());
145 
146  frame_pointer = (void **)*frame_pointer;
147  }
148 #endif // SIMPLE_STACK
149 #endif // TTG_HAS_BACKTRACE
150  }
151 
152  Backtrace::Backtrace(const Backtrace &other) : frames_(other.frames_), prefix_(other.prefix_) {}
153 
154  std::string Backtrace::str(size_t nframes_to_skip) const {
155  std::ostringstream oss;
156  std::copy(frames_.begin() + nframes_to_skip, frames_.end(), std::ostream_iterator<std::string>(oss, "\n"));
157  return oss.str();
158  }
159 
160  std::string Backtrace::__demangle(const std::string &symbol) {
161  std::string dsymbol;
162 #ifdef TTG_HAS_CXA_DEMANGLE
163  {
164  int status;
165  char *dsymbol_char = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
166  if (status == 0) { // success
167  dsymbol = dsymbol_char;
168  free(dsymbol_char);
169  } else // fail
170  dsymbol = symbol;
171  }
172 #else
173  dsymbol = symbol;
174 #endif
175  return dsymbol;
176  }
177 
178  } // namespace detail
179 } // namespace ttg
std::string str(const size_t nframes_to_skip=0) const
Definition: backtrace.cpp:154
Backtrace(const std::string &prefix=std::string(""))
Definition: backtrace.cpp:51
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8