backward.hpp
Go to the documentation of this file.
1 /*
2  * backward.hpp
3  * Copyright 2013 Google Inc. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #ifndef H_6B9572DA_A64B_49E6_B234_051480991C89
25 #define H_6B9572DA_A64B_49E6_B234_051480991C89
26 
27 #ifndef __cplusplus
28 # error "It's not going to compile without a C++ compiler..."
29 #endif
30 
31 #if defined(BACKWARD_CXX11)
32 #elif defined(BACKWARD_CXX98)
33 #else
34 # if __cplusplus >= 201103L
35 # define BACKWARD_CXX11
36 # define BACKWARD_ATLEAST_CXX11
37 # define BACKWARD_ATLEAST_CXX98
38 # else
39 # define BACKWARD_CXX98
40 # define BACKWARD_ATLEAST_CXX98
41 # endif
42 #endif
43 
44 // You can define one of the following (or leave it to the auto-detection):
45 //
46 // #define BACKWARD_SYSTEM_LINUX
47 // - specialization for linux
48 //
49 // #define BACKWARD_SYSTEM_UNKNOWN
50 // - placebo implementation, does nothing.
51 //
52 #if defined(BACKWARD_SYSTEM_LINUX)
53 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
54 #else
55 # if defined(__linux)
56 # define BACKWARD_SYSTEM_LINUX
57 # else
58 # define BACKWARD_SYSTEM_UNKNOWN
59 # endif
60 #endif
61 
62 #include <fstream>
63 #include <iostream>
64 #include <algorithm>
65 #include <cstdlib>
66 #include <cstdio>
67 #include <cstring>
68 #include <cctype>
69 #include <string>
70 #include <new>
71 #include <iomanip>
72 #include <vector>
73 
74 #if defined(BACKWARD_SYSTEM_LINUX)
75 
76 // On linux, backtrace can back-trace or "walk" the stack using the following
77 // libraries:
78 //
79 // #define BACKWARD_HAS_UNWIND 1
80 // - unwind comes from libgcc, but I saw an equivalent inside clang itself.
81 // - with unwind, the stacktrace is as accurate as it can possibly be, since
82 // this is used by the C++ runtine in gcc/clang for stack unwinding on
83 // exception.
84 // - normally libgcc is already linked to your program by default.
85 //
86 // #define BACKWARD_HAS_BACKTRACE == 1
87 // - backtrace seems to be a little bit more portable than libunwind, but on
88 // linux, it uses unwind anyway, but abstract away a tiny information that is
89 // sadly really important in order to get perfectly accurate stack traces.
90 // - backtrace is part of the (e)glib library.
91 //
92 // The default is:
93 // #define BACKWARD_HAS_UNWIND == 1
94 //
95 // Note that only one of the define should be set to 1 at a time.
96 //
97 # if BACKWARD_HAS_UNWIND == 1
98 # elif BACKWARD_HAS_BACKTRACE == 1
99 # else
100 # undef BACKWARD_HAS_UNWIND
101 # define BACKWARD_HAS_UNWIND 1
102 # undef BACKWARD_HAS_BACKTRACE
103 # define BACKWARD_HAS_BACKTRACE 0
104 # endif
105 
106 // On linux, backward can extract detailed information about a stack trace
107 // using one of the following libraries:
108 //
109 // #define BACKWARD_HAS_DW 1
110 // - libdw gives you the most juicy details out of your stack traces:
111 // - object filename
112 // - function name
113 // - source filename
114 // - line and column numbers
115 // - source code snippet (assuming the file is accessible)
116 // - variables name and values (if not optimized out)
117 // - You need to link with the lib "dw":
118 // - apt-get install libdw-dev
119 // - g++/clang++ -ldw ...
120 //
121 // #define BACKWARD_HAS_BFD 1
122 // - With libbfd, you get a fair amount of details:
123 // - object filename
124 // - function name
125 // - source filename
126 // - line numbers
127 // - source code snippet (assuming the file is accessible)
128 // - You need to link with the lib "bfd":
129 // - apt-get install binutils-dev
130 // - g++/clang++ -lbfd ...
131 //
132 // #define BACKWARD_HAS_BACKTRACE_SYMBOL 1
133 // - backtrace provides minimal details for a stack trace:
134 // - object filename
135 // - function name
136 // - backtrace is part of the (e)glib library.
137 //
138 // The default is:
139 // #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1
140 //
141 // Note that only one of the define should be set to 1 at a time.
142 //
143 # if BACKWARD_HAS_DW == 1
144 # elif BACKWARD_HAS_BFD == 1
145 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
146 # else
147 # undef BACKWARD_HAS_DW
148 # define BACKWARD_HAS_DW 0
149 # undef BACKWARD_HAS_BFD
150 # define BACKWARD_HAS_BFD 0
151 # undef BACKWARD_HAS_BACKTRACE_SYMBOL
152 # define BACKWARD_HAS_BACKTRACE_SYMBOL 1
153 # endif
154 
155 
156 # if BACKWARD_HAS_UNWIND == 1
157 
158 # include <unwind.h>
159 // while gcc's unwind.h defines something like that:
160 // extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
161 // extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
162 //
163 // clang's unwind.h defines something like this:
164 // uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
165 //
166 // Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we
167 // cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr
168 // anyway.
169 //
170 // Luckily we can play on the fact that the guard macros have a different name:
171 #ifdef __CLANG_UNWIND_H
172 // In fact, this function still comes from libgcc (on my different linux boxes,
173 // clang links against libgcc).
174 # include <inttypes.h>
175 extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*);
176 #endif
177 
178 # endif
179 
180 # include <cxxabi.h>
181 # include <fcntl.h>
182 # include <link.h>
183 # include <sys/stat.h>
184 # include <syscall.h>
185 # include <unistd.h>
186 # include <signal.h>
187 
188 # if BACKWARD_HAS_BFD == 1
189 // NOTE: defining PACKAGE{,_VERSION} is required before including
190 // bfd.h on some platforms, see also:
191 // https://sourceware.org/bugzilla/show_bug.cgi?id=14243
192 # ifndef PACKAGE
193 # define PACKAGE
194 # endif
195 # ifndef PACKAGE_VERSION
196 # define PACKAGE_VERSION
197 # endif
198 # include <bfd.h>
199 # ifndef _GNU_SOURCE
200 # define _GNU_SOURCE
201 # include <dlfcn.h>
202 # undef _GNU_SOURCE
203 # else
204 # include <dlfcn.h>
205 # endif
206 # endif
207 
208 # if BACKWARD_HAS_DW == 1
209 # include <elfutils/libdw.h>
210 # include <elfutils/libdwfl.h>
211 # include <dwarf.h>
212 # endif
213 
214 # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
215  // then we shall rely on backtrace
216 # include <execinfo.h>
217 # endif
218 
219 #endif // defined(BACKWARD_SYSTEM_LINUX)
220 
221 #ifdef BACKWARD_ATLEAST_CXX11
222 # include <unordered_map>
223 # include <utility> // for std::swap
224  namespace backward {
225  namespace details {
226  template <typename K, typename V>
227  struct hashtable {
228  typedef std::unordered_map<K, V> type;
229  };
230  using std::move;
231  } // namespace details
232  } // namespace backward
233 #else // NOT BACKWARD_ATLEAST_CXX11
234 # include <map>
235  namespace backward {
236  namespace details {
237  template <typename K, typename V>
238  struct hashtable {
239  typedef std::map<K, V> type;
240  };
241  template <typename T>
242  const T& move(const T& v) { return v; }
243  template <typename T>
244  T& move(T& v) { return v; }
245  } // namespace details
246  } // namespace backward
247 #endif // BACKWARD_ATLEAST_CXX11
248 
249 namespace backward {
250 
251 namespace system_tag {
252  struct linux_tag; // seems that I cannot call that "linux" because the name
253  // is already defined... so I am adding _tag everywhere.
254  struct unknown_tag;
255 
256 #if defined(BACKWARD_SYSTEM_LINUX)
257  typedef linux_tag current_tag;
258 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
259  typedef unknown_tag current_tag;
260 #else
261 # error "May I please get my system defines?"
262 #endif
263 } // namespace system_tag
264 
265 
266 namespace trace_resolver_tag {
267 #ifdef BACKWARD_SYSTEM_LINUX
268  struct libdw;
269  struct libbfd;
270  struct backtrace_symbol;
271 
272 # if BACKWARD_HAS_DW == 1
273  typedef libdw current;
274 # elif BACKWARD_HAS_BFD == 1
275  typedef libbfd current;
276 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
277  typedef backtrace_symbol current;
278 # else
279 # error "You shall not pass, until you know what you want."
280 # endif
281 #endif // BACKWARD_SYSTEM_LINUX
282 } // namespace trace_resolver_tag
283 
284 
285 namespace details {
286 
287 template <typename T>
288  struct rm_ptr { typedef T type; };
289 
290 template <typename T>
291  struct rm_ptr<T*> { typedef T type; };
292 
293 template <typename T>
294  struct rm_ptr<const T*> { typedef const T type; };
295 
296 template <typename R, typename T, R (*F)(T)>
297 struct deleter {
298  template <typename U>
299  void operator()(U& ptr) const {
300  (*F)(ptr);
301  }
302 };
303 
304 template <typename T>
306  void operator()(T& ptr) const {
307  delete ptr;
308  }
309 };
310 
311 template <typename T, typename Deleter = deleter<void, void*, &::free> >
312 class handle {
313  struct dummy;
314  T _val;
315  bool _empty;
316 
317 #ifdef BACKWARD_ATLEAST_CXX11
318  handle(const handle&) = delete;
319  handle& operator=(const handle&) = delete;
320 #endif
321 
322 public:
324  if (!_empty) {
325  Deleter()(_val);
326  }
327  }
328 
329  explicit handle(): _val(), _empty(true) {}
330  explicit handle(T val): _val(val), _empty(false) {}
331 
332 #ifdef BACKWARD_ATLEAST_CXX11
333  handle(handle&& from): _empty(true) {
334  swap(from);
335  }
336  handle& operator=(handle&& from) {
337  swap(from); return *this;
338  }
339 #else
340  explicit handle(const handle& from): _empty(true) {
341  // some sort of poor man's move semantic.
342  swap(const_cast<handle&>(from));
343  }
344  handle& operator=(const handle& from) {
345  // some sort of poor man's move semantic.
346  swap(const_cast<handle&>(from)); return *this;
347  }
348 #endif
349 
350  void reset(T new_val) {
351  handle tmp(new_val);
352  swap(tmp);
353  }
354  operator const dummy*() const {
355  if (_empty) {
356  return 0;
357  }
358  return reinterpret_cast<const dummy*>(_val);
359  }
360  T get() {
361  return _val;
362  }
363  T release() {
364  _empty = true;
365  return _val;
366  }
367  void swap(handle& b) {
368  using std::swap;
369  swap(b._val, _val); // can throw, we are safe here.
370  swap(b._empty, _empty); // should not throw: if you cannot swap two
371  // bools without throwing... It's a lost cause anyway!
372  }
373 
374  T operator->() { return _val; }
375  const T operator->() const { return _val; }
376 
377  typedef typename rm_ptr<T>::type& ref_t;
378  typedef const typename rm_ptr<T>::type& const_ref_t;
379  ref_t operator*() { return *_val; }
380  const_ref_t operator*() const { return *_val; }
381  ref_t operator[](size_t idx) { return _val[idx]; }
382 
383  // Watch out, we've got a badass over here
384  T* operator&() {
385  _empty = false;
386  return &_val;
387  }
388 };
389 
390 // Default demangler implementation (do nothing).
391 template <typename TAG>
393  static std::string demangle(const char* funcname) {
394  return funcname;
395  }
396 };
397 
398 #ifdef BACKWARD_SYSTEM_LINUX
399 
400 template <>
401 struct demangler_impl<system_tag::current_tag> {
402  demangler_impl(): _demangle_buffer_length(0) {}
403 
404  std::string demangle(const char* funcname) {
405  using namespace details;
406  _demangle_buffer.reset(
407  abi::__cxa_demangle(funcname, _demangle_buffer.release(),
408  &_demangle_buffer_length, 0)
409  );
410  if (_demangle_buffer) {
411  return _demangle_buffer.get();
412  }
413  return funcname;
414  }
415 
416 private:
417  details::handle<char*> _demangle_buffer;
418  size_t _demangle_buffer_length;
419 };
420 
421 #endif // BACKWARD_SYSTEM_LINUX
422 
423 struct demangler:
424  public demangler_impl<system_tag::current_tag> {};
425 
426 } // namespace details
427 
428 /*************** A TRACE ***************/
429 
430 struct Trace {
431  void* addr;
432  unsigned idx;
433 
434  Trace():
435  addr(0), idx(0) {}
436 
437  explicit Trace(void* addr, size_t idx):
438  addr(addr), idx(idx) {}
439 };
440 
441 struct ResolvedTrace: public Trace {
442 
443  struct SourceLoc {
444  std::string function;
445  std::string filename;
446  unsigned line;
447  unsigned col;
448 
449  SourceLoc(): line(0), col(0) {}
450 
451  bool operator==(const SourceLoc& b) const {
452  return function == b.function
453  && filename == b.filename
454  && line == b.line
455  && col == b.col;
456  }
457 
458  bool operator!=(const SourceLoc& b) const {
459  return !(*this == b);
460  }
461  };
462 
463  // In which binary object this trace is located.
464  std::string object_filename;
465 
466  // The function in the object that contain the trace. This is not the same
467  // as source.function which can be an function inlined in object_function.
468  std::string object_function;
469 
470  // The source location of this trace. It is possible for filename to be
471  // empty and for line/col to be invalid (value 0) if this information
472  // couldn't be deduced, for example if there is no debug information in the
473  // binary object.
475 
476  // An optionals list of "inliners". All the successive sources location
477  // from where the source location of the trace (the attribute right above)
478  // is inlined. It is especially useful when you compiled with optimization.
479  typedef std::vector<SourceLoc> source_locs_t;
480  source_locs_t inliners;
481 
483  Trace() {}
484  ResolvedTrace(const Trace& mini_trace):
485  Trace(mini_trace) {}
486 };
487 
488 /*************** STACK TRACE ***************/
489 
490 // default implemention.
491 template <typename TAG>
493 public:
494  size_t size() const { return 0; }
495  Trace operator[](size_t) { return Trace(); }
496  size_t load_here(size_t=0) { return 0; }
497  size_t load_from(void*, size_t=0) { return 0; }
498  unsigned thread_id() const { return 0; }
499  void skip_n_firsts(size_t) { }
500 };
501 
502 #ifdef BACKWARD_SYSTEM_LINUX
503 
504 class StackTraceLinuxImplBase {
505 public:
506  StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
507 
508  unsigned thread_id() const {
509  return _thread_id;
510  }
511 
512  void skip_n_firsts(size_t n) { _skip = n; }
513 
514 protected:
515  void load_thread_info() {
516  _thread_id = syscall(SYS_gettid);
517  if (_thread_id == (size_t) getpid()) {
518  // If the thread is the main one, let's hide that.
519  // I like to keep little secret sometimes.
520  _thread_id = 0;
521  }
522  }
523 
524  size_t skip_n_firsts() const { return _skip; }
525 
526 private:
527  size_t _thread_id;
528  size_t _skip;
529 };
530 
531 class StackTraceLinuxImplHolder: public StackTraceLinuxImplBase {
532 public:
533  size_t size() const {
534  return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
535  }
536  Trace operator[](size_t idx) {
537  if (idx >= size()) {
538  return Trace();
539  }
540  return Trace(_stacktrace[idx + skip_n_firsts()], idx);
541  }
542  void** begin() {
543  if (size()) {
544  return &_stacktrace[skip_n_firsts()];
545  }
546  return 0;
547  }
548 
549 protected:
550  std::vector<void*> _stacktrace;
551 };
552 
553 
554 #if BACKWARD_HAS_UNWIND == 1
555 
556 namespace details {
557 
558 template <typename F>
559 class Unwinder {
560 public:
561  size_t operator()(F& f, size_t depth) {
562  _f = &f;
563  _index = -1;
564  _depth = depth;
565  _Unwind_Backtrace(&this->backtrace_trampoline, this);
566  return _index;
567  }
568 
569 private:
570  F* _f;
571  ssize_t _index;
572  size_t _depth;
573 
574  static _Unwind_Reason_Code backtrace_trampoline(
575  _Unwind_Context* ctx, void *self) {
576  return ((Unwinder*)self)->backtrace(ctx);
577  }
578 
579  _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
580  if (_index >= 0 && static_cast<size_t>(_index) >= _depth)
581  return _URC_END_OF_STACK;
582 
583  int ip_before_instruction = 0;
584  uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
585 
586  if (!ip_before_instruction) {
587  ip -= 1;
588  }
589 
590  if (_index >= 0) { // ignore first frame.
591  (*_f)(_index, (void*)ip);
592  }
593  _index += 1;
594  return _URC_NO_REASON;
595  }
596 };
597 
598 template <typename F>
599 size_t unwind(F f, size_t depth) {
600  Unwinder<F> unwinder;
601  return unwinder(f, depth);
602 }
603 
604 } // namespace details
605 
606 
607 template <>
608 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
609 public:
610  __attribute__ ((noinline)) // TODO use some macro
611  size_t load_here(size_t depth=32) {
612  load_thread_info();
613  if (depth == 0) {
614  return 0;
615  }
616  _stacktrace.resize(depth);
617  size_t trace_cnt = details::unwind(callback(*this), depth);
618  _stacktrace.resize(trace_cnt);
619  skip_n_firsts(0);
620  return size();
621  }
622  size_t load_from(void* addr, size_t depth=32) {
623  load_here(depth + 8);
624 
625  for (size_t i = 0; i < _stacktrace.size(); ++i) {
626  if (_stacktrace[i] == addr) {
627  skip_n_firsts(i);
628  break;
629  }
630  }
631 
632  _stacktrace.resize(std::min(_stacktrace.size(),
633  skip_n_firsts() + depth));
634  return size();
635  }
636 
637 private:
638  struct callback {
639  StackTraceImpl& self;
640  callback(StackTraceImpl& self): self(self) {}
641 
642  void operator()(size_t idx, void* addr) {
643  self._stacktrace[idx] = addr;
644  }
645  };
646 };
647 
648 
649 #else // BACKWARD_HAS_UNWIND == 0
650 
651 template <>
652 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
653 public:
654  __attribute__ ((noinline)) // TODO use some macro
655  size_t load_here(size_t depth=32) {
656  load_thread_info();
657  if (depth == 0) {
658  return 0;
659  }
660  _stacktrace.resize(depth + 1);
661  size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
662  _stacktrace.resize(trace_cnt);
663  skip_n_firsts(1);
664  return size();
665  }
666 
667  size_t load_from(void* addr, size_t depth=32) {
668  load_here(depth + 8);
669 
670  for (size_t i = 0; i < _stacktrace.size(); ++i) {
671  if (_stacktrace[i] == addr) {
672  skip_n_firsts(i);
673  _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1);
674  break;
675  }
676  }
677 
678  _stacktrace.resize(std::min(_stacktrace.size(),
679  skip_n_firsts() + depth));
680  return size();
681  }
682 };
683 
684 #endif // BACKWARD_HAS_UNWIND
685 #endif // BACKWARD_SYSTEM_LINUX
686 
688  public StackTraceImpl<system_tag::current_tag> {};
689 
690 /*************** TRACE RESOLVER ***************/
691 
692 template <typename TAG>
694 
695 #ifdef BACKWARD_SYSTEM_UNKNOWN
696 
697 template <>
698 class TraceResolverImpl<system_tag::unknown_tag> {
699 public:
700  template <class ST>
701  void load_stacktrace(ST&) {}
703  return t;
704  }
705 };
706 
707 #endif
708 
709 #ifdef BACKWARD_SYSTEM_LINUX
710 
711 class TraceResolverLinuxImplBase {
712 protected:
713  std::string demangle(const char* funcname) {
714  return _demangler.demangle(funcname);
715  }
716 
717 private:
718  details::demangler _demangler;
719 };
720 
721 template <typename STACKTRACE_TAG>
722 class TraceResolverLinuxImpl;
723 
724 #if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
725 
726 template <>
727 class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
728  public TraceResolverLinuxImplBase {
729 public:
730  template <class ST>
731  void load_stacktrace(ST& st) {
732  using namespace details;
733  if (st.size() == 0) {
734  return;
735  }
736  _symbols.reset(
737  backtrace_symbols(st.begin(), st.size())
738  );
739  }
740 
742  char* filename = _symbols[trace.idx];
743  char* funcname = filename;
744  while (*funcname && *funcname != '(') {
745  funcname += 1;
746  }
747  trace.object_filename.assign(filename, funcname++);
748  char* funcname_end = funcname;
749  while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') {
750  funcname_end += 1;
751  }
752  *funcname_end = '\0';
753  trace.object_function = this->demangle(funcname);
754  trace.source.function = trace.object_function; // we cannot do better.
755  return trace;
756  }
757 
758 private:
759  details::handle<char**> _symbols;
760 };
761 
762 #endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
763 
764 #if BACKWARD_HAS_BFD == 1
765 
766 template <>
767 class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
768  public TraceResolverLinuxImplBase {
769 public:
770  TraceResolverLinuxImpl(): _bfd_loaded(false) {}
771 
772  template <class ST>
773  void load_stacktrace(ST&) {}
774 
776  Dl_info symbol_info;
777 
778  // trace.addr is a virtual address in memory pointing to some code.
779  // Let's try to find from which loaded object it comes from.
780  // The loaded object can be yourself btw.
781  if (!dladdr(trace.addr, &symbol_info)) {
782  return trace; // dat broken trace...
783  }
784 
785  // Now we get in symbol_info:
786  // .dli_fname:
787  // pathname of the shared object that contains the address.
788  // .dli_fbase:
789  // where the object is loaded in memory.
790  // .dli_sname:
791  // the name of the nearest symbol to trace.addr, we expect a
792  // function name.
793  // .dli_saddr:
794  // the exact address corresponding to .dli_sname.
795 
796  if (symbol_info.dli_sname) {
797  trace.object_function = demangle(symbol_info.dli_sname);
798  }
799 
800  if (!symbol_info.dli_fname) {
801  return trace;
802  }
803 
804  trace.object_filename = symbol_info.dli_fname;
805  bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
806  if (!fobj.handle) {
807  return trace; // sad, we couldn't load the object :(
808  }
809 
810 
811  find_sym_result* details_selected; // to be filled.
812 
813  // trace.addr is the next instruction to be executed after returning
814  // from the nested stack frame. In C++ this usually relate to the next
815  // statement right after the function call that leaded to a new stack
816  // frame. This is not usually what you want to see when printing out a
817  // stacktrace...
818  find_sym_result details_call_site = find_symbol_details(fobj,
819  trace.addr, symbol_info.dli_fbase);
820  details_selected = &details_call_site;
821 
822 #if BACKWARD_HAS_UNWIND == 0
823  // ...this is why we also try to resolve the symbol that is right
824  // before the return address. If we are lucky enough, we will get the
825  // line of the function that was called. But if the code is optimized,
826  // we might get something absolutely not related since the compiler
827  // can reschedule the return address with inline functions and
828  // tail-call optimisation (among other things that I don't even know
829  // or cannot even dream about with my tiny limited brain).
830  find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
831  (void*) (uintptr_t(trace.addr) - 1),
832  symbol_info.dli_fbase);
833 
834  // In debug mode, we should always get the right thing(TM).
835  if (details_call_site.found && details_adjusted_call_site.found) {
836  // Ok, we assume that details_adjusted_call_site is a better estimation.
837  details_selected = &details_adjusted_call_site;
838  trace.addr = (void*) (uintptr_t(trace.addr) - 1);
839  }
840 
841  if (details_selected == &details_call_site && details_call_site.found) {
842  // we have to re-resolve the symbol in order to reset some
843  // internal state in BFD... so we can call backtrace_inliners
844  // thereafter...
845  details_call_site = find_symbol_details(fobj, trace.addr,
846  symbol_info.dli_fbase);
847  }
848 #endif // BACKWARD_HAS_UNWIND
849 
850  if (details_selected->found) {
851  if (details_selected->filename) {
852  trace.source.filename = details_selected->filename;
853  }
854  trace.source.line = details_selected->line;
855 
856  if (details_selected->funcname) {
857  // this time we get the name of the function where the code is
858  // located, instead of the function were the address is
859  // located. In short, if the code was inlined, we get the
860  // function correspoding to the code. Else we already got in
861  // trace.function.
862  trace.source.function = demangle(details_selected->funcname);
863 
864  if (!symbol_info.dli_sname) {
865  // for the case dladdr failed to find the symbol name of
866  // the function, we might as well try to put something
867  // here.
868  trace.object_function = trace.source.function;
869  }
870  }
871 
872  // Maybe the source of the trace got inlined inside the function
873  // (trace.source.function). Let's see if we can get all the inlined
874  // calls along the way up to the initial call site.
875  trace.inliners = backtrace_inliners(fobj, *details_selected);
876 
877 #if 0
878  if (trace.inliners.size() == 0) {
879  // Maybe the trace was not inlined... or maybe it was and we
880  // are lacking the debug information. Let's try to make the
881  // world better and see if we can get the line number of the
882  // function (trace.source.function) now.
883  //
884  // We will get the location of where the function start (to be
885  // exact: the first instruction that really start the
886  // function), not where the name of the function is defined.
887  // This can be quite far away from the name of the function
888  // btw.
889  //
890  // If the source of the function is the same as the source of
891  // the trace, we cannot say if the trace was really inlined or
892  // not. However, if the filename of the source is different
893  // between the function and the trace... we can declare it as
894  // an inliner. This is not 100% accurate, but better than
895  // nothing.
896 
897  if (symbol_info.dli_saddr) {
898  find_sym_result details = find_symbol_details(fobj,
899  symbol_info.dli_saddr,
900  symbol_info.dli_fbase);
901 
902  if (details.found) {
903  ResolvedTrace::SourceLoc diy_inliner;
904  diy_inliner.line = details.line;
905  if (details.filename) {
906  diy_inliner.filename = details.filename;
907  }
908  if (details.funcname) {
909  diy_inliner.function = demangle(details.funcname);
910  } else {
911  diy_inliner.function = trace.source.function;
912  }
913  if (diy_inliner != trace.source) {
914  trace.inliners.push_back(diy_inliner);
915  }
916  }
917  }
918  }
919 #endif
920  }
921 
922  return trace;
923  }
924 
925 private:
926  bool _bfd_loaded;
927 
928  typedef details::handle<bfd*,
930  > bfd_handle_t;
931 
932  typedef details::handle<asymbol**> bfd_symtab_t;
933 
934 
935  struct bfd_fileobject {
936  bfd_handle_t handle;
937  bfd_vma base_addr;
938  bfd_symtab_t symtab;
939  bfd_symtab_t dynamic_symtab;
940  };
941 
943  fobj_bfd_map_t;
944  fobj_bfd_map_t _fobj_bfd_map;
945 
946  bfd_fileobject& load_object_with_bfd(const std::string& filename_object) {
947  using namespace details;
948 
949  if (!_bfd_loaded) {
950  using namespace details;
951  bfd_init();
952  _bfd_loaded = true;
953  }
954 
955  fobj_bfd_map_t::iterator it =
956  _fobj_bfd_map.find(filename_object);
957  if (it != _fobj_bfd_map.end()) {
958  return it->second;
959  }
960 
961  // this new object is empty for now.
962  bfd_fileobject& r = _fobj_bfd_map[filename_object];
963 
964  // we do the work temporary in this one;
965  bfd_handle_t bfd_handle;
966 
967  int fd = open(filename_object.c_str(), O_RDONLY);
968  bfd_handle.reset(
969  bfd_fdopenr(filename_object.c_str(), "default", fd)
970  );
971  if (!bfd_handle) {
972  close(fd);
973  return r;
974  }
975 
976  if (!bfd_check_format(bfd_handle.get(), bfd_object)) {
977  return r; // not an object? You lose.
978  }
979 
980  if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
981  return r; // that's what happen when you forget to compile in debug.
982  }
983 
984  ssize_t symtab_storage_size =
985  bfd_get_symtab_upper_bound(bfd_handle.get());
986 
987  ssize_t dyn_symtab_storage_size =
988  bfd_get_dynamic_symtab_upper_bound(bfd_handle.get());
989 
990  if (symtab_storage_size <= 0 && dyn_symtab_storage_size <= 0) {
991  return r; // weird, is the file is corrupted?
992  }
993 
994  bfd_symtab_t symtab, dynamic_symtab;
995  ssize_t symcount = 0, dyn_symcount = 0;
996 
997  if (symtab_storage_size > 0) {
998  symtab.reset(
999  (bfd_symbol**) malloc(symtab_storage_size)
1000  );
1001  symcount = bfd_canonicalize_symtab(
1002  bfd_handle.get(), symtab.get()
1003  );
1004  }
1005 
1006  if (dyn_symtab_storage_size > 0) {
1007  dynamic_symtab.reset(
1008  (bfd_symbol**) malloc(dyn_symtab_storage_size)
1009  );
1010  dyn_symcount = bfd_canonicalize_dynamic_symtab(
1011  bfd_handle.get(), dynamic_symtab.get()
1012  );
1013  }
1014 
1015 
1016  if (symcount <= 0 && dyn_symcount <= 0) {
1017  return r; // damned, that's a stripped file that you got there!
1018  }
1019 
1020  r.handle = move(bfd_handle);
1021  r.symtab = move(symtab);
1022  r.dynamic_symtab = move(dynamic_symtab);
1023  return r;
1024  }
1025 
1026  struct find_sym_result {
1027  bool found;
1028  const char* filename;
1029  const char* funcname;
1030  unsigned int line;
1031  };
1032 
1033  struct find_sym_context {
1034  TraceResolverLinuxImpl* self;
1035  bfd_fileobject* fobj;
1036  void* addr;
1037  void* base_addr;
1038  find_sym_result result;
1039  };
1040 
1041  find_sym_result find_symbol_details(bfd_fileobject& fobj, void* addr,
1042  void* base_addr) {
1043  find_sym_context context;
1044  context.self = this;
1045  context.fobj = &fobj;
1046  context.addr = addr;
1047  context.base_addr = base_addr;
1048  context.result.found = false;
1049  bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
1050  (void*)&context);
1051  return context.result;
1052  }
1053 
1054  static void find_in_section_trampoline(bfd*, asection* section,
1055  void* data) {
1056  find_sym_context* context = static_cast<find_sym_context*>(data);
1057  context->self->find_in_section(
1058  reinterpret_cast<bfd_vma>(context->addr),
1059  reinterpret_cast<bfd_vma>(context->base_addr),
1060  *context->fobj,
1061  section, context->result
1062  );
1063  }
1064 
1065  void find_in_section(bfd_vma addr, bfd_vma base_addr,
1066  bfd_fileobject& fobj, asection* section, find_sym_result& result)
1067  {
1068  if (result.found) return;
1069 
1070  if ((bfd_get_section_flags(fobj.handle.get(), section)
1071  & SEC_ALLOC) == 0)
1072  return; // a debug section is never loaded automatically.
1073 
1074  bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
1075  bfd_size_type size = bfd_get_section_size(section);
1076 
1077  // are we in the boundaries of the section?
1078  if (addr < sec_addr || addr >= sec_addr + size) {
1079  addr -= base_addr; // oups, a relocated object, lets try again...
1080  if (addr < sec_addr || addr >= sec_addr + size) {
1081  return;
1082  }
1083  }
1084 
1085  if (!result.found && fobj.symtab) {
1086  result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1087  fobj.symtab.get(), addr - sec_addr, &result.filename,
1088  &result.funcname, &result.line);
1089  }
1090 
1091  if (!result.found && fobj.dynamic_symtab) {
1092  result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1093  fobj.dynamic_symtab.get(), addr - sec_addr,
1094  &result.filename, &result.funcname, &result.line);
1095  }
1096 
1097  }
1098 
1099  ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj,
1100  find_sym_result previous_result) {
1101  // This function can be called ONLY after a SUCCESSFUL call to
1102  // find_symbol_details. The state is global to the bfd_handle.
1104  while (previous_result.found) {
1105  find_sym_result result;
1106  result.found = bfd_find_inliner_info(fobj.handle.get(),
1107  &result.filename, &result.funcname, &result.line);
1108 
1109  if (result.found) /* and not (
1110  cstrings_eq(previous_result.filename, result.filename)
1111  and cstrings_eq(previous_result.funcname, result.funcname)
1112  and result.line == previous_result.line
1113  )) */ {
1114  ResolvedTrace::SourceLoc src_loc;
1115  src_loc.line = result.line;
1116  if (result.filename) {
1117  src_loc.filename = result.filename;
1118  }
1119  if (result.funcname) {
1120  src_loc.function = demangle(result.funcname);
1121  }
1122  results.push_back(src_loc);
1123  }
1124  previous_result = result;
1125  }
1126  return results;
1127  }
1128 
1129  bool cstrings_eq(const char* a, const char* b) {
1130  if (!a || !b) {
1131  return false;
1132  }
1133  return strcmp(a, b) == 0;
1134  }
1135 
1136 };
1137 #endif // BACKWARD_HAS_BFD == 1
1138 
1139 #if BACKWARD_HAS_DW == 1
1140 
1141 template <>
1142 class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
1143  public TraceResolverLinuxImplBase {
1144 public:
1145  TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
1146 
1147  template <class ST>
1148  void load_stacktrace(ST&) {}
1149 
1151  using namespace details;
1152 
1153  Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr;
1154 
1155  if (!_dwfl_handle_initialized) {
1156  // initialize dwfl...
1157  _dwfl_cb.reset(new Dwfl_Callbacks);
1158  _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
1159  _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
1160  _dwfl_cb->debuginfo_path = 0;
1161 
1162  _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
1163  _dwfl_handle_initialized = true;
1164 
1165  if (!_dwfl_handle) {
1166  return trace;
1167  }
1168 
1169  // ...from the current process.
1170  dwfl_report_begin(_dwfl_handle.get());
1171  int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid());
1172  dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
1173  if (r < 0) {
1174  return trace;
1175  }
1176  }
1177 
1178  if (!_dwfl_handle) {
1179  return trace;
1180  }
1181 
1182  // find the module (binary object) that contains the trace's address.
1183  // This is not using any debug information, but the addresses ranges of
1184  // all the currently loaded binary object.
1185  Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
1186  if (mod) {
1187  // now that we found it, lets get the name of it, this will be the
1188  // full path to the running binary or one of the loaded library.
1189  const char* module_name = dwfl_module_info (mod,
1190  0, 0, 0, 0, 0, 0, 0);
1191  if (module_name) {
1192  trace.object_filename = module_name;
1193  }
1194  // We also look after the name of the symbol, equal or before this
1195  // address. This is found by walking the symtab. We should get the
1196  // symbol corresponding to the function (mangled) containing the
1197  // address. If the code corresponding to the address was inlined,
1198  // this is the name of the out-most inliner function.
1199  const char* sym_name = dwfl_module_addrname(mod, trace_addr);
1200  if (sym_name) {
1201  trace.object_function = demangle(sym_name);
1202  }
1203  }
1204 
1205  // now let's get serious, and find out the source location (file and
1206  // line number) of the address.
1207 
1208  // This function will look in .debug_aranges for the address and map it
1209  // to the location of the compilation unit DIE in .debug_info and
1210  // return it.
1211  Dwarf_Addr mod_bias = 0;
1212  Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
1213 
1214 #if 1
1215  if (!cudie) {
1216  // Sadly clang does not generate the section .debug_aranges, thus
1217  // dwfl_module_addrdie will fail early. Clang doesn't either set
1218  // the lowpc/highpc/range info for every compilation unit.
1219  //
1220  // So in order to save the world:
1221  // for every compilation unit, we will iterate over every single
1222  // DIEs. Normally functions should have a lowpc/highpc/range, which
1223  // we will use to infer the compilation unit.
1224 
1225  // note that this is probably badly inefficient.
1226  while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
1227  Dwarf_Die die_mem;
1228  Dwarf_Die* fundie = find_fundie_by_pc(cudie,
1229  trace_addr - mod_bias, &die_mem);
1230  if (fundie) {
1231  break;
1232  }
1233  }
1234  }
1235 #endif
1236 
1237 //#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
1238 #ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
1239  if (!cudie) {
1240  // If it's still not enough, lets dive deeper in the shit, and try
1241  // to save the world again: for every compilation unit, we will
1242  // load the corresponding .debug_line section, and see if we can
1243  // find our address in it.
1244 
1245  Dwarf_Addr cfi_bias;
1246  Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
1247 
1248  Dwarf_Addr bias;
1249  while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
1250  if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
1251 
1252  // ...but if we get a match, it might be a false positive
1253  // because our (address - bias) might as well be valid in a
1254  // different compilation unit. So we throw our last card on
1255  // the table and lookup for the address into the .eh_frame
1256  // section.
1257 
1258  handle<Dwarf_Frame*> frame;
1259  dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
1260  if (frame) {
1261  break;
1262  }
1263  }
1264  }
1265  }
1266 #endif
1267 
1268  if (!cudie) {
1269  return trace; // this time we lost the game :/
1270  }
1271 
1272  // Now that we have a compilation unit DIE, this function will be able
1273  // to load the corresponding section in .debug_line (if not already
1274  // loaded) and hopefully find the source location mapped to our
1275  // address.
1276  Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
1277 
1278  if (srcloc) {
1279  const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
1280  if (srcfile) {
1281  trace.source.filename = srcfile;
1282  }
1283  int line = 0, col = 0;
1284  dwarf_lineno(srcloc, &line);
1285  dwarf_linecol(srcloc, &col);
1286  trace.source.line = line;
1287  trace.source.col = col;
1288  }
1289 
1290  deep_first_search_by_pc(cudie, trace_addr - mod_bias,
1291  inliners_search_cb(trace));
1292  if (trace.source.function.size() == 0) {
1293  // fallback.
1294  trace.source.function = trace.object_function;
1295  }
1296 
1297  return trace;
1298  }
1299 
1300 private:
1302  dwfl_handle_t;
1304  _dwfl_cb;
1305  dwfl_handle_t _dwfl_handle;
1306  bool _dwfl_handle_initialized;
1307 
1308  // defined here because in C++98, template function cannot take locally
1309  // defined types... grrr.
1310  struct inliners_search_cb {
1311  void operator()(Dwarf_Die* die) {
1312  switch (dwarf_tag(die)) {
1313  const char* name;
1314  case DW_TAG_subprogram:
1315  if ((name = dwarf_diename(die))) {
1316  trace.source.function = name;
1317  }
1318  break;
1319 
1320  case DW_TAG_inlined_subroutine:
1322  Dwarf_Attribute attr_mem;
1323 
1324  if ((name = dwarf_diename(die))) {
1325  sloc.function = name;
1326  }
1327  if ((name = die_call_file(die))) {
1328  sloc.filename = name;
1329  }
1330 
1331  Dwarf_Word line = 0, col = 0;
1332  dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
1333  &attr_mem), &line);
1334  dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
1335  &attr_mem), &col);
1336  sloc.line = line;
1337  sloc.col = col;
1338 
1339  trace.inliners.push_back(sloc);
1340  break;
1341  };
1342  }
1343  ResolvedTrace& trace;
1344  inliners_search_cb(ResolvedTrace& t): trace(t) {}
1345  };
1346 
1347 
1348  static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1349  Dwarf_Addr low, high;
1350 
1351  // continuous range
1352  if (dwarf_hasattr(die, DW_AT_low_pc) &&
1353  dwarf_hasattr(die, DW_AT_high_pc)) {
1354  if (dwarf_lowpc(die, &low) != 0) {
1355  return false;
1356  }
1357  if (dwarf_highpc(die, &high) != 0) {
1358  Dwarf_Attribute attr_mem;
1359  Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
1360  Dwarf_Word value;
1361  if (dwarf_formudata(attr, &value) != 0) {
1362  return false;
1363  }
1364  high = low + value;
1365  }
1366  return pc >= low && pc < high;
1367  }
1368 
1369  // non-continuous range.
1370  Dwarf_Addr base;
1371  ptrdiff_t offset = 0;
1372  while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
1373  if (pc >= low && pc < high) {
1374  return true;
1375  }
1376  }
1377  return false;
1378  }
1379 
1380  static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
1381  Dwarf_Die* result) {
1382  if (dwarf_child(parent_die, result) != 0) {
1383  return 0;
1384  }
1385 
1386  Dwarf_Die* die = result;
1387  do {
1388  switch (dwarf_tag(die)) {
1389  case DW_TAG_subprogram:
1390  case DW_TAG_inlined_subroutine:
1391  if (die_has_pc(die, pc)) {
1392  return result;
1393  }
1394  default:
1395  bool declaration = false;
1396  Dwarf_Attribute attr_mem;
1397  dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
1398  &attr_mem), &declaration);
1399  if (!declaration) {
1400  // let's be curious and look deeper in the tree,
1401  // function are not necessarily at the first level, but
1402  // might be nested inside a namespace, structure etc.
1403  Dwarf_Die die_mem;
1404  Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
1405  if (indie) {
1406  *result = die_mem;
1407  return result;
1408  }
1409  }
1410  };
1411  } while (dwarf_siblingof(die, result) == 0);
1412  return 0;
1413  }
1414 
1415  template <typename CB>
1416  static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
1417  Dwarf_Addr pc, CB cb) {
1418  Dwarf_Die die_mem;
1419  if (dwarf_child(parent_die, &die_mem) != 0) {
1420  return false;
1421  }
1422 
1423  bool branch_has_pc = false;
1424  Dwarf_Die* die = &die_mem;
1425  do {
1426  bool declaration = false;
1427  Dwarf_Attribute attr_mem;
1428  dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
1429  if (!declaration) {
1430  // let's be curious and look deeper in the tree, function are
1431  // not necessarily at the first level, but might be nested
1432  // inside a namespace, structure, a function, an inlined
1433  // function etc.
1434  branch_has_pc = deep_first_search_by_pc(die, pc, cb);
1435  }
1436  if (!branch_has_pc) {
1437  branch_has_pc = die_has_pc(die, pc);
1438  }
1439  if (branch_has_pc) {
1440  cb(die);
1441  }
1442  } while (dwarf_siblingof(die, &die_mem) == 0);
1443  return branch_has_pc;
1444  }
1445 
1446  static const char* die_call_file(Dwarf_Die *die) {
1447  Dwarf_Attribute attr_mem;
1448  Dwarf_Sword file_idx = 0;
1449 
1450  dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
1451  &file_idx);
1452 
1453  if (file_idx == 0) {
1454  return 0;
1455  }
1456 
1457  Dwarf_Die die_mem;
1458  Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
1459  if (!cudie) {
1460  return 0;
1461  }
1462 
1463  Dwarf_Files* files = 0;
1464  size_t nfiles;
1465  dwarf_getsrcfiles(cudie, &files, &nfiles);
1466  if (!files) {
1467  return 0;
1468  }
1469 
1470  return dwarf_filesrc(files, file_idx, 0, 0);
1471  }
1472 
1473 };
1474 #endif // BACKWARD_HAS_DW == 1
1475 
1476 template<>
1477 class TraceResolverImpl<system_tag::linux_tag>:
1478  public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1479 
1480 #endif // BACKWARD_SYSTEM_LINUX
1481 
1483  public TraceResolverImpl<system_tag::current_tag> {};
1484 
1485 /*************** CODE SNIPPET ***************/
1486 
1487 class SourceFile {
1488 public:
1489  typedef std::vector<std::pair<unsigned, std::string> > lines_t;
1490 
1492  SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
1493  bool is_open() const { return _file->is_open(); }
1494 
1495  lines_t& get_lines(unsigned line_start, unsigned line_count, lines_t& lines) {
1496  using namespace std;
1497  // This function make uses of the dumbest algo ever:
1498  // 1) seek(0)
1499  // 2) read lines one by one and discard until line_start
1500  // 3) read line one by one until line_start + line_count
1501  //
1502  // If you are getting snippets many time from the same file, it is
1503  // somewhat a waste of CPU, feel free to benchmark and propose a
1504  // better solution ;)
1505 
1506  _file->clear();
1507  _file->seekg(0);
1508  string line;
1509  unsigned line_idx;
1510 
1511  for (line_idx = 1; line_idx < line_start; ++line_idx) {
1512  std::getline(*_file, line);
1513  if (!*_file) {
1514  return lines;
1515  }
1516  }
1517 
1518  // think of it like a lambda in C++98 ;)
1519  // but look, I will reuse it two times!
1520  // What a good boy am I.
1521  struct isspace {
1522  bool operator()(char c) {
1523  return std::isspace(c);
1524  }
1525  };
1526 
1527  bool started = false;
1528  for (; line_idx < line_start + line_count; ++line_idx) {
1529  getline(*_file, line);
1530  if (!*_file) {
1531  return lines;
1532  }
1533  if (!started) {
1534  if (std::find_if(line.begin(), line.end(),
1535  not_isspace()) == line.end())
1536  continue;
1537  started = true;
1538  }
1539  lines.push_back(make_pair(line_idx, line));
1540  }
1541 
1542  lines.erase(
1543  std::find_if(lines.rbegin(), lines.rend(),
1544  not_isempty()).base(), lines.end()
1545  );
1546  return lines;
1547  }
1548 
1549  lines_t get_lines(unsigned line_start, unsigned line_count) {
1550  lines_t lines;
1551  return get_lines(line_start, line_count, lines);
1552  }
1553 
1554  // there is no find_if_not in C++98, lets do something crappy to
1555  // workaround.
1556  struct not_isspace {
1557  bool operator()(char c) {
1558  return !std::isspace(c);
1559  }
1560  };
1561  // and define this one here because C++98 is not happy with local defined
1562  // struct passed to template functions, fuuuu.
1563  struct not_isempty {
1564  bool operator()(const lines_t::value_type& p) {
1565  return !(std::find_if(p.second.begin(), p.second.end(),
1566  not_isspace()) == p.second.end());
1567  }
1568  };
1569 
1570  void swap(SourceFile& b) {
1571  _file.swap(b._file);
1572  }
1573 
1574 #ifdef BACKWARD_ATLEAST_CXX11
1575  SourceFile(SourceFile&& from): _file(0) {
1576  swap(from);
1577  }
1578  SourceFile& operator=(SourceFile&& from) {
1579  swap(from); return *this;
1580  }
1581 #else
1582  explicit SourceFile(const SourceFile& from) {
1583  // some sort of poor man's move semantic.
1584  swap(const_cast<SourceFile&>(from));
1585  }
1587  // some sort of poor man's move semantic.
1588  swap(const_cast<SourceFile&>(from)); return *this;
1589  }
1590 #endif
1591 
1592 private:
1593  details::handle<std::ifstream*,
1596 
1597 #ifdef BACKWARD_ATLEAST_CXX11
1598  SourceFile(const SourceFile&) = delete;
1599  SourceFile& operator=(const SourceFile&) = delete;
1600 #endif
1601 };
1602 
1604 public:
1606 
1607  lines_t get_snippet(const std::string& filename,
1608  unsigned line_start, unsigned context_size) {
1609 
1610  SourceFile& src_file = get_src_file(filename);
1611  unsigned start = line_start - context_size / 2;
1612  return src_file.get_lines(start, context_size);
1613  }
1614 
1616  const std::string& filename_a, unsigned line_a,
1617  const std::string& filename_b, unsigned line_b,
1618  unsigned context_size) {
1619  SourceFile& src_file_a = get_src_file(filename_a);
1620  SourceFile& src_file_b = get_src_file(filename_b);
1621 
1622  lines_t lines = src_file_a.get_lines(line_a - context_size / 4,
1623  context_size / 2);
1624  src_file_b.get_lines(line_b - context_size / 4, context_size / 2,
1625  lines);
1626  return lines;
1627  }
1628 
1629  lines_t get_coalesced_snippet(const std::string& filename,
1630  unsigned line_a, unsigned line_b, unsigned context_size) {
1631  SourceFile& src_file = get_src_file(filename);
1632 
1633  using std::min; using std::max;
1634  unsigned a = min(line_a, line_b);
1635  unsigned b = max(line_a, line_b);
1636 
1637  if ((b - a) < (context_size / 3)) {
1638  return src_file.get_lines((a + b - context_size + 1) / 2,
1639  context_size);
1640  }
1641 
1642  lines_t lines = src_file.get_lines(a - context_size / 4,
1643  context_size / 2);
1644  src_file.get_lines(b - context_size / 4, context_size / 2, lines);
1645  return lines;
1646  }
1647 
1648 
1649 private:
1651  src_files_t _src_files;
1652 
1653  SourceFile& get_src_file(const std::string& filename) {
1654  src_files_t::iterator it = _src_files.find(filename);
1655  if (it != _src_files.end()) {
1656  return it->second;
1657  }
1658  SourceFile& new_src_file = _src_files[filename];
1659  new_src_file = SourceFile(filename);
1660  return new_src_file;
1661  }
1662 };
1663 
1664 /*************** PRINTER ***************/
1665 
1666 #ifdef BACKWARD_SYSTEM_LINUX
1667 
1668 namespace Color {
1669  enum type {
1670  yellow = 33,
1671  purple = 35,
1672  reset = 39
1673  };
1674 } // namespace Color
1675 
1676 class Colorize {
1677 public:
1678  Colorize(std::FILE* os):
1679  _os(os), _reset(false), _istty(false) {}
1680 
1681  void init() {
1682  _istty = isatty(fileno(_os));
1683  }
1684 
1685  void set_color(Color::type ccode) {
1686  if (!_istty) return;
1687 
1688  // I assume that the terminal can handle basic colors. Seriously I
1689  // don't want to deal with all the termcap shit.
1690  fprintf(_os, "\033[%im", static_cast<int>(ccode));
1691  _reset = (ccode != Color::reset);
1692  }
1693 
1694  ~Colorize() {
1695  if (_reset) {
1696  set_color(Color::reset);
1697  }
1698  }
1699 
1700 private:
1701  std::FILE* _os;
1702  bool _reset;
1703  bool _istty;
1704 };
1705 
1706 #else // ndef BACKWARD_SYSTEM_LINUX
1707 
1708 
1709 namespace Color {
1710  enum type {
1711  yellow = 0,
1712  purple = 0,
1713  reset = 0
1714  };
1715 } // namespace Color
1716 
1717 class Colorize {
1718 public:
1719  Colorize(std::FILE*) {}
1720  void init() {}
1722 };
1723 
1724 #endif // BACKWARD_SYSTEM_LINUX
1725 
1726 class Printer {
1727 public:
1728  bool snippet;
1729  bool color;
1730  bool address;
1731  bool object;
1734 
1736  snippet(true),
1737  color(true),
1738  address(false),
1739  object(false),
1740  inliner_context_size(5),
1741  trace_context_size(7)
1742  {}
1743 
1744  template <typename ST>
1745  FILE* print(ST& st, FILE* os = stderr) {
1746  Colorize colorize(os);
1747  if (color) {
1748  colorize.init();
1749  }
1750  print_header(os, st.thread_id());
1751  _resolver.load_stacktrace(st);
1752  for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1753  print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize);
1754  }
1755  return os;
1756  }
1757 
1758  template <typename IT>
1759  FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) {
1760  Colorize colorize(os);
1761  if (color) {
1762  colorize.init();
1763  }
1764  print_header(os, thread_id);
1765  for (; begin != end; ++begin) {
1766  print_trace(os, *begin, colorize);
1767  }
1768  return os;
1769  }
1770 private:
1773 
1774  void print_header(FILE* os, unsigned thread_id) {
1775  fprintf(os, "Stack trace (most recent call last)");
1776  if (thread_id) {
1777  fprintf(os, " in thread %u:\n", thread_id);
1778  } else {
1779  fprintf(os, ":\n");
1780  }
1781  }
1782 
1783  void print_trace(FILE* os, const ResolvedTrace& trace,
1784  Colorize& colorize) {
1785  fprintf(os, "#%-2u", trace.idx);
1786  bool already_indented = true;
1787 
1788  if (!trace.source.filename.size() || object) {
1789  fprintf(os, " Object \"%s\", at %p, in %s\n",
1790  trace.object_filename.c_str(), trace.addr,
1791  trace.object_function.c_str());
1792  already_indented = false;
1793  }
1794 
1795  for (size_t inliner_idx = trace.inliners.size();
1796  inliner_idx > 0; --inliner_idx) {
1797  if (!already_indented) {
1798  fprintf(os, " ");
1799  }
1800  const ResolvedTrace::SourceLoc& inliner_loc
1801  = trace.inliners[inliner_idx-1];
1802  print_source_loc(os, " | ", inliner_loc);
1803  if (snippet) {
1804  print_snippet(os, " | ", inliner_loc,
1805  colorize, Color::purple, inliner_context_size);
1806  }
1807  already_indented = false;
1808  }
1809 
1810  if (trace.source.filename.size()) {
1811  if (!already_indented) {
1812  fprintf(os, " ");
1813  }
1814  print_source_loc(os, " ", trace.source, trace.addr);
1815  if (snippet) {
1816  print_snippet(os, " ", trace.source,
1817  colorize, Color::yellow, trace_context_size);
1818  }
1819  }
1820  }
1821 
1822  void print_snippet(FILE* os, const char* indent,
1823  const ResolvedTrace::SourceLoc& source_loc,
1824  Colorize& colorize, Color::type color_code,
1825  int context_size)
1826  {
1827  using namespace std;
1828  typedef SnippetFactory::lines_t lines_t;
1829 
1830  lines_t lines = _snippets.get_snippet(source_loc.filename,
1831  source_loc.line, context_size);
1832 
1833  for (lines_t::const_iterator it = lines.begin();
1834  it != lines.end(); ++it) {
1835  if (it-> first == source_loc.line) {
1836  colorize.set_color(color_code);
1837  fprintf(os, "%s>", indent);
1838  } else {
1839  fprintf(os, "%s ", indent);
1840  }
1841  fprintf(os, "%4u: %s\n", it->first, it->second.c_str());
1842  if (it-> first == source_loc.line) {
1843  colorize.set_color(Color::reset);
1844  }
1845  }
1846  }
1847 
1848  void print_source_loc(FILE* os, const char* indent,
1849  const ResolvedTrace::SourceLoc& source_loc,
1850  void* addr=0) {
1851  fprintf(os, "%sSource \"%s\", line %i, in %s",
1852  indent, source_loc.filename.c_str(), (int)source_loc.line,
1853  source_loc.function.c_str());
1854 
1855  if (address && addr != 0) {
1856  fprintf(os, " [%p]\n", addr);
1857  } else {
1858  fprintf(os, "\n");
1859  }
1860  }
1861 };
1862 
1863 /*************** SIGNALS HANDLING ***************/
1864 
1865 #ifdef BACKWARD_SYSTEM_LINUX
1866 
1867 
1868 class SignalHandling {
1869 public:
1870  static std::vector<int> make_default_signals() {
1871  const int posix_signals[] = {
1872  // Signals for which the default action is "Core".
1873  SIGABRT, // Abort signal from abort(3)
1874  SIGBUS, // Bus error (bad memory access)
1875  SIGFPE, // Floating point exception
1876  SIGILL, // Illegal Instruction
1877  SIGIOT, // IOT trap. A synonym for SIGABRT
1878  SIGQUIT, // Quit from keyboard
1879  SIGSEGV, // Invalid memory reference
1880  SIGSYS, // Bad argument to routine (SVr4)
1881  SIGTRAP, // Trace/breakpoint trap
1882  SIGXCPU, // CPU time limit exceeded (4.2BSD)
1883  SIGXFSZ, // File size limit exceeded (4.2BSD)
1884  };
1885  return std::vector<int>(posix_signals, posix_signals + sizeof posix_signals / sizeof posix_signals[0] );
1886  }
1887 
1888  SignalHandling(const std::vector<int>& posix_signals = make_default_signals()):
1889  _loaded(false) {
1890  bool success = true;
1891 
1892  const size_t stack_size = 1024 * 1024 * 8;
1893  _stack_content.reset((char*)malloc(stack_size));
1894  if (_stack_content) {
1895  stack_t ss;
1896  ss.ss_sp = _stack_content.get();
1897  ss.ss_size = stack_size;
1898  ss.ss_flags = 0;
1899  if (sigaltstack(&ss, 0) < 0) {
1900  success = false;
1901  }
1902  } else {
1903  success = false;
1904  }
1905 
1906  for (size_t i = 0; i < posix_signals.size(); ++i) {
1907  struct sigaction action;
1908  memset(&action, 0, sizeof action);
1909  action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1910  SA_RESETHAND);
1911  sigfillset(&action.sa_mask);
1912  sigdelset(&action.sa_mask, posix_signals[i]);
1913  action.sa_sigaction = &sig_handler;
1914 
1915  int r = sigaction(posix_signals[i], &action, 0);
1916  if (r < 0) success = false;
1917  }
1918 
1919  _loaded = success;
1920  }
1921 
1922  bool loaded() const { return _loaded; }
1923 
1924 private:
1925  details::handle<char*> _stack_content;
1926  bool _loaded;
1927 
1928 #ifdef __GNUC__
1929  __attribute__((noreturn))
1930 #endif
1931  static void sig_handler(int, siginfo_t* info, void* _ctx) {
1932  ucontext_t *uctx = (ucontext_t*) _ctx;
1933 
1934  StackTrace st;
1935  void* error_addr = 0;
1936 #ifdef REG_RIP // x86_64
1937  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
1938 #elif defined(REG_EIP) // x86_32
1939  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
1940 #elif defined(__arm__)
1941  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.arm_pc);
1942 #elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
1943  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.regs->nip);
1944 #else
1945 # warning ":/ sorry, ain't know no nothing none not of your architecture!"
1946 #endif
1947  if (error_addr) {
1948  st.load_from(error_addr, 32);
1949  } else {
1950  st.load_here(32);
1951  }
1952 
1953  Printer printer;
1954  printer.address = true;
1955  printer.object = true;
1956  printer.color = true;
1957  printer.snippet = true;
1958  printer.print(st, stderr);
1959 
1960 #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
1961  psiginfo(info, 0);
1962 #endif
1963 
1964  // try to forward the signal.
1965  raise(info->si_signo);
1966 
1967  // terminate the process immediately.
1968  puts("watf? exit");
1969  _exit(EXIT_FAILURE);
1970  }
1971 };
1972 
1973 #endif // BACKWARD_SYSTEM_LINUX
1974 
1975 #ifdef BACKWARD_SYSTEM_UNKNOWN
1976 
1978 public:
1979  SignalHandling(const std::vector<int>& = std::vector<int>()) {}
1980  bool init() { return false; }
1981  bool loaded() { return false; }
1982 };
1983 
1984 #endif // BACKWARD_SYSTEM_UNKNOWN
1985 
1986 } // namespace backward
1987 
1988 #endif /* H_GUARD */
void reset(T new_val)
Definition: backward.hpp:350
void swap(any &x, any &y) any_noexcept
Definition: any.hpp:406
filename
const_ref_t operator*() const
Definition: backward.hpp:380
std::vector< std::pair< unsigned, std::string > > lines_t
Definition: backward.hpp:1489
SourceFile::lines_t lines_t
Definition: backward.hpp:1605
bool is_open() const
Definition: backward.hpp:1493
char * begin
f
std::string object_filename
Definition: backward.hpp:464
const T operator->() const
Definition: backward.hpp:375
lines_t & get_lines(unsigned line_start, unsigned line_count, lines_t &lines)
Definition: backward.hpp:1495
lines_t get_lines(unsigned line_start, unsigned line_count)
Definition: backward.hpp:1549
void print_source_loc(FILE *os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, void *addr=0)
Definition: backward.hpp:1848
ref_t operator[](size_t idx)
Definition: backward.hpp:381
ROSCPP_DECL std::string resolve(const std::string &name, bool remap=true)
void operator()(U &ptr) const
Definition: backward.hpp:299
rm_ptr< T >::type & ref_t
Definition: backward.hpp:377
lines_t get_coalesced_snippet(const std::string &filename, unsigned line_a, unsigned line_b, unsigned context_size)
Definition: backward.hpp:1629
FILE * print(IT begin, IT end, FILE *os=stderr, size_t thread_id=0)
Definition: backward.hpp:1759
void swap(SourceFile &b)
Definition: backward.hpp:1570
handle & operator=(const handle &from)
Definition: backward.hpp:344
bool operator()(const lines_t::value_type &p)
Definition: backward.hpp:1564
void operator()(T &ptr) const
Definition: backward.hpp:306
details::hashtable< std::string, SourceFile >::type src_files_t
Definition: backward.hpp:1650
void set_color(Color::type)
Definition: backward.hpp:1721
T value
void print_snippet(FILE *os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, Colorize &colorize, Color::type color_code, int context_size)
Definition: backward.hpp:1822
std::string object_function
Definition: backward.hpp:468
lines_t get_combined_snippet(const std::string &filename_a, unsigned line_a, const std::string &filename_b, unsigned line_b, unsigned context_size)
Definition: backward.hpp:1615
FILE * print(ST &st, FILE *os=stderr)
Definition: backward.hpp:1745
ResolvedTrace(const Trace &mini_trace)
Definition: backward.hpp:484
SnippetFactory _snippets
Definition: backward.hpp:1772
void swap(handle &b)
Definition: backward.hpp:367
std::vector< SourceLoc > source_locs_t
Definition: backward.hpp:479
unknown_tag current_tag
Definition: backward.hpp:254
SourceFile(const SourceFile &from)
Definition: backward.hpp:1582
char name[1]
const T & move(const T &v)
Definition: backward.hpp:242
unsigned idx
Definition: backward.hpp:432
bool operator!=(const SourceLoc &b) const
Definition: backward.hpp:458
size_t load_here(size_t=0)
Definition: backward.hpp:496
source_locs_t inliners
Definition: backward.hpp:480
uintptr_t size
size_t size() const
Definition: backward.hpp:494
unsigned thread_id() const
Definition: backward.hpp:498
Trace(void *addr, size_t idx)
Definition: backward.hpp:437
void print_header(FILE *os, unsigned thread_id)
Definition: backward.hpp:1774
int min(int a, int b)
lines_t get_snippet(const std::string &filename, unsigned line_start, unsigned context_size)
Definition: backward.hpp:1607
SourceFile & get_src_file(const std::string &filename)
Definition: backward.hpp:1653
SourceFile(const std::string &path)
Definition: backward.hpp:1492
void print_trace(FILE *os, const ResolvedTrace &trace, Colorize &colorize)
Definition: backward.hpp:1783
static std::string demangle(const char *funcname)
Definition: backward.hpp:393
Trace operator[](size_t)
Definition: backward.hpp:495
SignalHandling(const std::vector< int > &=std::vector< int >())
Definition: backward.hpp:1979
size_t load_from(void *, size_t=0)
Definition: backward.hpp:497
details::handle< std::ifstream *, details::default_delete< std::ifstream * > > _file
Definition: backward.hpp:1595
uint64_t b
handle(const handle &from)
Definition: backward.hpp:340
bool operator==(const SourceLoc &b) const
Definition: backward.hpp:451
empty_struct data[sizeof(T)/sizeof(empty_struct)]
int i
void skip_n_firsts(size_t)
Definition: backward.hpp:499
size_t from
SourceFile & operator=(const SourceFile &from)
Definition: backward.hpp:1586
int a
Colorize(std::FILE *)
Definition: backward.hpp:1719
const rm_ptr< T >::type & const_ref_t
Definition: backward.hpp:378
TraceResolver _resolver
Definition: backward.hpp:1771
int n
tf::tfVector4 __attribute__


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17