00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef H_6B9572DA_A64B_49E6_B234_051480991C89
00025 #define H_6B9572DA_A64B_49E6_B234_051480991C89
00026
00027 #ifndef __cplusplus
00028 # error "It's not going to compile without a C++ compiler..."
00029 #endif
00030
00031 #if defined(BACKWARD_CXX11)
00032 #elif defined(BACKWARD_CXX98)
00033 #else
00034 # if __cplusplus >= 201103L
00035 # define BACKWARD_CXX11
00036 # define BACKWARD_ATLEAST_CXX11
00037 # define BACKWARD_ATLEAST_CXX98
00038 # else
00039 # define BACKWARD_CXX98
00040 # define BACKWARD_ATLEAST_CXX98
00041 # endif
00042 #endif
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #if defined(BACKWARD_SYSTEM_LINUX)
00053 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
00054 #else
00055 # if defined(__linux)
00056 # define BACKWARD_SYSTEM_LINUX
00057 # else
00058 # define BACKWARD_SYSTEM_UNKNOWN
00059 # endif
00060 #endif
00061
00062 #include <fstream>
00063 #include <iostream>
00064 #include <algorithm>
00065 #include <cstdlib>
00066 #include <cstdio>
00067 #include <cstring>
00068 #include <cctype>
00069 #include <string>
00070 #include <new>
00071 #include <iomanip>
00072 #include <vector>
00073
00074 #if defined(BACKWARD_SYSTEM_LINUX)
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 # if BACKWARD_HAS_UNWIND == 1
00098 # elif BACKWARD_HAS_BACKTRACE == 1
00099 # else
00100 # undef BACKWARD_HAS_UNWIND
00101 # define BACKWARD_HAS_UNWIND 1
00102 # undef BACKWARD_HAS_BACKTRACE
00103 # define BACKWARD_HAS_BACKTRACE 0
00104 # endif
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 # if BACKWARD_HAS_DW == 1
00144 # elif BACKWARD_HAS_BFD == 1
00145 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
00146 # else
00147 # undef BACKWARD_HAS_DW
00148 # define BACKWARD_HAS_DW 0
00149 # undef BACKWARD_HAS_BFD
00150 # define BACKWARD_HAS_BFD 0
00151 # undef BACKWARD_HAS_BACKTRACE_SYMBOL
00152 # define BACKWARD_HAS_BACKTRACE_SYMBOL 1
00153 # endif
00154
00155
00156 # if BACKWARD_HAS_UNWIND == 1
00157
00158 # include <unwind.h>
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 #ifdef __CLANG_UNWIND_H
00172
00173
00174 # include <inttypes.h>
00175 extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*);
00176 #endif
00177
00178 # endif
00179
00180 # include <cxxabi.h>
00181 # include <fcntl.h>
00182 # include <link.h>
00183 # include <sys/stat.h>
00184 # include <syscall.h>
00185 # include <unistd.h>
00186 # include <signal.h>
00187
00188 # if BACKWARD_HAS_BFD == 1
00189
00190
00191
00192 # ifndef PACKAGE
00193 # define PACKAGE
00194 # endif
00195 # ifndef PACKAGE_VERSION
00196 # define PACKAGE_VERSION
00197 # endif
00198 # include <bfd.h>
00199 # ifndef _GNU_SOURCE
00200 # define _GNU_SOURCE
00201 # include <dlfcn.h>
00202 # undef _GNU_SOURCE
00203 # else
00204 # include <dlfcn.h>
00205 # endif
00206 # endif
00207
00208 # if BACKWARD_HAS_DW == 1
00209 # include <elfutils/libdw.h>
00210 # include <elfutils/libdwfl.h>
00211 # include <dwarf.h>
00212 # endif
00213
00214 # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
00215
00216 # include <execinfo.h>
00217 # endif
00218
00219 #endif // defined(BACKWARD_SYSTEM_LINUX)
00220
00221 #ifdef BACKWARD_ATLEAST_CXX11
00222 # include <unordered_map>
00223 # include <utility>
00224 namespace backward {
00225 namespace details {
00226 template <typename K, typename V>
00227 struct hashtable {
00228 typedef std::unordered_map<K, V> type;
00229 };
00230 using std::move;
00231 }
00232 }
00233 #else // NOT BACKWARD_ATLEAST_CXX11
00234 # include <map>
00235 namespace backward {
00236 namespace details {
00237 template <typename K, typename V>
00238 struct hashtable {
00239 typedef std::map<K, V> type;
00240 };
00241 template <typename T>
00242 const T& move(const T& v) { return v; }
00243 template <typename T>
00244 T& move(T& v) { return v; }
00245 }
00246 }
00247 #endif // BACKWARD_ATLEAST_CXX11
00248
00249 namespace backward {
00250
00251 namespace system_tag {
00252 struct linux_tag;
00253
00254 struct unknown_tag;
00255
00256 #if defined(BACKWARD_SYSTEM_LINUX)
00257 typedef linux_tag current_tag;
00258 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
00259 typedef unknown_tag current_tag;
00260 #else
00261 # error "May I please get my system defines?"
00262 #endif
00263 }
00264
00265
00266 namespace trace_resolver_tag {
00267 #ifdef BACKWARD_SYSTEM_LINUX
00268 struct libdw;
00269 struct libbfd;
00270 struct backtrace_symbol;
00271
00272 # if BACKWARD_HAS_DW == 1
00273 typedef libdw current;
00274 # elif BACKWARD_HAS_BFD == 1
00275 typedef libbfd current;
00276 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
00277 typedef backtrace_symbol current;
00278 # else
00279 # error "You shall not pass, until you know what you want."
00280 # endif
00281 #endif // BACKWARD_SYSTEM_LINUX
00282 }
00283
00284
00285 namespace details {
00286
00287 template <typename T>
00288 struct rm_ptr { typedef T type; };
00289
00290 template <typename T>
00291 struct rm_ptr<T*> { typedef T type; };
00292
00293 template <typename T>
00294 struct rm_ptr<const T*> { typedef const T type; };
00295
00296 template <typename R, typename T, R (*F)(T)>
00297 struct deleter {
00298 template <typename U>
00299 void operator()(U& ptr) const {
00300 (*F)(ptr);
00301 }
00302 };
00303
00304 template <typename T>
00305 struct default_delete {
00306 void operator()(T& ptr) const {
00307 delete ptr;
00308 }
00309 };
00310
00311 template <typename T, typename Deleter = deleter<void, void*, &::free> >
00312 class handle {
00313 struct dummy;
00314 T _val;
00315 bool _empty;
00316
00317 #ifdef BACKWARD_ATLEAST_CXX11
00318 handle(const handle&) = delete;
00319 handle& operator=(const handle&) = delete;
00320 #endif
00321
00322 public:
00323 ~handle() {
00324 if (!_empty) {
00325 Deleter()(_val);
00326 }
00327 }
00328
00329 explicit handle(): _val(), _empty(true) {}
00330 explicit handle(T val): _val(val), _empty(false) {}
00331
00332 #ifdef BACKWARD_ATLEAST_CXX11
00333 handle(handle&& from): _empty(true) {
00334 swap(from);
00335 }
00336 handle& operator=(handle&& from) {
00337 swap(from); return *this;
00338 }
00339 #else
00340 explicit handle(const handle& from): _empty(true) {
00341
00342 swap(const_cast<handle&>(from));
00343 }
00344 handle& operator=(const handle& from) {
00345
00346 swap(const_cast<handle&>(from)); return *this;
00347 }
00348 #endif
00349
00350 void reset(T new_val) {
00351 handle tmp(new_val);
00352 swap(tmp);
00353 }
00354 operator const dummy*() const {
00355 if (_empty) {
00356 return 0;
00357 }
00358 return reinterpret_cast<const dummy*>(_val);
00359 }
00360 T get() {
00361 return _val;
00362 }
00363 T release() {
00364 _empty = true;
00365 return _val;
00366 }
00367 void swap(handle& b) {
00368 using std::swap;
00369 swap(b._val, _val);
00370 swap(b._empty, _empty);
00371
00372 }
00373
00374 T operator->() { return _val; }
00375 const T operator->() const { return _val; }
00376
00377 typedef typename rm_ptr<T>::type& ref_t;
00378 typedef const typename rm_ptr<T>::type& const_ref_t;
00379 ref_t operator*() { return *_val; }
00380 const_ref_t operator*() const { return *_val; }
00381 ref_t operator[](size_t idx) { return _val[idx]; }
00382
00383
00384 T* operator&() {
00385 _empty = false;
00386 return &_val;
00387 }
00388 };
00389
00390
00391 template <typename TAG>
00392 struct demangler_impl {
00393 static std::string demangle(const char* funcname) {
00394 return funcname;
00395 }
00396 };
00397
00398 #ifdef BACKWARD_SYSTEM_LINUX
00399
00400 template <>
00401 struct demangler_impl<system_tag::current_tag> {
00402 demangler_impl(): _demangle_buffer_length(0) {}
00403
00404 std::string demangle(const char* funcname) {
00405 using namespace details;
00406 _demangle_buffer.reset(
00407 abi::__cxa_demangle(funcname, _demangle_buffer.release(),
00408 &_demangle_buffer_length, 0)
00409 );
00410 if (_demangle_buffer) {
00411 return _demangle_buffer.get();
00412 }
00413 return funcname;
00414 }
00415
00416 private:
00417 details::handle<char*> _demangle_buffer;
00418 size_t _demangle_buffer_length;
00419 };
00420
00421 #endif // BACKWARD_SYSTEM_LINUX
00422
00423 struct demangler:
00424 public demangler_impl<system_tag::current_tag> {};
00425
00426 }
00427
00428
00429
00430 struct Trace {
00431 void* addr;
00432 unsigned idx;
00433
00434 Trace():
00435 addr(0), idx(0) {}
00436
00437 explicit Trace(void* addr, size_t idx):
00438 addr(addr), idx(idx) {}
00439 };
00440
00441 struct ResolvedTrace: public Trace {
00442
00443 struct SourceLoc {
00444 std::string function;
00445 std::string filename;
00446 unsigned line;
00447 unsigned col;
00448
00449 SourceLoc(): line(0), col(0) {}
00450
00451 bool operator==(const SourceLoc& b) const {
00452 return function == b.function
00453 && filename == b.filename
00454 && line == b.line
00455 && col == b.col;
00456 }
00457
00458 bool operator!=(const SourceLoc& b) const {
00459 return !(*this == b);
00460 }
00461 };
00462
00463
00464 std::string object_filename;
00465
00466
00467
00468 std::string object_function;
00469
00470
00471
00472
00473
00474 SourceLoc source;
00475
00476
00477
00478
00479 typedef std::vector<SourceLoc> source_locs_t;
00480 source_locs_t inliners;
00481
00482 ResolvedTrace():
00483 Trace() {}
00484 ResolvedTrace(const Trace& mini_trace):
00485 Trace(mini_trace) {}
00486 };
00487
00488
00489
00490
00491 template <typename TAG>
00492 class StackTraceImpl {
00493 public:
00494 size_t size() const { return 0; }
00495 Trace operator[](size_t) { return Trace(); }
00496 size_t load_here(size_t=0) { return 0; }
00497 size_t load_from(void*, size_t=0) { return 0; }
00498 unsigned thread_id() const { return 0; }
00499 void skip_n_firsts(size_t) { }
00500 };
00501
00502 #ifdef BACKWARD_SYSTEM_LINUX
00503
00504 class StackTraceLinuxImplBase {
00505 public:
00506 StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
00507
00508 unsigned thread_id() const {
00509 return _thread_id;
00510 }
00511
00512 void skip_n_firsts(size_t n) { _skip = n; }
00513
00514 protected:
00515 void load_thread_info() {
00516 _thread_id = syscall(SYS_gettid);
00517 if (_thread_id == (size_t) getpid()) {
00518
00519
00520 _thread_id = 0;
00521 }
00522 }
00523
00524 size_t skip_n_firsts() const { return _skip; }
00525
00526 private:
00527 size_t _thread_id;
00528 size_t _skip;
00529 };
00530
00531 class StackTraceLinuxImplHolder: public StackTraceLinuxImplBase {
00532 public:
00533 size_t size() const {
00534 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
00535 }
00536 Trace operator[](size_t idx) {
00537 if (idx >= size()) {
00538 return Trace();
00539 }
00540 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
00541 }
00542 void** begin() {
00543 if (size()) {
00544 return &_stacktrace[skip_n_firsts()];
00545 }
00546 return 0;
00547 }
00548
00549 protected:
00550 std::vector<void*> _stacktrace;
00551 };
00552
00553
00554 #if BACKWARD_HAS_UNWIND == 1
00555
00556 namespace details {
00557
00558 template <typename F>
00559 class Unwinder {
00560 public:
00561 size_t operator()(F& f, size_t depth) {
00562 _f = &f;
00563 _index = -1;
00564 _depth = depth;
00565 _Unwind_Backtrace(&this->backtrace_trampoline, this);
00566 return _index;
00567 }
00568
00569 private:
00570 F* _f;
00571 ssize_t _index;
00572 size_t _depth;
00573
00574 static _Unwind_Reason_Code backtrace_trampoline(
00575 _Unwind_Context* ctx, void *self) {
00576 return ((Unwinder*)self)->backtrace(ctx);
00577 }
00578
00579 _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
00580 if (_index >= 0 && static_cast<size_t>(_index) >= _depth)
00581 return _URC_END_OF_STACK;
00582
00583 int ip_before_instruction = 0;
00584 uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
00585
00586 if (!ip_before_instruction) {
00587 ip -= 1;
00588 }
00589
00590 if (_index >= 0) {
00591 (*_f)(_index, (void*)ip);
00592 }
00593 _index += 1;
00594 return _URC_NO_REASON;
00595 }
00596 };
00597
00598 template <typename F>
00599 size_t unwind(F f, size_t depth) {
00600 Unwinder<F> unwinder;
00601 return unwinder(f, depth);
00602 }
00603
00604 }
00605
00606
00607 template <>
00608 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
00609 public:
00610 __attribute__ ((noinline))
00611 size_t load_here(size_t depth=32) {
00612 load_thread_info();
00613 if (depth == 0) {
00614 return 0;
00615 }
00616 _stacktrace.resize(depth);
00617 size_t trace_cnt = details::unwind(callback(*this), depth);
00618 _stacktrace.resize(trace_cnt);
00619 skip_n_firsts(0);
00620 return size();
00621 }
00622 size_t load_from(void* addr, size_t depth=32) {
00623 load_here(depth + 8);
00624
00625 for (size_t i = 0; i < _stacktrace.size(); ++i) {
00626 if (_stacktrace[i] == addr) {
00627 skip_n_firsts(i);
00628 break;
00629 }
00630 }
00631
00632 _stacktrace.resize(std::min(_stacktrace.size(),
00633 skip_n_firsts() + depth));
00634 return size();
00635 }
00636
00637 private:
00638 struct callback {
00639 StackTraceImpl& self;
00640 callback(StackTraceImpl& self): self(self) {}
00641
00642 void operator()(size_t idx, void* addr) {
00643 self._stacktrace[idx] = addr;
00644 }
00645 };
00646 };
00647
00648
00649 #else // BACKWARD_HAS_UNWIND == 0
00650
00651 template <>
00652 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
00653 public:
00654 __attribute__ ((noinline))
00655 size_t load_here(size_t depth=32) {
00656 load_thread_info();
00657 if (depth == 0) {
00658 return 0;
00659 }
00660 _stacktrace.resize(depth + 1);
00661 size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
00662 _stacktrace.resize(trace_cnt);
00663 skip_n_firsts(1);
00664 return size();
00665 }
00666
00667 size_t load_from(void* addr, size_t depth=32) {
00668 load_here(depth + 8);
00669
00670 for (size_t i = 0; i < _stacktrace.size(); ++i) {
00671 if (_stacktrace[i] == addr) {
00672 skip_n_firsts(i);
00673 _stacktrace[i] = (void*)( (uintptr_t)_stacktrace[i] + 1);
00674 break;
00675 }
00676 }
00677
00678 _stacktrace.resize(std::min(_stacktrace.size(),
00679 skip_n_firsts() + depth));
00680 return size();
00681 }
00682 };
00683
00684 #endif // BACKWARD_HAS_UNWIND
00685 #endif // BACKWARD_SYSTEM_LINUX
00686
00687 class StackTrace:
00688 public StackTraceImpl<system_tag::current_tag> {};
00689
00690
00691
00692 template <typename TAG>
00693 class TraceResolverImpl;
00694
00695 #ifdef BACKWARD_SYSTEM_UNKNOWN
00696
00697 template <>
00698 class TraceResolverImpl<system_tag::unknown_tag> {
00699 public:
00700 template <class ST>
00701 void load_stacktrace(ST&) {}
00702 ResolvedTrace resolve(ResolvedTrace t) {
00703 return t;
00704 }
00705 };
00706
00707 #endif
00708
00709 #ifdef BACKWARD_SYSTEM_LINUX
00710
00711 class TraceResolverLinuxImplBase {
00712 protected:
00713 std::string demangle(const char* funcname) {
00714 return _demangler.demangle(funcname);
00715 }
00716
00717 private:
00718 details::demangler _demangler;
00719 };
00720
00721 template <typename STACKTRACE_TAG>
00722 class TraceResolverLinuxImpl;
00723
00724 #if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
00725
00726 template <>
00727 class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
00728 public TraceResolverLinuxImplBase {
00729 public:
00730 template <class ST>
00731 void load_stacktrace(ST& st) {
00732 using namespace details;
00733 if (st.size() == 0) {
00734 return;
00735 }
00736 _symbols.reset(
00737 backtrace_symbols(st.begin(), st.size())
00738 );
00739 }
00740
00741 ResolvedTrace resolve(ResolvedTrace trace) {
00742 char* filename = _symbols[trace.idx];
00743 char* funcname = filename;
00744 while (*funcname && *funcname != '(') {
00745 funcname += 1;
00746 }
00747 trace.object_filename.assign(filename, funcname++);
00748 char* funcname_end = funcname;
00749 while (*funcname_end && *funcname_end != ')' && *funcname_end != '+') {
00750 funcname_end += 1;
00751 }
00752 *funcname_end = '\0';
00753 trace.object_function = this->demangle(funcname);
00754 trace.source.function = trace.object_function;
00755 return trace;
00756 }
00757
00758 private:
00759 details::handle<char**> _symbols;
00760 };
00761
00762 #endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
00763
00764 #if BACKWARD_HAS_BFD == 1
00765
00766 template <>
00767 class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
00768 public TraceResolverLinuxImplBase {
00769 public:
00770 TraceResolverLinuxImpl(): _bfd_loaded(false) {}
00771
00772 template <class ST>
00773 void load_stacktrace(ST&) {}
00774
00775 ResolvedTrace resolve(ResolvedTrace trace) {
00776 Dl_info symbol_info;
00777
00778
00779
00780
00781 if (!dladdr(trace.addr, &symbol_info)) {
00782 return trace;
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 if (symbol_info.dli_sname) {
00797 trace.object_function = demangle(symbol_info.dli_sname);
00798 }
00799
00800 if (!symbol_info.dli_fname) {
00801 return trace;
00802 }
00803
00804 trace.object_filename = symbol_info.dli_fname;
00805 bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
00806 if (!fobj.handle) {
00807 return trace;
00808 }
00809
00810
00811 find_sym_result* details_selected;
00812
00813
00814
00815
00816
00817
00818 find_sym_result details_call_site = find_symbol_details(fobj,
00819 trace.addr, symbol_info.dli_fbase);
00820 details_selected = &details_call_site;
00821
00822 #if BACKWARD_HAS_UNWIND == 0
00823
00824
00825
00826
00827
00828
00829
00830 find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
00831 (void*) (uintptr_t(trace.addr) - 1),
00832 symbol_info.dli_fbase);
00833
00834
00835 if (details_call_site.found && details_adjusted_call_site.found) {
00836
00837 details_selected = &details_adjusted_call_site;
00838 trace.addr = (void*) (uintptr_t(trace.addr) - 1);
00839 }
00840
00841 if (details_selected == &details_call_site && details_call_site.found) {
00842
00843
00844
00845 details_call_site = find_symbol_details(fobj, trace.addr,
00846 symbol_info.dli_fbase);
00847 }
00848 #endif // BACKWARD_HAS_UNWIND
00849
00850 if (details_selected->found) {
00851 if (details_selected->filename) {
00852 trace.source.filename = details_selected->filename;
00853 }
00854 trace.source.line = details_selected->line;
00855
00856 if (details_selected->funcname) {
00857
00858
00859
00860
00861
00862 trace.source.function = demangle(details_selected->funcname);
00863
00864 if (!symbol_info.dli_sname) {
00865
00866
00867
00868 trace.object_function = trace.source.function;
00869 }
00870 }
00871
00872
00873
00874
00875 trace.inliners = backtrace_inliners(fobj, *details_selected);
00876
00877 #if 0
00878 if (trace.inliners.size() == 0) {
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 if (symbol_info.dli_saddr) {
00898 find_sym_result details = find_symbol_details(fobj,
00899 symbol_info.dli_saddr,
00900 symbol_info.dli_fbase);
00901
00902 if (details.found) {
00903 ResolvedTrace::SourceLoc diy_inliner;
00904 diy_inliner.line = details.line;
00905 if (details.filename) {
00906 diy_inliner.filename = details.filename;
00907 }
00908 if (details.funcname) {
00909 diy_inliner.function = demangle(details.funcname);
00910 } else {
00911 diy_inliner.function = trace.source.function;
00912 }
00913 if (diy_inliner != trace.source) {
00914 trace.inliners.push_back(diy_inliner);
00915 }
00916 }
00917 }
00918 }
00919 #endif
00920 }
00921
00922 return trace;
00923 }
00924
00925 private:
00926 bool _bfd_loaded;
00927
00928 typedef details::handle<bfd*,
00929 details::deleter<bfd_boolean, bfd*, &bfd_close>
00930 > bfd_handle_t;
00931
00932 typedef details::handle<asymbol**> bfd_symtab_t;
00933
00934
00935 struct bfd_fileobject {
00936 bfd_handle_t handle;
00937 bfd_vma base_addr;
00938 bfd_symtab_t symtab;
00939 bfd_symtab_t dynamic_symtab;
00940 };
00941
00942 typedef details::hashtable<std::string, bfd_fileobject>::type
00943 fobj_bfd_map_t;
00944 fobj_bfd_map_t _fobj_bfd_map;
00945
00946 bfd_fileobject& load_object_with_bfd(const std::string& filename_object) {
00947 using namespace details;
00948
00949 if (!_bfd_loaded) {
00950 using namespace details;
00951 bfd_init();
00952 _bfd_loaded = true;
00953 }
00954
00955 fobj_bfd_map_t::iterator it =
00956 _fobj_bfd_map.find(filename_object);
00957 if (it != _fobj_bfd_map.end()) {
00958 return it->second;
00959 }
00960
00961
00962 bfd_fileobject& r = _fobj_bfd_map[filename_object];
00963
00964
00965 bfd_handle_t bfd_handle;
00966
00967 int fd = open(filename_object.c_str(), O_RDONLY);
00968 bfd_handle.reset(
00969 bfd_fdopenr(filename_object.c_str(), "default", fd)
00970 );
00971 if (!bfd_handle) {
00972 close(fd);
00973 return r;
00974 }
00975
00976 if (!bfd_check_format(bfd_handle.get(), bfd_object)) {
00977 return r;
00978 }
00979
00980 if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
00981 return r;
00982 }
00983
00984 ssize_t symtab_storage_size =
00985 bfd_get_symtab_upper_bound(bfd_handle.get());
00986
00987 ssize_t dyn_symtab_storage_size =
00988 bfd_get_dynamic_symtab_upper_bound(bfd_handle.get());
00989
00990 if (symtab_storage_size <= 0 && dyn_symtab_storage_size <= 0) {
00991 return r;
00992 }
00993
00994 bfd_symtab_t symtab, dynamic_symtab;
00995 ssize_t symcount = 0, dyn_symcount = 0;
00996
00997 if (symtab_storage_size > 0) {
00998 symtab.reset(
00999 (bfd_symbol**) malloc(symtab_storage_size)
01000 );
01001 symcount = bfd_canonicalize_symtab(
01002 bfd_handle.get(), symtab.get()
01003 );
01004 }
01005
01006 if (dyn_symtab_storage_size > 0) {
01007 dynamic_symtab.reset(
01008 (bfd_symbol**) malloc(dyn_symtab_storage_size)
01009 );
01010 dyn_symcount = bfd_canonicalize_dynamic_symtab(
01011 bfd_handle.get(), dynamic_symtab.get()
01012 );
01013 }
01014
01015
01016 if (symcount <= 0 && dyn_symcount <= 0) {
01017 return r;
01018 }
01019
01020 r.handle = move(bfd_handle);
01021 r.symtab = move(symtab);
01022 r.dynamic_symtab = move(dynamic_symtab);
01023 return r;
01024 }
01025
01026 struct find_sym_result {
01027 bool found;
01028 const char* filename;
01029 const char* funcname;
01030 unsigned int line;
01031 };
01032
01033 struct find_sym_context {
01034 TraceResolverLinuxImpl* self;
01035 bfd_fileobject* fobj;
01036 void* addr;
01037 void* base_addr;
01038 find_sym_result result;
01039 };
01040
01041 find_sym_result find_symbol_details(bfd_fileobject& fobj, void* addr,
01042 void* base_addr) {
01043 find_sym_context context;
01044 context.self = this;
01045 context.fobj = &fobj;
01046 context.addr = addr;
01047 context.base_addr = base_addr;
01048 context.result.found = false;
01049 bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
01050 (void*)&context);
01051 return context.result;
01052 }
01053
01054 static void find_in_section_trampoline(bfd*, asection* section,
01055 void* data) {
01056 find_sym_context* context = static_cast<find_sym_context*>(data);
01057 context->self->find_in_section(
01058 reinterpret_cast<bfd_vma>(context->addr),
01059 reinterpret_cast<bfd_vma>(context->base_addr),
01060 *context->fobj,
01061 section, context->result
01062 );
01063 }
01064
01065 void find_in_section(bfd_vma addr, bfd_vma base_addr,
01066 bfd_fileobject& fobj, asection* section, find_sym_result& result)
01067 {
01068 if (result.found) return;
01069
01070 if ((bfd_get_section_flags(fobj.handle.get(), section)
01071 & SEC_ALLOC) == 0)
01072 return;
01073
01074 bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
01075 bfd_size_type size = bfd_get_section_size(section);
01076
01077
01078 if (addr < sec_addr || addr >= sec_addr + size) {
01079 addr -= base_addr;
01080 if (addr < sec_addr || addr >= sec_addr + size) {
01081 return;
01082 }
01083 }
01084
01085 if (!result.found && fobj.symtab) {
01086 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
01087 fobj.symtab.get(), addr - sec_addr, &result.filename,
01088 &result.funcname, &result.line);
01089 }
01090
01091 if (!result.found && fobj.dynamic_symtab) {
01092 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
01093 fobj.dynamic_symtab.get(), addr - sec_addr,
01094 &result.filename, &result.funcname, &result.line);
01095 }
01096
01097 }
01098
01099 ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj,
01100 find_sym_result previous_result) {
01101
01102
01103 ResolvedTrace::source_locs_t results;
01104 while (previous_result.found) {
01105 find_sym_result result;
01106 result.found = bfd_find_inliner_info(fobj.handle.get(),
01107 &result.filename, &result.funcname, &result.line);
01108
01109 if (result.found)
01110
01111
01112
01113 {
01114 ResolvedTrace::SourceLoc src_loc;
01115 src_loc.line = result.line;
01116 if (result.filename) {
01117 src_loc.filename = result.filename;
01118 }
01119 if (result.funcname) {
01120 src_loc.function = demangle(result.funcname);
01121 }
01122 results.push_back(src_loc);
01123 }
01124 previous_result = result;
01125 }
01126 return results;
01127 }
01128
01129 bool cstrings_eq(const char* a, const char* b) {
01130 if (!a || !b) {
01131 return false;
01132 }
01133 return strcmp(a, b) == 0;
01134 }
01135
01136 };
01137 #endif // BACKWARD_HAS_BFD == 1
01138
01139 #if BACKWARD_HAS_DW == 1
01140
01141 template <>
01142 class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
01143 public TraceResolverLinuxImplBase {
01144 public:
01145 TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
01146
01147 template <class ST>
01148 void load_stacktrace(ST&) {}
01149
01150 ResolvedTrace resolve(ResolvedTrace trace) {
01151 using namespace details;
01152
01153 Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr;
01154
01155 if (!_dwfl_handle_initialized) {
01156
01157 _dwfl_cb.reset(new Dwfl_Callbacks);
01158 _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
01159 _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
01160 _dwfl_cb->debuginfo_path = 0;
01161
01162 _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
01163 _dwfl_handle_initialized = true;
01164
01165 if (!_dwfl_handle) {
01166 return trace;
01167 }
01168
01169
01170 dwfl_report_begin(_dwfl_handle.get());
01171 int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid());
01172 dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
01173 if (r < 0) {
01174 return trace;
01175 }
01176 }
01177
01178 if (!_dwfl_handle) {
01179 return trace;
01180 }
01181
01182
01183
01184
01185 Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
01186 if (mod) {
01187
01188
01189 const char* module_name = dwfl_module_info (mod,
01190 0, 0, 0, 0, 0, 0, 0);
01191 if (module_name) {
01192 trace.object_filename = module_name;
01193 }
01194
01195
01196
01197
01198
01199 const char* sym_name = dwfl_module_addrname(mod, trace_addr);
01200 if (sym_name) {
01201 trace.object_function = demangle(sym_name);
01202 }
01203 }
01204
01205
01206
01207
01208
01209
01210
01211 Dwarf_Addr mod_bias = 0;
01212 Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
01213
01214 #if 1
01215 if (!cudie) {
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
01227 Dwarf_Die die_mem;
01228 Dwarf_Die* fundie = find_fundie_by_pc(cudie,
01229 trace_addr - mod_bias, &die_mem);
01230 if (fundie) {
01231 break;
01232 }
01233 }
01234 }
01235 #endif
01236
01237
01238 #ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
01239 if (!cudie) {
01240
01241
01242
01243
01244
01245 Dwarf_Addr cfi_bias;
01246 Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
01247
01248 Dwarf_Addr bias;
01249 while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
01250 if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
01251
01252
01253
01254
01255
01256
01257
01258 handle<Dwarf_Frame*> frame;
01259 dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
01260 if (frame) {
01261 break;
01262 }
01263 }
01264 }
01265 }
01266 #endif
01267
01268 if (!cudie) {
01269 return trace;
01270 }
01271
01272
01273
01274
01275
01276 Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
01277
01278 if (srcloc) {
01279 const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
01280 if (srcfile) {
01281 trace.source.filename = srcfile;
01282 }
01283 int line = 0, col = 0;
01284 dwarf_lineno(srcloc, &line);
01285 dwarf_linecol(srcloc, &col);
01286 trace.source.line = line;
01287 trace.source.col = col;
01288 }
01289
01290 deep_first_search_by_pc(cudie, trace_addr - mod_bias,
01291 inliners_search_cb(trace));
01292 if (trace.source.function.size() == 0) {
01293
01294 trace.source.function = trace.object_function;
01295 }
01296
01297 return trace;
01298 }
01299
01300 private:
01301 typedef details::handle<Dwfl*, details::deleter<void, Dwfl*, &dwfl_end> >
01302 dwfl_handle_t;
01303 details::handle<Dwfl_Callbacks*, details::default_delete<Dwfl_Callbacks*> >
01304 _dwfl_cb;
01305 dwfl_handle_t _dwfl_handle;
01306 bool _dwfl_handle_initialized;
01307
01308
01309
01310 struct inliners_search_cb {
01311 void operator()(Dwarf_Die* die) {
01312 switch (dwarf_tag(die)) {
01313 const char* name;
01314 case DW_TAG_subprogram:
01315 if ((name = dwarf_diename(die))) {
01316 trace.source.function = name;
01317 }
01318 break;
01319
01320 case DW_TAG_inlined_subroutine:
01321 ResolvedTrace::SourceLoc sloc;
01322 Dwarf_Attribute attr_mem;
01323
01324 if ((name = dwarf_diename(die))) {
01325 sloc.function = name;
01326 }
01327 if ((name = die_call_file(die))) {
01328 sloc.filename = name;
01329 }
01330
01331 Dwarf_Word line = 0, col = 0;
01332 dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
01333 &attr_mem), &line);
01334 dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
01335 &attr_mem), &col);
01336 sloc.line = line;
01337 sloc.col = col;
01338
01339 trace.inliners.push_back(sloc);
01340 break;
01341 };
01342 }
01343 ResolvedTrace& trace;
01344 inliners_search_cb(ResolvedTrace& t): trace(t) {}
01345 };
01346
01347
01348 static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
01349 Dwarf_Addr low, high;
01350
01351
01352 if (dwarf_hasattr(die, DW_AT_low_pc) &&
01353 dwarf_hasattr(die, DW_AT_high_pc)) {
01354 if (dwarf_lowpc(die, &low) != 0) {
01355 return false;
01356 }
01357 if (dwarf_highpc(die, &high) != 0) {
01358 Dwarf_Attribute attr_mem;
01359 Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
01360 Dwarf_Word value;
01361 if (dwarf_formudata(attr, &value) != 0) {
01362 return false;
01363 }
01364 high = low + value;
01365 }
01366 return pc >= low && pc < high;
01367 }
01368
01369
01370 Dwarf_Addr base;
01371 ptrdiff_t offset = 0;
01372 while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
01373 if (pc >= low && pc < high) {
01374 return true;
01375 }
01376 }
01377 return false;
01378 }
01379
01380 static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
01381 Dwarf_Die* result) {
01382 if (dwarf_child(parent_die, result) != 0) {
01383 return 0;
01384 }
01385
01386 Dwarf_Die* die = result;
01387 do {
01388 switch (dwarf_tag(die)) {
01389 case DW_TAG_subprogram:
01390 case DW_TAG_inlined_subroutine:
01391 if (die_has_pc(die, pc)) {
01392 return result;
01393 }
01394 default:
01395 bool declaration = false;
01396 Dwarf_Attribute attr_mem;
01397 dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
01398 &attr_mem), &declaration);
01399 if (!declaration) {
01400
01401
01402
01403 Dwarf_Die die_mem;
01404 Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
01405 if (indie) {
01406 *result = die_mem;
01407 return result;
01408 }
01409 }
01410 };
01411 } while (dwarf_siblingof(die, result) == 0);
01412 return 0;
01413 }
01414
01415 template <typename CB>
01416 static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
01417 Dwarf_Addr pc, CB cb) {
01418 Dwarf_Die die_mem;
01419 if (dwarf_child(parent_die, &die_mem) != 0) {
01420 return false;
01421 }
01422
01423 bool branch_has_pc = false;
01424 Dwarf_Die* die = &die_mem;
01425 do {
01426 bool declaration = false;
01427 Dwarf_Attribute attr_mem;
01428 dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
01429 if (!declaration) {
01430
01431
01432
01433
01434 branch_has_pc = deep_first_search_by_pc(die, pc, cb);
01435 }
01436 if (!branch_has_pc) {
01437 branch_has_pc = die_has_pc(die, pc);
01438 }
01439 if (branch_has_pc) {
01440 cb(die);
01441 }
01442 } while (dwarf_siblingof(die, &die_mem) == 0);
01443 return branch_has_pc;
01444 }
01445
01446 static const char* die_call_file(Dwarf_Die *die) {
01447 Dwarf_Attribute attr_mem;
01448 Dwarf_Sword file_idx = 0;
01449
01450 dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
01451 &file_idx);
01452
01453 if (file_idx == 0) {
01454 return 0;
01455 }
01456
01457 Dwarf_Die die_mem;
01458 Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
01459 if (!cudie) {
01460 return 0;
01461 }
01462
01463 Dwarf_Files* files = 0;
01464 size_t nfiles;
01465 dwarf_getsrcfiles(cudie, &files, &nfiles);
01466 if (!files) {
01467 return 0;
01468 }
01469
01470 return dwarf_filesrc(files, file_idx, 0, 0);
01471 }
01472
01473 };
01474 #endif // BACKWARD_HAS_DW == 1
01475
01476 template<>
01477 class TraceResolverImpl<system_tag::linux_tag>:
01478 public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
01479
01480 #endif // BACKWARD_SYSTEM_LINUX
01481
01482 class TraceResolver:
01483 public TraceResolverImpl<system_tag::current_tag> {};
01484
01485
01486
01487 class SourceFile {
01488 public:
01489 typedef std::vector<std::pair<unsigned, std::string> > lines_t;
01490
01491 SourceFile() {}
01492 SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {}
01493 bool is_open() const { return _file->is_open(); }
01494
01495 lines_t& get_lines(unsigned line_start, unsigned line_count, lines_t& lines) {
01496 using namespace std;
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506 _file->clear();
01507 _file->seekg(0);
01508 string line;
01509 unsigned line_idx;
01510
01511 for (line_idx = 1; line_idx < line_start; ++line_idx) {
01512 std::getline(*_file, line);
01513 if (!*_file) {
01514 return lines;
01515 }
01516 }
01517
01518
01519
01520
01521 struct isspace {
01522 bool operator()(char c) {
01523 return std::isspace(c);
01524 }
01525 };
01526
01527 bool started = false;
01528 for (; line_idx < line_start + line_count; ++line_idx) {
01529 getline(*_file, line);
01530 if (!*_file) {
01531 return lines;
01532 }
01533 if (!started) {
01534 if (std::find_if(line.begin(), line.end(),
01535 not_isspace()) == line.end())
01536 continue;
01537 started = true;
01538 }
01539 lines.push_back(make_pair(line_idx, line));
01540 }
01541
01542 lines.erase(
01543 std::find_if(lines.rbegin(), lines.rend(),
01544 not_isempty()).base(), lines.end()
01545 );
01546 return lines;
01547 }
01548
01549 lines_t get_lines(unsigned line_start, unsigned line_count) {
01550 lines_t lines;
01551 return get_lines(line_start, line_count, lines);
01552 }
01553
01554
01555
01556 struct not_isspace {
01557 bool operator()(char c) {
01558 return !std::isspace(c);
01559 }
01560 };
01561
01562
01563 struct not_isempty {
01564 bool operator()(const lines_t::value_type& p) {
01565 return !(std::find_if(p.second.begin(), p.second.end(),
01566 not_isspace()) == p.second.end());
01567 }
01568 };
01569
01570 void swap(SourceFile& b) {
01571 _file.swap(b._file);
01572 }
01573
01574 #ifdef BACKWARD_ATLEAST_CXX11
01575 SourceFile(SourceFile&& from): _file(0) {
01576 swap(from);
01577 }
01578 SourceFile& operator=(SourceFile&& from) {
01579 swap(from); return *this;
01580 }
01581 #else
01582 explicit SourceFile(const SourceFile& from) {
01583
01584 swap(const_cast<SourceFile&>(from));
01585 }
01586 SourceFile& operator=(const SourceFile& from) {
01587
01588 swap(const_cast<SourceFile&>(from)); return *this;
01589 }
01590 #endif
01591
01592 private:
01593 details::handle<std::ifstream*,
01594 details::default_delete<std::ifstream*>
01595 > _file;
01596
01597 #ifdef BACKWARD_ATLEAST_CXX11
01598 SourceFile(const SourceFile&) = delete;
01599 SourceFile& operator=(const SourceFile&) = delete;
01600 #endif
01601 };
01602
01603 class SnippetFactory {
01604 public:
01605 typedef SourceFile::lines_t lines_t;
01606
01607 lines_t get_snippet(const std::string& filename,
01608 unsigned line_start, unsigned context_size) {
01609
01610 SourceFile& src_file = get_src_file(filename);
01611 unsigned start = line_start - context_size / 2;
01612 return src_file.get_lines(start, context_size);
01613 }
01614
01615 lines_t get_combined_snippet(
01616 const std::string& filename_a, unsigned line_a,
01617 const std::string& filename_b, unsigned line_b,
01618 unsigned context_size) {
01619 SourceFile& src_file_a = get_src_file(filename_a);
01620 SourceFile& src_file_b = get_src_file(filename_b);
01621
01622 lines_t lines = src_file_a.get_lines(line_a - context_size / 4,
01623 context_size / 2);
01624 src_file_b.get_lines(line_b - context_size / 4, context_size / 2,
01625 lines);
01626 return lines;
01627 }
01628
01629 lines_t get_coalesced_snippet(const std::string& filename,
01630 unsigned line_a, unsigned line_b, unsigned context_size) {
01631 SourceFile& src_file = get_src_file(filename);
01632
01633 using std::min; using std::max;
01634 unsigned a = min(line_a, line_b);
01635 unsigned b = max(line_a, line_b);
01636
01637 if ((b - a) < (context_size / 3)) {
01638 return src_file.get_lines((a + b - context_size + 1) / 2,
01639 context_size);
01640 }
01641
01642 lines_t lines = src_file.get_lines(a - context_size / 4,
01643 context_size / 2);
01644 src_file.get_lines(b - context_size / 4, context_size / 2, lines);
01645 return lines;
01646 }
01647
01648
01649 private:
01650 typedef details::hashtable<std::string, SourceFile>::type src_files_t;
01651 src_files_t _src_files;
01652
01653 SourceFile& get_src_file(const std::string& filename) {
01654 src_files_t::iterator it = _src_files.find(filename);
01655 if (it != _src_files.end()) {
01656 return it->second;
01657 }
01658 SourceFile& new_src_file = _src_files[filename];
01659 new_src_file = SourceFile(filename);
01660 return new_src_file;
01661 }
01662 };
01663
01664
01665
01666 #ifdef BACKWARD_SYSTEM_LINUX
01667
01668 namespace Color {
01669 enum type {
01670 yellow = 33,
01671 purple = 35,
01672 reset = 39
01673 };
01674 }
01675
01676 class Colorize {
01677 public:
01678 Colorize(std::FILE* os):
01679 _os(os), _reset(false), _istty(false) {}
01680
01681 void init() {
01682 _istty = isatty(fileno(_os));
01683 }
01684
01685 void set_color(Color::type ccode) {
01686 if (!_istty) return;
01687
01688
01689
01690 fprintf(_os, "\033[%im", static_cast<int>(ccode));
01691 _reset = (ccode != Color::reset);
01692 }
01693
01694 ~Colorize() {
01695 if (_reset) {
01696 set_color(Color::reset);
01697 }
01698 }
01699
01700 private:
01701 std::FILE* _os;
01702 bool _reset;
01703 bool _istty;
01704 };
01705
01706 #else // ndef BACKWARD_SYSTEM_LINUX
01707
01708
01709 namespace Color {
01710 enum type {
01711 yellow = 0,
01712 purple = 0,
01713 reset = 0
01714 };
01715 }
01716
01717 class Colorize {
01718 public:
01719 Colorize(std::FILE*) {}
01720 void init() {}
01721 void set_color(Color::type) {}
01722 };
01723
01724 #endif // BACKWARD_SYSTEM_LINUX
01725
01726 class Printer {
01727 public:
01728 bool snippet;
01729 bool color;
01730 bool address;
01731 bool object;
01732 int inliner_context_size;
01733 int trace_context_size;
01734
01735 Printer():
01736 snippet(true),
01737 color(true),
01738 address(false),
01739 object(false),
01740 inliner_context_size(5),
01741 trace_context_size(7)
01742 {}
01743
01744 template <typename ST>
01745 FILE* print(ST& st, FILE* os = stderr) {
01746 Colorize colorize(os);
01747 if (color) {
01748 colorize.init();
01749 }
01750 print_header(os, st.thread_id());
01751 _resolver.load_stacktrace(st);
01752 for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
01753 print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize);
01754 }
01755 return os;
01756 }
01757
01758 template <typename IT>
01759 FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) {
01760 Colorize colorize(os);
01761 if (color) {
01762 colorize.init();
01763 }
01764 print_header(os, thread_id);
01765 for (; begin != end; ++begin) {
01766 print_trace(os, *begin, colorize);
01767 }
01768 return os;
01769 }
01770 private:
01771 TraceResolver _resolver;
01772 SnippetFactory _snippets;
01773
01774 void print_header(FILE* os, unsigned thread_id) {
01775 fprintf(os, "Stack trace (most recent call last)");
01776 if (thread_id) {
01777 fprintf(os, " in thread %u:\n", thread_id);
01778 } else {
01779 fprintf(os, ":\n");
01780 }
01781 }
01782
01783 void print_trace(FILE* os, const ResolvedTrace& trace,
01784 Colorize& colorize) {
01785 fprintf(os, "#%-2u", trace.idx);
01786 bool already_indented = true;
01787
01788 if (!trace.source.filename.size() || object) {
01789 fprintf(os, " Object \"%s\", at %p, in %s\n",
01790 trace.object_filename.c_str(), trace.addr,
01791 trace.object_function.c_str());
01792 already_indented = false;
01793 }
01794
01795 for (size_t inliner_idx = trace.inliners.size();
01796 inliner_idx > 0; --inliner_idx) {
01797 if (!already_indented) {
01798 fprintf(os, " ");
01799 }
01800 const ResolvedTrace::SourceLoc& inliner_loc
01801 = trace.inliners[inliner_idx-1];
01802 print_source_loc(os, " | ", inliner_loc);
01803 if (snippet) {
01804 print_snippet(os, " | ", inliner_loc,
01805 colorize, Color::purple, inliner_context_size);
01806 }
01807 already_indented = false;
01808 }
01809
01810 if (trace.source.filename.size()) {
01811 if (!already_indented) {
01812 fprintf(os, " ");
01813 }
01814 print_source_loc(os, " ", trace.source, trace.addr);
01815 if (snippet) {
01816 print_snippet(os, " ", trace.source,
01817 colorize, Color::yellow, trace_context_size);
01818 }
01819 }
01820 }
01821
01822 void print_snippet(FILE* os, const char* indent,
01823 const ResolvedTrace::SourceLoc& source_loc,
01824 Colorize& colorize, Color::type color_code,
01825 int context_size)
01826 {
01827 using namespace std;
01828 typedef SnippetFactory::lines_t lines_t;
01829
01830 lines_t lines = _snippets.get_snippet(source_loc.filename,
01831 source_loc.line, context_size);
01832
01833 for (lines_t::const_iterator it = lines.begin();
01834 it != lines.end(); ++it) {
01835 if (it-> first == source_loc.line) {
01836 colorize.set_color(color_code);
01837 fprintf(os, "%s>", indent);
01838 } else {
01839 fprintf(os, "%s ", indent);
01840 }
01841 fprintf(os, "%4u: %s\n", it->first, it->second.c_str());
01842 if (it-> first == source_loc.line) {
01843 colorize.set_color(Color::reset);
01844 }
01845 }
01846 }
01847
01848 void print_source_loc(FILE* os, const char* indent,
01849 const ResolvedTrace::SourceLoc& source_loc,
01850 void* addr=0) {
01851 fprintf(os, "%sSource \"%s\", line %i, in %s",
01852 indent, source_loc.filename.c_str(), (int)source_loc.line,
01853 source_loc.function.c_str());
01854
01855 if (address && addr != 0) {
01856 fprintf(os, " [%p]\n", addr);
01857 } else {
01858 fprintf(os, "\n");
01859 }
01860 }
01861 };
01862
01863
01864
01865 #ifdef BACKWARD_SYSTEM_LINUX
01866
01867
01868 class SignalHandling {
01869 public:
01870 static std::vector<int> make_default_signals() {
01871 const int posix_signals[] = {
01872
01873 SIGABRT,
01874 SIGBUS,
01875 SIGFPE,
01876 SIGILL,
01877 SIGIOT,
01878 SIGQUIT,
01879 SIGSEGV,
01880 SIGSYS,
01881 SIGTRAP,
01882 SIGUNUSED,
01883 SIGXCPU,
01884 SIGXFSZ,
01885 };
01886 return std::vector<int>(posix_signals, posix_signals + sizeof posix_signals / sizeof posix_signals[0] );
01887 }
01888
01889 SignalHandling(const std::vector<int>& posix_signals = make_default_signals()):
01890 _loaded(false) {
01891 bool success = true;
01892
01893 const size_t stack_size = 1024 * 1024 * 8;
01894 _stack_content.reset((char*)malloc(stack_size));
01895 if (_stack_content) {
01896 stack_t ss;
01897 ss.ss_sp = _stack_content.get();
01898 ss.ss_size = stack_size;
01899 ss.ss_flags = 0;
01900 if (sigaltstack(&ss, 0) < 0) {
01901 success = false;
01902 }
01903 } else {
01904 success = false;
01905 }
01906
01907 for (size_t i = 0; i < posix_signals.size(); ++i) {
01908 struct sigaction action;
01909 memset(&action, 0, sizeof action);
01910 action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
01911 SA_RESETHAND);
01912 sigfillset(&action.sa_mask);
01913 sigdelset(&action.sa_mask, posix_signals[i]);
01914 action.sa_sigaction = &sig_handler;
01915
01916 int r = sigaction(posix_signals[i], &action, 0);
01917 if (r < 0) success = false;
01918 }
01919
01920 _loaded = success;
01921 }
01922
01923 bool loaded() const { return _loaded; }
01924
01925 private:
01926 details::handle<char*> _stack_content;
01927 bool _loaded;
01928
01929 #ifdef __GNUC__
01930 __attribute__((noreturn))
01931 #endif
01932 static void sig_handler(int, siginfo_t* info, void* _ctx) {
01933 ucontext_t *uctx = (ucontext_t*) _ctx;
01934
01935 StackTrace st;
01936 void* error_addr = 0;
01937 #ifdef REG_RIP // x86_64
01938 error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_RIP]);
01939 #elif defined(REG_EIP) // x86_32
01940 error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.gregs[REG_EIP]);
01941 #elif defined(__arm__)
01942 error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.arm_pc);
01943 #elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
01944 error_addr = reinterpret_cast<void*>(uctx->uc_mcontext.regs->nip);
01945 #else
01946 # warning ":/ sorry, ain't know no nothing none not of your architecture!"
01947 #endif
01948 if (error_addr) {
01949 st.load_from(error_addr, 32);
01950 } else {
01951 st.load_here(32);
01952 }
01953
01954 Printer printer;
01955 printer.address = true;
01956 printer.object = true;
01957 printer.color = true;
01958 printer.snippet = true;
01959 printer.print(st, stderr);
01960
01961 #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
01962 psiginfo(info, 0);
01963 #endif
01964
01965
01966 raise(info->si_signo);
01967
01968
01969 puts("watf? exit");
01970 _exit(EXIT_FAILURE);
01971 }
01972 };
01973
01974 #endif // BACKWARD_SYSTEM_LINUX
01975
01976 #ifdef BACKWARD_SYSTEM_UNKNOWN
01977
01978 class SignalHandling {
01979 public:
01980 SignalHandling(const std::vector<int>& = std::vector<int>()) {}
01981 bool init() { return false; }
01982 bool loaded() { return false; }
01983 };
01984
01985 #endif // BACKWARD_SYSTEM_UNKNOWN
01986
01987 }
01988
01989 #endif