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