Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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 <sstream>
65 #include <algorithm>
66 #include <cstdlib>
67 #include <cstdio>
68 #include <cstring>
69 #include <cctype>
70 #include <string>
71 #include <new>
72 #include <iomanip>
73 #include <vector>
74 
75 #if defined(BACKWARD_SYSTEM_LINUX)
76 
77 // On linux, backtrace can back-trace or "walk" the stack using the following
78 // libraries:
79 //
80 // #define BACKWARD_HAS_UNWIND 1
81 // - unwind comes from libgcc, but I saw an equivalent inside clang itself.
82 // - with unwind, the stacktrace is as accurate as it can possibly be, since
83 // this is used by the C++ runtine in gcc/clang for stack unwinding on
84 // exception.
85 // - normally libgcc is already linked to your program by default.
86 //
87 // #define BACKWARD_HAS_BACKTRACE == 1
88 // - backtrace seems to be a little bit more portable than libunwind, but on
89 // linux, it uses unwind anyway, but abstract away a tiny information that is
90 // sadly really important in order to get perfectly accurate stack traces.
91 // - backtrace is part of the (e)glib library.
92 //
93 // The default is:
94 // #define BACKWARD_HAS_UNWIND == 1
95 //
96 // Note that only one of the define should be set to 1 at a time.
97 //
98 # if BACKWARD_HAS_UNWIND == 1
99 # elif BACKWARD_HAS_BACKTRACE == 1
100 # else
101 # undef BACKWARD_HAS_UNWIND
102 # define BACKWARD_HAS_UNWIND 1
103 # undef BACKWARD_HAS_BACKTRACE
104 # define BACKWARD_HAS_BACKTRACE 0
105 # endif
106 
107 // On linux, backward can extract detailed information about a stack trace
108 // using one of the following libraries:
109 //
110 // #define BACKWARD_HAS_DW 1
111 // - libdw gives you the most juicy details out of your stack traces:
112 // - object filename
113 // - function name
114 // - source filename
115 // - line and column numbers
116 // - source code snippet (assuming the file is accessible)
117 // - variables name and values (if not optimized out)
118 // - You need to link with the lib "dw":
119 // - apt-get install libdw-dev
120 // - g++/clang++ -ldw ...
121 //
122 // #define BACKWARD_HAS_BFD 1
123 // - With libbfd, you get a fair amount of details:
124 // - object filename
125 // - function name
126 // - source filename
127 // - line numbers
128 // - source code snippet (assuming the file is accessible)
129 // - You need to link with the lib "bfd":
130 // - apt-get install binutils-dev
131 // - g++/clang++ -lbfd ...
132 //
133 // #define BACKWARD_HAS_BACKTRACE_SYMBOL 1
134 // - backtrace provides minimal details for a stack trace:
135 // - object filename
136 // - function name
137 // - backtrace is part of the (e)glib library.
138 //
139 // The default is:
140 // #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1
141 //
142 // Note that only one of the define should be set to 1 at a time.
143 //
144 # if BACKWARD_HAS_DW == 1
145 # elif BACKWARD_HAS_BFD == 1
146 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
147 # else
148 # undef BACKWARD_HAS_DW
149 # define BACKWARD_HAS_DW 0
150 # undef BACKWARD_HAS_BFD
151 # define BACKWARD_HAS_BFD 0
152 # undef BACKWARD_HAS_BACKTRACE_SYMBOL
153 # define BACKWARD_HAS_BACKTRACE_SYMBOL 1
154 # endif
155 
156 
157 # if BACKWARD_HAS_UNWIND == 1
158 
159 # include <unwind.h>
160 // while gcc's unwind.h defines something like that:
161 // extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
162 // extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
163 //
164 // clang's unwind.h defines something like this:
165 // uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
166 //
167 // Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we
168 // cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr
169 // anyway.
170 //
171 // Luckily we can play on the fact that the guard macros have a different name:
172 #ifdef __CLANG_UNWIND_H
173 // In fact, this function still comes from libgcc (on my different linux boxes,
174 // clang links against libgcc).
175 # include <inttypes.h>
176 extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*);
177 #endif
178 
179 # endif
180 
181 # include <cxxabi.h>
182 # include <fcntl.h>
183 # include <link.h>
184 # include <sys/stat.h>
185 # include <syscall.h>
186 # include <unistd.h>
187 # include <signal.h>
188 
189 # if BACKWARD_HAS_BFD == 1
190 // NOTE: defining PACKAGE{,_VERSION} is required before including
191 // bfd.h on some platforms, see also:
192 // https://sourceware.org/bugzilla/show_bug.cgi?id=14243
193 # ifndef PACKAGE
194 # define PACKAGE
195 # endif
196 # ifndef PACKAGE_VERSION
197 # define PACKAGE_VERSION
198 # endif
199 # include <bfd.h>
200 # ifndef _GNU_SOURCE
201 # define _GNU_SOURCE
202 # include <dlfcn.h>
203 # undef _GNU_SOURCE
204 # else
205 # include <dlfcn.h>
206 # endif
207 # endif
208 
209 # if BACKWARD_HAS_DW == 1
210 # include <elfutils/libdw.h>
211 # include <elfutils/libdwfl.h>
212 # include <dwarf.h>
213 # endif
214 
215 # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
216  // then we shall rely on backtrace
217 # include <execinfo.h>
218 # endif
219 
220 #endif // defined(BACKWARD_SYSTEM_LINUX)
221 
222 #ifdef BACKWARD_ATLEAST_CXX11
223 # include <unordered_map>
224 # include <utility> // for std::swap
225  namespace backward {
226  namespace details {
227  template <typename K, typename V>
228  struct hashtable {
229  using type = std::unordered_map<K, V>;
230  };
231  using std::move;
232  }
233  }
234 #else // NOT BACKWARD_ATLEAST_CXX11
235 # include <map>
236  namespace backward {
237  namespace details {
238  template <typename K, typename V>
239  struct hashtable {
240  using type = std::map<K, V>;
241  };
242  template <typename T>
243  const T& move(const T& v) { return v; }
244  template <typename T>
245  T& move(T& v) { return v; }
246  }
247  }
248 #endif // BACKWARD_ATLEAST_CXX11
249 
250 namespace backward {
251 
252 namespace system_tag {
253  struct linux_tag; // seems that I cannot call that "linux" because the name
254  // is already defined... so I am adding _tag everywhere.
255  struct unknown_tag;
256 
257 #if defined(BACKWARD_SYSTEM_LINUX)
258  using current_tag = linux_tag;
259 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
260  using current_tag = unknown_tag;
261 #else
262 # error "May I please get my system defines?"
263 #endif
264 }
265 
266 
267 namespace trace_resolver_tag {
268 #ifdef BACKWARD_SYSTEM_LINUX
269  struct libdw;
270  struct libbfd;
271  struct backtrace_symbol;
272 
273 # if BACKWARD_HAS_DW == 1
274  using current = libdw;
275 # elif BACKWARD_HAS_BFD == 1
276  using current = libbfd;
277 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
278  using current = backtrace_symbol;
279 # else
280 # error "You shall not pass, until you know what you want."
281 # endif
282 #endif // BACKWARD_SYSTEM_LINUX
283 }
284 
285 
286 namespace details {
287 
288 template <typename T>
289  struct rm_ptr { using type = T; };
290 
291 template <typename T>
292  struct rm_ptr<T*> { using type = T; };
293 
294 template <typename T>
295  struct rm_ptr<const T*> { using type = const T; };
296 
297 template <typename R, typename T, R (*F)(T)>
298 struct deleter {
299  template <typename U>
300  void operator()(U& ptr) const {
301  (*F)(ptr);
302  }
303 };
304 
305 template <typename T>
307  void operator()(T& ptr) const {
308  delete ptr;
309  }
310 };
311 
312 template <typename T, typename Deleter = deleter<void, void*, &::free> >
313 class handle {
314  struct dummy;
315  T _val;
316  bool _empty;
317 
318 #ifdef BACKWARD_ATLEAST_CXX11
319  handle(const handle&) = delete;
320  handle& operator=(const handle&) = delete;
321 #endif
322 
323 public:
325  if (!_empty) {
326  Deleter()(_val);
327  }
328  }
329 
330  explicit handle(): _val(), _empty(true) {}
331  explicit handle(T val): _val(val), _empty(false) {}
332 
333 #ifdef BACKWARD_ATLEAST_CXX11
334  handle(handle&& from): _empty(true) {
335  swap(from);
336  }
337  handle& operator=(handle&& from) {
338  swap(from); return *this;
339  }
340 #else
341  explicit handle(const handle& from): _empty(true) {
342  // some sort of poor man's move semantic.
343  swap(const_cast<handle&>(from));
344  }
345  handle& operator=(const handle& from) {
346  // some sort of poor man's move semantic.
347  swap(const_cast<handle&>(from)); return *this;
348  }
349 #endif
350 
351  void reset(T new_val) {
352  handle tmp(new_val);
353  swap(tmp);
354  }
355  operator const dummy*() const {
356  if (_empty) {
357  return 0;
358  }
359  return reinterpret_cast<const dummy*>(_val);
360  }
361  T get() {
362  return _val;
363  }
364  T release() {
365  _empty = true;
366  return _val;
367  }
368  void swap(handle& b) {
369  using std::swap;
370  swap(b._val, _val); // can throw, we are safe here.
371  swap(b._empty, _empty); // should not throw: if you cannot swap two
372  // bools without throwing... It's a lost cause anyway!
373  }
374 
375  T operator->() { return _val; }
376  const T operator->() const { return _val; }
377 
378  using ref_t = typename rm_ptr<T>::type&;
379  using const_ref_t = const typename rm_ptr<T>::type&;
380  ref_t operator*() { return *_val; }
381  const_ref_t operator*() const { return *_val; }
382  ref_t operator[](size_t idx) { return _val[idx]; }
383 
384  // Watch out, we've got a badass over here
385  T* operator&() {
386  _empty = false;
387  return &_val;
388  }
389 };
390 
391 // Default demangler implementation (do nothing).
392 template <typename TAG>
394  static std::string demangle(const char* funcname) {
395  return funcname;
396  }
397 };
398 
399 #ifdef BACKWARD_SYSTEM_LINUX
400 
401 template <>
402 struct demangler_impl<system_tag::current_tag> {
403  demangler_impl(): _demangle_buffer_length(0) {}
404 
405  std::string demangle(const char* funcname) {
406  using namespace details;
407  _demangle_buffer.reset(
408  abi::__cxa_demangle(funcname, NULL,
409  &_demangle_buffer_length, 0)
410  );
411  if (_demangle_buffer) {
412  return _demangle_buffer.get();
413  }
414  return funcname;
415  }
416 
417 private:
418  details::handle<char*> _demangle_buffer;
419  size_t _demangle_buffer_length;
420 };
421 
422 #endif // BACKWARD_SYSTEM_LINUX
423 
424 struct demangler:
425  public demangler_impl<system_tag::current_tag> {};
426 
427 }
428 
429 /*************** A TRACE ***************/
430 
431 struct Trace {
432  void* addr;
433  unsigned idx;
434 
435  Trace():
436  addr(0), idx(0) {}
437 
438  explicit Trace(void* _addr, size_t _idx):
439  addr(_addr), idx(_idx) {}
440 };
441 
442 struct ResolvedTrace: public Trace {
443 
444  struct SourceLoc {
445  std::string function;
446  std::string filename;
447  unsigned line;
448  unsigned col;
449 
450  SourceLoc(): line(0), col(0) {}
451 
452  bool operator==(const SourceLoc& b) const {
453  return function == b.function
454  && filename == b.filename
455  && line == b.line
456  && col == b.col;
457  }
458 
459  bool operator!=(const SourceLoc& b) const {
460  return !(*this == b);
461  }
462  };
463 
464  // In which binary object this trace is located.
465  std::string object_filename;
466 
467  // The function in the object that contain the trace. This is not the same
468  // as source.function which can be an function inlined in object_function.
469  std::string object_function;
470 
471  // The source location of this trace. It is possible for filename to be
472  // empty and for line/col to be invalid (value 0) if this information
473  // couldn't be deduced, for example if there is no debug information in the
474  // binary object.
476 
477  // An optionals list of "inliners". All the successive sources location
478  // from where the source location of the trace (the attribute right above)
479  // is inlined. It is especially useful when you compiled with optimization.
480  using source_locs_t = std::vector<SourceLoc>;
482 
484  Trace() {}
485  ResolvedTrace(const Trace& mini_trace):
486  Trace(mini_trace) {}
487 };
488 
489 /*************** STACK TRACE ***************/
490 
491 // default implemention.
492 template <typename TAG>
494 public:
495  size_t size() const { return 0; }
496  Trace operator[](size_t) { return Trace(); }
497  size_t load_here(size_t=0) { return 0; }
498  size_t load_from(void*, size_t=0) { return 0; }
499  unsigned thread_id() const { return 0; }
500  void skip_n_firsts(size_t) { }
501 };
502 
503 #ifdef BACKWARD_SYSTEM_LINUX
504 
505 class StackTraceLinuxImplBase {
506 public:
507  StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
508 
509  unsigned thread_id() const {
510  return _thread_id;
511  }
512 
513  void skip_n_firsts(size_t n) { _skip = n; }
514 
515 protected:
516  void load_thread_info() {
517  _thread_id = syscall(SYS_gettid);
518  if (_thread_id == (size_t) getpid()) {
519  // If the thread is the main one, let's hide that.
520  // I like to keep little secret sometimes.
521  _thread_id = 0;
522  }
523  }
524 
525  size_t skip_n_firsts() const { return _skip; }
526 
527 private:
528  size_t _thread_id;
529  size_t _skip;
530 };
531 
532 class StackTraceLinuxImplHolder: public StackTraceLinuxImplBase {
533 public:
534  size_t size() const {
535  return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
536  }
537  Trace operator[](size_t idx) {
538  if (idx >= size()) {
539  return Trace();
540  }
541  return Trace(_stacktrace[idx + skip_n_firsts()], idx);
542  }
543  void** begin() {
544  if (size()) {
545  return &_stacktrace[skip_n_firsts()];
546  }
547  return 0;
548  }
549 
550 protected:
551  std::vector<void*> _stacktrace;
552 };
553 
554 
555 #if BACKWARD_HAS_UNWIND == 1
556 
557 namespace details {
558 
559 template <typename F>
560 class Unwinder {
561 public:
562  size_t operator()(F& f, size_t depth) {
563  _f = &f;
564  _index = -1;
565  _depth = depth;
566  _Unwind_Backtrace(&this->backtrace_trampoline, this);
567  return _index;
568  }
569 
570 private:
571  F* _f;
572  ssize_t _index;
573  size_t _depth;
574 
575  static _Unwind_Reason_Code backtrace_trampoline(
576  _Unwind_Context* ctx, void *self) {
577  return ((Unwinder*)self)->backtrace(ctx);
578  }
579 
580  _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
581  if (_index >= 0 && static_cast<size_t>(_index) >= _depth)
582  return _URC_END_OF_STACK;
583 
584  int ip_before_instruction = 0;
585  uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
586 
587  if (!ip_before_instruction) {
588  ip -= 1;
589  }
590 
591  if (_index >= 0) { // ignore first frame.
592  (*_f)(_index, (void*)ip);
593  }
594  _index += 1;
595  return _URC_NO_REASON;
596  }
597 };
598 
599 template <typename F>
600 size_t unwind(F f, size_t depth) {
601  Unwinder<F> unwinder;
602  return unwinder(f, depth);
603 }
604 
605 }
606 
607 
608 template <>
609 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
610 public:
611  __attribute__ ((noinline)) // TODO use some macro
612  size_t load_here(size_t depth=32) {
613  load_thread_info();
614  if (depth == 0) {
615  return 0;
616  }
617  _stacktrace.resize(depth);
618  size_t trace_cnt = details::unwind(callback(*this), depth);
619  _stacktrace.resize(trace_cnt);
620  skip_n_firsts(0);
621  return size();
622  }
623  size_t load_from(void* addr, size_t depth=32) {
624  load_here(depth + 8);
625 
626  for (size_t i = 0; i < _stacktrace.size(); ++i) {
627  if (_stacktrace[i] == addr) {
628  skip_n_firsts(i);
629  break;
630  }
631  }
632 
633  _stacktrace.resize(std::min(_stacktrace.size(),
634  skip_n_firsts() + depth));
635  return size();
636  }
637 
638 private:
639  struct callback {
640  StackTraceImpl& self;
641  callback(StackTraceImpl& _self): self(_self) {}
642 
643  void operator()(size_t idx, void* addr) {
644  self._stacktrace[idx] = addr;
645  }
646  };
647 };
648 
649 
650 #else // BACKWARD_HAS_UNWIND == 0
651 
652 template <>
653 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
654 public:
655  __attribute__ ((noinline)) // TODO use some macro
656  size_t load_here(size_t depth=32) {
657  load_thread_info();
658  if (depth == 0) {
659  return 0;
660  }
661  _stacktrace.resize(depth + 1);
662  size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
663  _stacktrace.resize(trace_cnt);
664  skip_n_firsts(1);
665  return size();
666  }
667 
668  size_t load_from(void* addr, size_t depth=32) {
669  load_here(depth + 8);
670 
671  for (size_t i = 0; i < _stacktrace.size(); ++i) {
672  if (_stacktrace[i] == addr) {
673  skip_n_firsts(i);
674  _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1);
675  break;
676  }
677  }
678 
679  _stacktrace.resize(std::min(_stacktrace.size(),
680  skip_n_firsts() + depth));
681  return size();
682  }
683 };
684 
685 #endif // BACKWARD_HAS_UNWIND
686 #endif // BACKWARD_SYSTEM_LINUX
687 
689  public StackTraceImpl<system_tag::current_tag> {};
690 
691 /*************** TRACE RESOLVER ***************/
692 
693 template <typename TAG>
695 
696 #ifdef BACKWARD_SYSTEM_UNKNOWN
697 
698 template <>
699 class TraceResolverImpl<system_tag::unknown_tag> {
700 public:
701  template <class ST>
702  void load_stacktrace(ST&) {}
704  return t;
705  }
706 };
707 
708 #endif
709 
710 #ifdef BACKWARD_SYSTEM_LINUX
711 
712 class TraceResolverLinuxImplBase {
713 protected:
714  std::string demangle(const char* funcname) {
715  return _demangler.demangle(funcname);
716  }
717 
718 private:
719  details::demangler _demangler;
720 };
721 
722 template <typename STACKTRACE_TAG>
723 class TraceResolverLinuxImpl;
724 
725 #if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
726 
727 template <>
728 class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
729  public TraceResolverLinuxImplBase {
730 public:
731  template <class ST>
732  void load_stacktrace(ST& st) {
733  using namespace details;
734  if (st.size() == 0) {
735  return;
736  }
737  _symbols.reset(
738  backtrace_symbols(st.begin(), st.size())
739  );
740  }
741 
742  ResolvedTrace resolve(ResolvedTrace trace) {
743  char* filename = _symbols[trace.idx];
744  char* funcname = filename;
745  while (*funcname && *funcname != '(') {
746  funcname += 1;
747  }
748  trace.object_filename.assign(filename, funcname++);
749  char* funcname_end = funcname;
750  while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') {
751  funcname_end += 1;
752  }
753  *funcname_end = '\0';
754  trace.object_function = this->demangle(funcname);
755  trace.source.function = trace.object_function; // we cannot do better.
756  return trace;
757  }
758 
759 private:
760  details::handle<char**> _symbols;
761 };
762 
763 #endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
764 
765 #if BACKWARD_HAS_BFD == 1
766 
767 template <>
768 class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
769  public TraceResolverLinuxImplBase {
770 public:
771  TraceResolverLinuxImpl(): _bfd_loaded(false) {}
772 
773  template <class ST>
774  void load_stacktrace(ST&) {}
775 
776  ResolvedTrace resolve(ResolvedTrace trace) {
777  Dl_info symbol_info;
778 
779  // trace.addr is a virtual address in memory pointing to some code.
780  // Let's try to find from which loaded object it comes from.
781  // The loaded object can be yourself btw.
782  if (!dladdr(trace.addr, &symbol_info)) {
783  return trace; // dat broken trace...
784  }
785 
786  // Now we get in symbol_info:
787  // .dli_fname:
788  // pathname of the shared object that contains the address.
789  // .dli_fbase:
790  // where the object is loaded in memory.
791  // .dli_sname:
792  // the name of the nearest symbol to trace.addr, we expect a
793  // function name.
794  // .dli_saddr:
795  // the exact address corresponding to .dli_sname.
796 
797  if (symbol_info.dli_sname) {
798  trace.object_function = demangle(symbol_info.dli_sname);
799  }
800 
801  if (!symbol_info.dli_fname) {
802  return trace;
803  }
804 
805  trace.object_filename = symbol_info.dli_fname;
806  bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
807  if (!fobj.handle) {
808  return trace; // sad, we couldn't load the object :(
809  }
810 
811 
812  find_sym_result* details_selected; // to be filled.
813 
814  // trace.addr is the next instruction to be executed after returning
815  // from the nested stack frame. In C++ this usually relate to the next
816  // statement right after the function call that leaded to a new stack
817  // frame. This is not usually what you want to see when printing out a
818  // stacktrace...
819  find_sym_result details_call_site = find_symbol_details(fobj,
820  trace.addr, symbol_info.dli_fbase);
821  details_selected = &details_call_site;
822 
823 #if BACKWARD_HAS_UNWIND == 0
824  // ...this is why we also try to resolve the symbol that is right
825  // before the return address. If we are lucky enough, we will get the
826  // line of the function that was called. But if the code is optimized,
827  // we might get something absolutely not related since the compiler
828  // can reschedule the return address with inline functions and
829  // tail-call optimisation (among other things that I don't even know
830  // or cannot even dream about with my tiny limited brain).
831  find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
832  (void*) (uintptr_t(trace.addr) - 1),
833  symbol_info.dli_fbase);
834 
835  // In debug mode, we should always get the right thing(TM).
836  if (details_call_site.found && details_adjusted_call_site.found) {
837  // Ok, we assume that details_adjusted_call_site is a better estimation.
838  details_selected = &details_adjusted_call_site;
839  trace.addr = (void*) (uintptr_t(trace.addr) - 1);
840  }
841 
842  if (details_selected == &details_call_site && details_call_site.found) {
843  // we have to re-resolve the symbol in order to reset some
844  // internal state in BFD... so we can call backtrace_inliners
845  // thereafter...
846  details_call_site = find_symbol_details(fobj, trace.addr,
847  symbol_info.dli_fbase);
848  }
849 #endif // BACKWARD_HAS_UNWIND
850 
851  if (details_selected->found) {
852  if (details_selected->filename) {
853  trace.source.filename = details_selected->filename;
854  }
855  trace.source.line = details_selected->line;
856 
857  if (details_selected->funcname) {
858  // this time we get the name of the function where the code is
859  // located, instead of the function were the address is
860  // located. In short, if the code was inlined, we get the
861  // function correspoding to the code. Else we already got in
862  // trace.function.
863  trace.source.function = demangle(details_selected->funcname);
864 
865  if (!symbol_info.dli_sname) {
866  // for the case dladdr failed to find the symbol name of
867  // the function, we might as well try to put something
868  // here.
869  trace.object_function = trace.source.function;
870  }
871  }
872 
873  // Maybe the source of the trace got inlined inside the function
874  // (trace.source.function). Let's see if we can get all the inlined
875  // calls along the way up to the initial call site.
876  trace.inliners = backtrace_inliners(fobj, *details_selected);
877 
878 #if 0
879  if (trace.inliners.size() == 0) {
880  // Maybe the trace was not inlined... or maybe it was and we
881  // are lacking the debug information. Let's try to make the
882  // world better and see if we can get the line number of the
883  // function (trace.source.function) now.
884  //
885  // We will get the location of where the function start (to be
886  // exact: the first instruction that really start the
887  // function), not where the name of the function is defined.
888  // This can be quite far away from the name of the function
889  // btw.
890  //
891  // If the source of the function is the same as the source of
892  // the trace, we cannot say if the trace was really inlined or
893  // not. However, if the filename of the source is different
894  // between the function and the trace... we can declare it as
895  // an inliner. This is not 100% accurate, but better than
896  // nothing.
897 
898  if (symbol_info.dli_saddr) {
899  find_sym_result details = find_symbol_details(fobj,
900  symbol_info.dli_saddr,
901  symbol_info.dli_fbase);
902 
903  if (details.found) {
904  ResolvedTrace::SourceLoc diy_inliner;
905  diy_inliner.line = details.line;
906  if (details.filename) {
907  diy_inliner.filename = details.filename;
908  }
909  if (details.funcname) {
910  diy_inliner.function = demangle(details.funcname);
911  } else {
912  diy_inliner.function = trace.source.function;
913  }
914  if (diy_inliner != trace.source) {
915  trace.inliners.push_back(diy_inliner);
916  }
917  }
918  }
919  }
920 #endif
921  }
922 
923  return trace;
924  }
925 
926 private:
927  bool _bfd_loaded;
928 
929  using bfd_handle_t = details::handle<bfd*,
930  details::deleter<bfd_boolean, bfd*, &bfd_close>
931  >;
932 
933  using bfd_symtab_t = details::handle<asymbol**>;
934 
935 
936  struct bfd_fileobject {
937  bfd_handle_t handle;
938  bfd_vma base_addr;
939  bfd_symtab_t symtab;
940  bfd_symtab_t dynamic_symtab;
941  };
942 
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 
1150  ResolvedTrace resolve(ResolvedTrace trace) {
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:
1301  using dwfl_handle_t = details::handle<Dwfl*, details::deleter<void, Dwfl*, &dwfl_end>>;
1302  details::handle<Dwfl_Callbacks*, details::default_delete<Dwfl_Callbacks*> >
1303  _dwfl_cb;
1304  dwfl_handle_t _dwfl_handle;
1305  bool _dwfl_handle_initialized;
1306 
1307  // defined here because in C++98, template function cannot take locally
1308  // defined types... grrr.
1309  struct inliners_search_cb {
1310  void operator()(Dwarf_Die* die) {
1311  switch (dwarf_tag(die)) {
1312  const char* name;
1313  case DW_TAG_subprogram:
1314  if ((name = dwarf_diename(die))) {
1315  trace.source.function = name;
1316  }
1317  break;
1318 
1319  case DW_TAG_inlined_subroutine:
1320  ResolvedTrace::SourceLoc sloc;
1321  Dwarf_Attribute attr_mem;
1322 
1323  if ((name = dwarf_diename(die))) {
1324  sloc.function = name;
1325  }
1326  if ((name = die_call_file(die))) {
1327  sloc.filename = name;
1328  }
1329 
1330  Dwarf_Word line = 0, col = 0;
1331  dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
1332  &attr_mem), &line);
1333  dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
1334  &attr_mem), &col);
1335  sloc.line = line;
1336  sloc.col = col;
1337 
1338  trace.inliners.push_back(sloc);
1339  break;
1340  };
1341  }
1342  ResolvedTrace& trace;
1343  inliners_search_cb(ResolvedTrace& t): trace(t) {}
1344  };
1345 
1346 
1347  static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1348  Dwarf_Addr low, high;
1349 
1350  // continuous range
1351  if (dwarf_hasattr(die, DW_AT_low_pc) and
1352  dwarf_hasattr(die, DW_AT_high_pc)) {
1353  if (dwarf_lowpc(die, &low) != 0) {
1354  return false;
1355  }
1356  if (dwarf_highpc(die, &high) != 0) {
1357  Dwarf_Attribute attr_mem;
1358  Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
1359  Dwarf_Word value;
1360  if (dwarf_formudata(attr, &value) != 0) {
1361  return false;
1362  }
1363  high = low + value;
1364  }
1365  return pc >= low && pc < high;
1366  }
1367 
1368  // non-continuous range.
1369  Dwarf_Addr base;
1370  ptrdiff_t offset = 0;
1371  while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
1372  if (pc >= low && pc < high) {
1373  return true;
1374  }
1375  }
1376  return false;
1377  }
1378 
1379  static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
1380  Dwarf_Die* result) {
1381  if (dwarf_child(parent_die, result) != 0) {
1382  return 0;
1383  }
1384 
1385  Dwarf_Die* die = result;
1386  do {
1387  switch (dwarf_tag(die)) {
1388  case DW_TAG_subprogram:
1389  case DW_TAG_inlined_subroutine:
1390  if (die_has_pc(die, pc)) {
1391  return result;
1392  }
1393  };
1394  bool declaration = false;
1395  Dwarf_Attribute attr_mem;
1396  dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
1397  &attr_mem), &declaration);
1398  if (!declaration) {
1399  // let's be curious and look deeper in the tree,
1400  // function are not necessarily at the first level, but
1401  // might be nested inside a namespace, structure etc.
1402  Dwarf_Die die_mem;
1403  Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
1404  if (indie) {
1405  *result = die_mem;
1406  return result;
1407  }
1408  }
1409  } while (dwarf_siblingof(die, result) == 0);
1410  return 0;
1411  }
1412 
1413  template <typename CB>
1414  static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
1415  Dwarf_Addr pc, CB cb) {
1416  Dwarf_Die die_mem;
1417  if (dwarf_child(parent_die, &die_mem) != 0) {
1418  return false;
1419  }
1420 
1421  bool branch_has_pc = false;
1422  Dwarf_Die* die = &die_mem;
1423  do {
1424  bool declaration = false;
1425  Dwarf_Attribute attr_mem;
1426  dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
1427  if (!declaration) {
1428  // let's be curious and look deeper in the tree, function are
1429  // not necessarily at the first level, but might be nested
1430  // inside a namespace, structure, a function, an inlined
1431  // function etc.
1432  branch_has_pc = deep_first_search_by_pc(die, pc, cb);
1433  }
1434  if (!branch_has_pc) {
1435  branch_has_pc = die_has_pc(die, pc);
1436  }
1437  if (branch_has_pc) {
1438  cb(die);
1439  }
1440  } while (dwarf_siblingof(die, &die_mem) == 0);
1441  return branch_has_pc;
1442  }
1443 
1444  static const char* die_call_file(Dwarf_Die *die) {
1445  Dwarf_Attribute attr_mem;
1446  Dwarf_Sword file_idx = 0;
1447 
1448  dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
1449  &file_idx);
1450 
1451  if (file_idx == 0) {
1452  return 0;
1453  }
1454 
1455  Dwarf_Die die_mem;
1456  Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
1457  if (!cudie) {
1458  return 0;
1459  }
1460 
1461  Dwarf_Files* files = 0;
1462  size_t nfiles;
1463  dwarf_getsrcfiles(cudie, &files, &nfiles);
1464  if (!files) {
1465  return 0;
1466  }
1467 
1468  return dwarf_filesrc(files, file_idx, 0, 0);
1469  }
1470 
1471 };
1472 #endif // BACKWARD_HAS_DW == 1
1473 
1474 template<>
1475 class TraceResolverImpl<system_tag::linux_tag>:
1476  public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1477 
1478 #endif // BACKWARD_SYSTEM_LINUX
1479 
1481  public TraceResolverImpl<system_tag::current_tag> {};
1482 
1483 /*************** CODE SNIPPET ***************/
1484 
1485 class SourceFile {
1486 public:
1487  using lines_t = std::vector<std::pair<unsigned, std::string>>;
1488 
1490  SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
1491  bool is_open() const { return _file->is_open(); }
1492 
1493  lines_t& get_lines(unsigned line_start, unsigned line_count, lines_t& lines) {
1494  using namespace std;
1495  // This function make uses of the dumbest algo ever:
1496  // 1) seek(0)
1497  // 2) read lines one by one and discard until line_start
1498  // 3) read line one by one until line_start + line_count
1499  //
1500  // If you are getting snippets many time from the same file, it is
1501  // somewhat a waste of CPU, feel free to benchmark and propose a
1502  // better solution ;)
1503 
1504  _file->clear();
1505  _file->seekg(0);
1506  string line;
1507  unsigned line_idx;
1508 
1509  for (line_idx = 1; line_idx < line_start; ++line_idx) {
1510  std::getline(*_file, line);
1511  if (!*_file) {
1512  return lines;
1513  }
1514  }
1515 
1516  // think of it like a lambda in C++98 ;)
1517  // but look, I will reuse it two times!
1518  // What a good boy am I.
1519  struct isspace {
1520  bool operator()(char c) {
1521  return std::isspace(c);
1522  }
1523  };
1524 
1525  bool started = false;
1526  for (; line_idx < line_start + line_count; ++line_idx) {
1527  getline(*_file, line);
1528  if (!*_file) {
1529  return lines;
1530  }
1531  if (!started) {
1532  if (std::find_if(line.begin(), line.end(),
1533  not_isspace()) == line.end())
1534  continue;
1535  started = true;
1536  }
1537  lines.push_back(make_pair(line_idx, line));
1538  }
1539 
1540  lines.erase(
1541  std::find_if(lines.rbegin(), lines.rend(),
1542  not_isempty()).base(), lines.end()
1543  );
1544  return lines;
1545  }
1546 
1547  lines_t get_lines(unsigned line_start, unsigned line_count) {
1548  lines_t lines;
1549  return get_lines(line_start, line_count, lines);
1550  }
1551 
1552  // there is no find_if_not in C++98, lets do something crappy to
1553  // workaround.
1554  struct not_isspace {
1555  bool operator()(char c) {
1556  return !std::isspace(c);
1557  }
1558  };
1559  // and define this one here because C++98 is not happy with local defined
1560  // struct passed to template functions, fuuuu.
1561  struct not_isempty {
1562  bool operator()(const lines_t::value_type& p) {
1563  return !(std::find_if(p.second.begin(), p.second.end(),
1564  not_isspace()) == p.second.end());
1565  }
1566  };
1567 
1568  void swap(SourceFile& b) {
1569  _file.swap(b._file);
1570  }
1571 
1572 #ifdef BACKWARD_ATLEAST_CXX11
1573  SourceFile(SourceFile&& from): _file(0) {
1574  swap(from);
1575  }
1576  SourceFile& operator=(SourceFile&& from) {
1577  swap(from); return *this;
1578  }
1579 #else
1580  explicit SourceFile(const SourceFile& from) {
1581  // some sort of poor man's move semantic.
1582  swap(const_cast<SourceFile&>(from));
1583  }
1585  // some sort of poor man's move semantic.
1586  swap(const_cast<SourceFile&>(from)); return *this;
1587  }
1588 #endif
1589 
1590 private:
1591  details::handle<std::ifstream*,
1594 
1595 #ifdef BACKWARD_ATLEAST_CXX11
1596  SourceFile(const SourceFile&) = delete;
1597  SourceFile& operator=(const SourceFile&) = delete;
1598 #endif
1599 };
1600 
1602 public:
1604 
1605  lines_t get_snippet(const std::string& filename,
1606  unsigned line_start, unsigned context_size) {
1607 
1608  SourceFile& src_file = get_src_file(filename);
1609  unsigned start = line_start - context_size / 2;
1610  return src_file.get_lines(start, context_size);
1611  }
1612 
1614  const std::string& filename_a, unsigned line_a,
1615  const std::string& filename_b, unsigned line_b,
1616  unsigned context_size) {
1617  SourceFile& src_file_a = get_src_file(filename_a);
1618  SourceFile& src_file_b = get_src_file(filename_b);
1619 
1620  lines_t lines = src_file_a.get_lines(line_a - context_size / 4,
1621  context_size / 2);
1622  src_file_b.get_lines(line_b - context_size / 4, context_size / 2,
1623  lines);
1624  return lines;
1625  }
1626 
1627  lines_t get_coalesced_snippet(const std::string& filename,
1628  unsigned line_a, unsigned line_b, unsigned context_size) {
1629  SourceFile& src_file = get_src_file(filename);
1630 
1631  using std::min; using std::max;
1632  unsigned a = min(line_a, line_b);
1633  unsigned b = max(line_a, line_b);
1634 
1635  if ((b - a) < (context_size / 3)) {
1636  return src_file.get_lines((a + b - context_size + 1) / 2,
1637  context_size);
1638  }
1639 
1640  lines_t lines = src_file.get_lines(a - context_size / 4,
1641  context_size / 2);
1642  src_file.get_lines(b - context_size / 4, context_size / 2, lines);
1643  return lines;
1644  }
1645 
1646 
1647 private:
1650 
1651  SourceFile& get_src_file(const std::string& filename) {
1652  src_files_t::iterator it = _src_files.find(filename);
1653  if (it != _src_files.end()) {
1654  return it->second;
1655  }
1656  SourceFile& new_src_file = _src_files[filename];
1657  new_src_file = SourceFile(filename);
1658  return new_src_file;
1659  }
1660 };
1661 
1662 /*************** PRINTER ***************/
1663 
1664 #ifdef BACKWARD_SYSTEM_LINUX
1665 
1666 namespace Color {
1667  enum type {
1668  yellow = 33,
1669  purple = 35,
1670  reset = 39
1671  };
1672 }
1673 
1674 class Colorize {
1675 public:
1676  Colorize(std::ostream& os):
1677  _os(os), _reset(false), _use_colors(false) {}
1678 
1679  void activate() {
1680  _use_colors = true;
1681  // in a colorful environment, reset at the beginning
1682  set_color(Color::reset);
1683  }
1684 
1685  void activate_if_tty(std::FILE *desc) {
1686  if (isatty(fileno(desc))) {
1687  activate();
1688  }
1689  }
1690 
1691  void set_color(Color::type ccode) {
1692  if (!_use_colors) return;
1693 
1694  // I assume that the terminal can handle basic colors. Seriously I
1695  // don't want to deal with all the termcap shit.
1696  _os << "\033[" << static_cast<int>(ccode) << "m";
1697  _reset = (ccode != Color::reset);
1698  }
1699 
1700  ~Colorize() {
1701  if (_reset) {
1702  set_color(Color::reset);
1703  }
1704  }
1705 
1706 private:
1707  std::ostream& _os;
1708  bool _reset;
1709  bool _use_colors;
1710 };
1711 
1712 #else // ndef BACKWARD_SYSTEM_LINUX
1713 
1714 
1715 namespace Color {
1716  enum type {
1717  yellow = 0,
1718  purple = 0,
1719  reset = 0
1720  };
1721 }
1722 
1723 class Colorize {
1724 public:
1725  Colorize(std::ostream&) {}
1726  void activate() {}
1729 };
1730 
1731 #endif // BACKWARD_SYSTEM_LINUX
1732 
1733 class Printer {
1734 public:
1735  bool snippet;
1736  bool color;
1737  bool address;
1738  bool object;
1741 
1743  snippet(true),
1744  color(true),
1745  address(false),
1746  object(false),
1747  inliner_context_size(5),
1748  trace_context_size(7)
1749  {}
1750 
1751  template <typename ST>
1752  FILE* print(ST& st, FILE* os = stderr) {
1753  std::stringstream ss;
1754  Colorize colorize(ss);
1755  if (color) {
1756  colorize.activate_if_tty(os);
1757  }
1758  print(st, ss, colorize);
1759  fprintf(os, "%s", ss.str().c_str());
1760  return os;
1761  }
1762 
1763  template <typename ST>
1764  void print(ST& st, std::ostream& os) {
1765  Colorize colorize(os);
1766  if (color) {
1767  colorize.activate();
1768  }
1769  print(st, os, colorize);
1770  }
1771 
1772  template <typename IT>
1773  FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) {
1774  std::stringstream ss;
1775  Colorize colorize(ss);
1776  if (color) {
1777  colorize.activate_if_tty(os);
1778  }
1779  print(begin, end, ss, thread_id, colorize);
1780  fprintf(os, "%s", ss.str().c_str());
1781  return os;
1782  }
1783 
1784  template <typename IT>
1785  void print(IT begin, IT end, std::ostream& os, size_t thread_id = 0) {
1786  Colorize colorize(os);
1787  if (color) {
1788  colorize.activate();
1789  }
1790  print(begin, end, os, thread_id, colorize);
1791  }
1792 
1793 private:
1796 
1797  template <typename ST>
1798  void print(ST& st, std::ostream& os, Colorize& colorize) {
1799  print_header(os, st.thread_id());
1800  _resolver.load_stacktrace(st);
1801  for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1802  print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize);
1803  }
1804  }
1805 
1806  template <typename IT>
1807  void print(IT begin, IT end, std::ostream& os, size_t thread_id, Colorize& colorize) {
1808  print_header(os, thread_id);
1809  for (; begin != end; ++begin) {
1810  print_trace(os, *begin, colorize);
1811  }
1812  }
1813 
1814  void print_header(std::ostream& os, unsigned thread_id) {
1815  os << "Stack trace (most recent call last)";
1816  if (thread_id) {
1817  os << " in thread " << thread_id;
1818  }
1819  os << ":\n";
1820  }
1821 
1822  void print_trace(std::ostream& os, const ResolvedTrace& trace,
1823  Colorize& colorize) {
1824  os << "#"
1825  << std::left << std::setw(2) << trace.idx
1826  << std::right;
1827  bool already_indented = true;
1828 
1829  if (!trace.source.filename.size() || object) {
1830  os << " Object \""
1831  << trace.object_filename
1832  << ", at "
1833  << trace.addr
1834  << ", in "
1835  << trace.object_function
1836  << "\n";
1837  already_indented = false;
1838  }
1839 
1840  for (size_t inliner_idx = trace.inliners.size();
1841  inliner_idx > 0; --inliner_idx) {
1842  if (!already_indented) {
1843  os << " ";
1844  }
1845  const ResolvedTrace::SourceLoc& inliner_loc
1846  = trace.inliners[inliner_idx-1];
1847  print_source_loc(os, " | ", inliner_loc);
1848  if (snippet) {
1849  print_snippet(os, " | ", inliner_loc,
1850  colorize, Color::purple, inliner_context_size);
1851  }
1852  already_indented = false;
1853  }
1854 
1855  if (trace.source.filename.size()) {
1856  if (!already_indented) {
1857  os << " ";
1858  }
1859  print_source_loc(os, " ", trace.source, trace.addr);
1860  if (snippet) {
1861  print_snippet(os, " ", trace.source,
1862  colorize, Color::yellow, trace_context_size);
1863  }
1864  }
1865  }
1866 
1867  void print_snippet(std::ostream& os, const char* indent,
1868  const ResolvedTrace::SourceLoc& source_loc,
1869  Colorize& colorize, Color::type color_code,
1870  int context_size)
1871  {
1872  using namespace std;
1873  using lines_t = SnippetFactory::lines_t;
1874 
1875  lines_t lines = _snippets.get_snippet(source_loc.filename,
1876  source_loc.line, context_size);
1877 
1878  for (lines_t::const_iterator it = lines.begin();
1879  it != lines.end(); ++it) {
1880  if (it-> first == source_loc.line) {
1881  colorize.set_color(color_code);
1882  os << indent << ">";
1883  } else {
1884  os << indent << " ";
1885  }
1886  os << std::setw(4) << it->first
1887  << ": "
1888  << it->second
1889  << "\n";
1890  if (it-> first == source_loc.line) {
1891  colorize.set_color(Color::reset);
1892  }
1893  }
1894  }
1895 
1896  void print_source_loc(std::ostream& os, const char* indent,
1897  const ResolvedTrace::SourceLoc& source_loc,
1898  void* addr=0) {
1899  os << indent
1900  << "Source \""
1901  << source_loc.filename
1902  << "\", line "
1903  << source_loc.line
1904  << ", in "
1905  << source_loc.function;
1906 
1907  if (address && addr != 0) {
1908  os << " [" << addr << "]";
1909  }
1910  os << "\n";
1911  }
1912 };
1913 
1914 /*************** SIGNALS HANDLING ***************/
1915 
1916 #ifdef BACKWARD_SYSTEM_LINUX
1917 
1918 
1919 class SignalHandling {
1920 public:
1921  static std::vector<int> make_default_signals() {
1922  const int posix_signals[] = {
1923  // default action: Core
1924  SIGILL,
1925  SIGABRT,
1926  SIGFPE,
1927  SIGSEGV,
1928  SIGBUS,
1929  // I am not sure the following signals should be enabled by
1930  // default:
1931  // default action: Term
1932  SIGHUP,
1933  SIGINT,
1934  SIGPIPE,
1935  SIGALRM,
1936  SIGTERM,
1937  SIGUSR1,
1938  SIGUSR2,
1939  SIGPOLL,
1940  SIGPROF,
1941  SIGVTALRM,
1942  SIGIO,
1943  SIGPWR,
1944  // default action: Core
1945  SIGQUIT,
1946  SIGSYS,
1947  SIGTRAP,
1948  SIGXCPU,
1949  SIGXFSZ
1950  };
1951  return std::vector<int>(posix_signals, posix_signals + sizeof posix_signals / sizeof posix_signals[0] );
1952  }
1953 
1954  SignalHandling(const std::vector<int>& posix_signals = make_default_signals()):
1955  _loaded(false) {
1956  bool success = true;
1957 
1958  const size_t stack_size = 1024 * 1024 * 8;
1959  _stack_content.reset((char*)malloc(stack_size));
1960  if (_stack_content) {
1961  stack_t ss;
1962  ss.ss_sp = _stack_content.get();
1963  ss.ss_size = stack_size;
1964  ss.ss_flags = 0;
1965  if (sigaltstack(&ss, 0) < 0) {
1966  success = false;
1967  }
1968  } else {
1969  success = false;
1970  }
1971 
1972  for (size_t i = 0; i < posix_signals.size(); ++i) {
1973  struct sigaction action;
1974  memset(&action, 0, sizeof action);
1975  action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1976  SA_RESETHAND);
1977  sigfillset(&action.sa_mask);
1978  sigdelset(&action.sa_mask, posix_signals[i]);
1979  action.sa_sigaction = &sig_handler;
1980 
1981  int r = sigaction(posix_signals[i], &action, 0);
1982  if (r < 0) success = false;
1983  }
1984 
1985  _loaded = success;
1986  }
1987 
1988  bool loaded() const { return _loaded; }
1989 
1990 private:
1991  details::handle<char*> _stack_content;
1992  bool _loaded;
1993 
1994  static void sig_handler(int, siginfo_t* info, void* _ctx) {
1995  ucontext_t *uctx = (ucontext_t*) _ctx;
1996 
1997  StackTrace st;
1998  void* error_addr = 0;
1999 #ifdef REG_RIP // x86_64
2000  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
2001 #elif defined(REG_EIP) // x86_32
2002  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
2003 #elif defined(__arm__)
2004  error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.arm_pc);
2005 #else
2006 # warning ":/ sorry, ain't know no nothing none not of your architecture!"
2007 #endif
2008  if (error_addr) {
2009  st.load_from(error_addr, 32);
2010  } else {
2011  st.load_here(32);
2012  }
2013 
2014  Printer printer;
2015  printer.address = true;
2016  printer.print(st, stderr);
2017 
2018 #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
2019  psiginfo(info, 0);
2020 #endif
2021 
2022  // try to forward the signal.
2023  raise(info->si_signo);
2024 
2025  // terminate the process immediately.
2026  puts("watf? exit");
2027  _exit(EXIT_FAILURE);
2028  }
2029 };
2030 
2031 #endif // BACKWARD_SYSTEM_LINUX
2032 
2033 #ifdef BACKWARD_SYSTEM_UNKNOWN
2034 
2036 public:
2037  SignalHandling(const std::vector<int>& = std::vector<int>()) {}
2038  bool init() { return false; }
2039  bool loaded() { return false; }
2040 };
2041 
2042 #endif // BACKWARD_SYSTEM_UNKNOWN
2043 
2044 }
2045 
2046 #endif /* H_GUARD */
backward::TraceResolverImpl< system_tag::unknown_tag >::load_stacktrace
void load_stacktrace(ST &)
Definition: backward.hpp:702
backward::Printer::_resolver
TraceResolver _resolver
Definition: backward.hpp:1794
backward::details::handle::handle
handle(const handle &from)
Definition: backward.hpp:341
backward::details::rm_ptr< const T * >::type
const T type
Definition: backward.hpp:295
backward::StackTraceImpl
Definition: backward.hpp:493
backward::Printer::print
void print(ST &st, std::ostream &os)
Definition: backward.hpp:1764
backward::ResolvedTrace::SourceLoc::function
std::string function
Definition: backward.hpp:445
backward::TraceResolver
Definition: backward.hpp:1480
backward::Colorize
Definition: backward.hpp:1723
backward::SourceFile::not_isspace
Definition: backward.hpp:1554
backward::Trace::idx
unsigned idx
Definition: backward.hpp:433
backward::details::hashtable::type
std::map< K, V > type
Definition: backward.hpp:240
backward::ResolvedTrace
Definition: backward.hpp:442
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
backward::Printer::print_snippet
void print_snippet(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, Colorize &colorize, Color::type color_code, int context_size)
Definition: backward.hpp:1867
backward::SourceFile::get_lines
lines_t get_lines(unsigned line_start, unsigned line_count)
Definition: backward.hpp:1547
backward::SnippetFactory::get_snippet
lines_t get_snippet(const std::string &filename, unsigned line_start, unsigned context_size)
Definition: backward.hpp:1605
backward::Printer::trace_context_size
int trace_context_size
Definition: backward.hpp:1740
backward::details::handle::operator*
ref_t operator*()
Definition: backward.hpp:380
backward::SourceFile::lines_t
std::vector< std::pair< unsigned, std::string > > lines_t
Definition: backward.hpp:1487
backward::details::deleter
Definition: backward.hpp:298
backward::details::demangler_impl
Definition: backward.hpp:393
backward::TraceResolverImpl
Definition: backward.hpp:694
backward::Color::reset
@ reset
Definition: backward.hpp:1719
backward::StackTraceImpl::operator[]
Trace operator[](size_t)
Definition: backward.hpp:496
backward::Printer::print
FILE * print(ST &st, FILE *os=stderr)
Definition: backward.hpp:1752
backward::details::handle::release
T release()
Definition: backward.hpp:364
backward::details::demangler_impl::demangle
static std::string demangle(const char *funcname)
Definition: backward.hpp:394
backward::Printer::object
bool object
Definition: backward.hpp:1738
backward::ResolvedTrace::SourceLoc::SourceLoc
SourceLoc()
Definition: backward.hpp:450
backward::SignalHandling::init
bool init()
Definition: backward.hpp:2038
backward::details::default_delete::operator()
void operator()(T &ptr) const
Definition: backward.hpp:307
backward::ResolvedTrace::SourceLoc::line
unsigned line
Definition: backward.hpp:447
backward::Printer::print
void print(IT begin, IT end, std::ostream &os, size_t thread_id=0)
Definition: backward.hpp:1785
backward::Printer::color
bool color
Definition: backward.hpp:1736
backward::SnippetFactory::_src_files
src_files_t _src_files
Definition: backward.hpp:1649
backward::StackTraceImpl::thread_id
unsigned thread_id() const
Definition: backward.hpp:499
backward::details::handle::operator=
handle & operator=(const handle &from)
Definition: backward.hpp:345
backward::details::handle::_val
T _val
Definition: backward.hpp:314
backward::Printer::print_header
void print_header(std::ostream &os, unsigned thread_id)
Definition: backward.hpp:1814
backward::details::handle::operator&
T * operator&()
Definition: backward.hpp:385
ogdf::tlp::Attribute::size
@ size
backward::SourceFile::not_isempty::operator()
bool operator()(const lines_t::value_type &p)
Definition: backward.hpp:1562
backward::Printer::print_source_loc
void print_source_loc(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, void *addr=0)
Definition: backward.hpp:1896
backward::Color::yellow
@ yellow
Definition: backward.hpp:1717
backward::system_tag::current_tag
unknown_tag current_tag
Definition: backward.hpp:260
backward::details::handle::_empty
bool _empty
Definition: backward.hpp:316
backward::SnippetFactory::get_combined_snippet
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:1613
backward::details::handle< std::ifstream *, backward::details::default_delete< std::ifstream * > >::const_ref_t
const typename rm_ptr< std::ifstream * >::type & const_ref_t
Definition: backward.hpp:379
backward::Colorize::set_color
void set_color(Color::type)
Definition: backward.hpp:1728
backward::details::default_delete
Definition: backward.hpp:306
backward::details::rm_ptr
Definition: backward.hpp:289
backward::Colorize::activate_if_tty
void activate_if_tty()
Definition: backward.hpp:1727
backward::ResolvedTrace::SourceLoc::operator!=
bool operator!=(const SourceLoc &b) const
Definition: backward.hpp:459
backward::Printer::print
void print(IT begin, IT end, std::ostream &os, size_t thread_id, Colorize &colorize)
Definition: backward.hpp:1807
backward::details::handle::operator->
const T operator->() const
Definition: backward.hpp:376
IntTypes.h
backward::Printer::snippet
bool snippet
Definition: backward.hpp:1735
backward::details::handle::operator[]
ref_t operator[](size_t idx)
Definition: backward.hpp:382
backward::Color::purple
@ purple
Definition: backward.hpp:1718
backward::StackTraceImpl::load_from
size_t load_from(void *, size_t=0)
Definition: backward.hpp:498
r
int r[]
Definition: hierarchical-ranking.cpp:8
backward::ResolvedTrace::ResolvedTrace
ResolvedTrace()
Definition: backward.hpp:483
backward::Printer::Printer
Printer()
Definition: backward.hpp:1742
backward::SourceFile::get_lines
lines_t & get_lines(unsigned line_start, unsigned line_count, lines_t &lines)
Definition: backward.hpp:1493
backward::SourceFile::not_isempty
Definition: backward.hpp:1561
backward::Printer::print
void print(ST &st, std::ostream &os, Colorize &colorize)
Definition: backward.hpp:1798
backward::Color::type
type
Definition: backward.hpp:1716
backward::SourceFile::not_isspace::operator()
bool operator()(char c)
Definition: backward.hpp:1555
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:243
backward::Printer::print
FILE * print(IT begin, IT end, FILE *os=stderr, size_t thread_id=0)
Definition: backward.hpp:1773
backward::SnippetFactory::get_coalesced_snippet
lines_t get_coalesced_snippet(const std::string &filename, unsigned line_a, unsigned line_b, unsigned context_size)
Definition: backward.hpp:1627
backward::SignalHandling
Definition: backward.hpp:2035
backward::details::handle::swap
void swap(handle &b)
Definition: backward.hpp:368
backward::SourceFile::_file
details::handle< std::ifstream *, details::default_delete< std::ifstream * > > _file
Definition: backward.hpp:1593
backward::SourceFile::is_open
bool is_open() const
Definition: backward.hpp:1491
backward::details::rm_ptr::type
T type
Definition: backward.hpp:289
backward::ResolvedTrace::source
SourceLoc source
Definition: backward.hpp:475
backward::details::handle::handle
handle(T val)
Definition: backward.hpp:331
backward::SignalHandling::SignalHandling
SignalHandling(const std::vector< int > &=std::vector< int >())
Definition: backward.hpp:2037
backward::ResolvedTrace::object_function
std::string object_function
Definition: backward.hpp:469
backward::SourceFile::SourceFile
SourceFile(const SourceFile &from)
Definition: backward.hpp:1580
backward::details::handle::get
T get()
Definition: backward.hpp:361
backward::Trace::addr
void * addr
Definition: backward.hpp:432
backward::details::rm_ptr< T * >::type
T type
Definition: backward.hpp:292
backward::SourceFile::swap
void swap(SourceFile &b)
Definition: backward.hpp:1568
backward::SnippetFactory::src_files_t
details::hashtable< std::string, SourceFile >::type src_files_t
Definition: backward.hpp:1648
backward::Printer
Definition: backward.hpp:1733
backward::SnippetFactory::lines_t
SourceFile::lines_t lines_t
Definition: backward.hpp:1603
backward::details::handle::operator*
const_ref_t operator*() const
Definition: backward.hpp:381
backward::Trace
Definition: backward.hpp:431
backward::details::demangler
Definition: backward.hpp:424
backward::StackTraceImpl::size
size_t size() const
Definition: backward.hpp:495
std
Definition: GML.h:110
ogdf::end
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)
backward::details::handle::operator->
T operator->()
Definition: backward.hpp:375
backward::StackTraceImpl::load_here
size_t load_here(size_t=0)
Definition: backward.hpp:497
backward::details::deleter::operator()
void operator()(U &ptr) const
Definition: backward.hpp:300
ogdf::print
void print(std::ostream &os, const Array< E, INDEX > &a, char delim=' ')
Prints array a to output stream os using delimiter delim.
Definition: Array.h:967
backward::SourceFile::operator=
SourceFile & operator=(const SourceFile &from)
Definition: backward.hpp:1584
backward::StackTrace
Definition: backward.hpp:688
backward::SnippetFactory::get_src_file
SourceFile & get_src_file(const std::string &filename)
Definition: backward.hpp:1651
backward::SourceFile::SourceFile
SourceFile()
Definition: backward.hpp:1489
backward::details::handle
Definition: backward.hpp:313
backward::details::handle::reset
void reset(T new_val)
Definition: backward.hpp:351
backward::SignalHandling::loaded
bool loaded()
Definition: backward.hpp:2039
backward::ResolvedTrace::SourceLoc
Definition: backward.hpp:444
backward::SourceFile::SourceFile
SourceFile(const std::string &path)
Definition: backward.hpp:1490
backward::SnippetFactory
Definition: backward.hpp:1601
backward::Colorize::activate
void activate()
Definition: backward.hpp:1726
backward::ResolvedTrace::source_locs_t
std::vector< SourceLoc > source_locs_t
Definition: backward.hpp:480
backward::details::handle< std::ifstream *, backward::details::default_delete< std::ifstream * > >::ref_t
typename rm_ptr< std::ifstream * >::type & ref_t
Definition: backward.hpp:378
backward::ResolvedTrace::SourceLoc::filename
std::string filename
Definition: backward.hpp:446
backward::ResolvedTrace::SourceLoc::col
unsigned col
Definition: backward.hpp:448
backward::ResolvedTrace::object_filename
std::string object_filename
Definition: backward.hpp:465
backward::details::hashtable
Definition: backward.hpp:239
backward::details::handle::handle
handle()
Definition: backward.hpp:330
backward::Printer::inliner_context_size
int inliner_context_size
Definition: backward.hpp:1739
backward::Trace::Trace
Trace(void *_addr, size_t _idx)
Definition: backward.hpp:438
backward::ResolvedTrace::SourceLoc::operator==
bool operator==(const SourceLoc &b) const
Definition: backward.hpp:452
backward::details::handle::~handle
~handle()
Definition: backward.hpp:324
backward::details::move
T & move(T &v)
Definition: backward.hpp:245
backward::Printer::address
bool address
Definition: backward.hpp:1737
backward::Trace::Trace
Trace()
Definition: backward.hpp:435
backward::ResolvedTrace::inliners
source_locs_t inliners
Definition: backward.hpp:481
backward::Printer::print_trace
void print_trace(std::ostream &os, const ResolvedTrace &trace, Colorize &colorize)
Definition: backward.hpp:1822
backward::Printer::_snippets
SnippetFactory _snippets
Definition: backward.hpp:1795
backward
Definition: backward.hpp:236
backward::TraceResolverImpl< system_tag::unknown_tag >::resolve
ResolvedTrace resolve(ResolvedTrace t)
Definition: backward.hpp:703
backward::StackTraceImpl::skip_n_firsts
void skip_n_firsts(size_t)
Definition: backward.hpp:500
backward::ResolvedTrace::ResolvedTrace
ResolvedTrace(const Trace &mini_trace)
Definition: backward.hpp:485
backward::Colorize::Colorize
Colorize(std::ostream &)
Definition: backward.hpp:1725
backward::SourceFile
Definition: backward.hpp:1485