Loading [MathJax]/jax/input/TeX/config.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
backward.hpp
Go to the documentation of this file.
1/*
2 * backward.hpp
3 * Copyright 2013 Google Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifndef H_6B9572DA_A64B_49E6_B234_051480991C89
25#define H_6B9572DA_A64B_49E6_B234_051480991C89
26
27#ifndef __cplusplus
28# error "It's not going to compile without a C++ compiler..."
29#endif
30
31#if defined(BACKWARD_CXX11)
32#elif defined(BACKWARD_CXX98)
33#else
34# if __cplusplus >= 201103L
35# define BACKWARD_CXX11
36# define BACKWARD_ATLEAST_CXX11
37# define BACKWARD_ATLEAST_CXX98
38# else
39# define BACKWARD_CXX98
40# define BACKWARD_ATLEAST_CXX98
41# endif
42#endif
43
44// You can define one of the following (or leave it to the auto-detection):
45//
46// #define BACKWARD_SYSTEM_LINUX
47// - specialization for linux
48//
49// #define BACKWARD_SYSTEM_UNKNOWN
50// - placebo implementation, does nothing.
51//
52#if defined(BACKWARD_SYSTEM_LINUX)
53#elif defined(BACKWARD_SYSTEM_UNKNOWN)
54#else
55# if defined(__linux)
56# define BACKWARD_SYSTEM_LINUX
57# else
58# define BACKWARD_SYSTEM_UNKNOWN
59# endif
60#endif
61
62#include <fstream>
63#include <iostream>
64#include <sstream>
65#include <algorithm>
66#include <cstdlib>
67#include <cstdio>
68#include <cstring>
69#include <cctype>
70#include <string>
71#include <new>
72#include <iomanip>
73#include <vector>
74
75#if defined(BACKWARD_SYSTEM_LINUX)
76
77// On linux, backtrace can back-trace or "walk" the stack using the following
78// libraries:
79//
80// #define BACKWARD_HAS_UNWIND 1
81// - unwind comes from libgcc, but I saw an equivalent inside clang itself.
82// - with unwind, the stacktrace is as accurate as it can possibly be, since
83// this is used by the C++ runtine in gcc/clang for stack unwinding on
84// exception.
85// - normally libgcc is already linked to your program by default.
86//
87// #define BACKWARD_HAS_BACKTRACE == 1
88// - backtrace seems to be a little bit more portable than libunwind, but on
89// linux, it uses unwind anyway, but abstract away a tiny information that is
90// sadly really important in order to get perfectly accurate stack traces.
91// - backtrace is part of the (e)glib library.
92//
93// The default is:
94// #define BACKWARD_HAS_UNWIND == 1
95//
96// Note that only one of the define should be set to 1 at a time.
97//
98# if BACKWARD_HAS_UNWIND == 1
99# elif BACKWARD_HAS_BACKTRACE == 1
100# else
101# undef BACKWARD_HAS_UNWIND
102# define BACKWARD_HAS_UNWIND 1
103# undef BACKWARD_HAS_BACKTRACE
104# define BACKWARD_HAS_BACKTRACE 0
105# endif
106
107// On linux, backward can extract detailed information about a stack trace
108// using one of the following libraries:
109//
110// #define BACKWARD_HAS_DW 1
111// - libdw gives you the most juicy details out of your stack traces:
112// - object filename
113// - function name
114// - source filename
115// - line and column numbers
116// - source code snippet (assuming the file is accessible)
117// - variables name and values (if not optimized out)
118// - You need to link with the lib "dw":
119// - apt-get install libdw-dev
120// - g++/clang++ -ldw ...
121//
122// #define BACKWARD_HAS_BFD 1
123// - With libbfd, you get a fair amount of details:
124// - object filename
125// - function name
126// - source filename
127// - line numbers
128// - source code snippet (assuming the file is accessible)
129// - You need to link with the lib "bfd":
130// - apt-get install binutils-dev
131// - g++/clang++ -lbfd ...
132//
133// #define BACKWARD_HAS_BACKTRACE_SYMBOL 1
134// - backtrace provides minimal details for a stack trace:
135// - object filename
136// - function name
137// - backtrace is part of the (e)glib library.
138//
139// The default is:
140// #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1
141//
142// Note that only one of the define should be set to 1 at a time.
143//
144# if BACKWARD_HAS_DW == 1
145# elif BACKWARD_HAS_BFD == 1
146# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
147# else
148# undef BACKWARD_HAS_DW
149# define BACKWARD_HAS_DW 0
150# undef BACKWARD_HAS_BFD
151# define BACKWARD_HAS_BFD 0
152# undef BACKWARD_HAS_BACKTRACE_SYMBOL
153# define BACKWARD_HAS_BACKTRACE_SYMBOL 1
154# endif
155
156
157# if BACKWARD_HAS_UNWIND == 1
158
159# include <unwind.h>
160// while gcc's unwind.h defines something like that:
161// extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
162// extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
163//
164// clang's unwind.h defines something like this:
165// uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
166//
167// Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we
168// cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr
169// anyway.
170//
171// Luckily we can play on the fact that the guard macros have a different name:
172#ifdef __CLANG_UNWIND_H
173// In fact, this function still comes from libgcc (on my different linux boxes,
174// clang links against libgcc).
175# include <inttypes.h>
177#endif
178
179# endif
180
181# include <cxxabi.h>
182# include <fcntl.h>
183# include <link.h>
184# include <sys/stat.h>
185# include <syscall.h>
186# include <unistd.h>
187# include <signal.h>
188
189# if BACKWARD_HAS_BFD == 1
190// NOTE: defining PACKAGE{,_VERSION} is required before including
191// bfd.h on some platforms, see also:
192// https://sourceware.org/bugzilla/show_bug.cgi?id=14243
193# ifndef PACKAGE
194# define PACKAGE
195# endif
196# ifndef PACKAGE_VERSION
197# define PACKAGE_VERSION
198# endif
199# include <bfd.h>
200# ifndef _GNU_SOURCE
201# define _GNU_SOURCE
202# include <dlfcn.h>
203# undef _GNU_SOURCE
204# else
205# include <dlfcn.h>
206# endif
207# endif
208
209# if BACKWARD_HAS_DW == 1
210# include <elfutils/libdw.h>
211# include <elfutils/libdwfl.h>
212# include <dwarf.h>
213# endif
214
215# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
216 // then we shall rely on backtrace
217# include <execinfo.h>
218# endif
219
220#endif // defined(BACKWARD_SYSTEM_LINUX)
221
222#ifdef BACKWARD_ATLEAST_CXX11
223# include <unordered_map>
224# include <utility> // for std::swap
225 namespace backward {
226 namespace details {
227 template <typename K, typename V>
228 struct hashtable {
229 using type = std::unordered_map<K, V>;
230 };
231 using std::move;
232 }
233 }
234#else // NOT BACKWARD_ATLEAST_CXX11
235# include <map>
236 namespace backward {
237 namespace details {
238 template <typename K, typename V>
239 struct hashtable {
240 using type = std::map<K, V>;
241 };
242 template <typename T>
243 const T& move(const T& v) { return v; }
244 template <typename T>
245 T& move(T& v) { return v; }
246 }
247 }
248#endif // BACKWARD_ATLEAST_CXX11
249
250namespace backward {
251
252namespace 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)
261#else
262# error "May I please get my system defines?"
263#endif
264}
265
266
267namespace 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
279# else
280# error "You shall not pass, until you know what you want."
281# endif
282#endif // BACKWARD_SYSTEM_LINUX
283}
284
285
286namespace details {
287
288template <typename T>
289 struct rm_ptr { using type = T; };
290
291template <typename T>
292 struct rm_ptr<T*> { using type = T; };
293
294template <typename T>
295 struct rm_ptr<const T*> { using type = const T; };
296
297template <typename R, typename T, R (*F)(T)>
298struct deleter {
299 template <typename U>
300 void operator()(U& ptr) const {
301 (*F)(ptr);
302 }
303};
304
305template <typename T>
307 void operator()(T& ptr) const {
308 delete ptr;
309 }
310};
311
312template <typename T, typename Deleter = deleter<void, void*, &::free> >
313class handle {
314 struct dummy;
316 bool _empty;
317
318#ifdef BACKWARD_ATLEAST_CXX11
319 handle(const handle&) = delete;
320 handle& operator=(const handle&) = delete;
321#endif
322
323public:
325 if (!_empty) {
326 Deleter()(_val);
327 }
328 }
329
330 explicit handle(): _val(), _empty(true) {}
331 explicit handle(T val): _val(val), _empty(false) {}
332
333#ifdef BACKWARD_ATLEAST_CXX11
335 swap(from);
336 }
338 swap(from); return *this;
339 }
340#else
341 explicit handle(const handle& from): _empty(true) {
342 // some sort of poor man's move semantic.
343 swap(const_cast<handle&>(from));
344 }
346 // some sort of poor man's move semantic.
347 swap(const_cast<handle&>(from)); return *this;
348 }
349#endif
350
351 void reset(T new_val) {
353 swap(tmp);
354 }
355 operator const dummy*() const {
356 if (_empty) {
357 return 0;
358 }
359 return reinterpret_cast<const dummy*>(_val);
360 }
361 T get() {
362 return _val;
363 }
365 _empty = true;
366 return _val;
367 }
368 void swap(handle& b) {
369 using std::swap;
370 swap(b._val, _val); // can throw, we are safe here.
371 swap(b._empty, _empty); // should not throw: if you cannot swap two
372 // bools without throwing... It's a lost cause anyway!
373 }
374
375 T operator->() { return _val; }
376 const T operator->() const { return _val; }
377
378 using ref_t = typename rm_ptr<T>::type&;
379 using const_ref_t = const typename rm_ptr<T>::type&;
380 ref_t operator*() { return *_val; }
381 const_ref_t operator*() const { return *_val; }
382 ref_t operator[](size_t idx) { return _val[idx]; }
383
384 // Watch out, we've got a badass over here
386 _empty = false;
387 return &_val;
388 }
389};
390
391// Default demangler implementation (do nothing).
392template <typename TAG>
394 static std::string demangle(const char* funcname) {
395 return funcname;
396 }
397};
398
399#ifdef BACKWARD_SYSTEM_LINUX
400
401template <>
402struct demangler_impl<system_tag::current_tag> {
403 demangler_impl(): _demangle_buffer_length(0) {}
404
405 std::string demangle(const char* funcname) {
406 using namespace details;
407 _demangle_buffer.reset(
408 abi::__cxa_demangle(funcname, NULL,
410 );
411 if (_demangle_buffer) {
412 return _demangle_buffer.get();
413 }
414 return funcname;
415 }
416
417private:
418 details::handle<char*> _demangle_buffer;
420};
421
422#endif // BACKWARD_SYSTEM_LINUX
423
425 public demangler_impl<system_tag::current_tag> {};
426
427}
428
429/*************** A TRACE ***************/
430
431struct Trace {
432 void* addr;
433 unsigned idx;
434
436 addr(0), idx(0) {}
437
438 explicit Trace(void* _addr, size_t _idx):
439 addr(_addr), idx(_idx) {}
440};
441
442struct ResolvedTrace: public Trace {
443
444 struct SourceLoc {
445 std::string function;
446 std::string filename;
447 unsigned line;
448 unsigned col;
449
450 SourceLoc(): line(0), col(0) {}
451
452 bool operator==(const SourceLoc& b) const {
453 return function == b.function
454 && filename == b.filename
455 && line == b.line
456 && col == b.col;
457 }
458
459 bool operator!=(const SourceLoc& b) const {
460 return !(*this == b);
461 }
462 };
463
464 // In which binary object this trace is located.
465 std::string object_filename;
466
467 // The function in the object that contain the trace. This is not the same
468 // as source.function which can be an function inlined in object_function.
469 std::string object_function;
470
471 // The source location of this trace. It is possible for filename to be
472 // empty and for line/col to be invalid (value 0) if this information
473 // couldn't be deduced, for example if there is no debug information in the
474 // binary object.
476
477 // An optionals list of "inliners". All the successive sources location
478 // from where the source location of the trace (the attribute right above)
479 // is inlined. It is especially useful when you compiled with optimization.
480 using source_locs_t = std::vector<SourceLoc>;
482
484 Trace() {}
487};
488
489/*************** STACK TRACE ***************/
490
491// default implemention.
492template <typename TAG>
494public:
495 size_t size() const { return 0; }
496 Trace operator[](size_t) { return Trace(); }
497 size_t load_here(size_t=0) { return 0; }
498 size_t load_from(void*, size_t=0) { return 0; }
499 unsigned thread_id() const { return 0; }
500 void skip_n_firsts(size_t) { }
501};
502
503#ifdef BACKWARD_SYSTEM_LINUX
504
506public:
508
509 unsigned thread_id() const {
510 return _thread_id;
511 }
512
513 void skip_n_firsts(size_t n) { _skip = n; }
514
515protected:
516 void load_thread_info() {
518 if (_thread_id == (size_t) getpid()) {
519 // If the thread is the main one, let's hide that.
520 // I like to keep little secret sometimes.
521 _thread_id = 0;
522 }
523 }
524
525 size_t skip_n_firsts() const { return _skip; }
526
527private:
528 size_t _thread_id;
529 size_t _skip;
530};
531
533public:
534 size_t size() const {
535 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
536 }
537 Trace operator[](size_t idx) {
538 if (idx >= size()) {
539 return Trace();
540 }
541 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
542 }
543 void** begin() {
544 if (size()) {
545 return &_stacktrace[skip_n_firsts()];
546 }
547 return 0;
548 }
549
550protected:
551 std::vector<void*> _stacktrace;
552};
553
554
555#if BACKWARD_HAS_UNWIND == 1
556
557namespace details {
558
559template <typename F>
560class Unwinder {
561public:
562 size_t operator()(F& f, size_t depth) {
563 _f = &f;
564 _index = -1;
565 _depth = depth;
567 return _index;
568 }
569
570private:
571 F* _f;
573 size_t _depth;
574
576 _Unwind_Context* ctx, void *self) {
577 return ((Unwinder*)self)->backtrace(ctx);
578 }
579
581 if (_index >= 0 && static_cast<size_t>(_index) >= _depth)
582 return _URC_END_OF_STACK;
583
584 int ip_before_instruction = 0;
586
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
599template <typename F>
600size_t unwind(F f, size_t depth) {
602 return unwinder(f, depth);
603}
604
605}
606
607
608template <>
609class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
610public:
611 __attribute__ ((noinline)) // TODO use some macro
612 size_t load_here(size_t depth=32) {
614 if (depth == 0) {
615 return 0;
616 }
617 _stacktrace.resize(depth);
618 size_t trace_cnt = details::unwind(callback(*this), depth);
619 _stacktrace.resize(trace_cnt);
620 skip_n_firsts(0);
621 return size();
622 }
623 size_t load_from(void* addr, size_t depth=32) {
624 load_here(depth + 8);
625
626 for (size_t i = 0; i < _stacktrace.size(); ++i) {
627 if (_stacktrace[i] == addr) {
628 skip_n_firsts(i);
629 break;
630 }
631 }
632
633 _stacktrace.resize(std::min(_stacktrace.size(),
634 skip_n_firsts() + depth));
635 return size();
636 }
637
638private:
639 struct callback {
640 StackTraceImpl& self;
641 callback(StackTraceImpl& _self): self(_self) {}
642
643 void operator()(size_t idx, void* addr) {
644 self._stacktrace[idx] = addr;
645 }
646 };
647};
648
649
650#else // BACKWARD_HAS_UNWIND == 0
651
652template <>
653class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
654public:
655 __attribute__ ((noinline)) // TODO use some macro
656 size_t load_here(size_t depth=32) {
658 if (depth == 0) {
659 return 0;
660 }
661 _stacktrace.resize(depth + 1);
662 size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
663 _stacktrace.resize(trace_cnt);
664 skip_n_firsts(1);
665 return size();
666 }
667
668 size_t load_from(void* addr, size_t depth=32) {
669 load_here(depth + 8);
670
671 for (size_t i = 0; i < _stacktrace.size(); ++i) {
672 if (_stacktrace[i] == addr) {
673 skip_n_firsts(i);
674 _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1);
675 break;
676 }
677 }
678
679 _stacktrace.resize(std::min(_stacktrace.size(),
680 skip_n_firsts() + depth));
681 return size();
682 }
683};
684
685#endif // BACKWARD_HAS_UNWIND
686#endif // BACKWARD_SYSTEM_LINUX
687
689 public StackTraceImpl<system_tag::current_tag> {};
690
691/*************** TRACE RESOLVER ***************/
692
693template <typename TAG>
695
696#ifdef BACKWARD_SYSTEM_UNKNOWN
697
698template <>
699class TraceResolverImpl<system_tag::unknown_tag> {
700public:
701 template <class ST>
704 return t;
705 }
706};
707
708#endif
709
710#ifdef BACKWARD_SYSTEM_LINUX
711
713protected:
714 std::string demangle(const char* funcname) {
715 return _demangler.demangle(funcname);
716 }
717
718private:
719 details::demangler _demangler;
720};
721
722template <typename STACKTRACE_TAG>
724
725#if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
726
727template <>
728class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
730public:
731 template <class ST>
732 void load_stacktrace(ST& st) {
733 using namespace details;
734 if (st.size() == 0) {
735 return;
736 }
737 _symbols.reset(
738 backtrace_symbols(st.begin(), st.size())
739 );
740 }
741
742 ResolvedTrace resolve(ResolvedTrace trace) {
743 char* filename = _symbols[trace.idx];
744 char* funcname = filename;
745 while (*funcname && *funcname != '(') {
746 funcname += 1;
747 }
748 trace.object_filename.assign(filename, funcname++);
749 char* funcname_end = funcname;
750 while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') {
751 funcname_end += 1;
752 }
753 *funcname_end = '\0';
754 trace.object_function = this->demangle(funcname);
755 trace.source.function = trace.object_function; // we cannot do better.
756 return trace;
757 }
758
759private:
760 details::handle<char**> _symbols;
761};
762
763#endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
764
765#if BACKWARD_HAS_BFD == 1
766
767template <>
768class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
770public:
772
773 template <class ST>
774 void load_stacktrace(ST&) {}
775
776 ResolvedTrace resolve(ResolvedTrace trace) {
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;
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...
820 trace.addr, symbol_info.dli_fbase);
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).
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).
837 // Ok, we assume that details_adjusted_call_site is a better estimation.
839 trace.addr = (void*) (uintptr_t(trace.addr) - 1);
840 }
841
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...
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.
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) {
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
926private:
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;
941 };
942
943 using fobj_bfd_map_t = details::hashtable<std::string, bfd_fileobject>::type;
945
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 =
957 if (it != _fobj_bfd_map.end()) {
958 return it->second;
959 }
960
961 // this new object is empty for now.
963
964 // we do the work temporary in this one;
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
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
986
989
991 return r; // weird, is the file is corrupted?
992 }
993
996
997 if (symtab_storage_size > 0) {
998 symtab.reset(
1000 );
1002 bfd_handle.get(), symtab.get()
1003 );
1004 }
1005
1006 if (dyn_symtab_storage_size > 0) {
1007 dynamic_symtab.reset(
1009 );
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 {
1036 void* addr;
1037 void* base_addr;
1038 find_sym_result result;
1039 };
1040
1042 void* base_addr) {
1044 context.self = this;
1045 context.fobj = &fobj;
1046 context.addr = addr;
1047 context.base_addr = base_addr;
1048 context.result.found = false;
1050 (void*)&context);
1051 return context.result;
1052 }
1053
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
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
1076
1077 // are we in the boundaries of the section?
1078 if (addr < sec_addr || addr >= sec_addr + size) {
1079 addr -= base_addr; // oups, a relocated object, lets try again...
1080 if (addr < sec_addr || addr >= sec_addr + size) {
1081 return;
1082 }
1083 }
1084
1085 if (!result.found && fobj.symtab) {
1086 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1087 fobj.symtab.get(), addr - sec_addr, &result.filename,
1088 &result.funcname, &result.line);
1089 }
1090
1091 if (!result.found && fobj.dynamic_symtab) {
1092 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1093 fobj.dynamic_symtab.get(), addr - sec_addr,
1094 &result.filename, &result.funcname, &result.line);
1095 }
1096
1097 }
1098
1099 ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj,
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
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
1141template <>
1142class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
1144public:
1146
1147 template <class ST>
1148 void load_stacktrace(ST&) {}
1149
1150 ResolvedTrace resolve(ResolvedTrace trace) {
1151 using namespace details;
1152
1154
1156 // initialize dwfl...
1157 _dwfl_cb.reset(new Dwfl_Callbacks);
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()));
1164
1165 if (!_dwfl_handle) {
1166 return trace;
1167 }
1168
1169 // ...from the current process.
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.
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.
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;
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))) {
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
1247
1249 while ((cudie = dwfl_module_nextcu(mod, cudie, &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
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.
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
1292 if (trace.source.function.size() == 0) {
1293 // fallback.
1294 trace.source.function = trace.object_function;
1295 }
1296
1297 return trace;
1298 }
1299
1300private:
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;
1306
1307 // defined here because in C++98, template function cannot take locally
1308 // defined types... grrr.
1309 struct inliners_search_cb {
1310 void operator()(Dwarf_Die* die) {
1311 switch (dwarf_tag(die)) {
1312 const char* name;
1313 case DW_TAG_subprogram:
1314 if ((name = dwarf_diename(die))) {
1315 trace.source.function = name;
1316 }
1317 break;
1318
1320 ResolvedTrace::SourceLoc sloc;
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;
1332 &attr_mem), &line);
1334 &attr_mem), &col);
1335 sloc.line = line;
1336 sloc.col = col;
1337
1338 trace.inliners.push_back(sloc);
1339 break;
1340 };
1341 }
1342 ResolvedTrace& trace;
1343 inliners_search_cb(ResolvedTrace& t): trace(t) {}
1344 };
1345
1346
1347 static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1348 Dwarf_Addr low, high;
1349
1350 // continuous range
1353 if (dwarf_lowpc(die, &low) != 0) {
1354 return false;
1355 }
1356 if (dwarf_highpc(die, &high) != 0) {
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.
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
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:
1390 if (die_has_pc(die, pc)) {
1391 return result;
1392 }
1393 };
1394 bool declaration = false;
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.
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>
1415 Dwarf_Addr pc, CB cb) {
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;
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.
1433 }
1434 if (!branch_has_pc) {
1436 }
1437 if (branch_has_pc) {
1438 cb(die);
1439 }
1440 } while (dwarf_siblingof(die, &die_mem) == 0);
1441 return branch_has_pc;
1442 }
1443
1444 static const char* die_call_file(Dwarf_Die *die) {
1447
1449 &file_idx);
1450
1451 if (file_idx == 0) {
1452 return 0;
1453 }
1454
1457 if (!cudie) {
1458 return 0;
1459 }
1460
1461 Dwarf_Files* files = 0;
1462 size_t 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
1474template<>
1475class TraceResolverImpl<system_tag::linux_tag>:
1476 public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1477
1478#endif // BACKWARD_SYSTEM_LINUX
1479
1481 public TraceResolverImpl<system_tag::current_tag> {};
1482
1483/*************** CODE SNIPPET ***************/
1484
1486public:
1487 using lines_t = std::vector<std::pair<unsigned, std::string>>;
1488
1490 SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
1491 bool is_open() const { return _file->is_open(); }
1492
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
1548 lines_t lines;
1550 }
1551
1552 // there is no find_if_not in C++98, lets do something crappy to
1553 // workaround.
1555 bool operator()(char c) {
1556 return !std::isspace(c);
1557 }
1558 };
1559 // and define this one here because C++98 is not happy with local defined
1560 // struct passed to template functions, fuuuu.
1562 bool operator()(const lines_t::value_type& p) {
1563 return !(std::find_if(p.second.begin(), p.second.end(),
1564 not_isspace()) == p.second.end());
1565 }
1566 };
1567
1568 void swap(SourceFile& b) {
1569 _file.swap(b._file);
1570 }
1571
1572#ifdef BACKWARD_ATLEAST_CXX11
1574 swap(from);
1575 }
1577 swap(from); return *this;
1578 }
1579#else
1580 explicit SourceFile(const SourceFile& from) {
1581 // some sort of poor man's move semantic.
1582 swap(const_cast<SourceFile&>(from));
1583 }
1585 // some sort of poor man's move semantic.
1586 swap(const_cast<SourceFile&>(from)); return *this;
1587 }
1588#endif
1589
1590private:
1591 details::handle<std::ifstream*,
1594
1595#ifdef BACKWARD_ATLEAST_CXX11
1596 SourceFile(const SourceFile&) = delete;
1597 SourceFile& operator=(const SourceFile&) = delete;
1598#endif
1599};
1600
1602public:
1604
1605 lines_t get_snippet(const std::string& filename,
1606 unsigned line_start, unsigned context_size) {
1607
1608 SourceFile& src_file = get_src_file(filename);
1609 unsigned start = line_start - context_size / 2;
1610 return src_file.get_lines(start, context_size);
1611 }
1612
1614 const std::string& filename_a, unsigned line_a,
1615 const std::string& filename_b, unsigned line_b,
1616 unsigned context_size) {
1619
1620 lines_t lines = src_file_a.get_lines(line_a - context_size / 4,
1621 context_size / 2);
1622 src_file_b.get_lines(line_b - context_size / 4, context_size / 2,
1623 lines);
1624 return lines;
1625 }
1626
1627 lines_t get_coalesced_snippet(const std::string& filename,
1628 unsigned line_a, unsigned line_b, unsigned context_size) {
1629 SourceFile& src_file = get_src_file(filename);
1630
1631 using std::min; using std::max;
1632 unsigned a = min(line_a, line_b);
1633 unsigned b = max(line_a, line_b);
1634
1635 if ((b - a) < (context_size / 3)) {
1636 return src_file.get_lines((a + b - context_size + 1) / 2,
1637 context_size);
1638 }
1639
1640 lines_t lines = src_file.get_lines(a - context_size / 4,
1641 context_size / 2);
1642 src_file.get_lines(b - context_size / 4, context_size / 2, lines);
1643 return lines;
1644 }
1645
1646
1647private:
1650
1651 SourceFile& get_src_file(const std::string& filename) {
1652 src_files_t::iterator it = _src_files.find(filename);
1653 if (it != _src_files.end()) {
1654 return it->second;
1655 }
1656 SourceFile& new_src_file = _src_files[filename];
1657 new_src_file = SourceFile(filename);
1658 return new_src_file;
1659 }
1660};
1661
1662/*************** PRINTER ***************/
1663
1664#ifdef BACKWARD_SYSTEM_LINUX
1665
1666namespace Color {
1667 enum type {
1668 yellow = 33,
1669 purple = 35,
1670 reset = 39
1671 };
1672}
1673
1674class Colorize {
1675public:
1676 Colorize(std::ostream& os):
1678
1679 void activate() {
1680 _use_colors = true;
1681 // in a colorful environment, reset at the beginning
1683 }
1684
1685 void activate_if_tty(std::FILE *desc) {
1686 if (isatty(fileno(desc))) {
1687 activate();
1688 }
1689 }
1690
1692 if (!_use_colors) return;
1693
1694 // I assume that the terminal can handle basic colors. Seriously I
1695 // don't want to deal with all the termcap shit.
1696 _os << "\033[" << static_cast<int>(ccode) << "m";
1697 _reset = (ccode != Color::reset);
1698 }
1699
1700 ~Colorize() {
1701 if (_reset) {
1703 }
1704 }
1705
1706private:
1707 std::ostream& _os;
1708 bool _reset;
1709 bool _use_colors;
1710};
1711
1712#else // ndef BACKWARD_SYSTEM_LINUX
1713
1714
1715namespace Color {
1716 enum type {
1719 reset = 0
1721}
1722
1724public:
1725 Colorize(std::ostream&) {}
1726 void activate() {}
1729};
1730
1731#endif // BACKWARD_SYSTEM_LINUX
1732
1733class Printer {
1734public:
1736 bool color;
1741
1743 snippet(true),
1744 color(true),
1745 address(false),
1746 object(false),
1749 {}
1750
1751 template <typename ST>
1753 std::stringstream ss;
1755 if (color) {
1756 colorize.activate_if_tty(os);
1757 }
1758 print(st, ss, colorize);
1759 fprintf(os, "%s", ss.str().c_str());
1760 return os;
1761 }
1762
1763 template <typename ST>
1764 void print(ST& st, std::ostream& os) {
1766 if (color) {
1767 colorize.activate();
1768 }
1769 print(st, os, colorize);
1770 }
1771
1772 template <typename IT>
1773 FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) {
1774 std::stringstream ss;
1776 if (color) {
1777 colorize.activate_if_tty(os);
1778 }
1779 print(begin, end, ss, thread_id, colorize);
1780 fprintf(os, "%s", ss.str().c_str());
1781 return os;
1782 }
1783
1784 template <typename IT>
1785 void print(IT begin, IT end, std::ostream& os, size_t thread_id = 0) {
1787 if (color) {
1788 colorize.activate();
1789 }
1790 print(begin, end, os, thread_id, colorize);
1791 }
1792
1793private:
1796
1797 template <typename ST>
1798 void print(ST& st, std::ostream& os, Colorize& colorize) {
1799 print_header(os, st.thread_id());
1800 _resolver.load_stacktrace(st);
1801 for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1803 }
1804 }
1805
1806 template <typename IT>
1807 void print(IT begin, IT end, std::ostream& os, size_t thread_id, Colorize& colorize) {
1808 print_header(os, thread_id);
1809 for (; begin != end; ++begin) {
1810 print_trace(os, *begin, colorize);
1811 }
1812 }
1813
1814 void print_header(std::ostream& os, unsigned thread_id) {
1815 os << "Stack trace (most recent call last)";
1816 if (thread_id) {
1817 os << " in thread " << thread_id;
1818 }
1819 os << ":\n";
1820 }
1821
1822 void print_trace(std::ostream& os, const ResolvedTrace& trace,
1823 Colorize& colorize) {
1824 os << "#"
1825 << std::left << std::setw(2) << trace.idx
1826 << std::right;
1827 bool already_indented = true;
1828
1829 if (!trace.source.filename.size() || object) {
1830 os << " Object \""
1831 << trace.object_filename
1832 << ", at "
1833 << trace.addr
1834 << ", in "
1835 << trace.object_function
1836 << "\n";
1837 already_indented = false;
1838 }
1839
1840 for (size_t inliner_idx = trace.inliners.size();
1841 inliner_idx > 0; --inliner_idx) {
1842 if (!already_indented) {
1843 os << " ";
1844 }
1846 = trace.inliners[inliner_idx-1];
1848 if (snippet) {
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,
1863 }
1864 }
1865 }
1866
1867 void print_snippet(std::ostream& os, const char* indent,
1870 int context_size)
1871 {
1872 using namespace std;
1873 using lines_t = SnippetFactory::lines_t;
1874
1875 lines_t lines = _snippets.get_snippet(source_loc.filename,
1876 source_loc.line, context_size);
1877
1878 for (lines_t::const_iterator it = lines.begin();
1879 it != lines.end(); ++it) {
1880 if (it-> first == source_loc.line) {
1881 colorize.set_color(color_code);
1882 os << indent << ">";
1883 } else {
1884 os << indent << " ";
1885 }
1886 os << std::setw(4) << it->first
1887 << ": "
1888 << it->second
1889 << "\n";
1890 if (it-> first == source_loc.line) {
1891 colorize.set_color(Color::reset);
1892 }
1893 }
1894 }
1895
1896 void print_source_loc(std::ostream& os, const char* indent,
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
1919class SignalHandling {
1920public:
1921 static std::vector<int> make_default_signals() {
1922 const int posix_signals[] = {
1923 // default action: Core
1924 SIGILL,
1925 SIGABRT,
1926 SIGFPE,
1927 SIGSEGV,
1928 SIGBUS,
1929 // I am not sure the following signals should be enabled by
1930 // default:
1931 // default action: Term
1932 SIGHUP,
1933 SIGINT,
1934 SIGPIPE,
1935 SIGALRM,
1936 SIGTERM,
1937 SIGUSR1,
1938 SIGUSR2,
1939 SIGPOLL,
1940 SIGPROF,
1941 SIGVTALRM,
1942 SIGIO,
1943 SIGPWR,
1944 // default action: Core
1945 SIGQUIT,
1946 SIGSYS,
1947 SIGTRAP,
1948 SIGXCPU,
1949 SIGXFSZ
1950 };
1951 return std::vector<int>(posix_signals, posix_signals + sizeof posix_signals / sizeof posix_signals[0] );
1952 }
1953
1954 SignalHandling(const std::vector<int>& posix_signals = make_default_signals()):
1955 _loaded(false) {
1956 bool success = true;
1957
1958 const size_t stack_size = 1024 * 1024 * 8;
1959 _stack_content.reset((char*)malloc(stack_size));
1960 if (_stack_content) {
1961 stack_t ss;
1962 ss.ss_sp = _stack_content.get();
1963 ss.ss_size = stack_size;
1964 ss.ss_flags = 0;
1965 if (sigaltstack(&ss, 0) < 0) {
1966 success = false;
1967 }
1968 } else {
1969 success = false;
1970 }
1971
1972 for (size_t i = 0; i < posix_signals.size(); ++i) {
1973 struct sigaction action;
1974 memset(&action, 0, sizeof action);
1975 action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1976 SA_RESETHAND);
1977 sigfillset(&action.sa_mask);
1978 sigdelset(&action.sa_mask, posix_signals[i]);
1979 action.sa_sigaction = &sig_handler;
1980
1981 int r = sigaction(posix_signals[i], &action, 0);
1982 if (r < 0) success = false;
1983 }
1984
1985 _loaded = success;
1986 }
1987
1988 bool loaded() const { return _loaded; }
1989
1990private:
1991 details::handle<char*> _stack_content;
1992 bool _loaded;
1993
1994 static void sig_handler(int, siginfo_t* info, void* _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");
2028 }
2029};
2030
2031#endif // BACKWARD_SYSTEM_LINUX
2032
2033#ifdef BACKWARD_SYSTEM_UNKNOWN
2034
2036public:
2037 SignalHandling(const std::vector<int>& = std::vector<int>()) {}
2038 bool init() { return false; }
2039 bool loaded() { return false; }
2040};
2041
2042#endif // BACKWARD_SYSTEM_UNKNOWN
2043
2044}
2045
2046#endif /* H_GUARD */
Colorize(std::ostream &)
void set_color(Color::type)
void print_header(std::ostream &os, unsigned thread_id)
void print_source_loc(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, void *addr=0)
FILE * print(ST &st, FILE *os=stderr)
TraceResolver _resolver
void print(IT begin, IT end, std::ostream &os, size_t thread_id, Colorize &colorize)
void print(IT begin, IT end, std::ostream &os, size_t thread_id=0)
FILE * print(IT begin, IT end, FILE *os=stderr, size_t thread_id=0)
void print(ST &st, std::ostream &os, Colorize &colorize)
void print(ST &st, std::ostream &os)
SnippetFactory _snippets
void print_trace(std::ostream &os, const ResolvedTrace &trace, Colorize &colorize)
void print_snippet(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, Colorize &colorize, Color::type color_code, int context_size)
SignalHandling(const std::vector< int > &=std::vector< int >())
SourceFile & get_src_file(const std::string &filename)
SourceFile::lines_t lines_t
lines_t get_coalesced_snippet(const std::string &filename, unsigned line_a, unsigned line_b, unsigned context_size)
lines_t get_snippet(const std::string &filename, unsigned line_start, unsigned context_size)
details::hashtable< std::string, SourceFile >::type src_files_t
lines_t get_combined_snippet(const std::string &filename_a, unsigned line_a, const std::string &filename_b, unsigned line_b, unsigned context_size)
lines_t get_lines(unsigned line_start, unsigned line_count)
bool is_open() const
std::vector< std::pair< unsigned, std::string > > lines_t
SourceFile & operator=(const SourceFile &from)
SourceFile(const SourceFile &from)
void swap(SourceFile &b)
lines_t & get_lines(unsigned line_start, unsigned line_count, lines_t &lines)
details::handle< std::ifstream *, details::default_delete< std::ifstream * > > _file
SourceFile(const std::string &path)
Trace operator[](size_t)
Definition backward.hpp:496
size_t load_from(void *, size_t=0)
Definition backward.hpp:498
size_t load_here(size_t=0)
Definition backward.hpp:497
void skip_n_firsts(size_t)
Definition backward.hpp:500
unsigned thread_id() const
Definition backward.hpp:499
handle(const handle &from)
Definition backward.hpp:341
const typename rm_ptr< T >::type & const_ref_t
Definition backward.hpp:379
handle & operator=(const handle &from)
Definition backward.hpp:345
ref_t operator[](size_t idx)
Definition backward.hpp:382
const_ref_t operator*() const
Definition backward.hpp:381
typename rm_ptr< T >::type & ref_t
Definition backward.hpp:378
void reset(T new_val)
Definition backward.hpp:351
const T operator->() const
Definition backward.hpp:376
int r[]
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
const T & move(const T &v)
Definition backward.hpp:243
unknown_tag current_tag
Definition backward.hpp:260
Definition GML.h:110
bool operator==(const SourceLoc &b) const
Definition backward.hpp:452
bool operator!=(const SourceLoc &b) const
Definition backward.hpp:459
ResolvedTrace(const Trace &mini_trace)
Definition backward.hpp:485
std::vector< SourceLoc > source_locs_t
Definition backward.hpp:480
std::string object_filename
Definition backward.hpp:465
source_locs_t inliners
Definition backward.hpp:481
std::string object_function
Definition backward.hpp:469
bool operator()(const lines_t::value_type &p)
Trace(void *_addr, size_t _idx)
Definition backward.hpp:438
void operator()(U &ptr) const
Definition backward.hpp:300
static std::string demangle(const char *funcname)
Definition backward.hpp:394