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>
move(const T & v)243 const T& move(const T& v) { return v; }
244 template <typename T>
move(T & v)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>
operator ()backward::details::deleter300 void operator()(U& ptr) const {
301 (*F)(ptr);
302 }
303 };
304
305 template <typename T>
306 struct default_delete {
operator ()backward::details::default_delete307 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:
~handle()324 ~handle() {
325 if (!_empty) {
326 Deleter()(_val);
327 }
328 }
329
handle()330 explicit handle(): _val(), _empty(true) {}
handle(T val)331 explicit handle(T val): _val(val), _empty(false) {}
332
333 #ifdef BACKWARD_ATLEAST_CXX11
handle(handle && from)334 handle(handle&& from): _empty(true) {
335 swap(from);
336 }
operator =(handle && from)337 handle& operator=(handle&& from) {
338 swap(from); return *this;
339 }
340 #else
handle(const handle & from)341 explicit handle(const handle& from): _empty(true) {
342 // some sort of poor man's move semantic.
343 swap(const_cast<handle&>(from));
344 }
operator =(const handle & from)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
reset(T new_val)351 void reset(T new_val) {
352 handle tmp(new_val);
353 swap(tmp);
354 }
operator const dummy*() const355 operator const dummy*() const {
356 if (_empty) {
357 return 0;
358 }
359 return reinterpret_cast<const dummy*>(_val);
360 }
get()361 T get() {
362 return _val;
363 }
release()364 T release() {
365 _empty = true;
366 return _val;
367 }
swap(handle & b)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
operator ->()375 T operator->() { return _val; }
operator ->() const376 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&;
operator *()380 ref_t operator*() { return *_val; }
operator *() const381 const_ref_t operator*() const { return *_val; }
operator [](size_t idx)382 ref_t operator[](size_t idx) { return _val[idx]; }
383
384 // Watch out, we've got a badass over here
operator &()385 T* operator&() {
386 _empty = false;
387 return &_val;
388 }
389 };
390
391 // Default demangler implementation (do nothing).
392 template <typename TAG>
393 struct demangler_impl {
demanglebackward::details::demangler_impl394 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> {
demangler_implbackward::details::demangler_impl403 demangler_impl(): _demangle_buffer_length(0) {}
404
demanglebackward::details::demangler_impl405 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
Tracebackward::Trace435 Trace():
436 addr(0), idx(0) {}
437
Tracebackward::Trace438 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
SourceLocbackward::ResolvedTrace::SourceLoc450 SourceLoc(): line(0), col(0) {}
451
operator ==backward::ResolvedTrace::SourceLoc452 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
operator !=backward::ResolvedTrace::SourceLoc459 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.
475 SourceLoc source;
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>;
481 source_locs_t inliners;
482
ResolvedTracebackward::ResolvedTrace483 ResolvedTrace():
484 Trace() {}
ResolvedTracebackward::ResolvedTrace485 ResolvedTrace(const Trace& mini_trace):
486 Trace(mini_trace) {}
487 };
488
489 /*************** STACK TRACE ***************/
490
491 // default implemention.
492 template <typename TAG>
493 class StackTraceImpl {
494 public:
size() const495 size_t size() const { return 0; }
operator [](size_t)496 Trace operator[](size_t) { return Trace(); }
load_here(size_t=0)497 size_t load_here(size_t=0) { return 0; }
load_from(void *,size_t=0)498 size_t load_from(void*, size_t=0) { return 0; }
thread_id() const499 unsigned thread_id() const { return 0; }
skip_n_firsts(size_t)500 void skip_n_firsts(size_t) { }
501 };
502
503 #ifdef BACKWARD_SYSTEM_LINUX
504
505 class StackTraceLinuxImplBase {
506 public:
StackTraceLinuxImplBase()507 StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
508
thread_id() const509 unsigned thread_id() const {
510 return _thread_id;
511 }
512
skip_n_firsts(size_t n)513 void skip_n_firsts(size_t n) { _skip = n; }
514
515 protected:
load_thread_info()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
skip_n_firsts() const525 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:
size() const534 size_t size() const {
535 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
536 }
operator [](size_t idx)537 Trace operator[](size_t idx) {
538 if (idx >= size()) {
539 return Trace();
540 }
541 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
542 }
begin()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:
operator ()(F & f,size_t depth)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
backtrace_trampoline(_Unwind_Context * ctx,void * self)575 static _Unwind_Reason_Code backtrace_trampoline(
576 _Unwind_Context* ctx, void *self) {
577 return ((Unwinder*)self)->backtrace(ctx);
578 }
579
backtrace(_Unwind_Context * ctx)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>
unwind(F f,size_t depth)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
load_here(size_t depth=32)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 }
load_from(void * addr,size_t depth=32)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;
callbackbackward::StackTraceImpl::callback641 callback(StackTraceImpl& _self): self(_self) {}
642
operator ()backward::StackTraceImpl::callback643 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
load_here(size_t depth=32)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
load_from(void * addr,size_t depth=32)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
688 class StackTrace:
689 public StackTraceImpl<system_tag::current_tag> {};
690
691 /*************** TRACE RESOLVER ***************/
692
693 template <typename TAG>
694 class TraceResolverImpl;
695
696 #ifdef BACKWARD_SYSTEM_UNKNOWN
697
698 template <>
699 class TraceResolverImpl<system_tag::unknown_tag> {
700 public:
701 template <class ST>
load_stacktrace(ST &)702 void load_stacktrace(ST&) {}
resolve(ResolvedTrace t)703 ResolvedTrace resolve(ResolvedTrace t) {
704 return t;
705 }
706 };
707
708 #endif
709
710 #ifdef BACKWARD_SYSTEM_LINUX
711
712 class TraceResolverLinuxImplBase {
713 protected:
demangle(const char * funcname)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>
load_stacktrace(ST & 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
resolve(ResolvedTrace trace)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:
TraceResolverLinuxImpl()771 TraceResolverLinuxImpl(): _bfd_loaded(false) {}
772
773 template <class ST>
load_stacktrace(ST &)774 void load_stacktrace(ST&) {}
775
resolve(ResolvedTrace trace)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
943 using fobj_bfd_map_t = details::hashtable<std::string, bfd_fileobject>::type;
944 fobj_bfd_map_t _fobj_bfd_map;
945
load_object_with_bfd(const std::string & filename_object)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
find_symbol_details(bfd_fileobject & fobj,void * addr,void * base_addr)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
find_in_section_trampoline(bfd *,asection * section,void * data)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
find_in_section(bfd_vma addr,bfd_vma base_addr,bfd_fileobject & fobj,asection * section,find_sym_result & result)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
backtrace_inliners(bfd_fileobject & fobj,find_sym_result previous_result)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.
1103 ResolvedTrace::source_locs_t results;
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
cstrings_eq(const char * a,const char * b)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:
TraceResolverLinuxImpl()1145 TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
1146
1147 template <class ST>
load_stacktrace(ST &)1148 void load_stacktrace(ST&) {}
1149
resolve(ResolvedTrace trace)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 {
operator ()backward::TraceResolverLinuxImpl::inliners_search_cb1310 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;
inliners_search_cbbackward::TraceResolverLinuxImpl::inliners_search_cb1343 inliners_search_cb(ResolvedTrace& t): trace(t) {}
1344 };
1345
1346
die_has_pc(Dwarf_Die * die,Dwarf_Addr pc)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
find_fundie_by_pc(Dwarf_Die * parent_die,Dwarf_Addr pc,Dwarf_Die * result)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>
deep_first_search_by_pc(Dwarf_Die * parent_die,Dwarf_Addr pc,CB 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
die_call_file(Dwarf_Die * die)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
1480 class TraceResolver:
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
SourceFile()1489 SourceFile() {}
SourceFile(const std::string & path)1490 SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
is_open() const1491 bool is_open() const { return _file->is_open(); }
1492
get_lines(unsigned line_start,unsigned line_count,lines_t & lines)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
get_lines(unsigned line_start,unsigned line_count)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 {
operator ()backward::SourceFile::not_isspace1555 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 {
operator ()backward::SourceFile::not_isempty1562 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
swap(SourceFile & b)1568 void swap(SourceFile& b) {
1569 _file.swap(b._file);
1570 }
1571
1572 #ifdef BACKWARD_ATLEAST_CXX11
SourceFile(SourceFile && from)1573 SourceFile(SourceFile&& from): _file(0) {
1574 swap(from);
1575 }
operator =(SourceFile && from)1576 SourceFile& operator=(SourceFile&& from) {
1577 swap(from); return *this;
1578 }
1579 #else
SourceFile(const SourceFile & from)1580 explicit SourceFile(const SourceFile& from) {
1581 // some sort of poor man's move semantic.
1582 swap(const_cast<SourceFile&>(from));
1583 }
operator =(const SourceFile & from)1584 SourceFile& operator=(const SourceFile& from) {
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*,
1592 details::default_delete<std::ifstream*>
1593 > _file;
1594
1595 #ifdef BACKWARD_ATLEAST_CXX11
1596 SourceFile(const SourceFile&) = delete;
1597 SourceFile& operator=(const SourceFile&) = delete;
1598 #endif
1599 };
1600
1601 class SnippetFactory {
1602 public:
1603 using lines_t = SourceFile::lines_t;
1604
get_snippet(const std::string & filename,unsigned line_start,unsigned context_size)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
get_combined_snippet(const std::string & filename_a,unsigned line_a,const std::string & filename_b,unsigned line_b,unsigned context_size)1613 lines_t get_combined_snippet(
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
get_coalesced_snippet(const std::string & filename,unsigned line_a,unsigned line_b,unsigned context_size)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:
1648 using src_files_t = details::hashtable<std::string, SourceFile>::type;
1649 src_files_t _src_files;
1650
get_src_file(const std::string & filename)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:
Colorize(std::ostream & os)1676 Colorize(std::ostream& os):
1677 _os(os), _reset(false), _use_colors(false) {}
1678
activate()1679 void activate() {
1680 _use_colors = true;
1681 // in a colorful environment, reset at the beginning
1682 set_color(Color::reset);
1683 }
1684
activate_if_tty(std::FILE * desc)1685 void activate_if_tty(std::FILE *desc) {
1686 if (isatty(fileno(desc))) {
1687 activate();
1688 }
1689 }
1690
set_color(Color::type ccode)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
~Colorize()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:
Colorize(std::ostream &)1725 Colorize(std::ostream&) {}
activate()1726 void activate() {}
activate_if_tty()1727 void activate_if_tty() {}
set_color(Color::type)1728 void set_color(Color::type) {}
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;
1739 int inliner_context_size;
1740 int trace_context_size;
1741
Printer()1742 Printer():
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>
print(ST & st,FILE * os=stderr)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>
print(ST & st,std::ostream & os)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>
print(IT begin,IT end,FILE * os=stderr,size_t thread_id=0)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>
print(IT begin,IT end,std::ostream & os,size_t thread_id=0)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:
1794 TraceResolver _resolver;
1795 SnippetFactory _snippets;
1796
1797 template <typename ST>
print(ST & st,std::ostream & os,Colorize & colorize)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>
print(IT begin,IT end,std::ostream & os,size_t thread_id,Colorize & colorize)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
print_header(std::ostream & os,unsigned thread_id)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
print_trace(std::ostream & os,const ResolvedTrace & trace,Colorize & colorize)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
print_snippet(std::ostream & os,const char * indent,const ResolvedTrace::SourceLoc & source_loc,Colorize & colorize,Color::type color_code,int context_size)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
print_source_loc(std::ostream & os,const char * indent,const ResolvedTrace::SourceLoc & source_loc,void * addr=0)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:
make_default_signals()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
SignalHandling(const std::vector<int> & posix_signals=make_default_signals ())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
loaded() const1988 bool loaded() const { return _loaded; }
1989
1990 private:
1991 details::handle<char*> _stack_content;
1992 bool _loaded;
1993
sig_handler(int,siginfo_t * info,void * _ctx)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
2035 class SignalHandling {
2036 public:
SignalHandling(const std::vector<int> &=std::vector<int> ())2037 SignalHandling(const std::vector<int>& = std::vector<int>()) {}
init()2038 bool init() { return false; }
loaded()2039 bool loaded() { return false; }
2040 };
2041
2042 #endif // BACKWARD_SYSTEM_UNKNOWN
2043
2044 }
2045
2046 #endif /* H_GUARD */
2047