backward.hpp
Go to the documentation of this file.
00001 /*
00002  * backward.hpp
00003  * Copyright 2013 Google Inc. All Rights Reserved.
00004  *
00005  * Permission is hereby granted, free of charge, to any person obtaining a copy
00006  * of this software and associated documentation files (the "Software"), to deal
00007  * in the Software without restriction, including without limitation the rights
00008  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009  * copies of the Software, and to permit persons to whom the Software is
00010  * furnished to do so, subject to the following conditions:
00011  *
00012  * The above copyright notice and this permission notice shall be included in
00013  * all copies or substantial portions of the Software.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00021  * SOFTWARE.
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 // You can define one of the following (or leave it to the auto-detection):
00045 //
00046 // #define BACKWARD_SYSTEM_LINUX
00047 //      - specialization for linux
00048 //
00049 // #define BACKWARD_SYSTEM_UNKNOWN
00050 //      - placebo implementation, does nothing.
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 // On linux, backtrace can back-trace or "walk" the stack using the following
00077 // libraries:
00078 //
00079 // #define BACKWARD_HAS_UNWIND 1
00080 //  - unwind comes from libgcc, but I saw an equivalent inside clang itself.
00081 //  - with unwind, the stacktrace is as accurate as it can possibly be, since
00082 //  this is used by the C++ runtine in gcc/clang for stack unwinding on
00083 //  exception.
00084 //  - normally libgcc is already linked to your program by default.
00085 //
00086 // #define BACKWARD_HAS_BACKTRACE == 1
00087 //  - backtrace seems to be a little bit more portable than libunwind, but on
00088 //  linux, it uses unwind anyway, but abstract away a tiny information that is
00089 //  sadly really important in order to get perfectly accurate stack traces.
00090 //  - backtrace is part of the (e)glib library.
00091 //
00092 // The default is:
00093 // #define BACKWARD_HAS_UNWIND == 1
00094 //
00095 // Note that only one of the define should be set to 1 at a time.
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 // On linux, backward can extract detailed information about a stack trace
00107 // using one of the following libraries:
00108 //
00109 // #define BACKWARD_HAS_DW 1
00110 //  - libdw gives you the most juicy details out of your stack traces:
00111 //    - object filename
00112 //    - function name
00113 //    - source filename
00114 //        - line and column numbers
00115 //        - source code snippet (assuming the file is accessible)
00116 //        - variables name and values (if not optimized out)
00117 //  - You need to link with the lib "dw":
00118 //    - apt-get install libdw-dev
00119 //    - g++/clang++ -ldw ...
00120 //
00121 // #define BACKWARD_HAS_BFD 1
00122 //  - With libbfd, you get a fair amount of details:
00123 //    - object filename
00124 //    - function name
00125 //    - source filename
00126 //        - line numbers
00127 //        - source code snippet (assuming the file is accessible)
00128 //  - You need to link with the lib "bfd":
00129 //    - apt-get install binutils-dev
00130 //    - g++/clang++ -lbfd ...
00131 //
00132 // #define BACKWARD_HAS_BACKTRACE_SYMBOL 1
00133 //  - backtrace provides minimal details for a stack trace:
00134 //    - object filename
00135 //    - function name
00136 //  - backtrace is part of the (e)glib library.
00137 //
00138 // The default is:
00139 // #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1
00140 //
00141 // Note that only one of the define should be set to 1 at a time.
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 // while gcc's unwind.h defines something like that:
00160 //  extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
00161 //  extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
00162 //
00163 // clang's unwind.h defines something like this:
00164 //  uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
00165 //
00166 // Even if the _Unwind_GetIPInfo can be linked to, it is not declared, worse we
00167 // cannot just redeclare it because clang's unwind.h doesn't define _Unwind_Ptr
00168 // anyway.
00169 //
00170 // Luckily we can play on the fact that the guard macros have a different name:
00171 #ifdef __CLANG_UNWIND_H
00172 // In fact, this function still comes from libgcc (on my different linux boxes,
00173 // clang links against libgcc).
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 //              NOTE: defining PACKAGE{,_VERSION} is required before including
00190 //                    bfd.h on some platforms, see also:
00191 //                    https://sourceware.org/bugzilla/show_bug.cgi?id=14243
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                 // then we shall rely on backtrace
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> // for std::swap
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         } // namespace details
00232         } // namespace backward
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         } // namespace details
00246         } // namespace backward
00247 #endif // BACKWARD_ATLEAST_CXX11
00248 
00249 namespace backward {
00250 
00251 namespace system_tag {
00252         struct linux_tag; // seems that I cannot call that "linux" because the name
00253         // is already defined... so I am adding _tag everywhere.
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 } // namespace system_tag
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 } // namespace trace_resolver_tag
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                 // some sort of poor man's move semantic.
00342                 swap(const_cast<handle&>(from));
00343         }
00344         handle& operator=(const handle& from) {
00345                 // some sort of poor man's move semantic.
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); // can throw, we are safe here.
00370                 swap(b._empty, _empty); // should not throw: if you cannot swap two
00371                 // bools without throwing... It's a lost cause anyway!
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         // Watch out, we've got a badass over here
00384         T* operator&() {
00385                 _empty = false;
00386                 return &_val;
00387         }
00388 };
00389 
00390 // Default demangler implementation (do nothing).
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 } // namespace details
00427 
00428 /*************** A TRACE ***************/
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         // In which binary object this trace is located.
00464         std::string                    object_filename;
00465 
00466         // The function in the object that contain the trace. This is not the same
00467         // as source.function which can be an function inlined in object_function.
00468         std::string                    object_function;
00469 
00470         // The source location of this trace. It is possible for filename to be
00471         // empty and for line/col to be invalid (value 0) if this information
00472         // couldn't be deduced, for example if there is no debug information in the
00473         // binary object.
00474         SourceLoc                      source;
00475 
00476         // An optionals list of "inliners". All the successive sources location
00477         // from where the source location of the trace (the attribute right above)
00478         // is inlined. It is especially useful when you compiled with optimization.
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 /*************** STACK TRACE ***************/
00489 
00490 // default implemention.
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                         // If the thread is the main one, let's hide that.
00519                         // I like to keep little secret sometimes.
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) { // ignore first frame.
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 } // namespace details
00605 
00606 
00607 template <>
00608 class StackTraceImpl<system_tag::linux_tag>: public StackTraceLinuxImplHolder {
00609 public:
00610         __attribute__ ((noinline)) // TODO use some macro
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)) // TODO use some macro
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 /*************** TRACE RESOLVER ***************/
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; // we cannot do better.
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                 // trace.addr is a virtual address in memory pointing to some code.
00779                 // Let's try to find from which loaded object it comes from.
00780                 // The loaded object can be yourself btw.
00781                 if (!dladdr(trace.addr, &symbol_info)) {
00782                         return trace; // dat broken trace...
00783                 }
00784 
00785                 // Now we get in symbol_info:
00786                 // .dli_fname:
00787                 //              pathname of the shared object that contains the address.
00788                 // .dli_fbase:
00789                 //              where the object is loaded in memory.
00790                 // .dli_sname:
00791                 //              the name of the nearest symbol to trace.addr, we expect a
00792                 //              function name.
00793                 // .dli_saddr:
00794                 //              the exact address corresponding to .dli_sname.
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; // sad, we couldn't load the object :(
00808                 }
00809 
00810 
00811                 find_sym_result* details_selected; // to be filled.
00812 
00813                 // trace.addr is the next instruction to be executed after returning
00814                 // from the nested stack frame. In C++ this usually relate to the next
00815                 // statement right after the function call that leaded to a new stack
00816                 // frame. This is not usually what you want to see when printing out a
00817                 // stacktrace...
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                 // ...this is why we also try to resolve the symbol that is right
00824                 // before the return address. If we are lucky enough, we will get the
00825                 // line of the function that was called. But if the code is optimized,
00826                 // we might get something absolutely not related since the compiler
00827                 // can reschedule the return address with inline functions and
00828                 // tail-call optimisation (among other things that I don't even know
00829                 // or cannot even dream about with my tiny limited brain).
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                 // In debug mode, we should always get the right thing(TM).
00835                 if (details_call_site.found && details_adjusted_call_site.found) {
00836                         // Ok, we assume that details_adjusted_call_site is a better estimation.
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                         // we have to re-resolve the symbol in order to reset some
00843                         // internal state in BFD... so we can call backtrace_inliners
00844                         // thereafter...
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                                 // this time we get the name of the function where the code is
00858                                 // located, instead of the function were the address is
00859                                 // located. In short, if the code was inlined, we get the
00860                                 // function correspoding to the code. Else we already got in
00861                                 // trace.function.
00862                                 trace.source.function = demangle(details_selected->funcname);
00863 
00864                                 if (!symbol_info.dli_sname) {
00865                                         // for the case dladdr failed to find the symbol name of
00866                                         // the function, we might as well try to put something
00867                                         // here.
00868                                         trace.object_function = trace.source.function;
00869                                 }
00870                         }
00871 
00872                         // Maybe the source of the trace got inlined inside the function
00873                         // (trace.source.function). Let's see if we can get all the inlined
00874                         // calls along the way up to the initial call site.
00875                         trace.inliners = backtrace_inliners(fobj, *details_selected);
00876 
00877 #if 0
00878                         if (trace.inliners.size() == 0) {
00879                                 // Maybe the trace was not inlined... or maybe it was and we
00880                                 // are lacking the debug information. Let's try to make the
00881                                 // world better and see if we can get the line number of the
00882                                 // function (trace.source.function) now.
00883                                 //
00884                                 // We will get the location of where the function start (to be
00885                                 // exact: the first instruction that really start the
00886                                 // function), not where the name of the function is defined.
00887                                 // This can be quite far away from the name of the function
00888                                 // btw.
00889                                 //
00890                                 // If the source of the function is the same as the source of
00891                                 // the trace, we cannot say if the trace was really inlined or
00892                                 // not.  However, if the filename of the source is different
00893                                 // between the function and the trace... we can declare it as
00894                                 // an inliner.  This is not 100% accurate, but better than
00895                                 // nothing.
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                 // this new object is empty for now.
00962                 bfd_fileobject& r = _fobj_bfd_map[filename_object];
00963 
00964                 // we do the work temporary in this one;
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; // not an object? You lose.
00978                 }
00979 
00980                 if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
00981                         return r; // that's what happen when you forget to compile in debug.
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; // weird, is the file is corrupted?
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; // damned, that's a stripped file that you got there!
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; // a debug section is never loaded automatically.
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                 // are we in the boundaries of the section?
01078                 if (addr < sec_addr || addr >= sec_addr + size) {
01079                         addr -= base_addr; // oups, a relocated object, lets try again...
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                 // This function can be called ONLY after a SUCCESSFUL call to
01102                 // find_symbol_details. The state is global to the bfd_handle.
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) /* and not (
01110                                                 cstrings_eq(previous_result.filename, result.filename)
01111                                                 and cstrings_eq(previous_result.funcname, result.funcname)
01112                                                 and result.line == previous_result.line
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                         // initialize dwfl...
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                         // ...from the current process.
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                 // find the module (binary object) that contains the trace's address.
01183                 // This is not using any debug information, but the addresses ranges of
01184                 // all the currently loaded binary object.
01185                 Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
01186                 if (mod) {
01187                         // now that we found it, lets get the name of it, this will be the
01188                         // full path to the running binary or one of the loaded library.
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                         // We also look after the name of the symbol, equal or before this
01195                         // address. This is found by walking the symtab. We should get the
01196                         // symbol corresponding to the function (mangled) containing the
01197                         // address. If the code corresponding to the address was inlined,
01198                         // this is the name of the out-most inliner function.
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                 // now let's get serious, and find out the source location (file and
01206                 // line number) of the address.
01207 
01208                 // This function will look in .debug_aranges for the address and map it
01209                 // to the location of the compilation unit DIE in .debug_info and
01210                 // return it.
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                         // Sadly clang does not generate the section .debug_aranges, thus
01217                         // dwfl_module_addrdie will fail early. Clang doesn't either set
01218                         // the lowpc/highpc/range info for every compilation unit.
01219                         //
01220                         // So in order to save the world:
01221                         // for every compilation unit, we will iterate over every single
01222                         // DIEs. Normally functions should have a lowpc/highpc/range, which
01223                         // we will use to infer the compilation unit.
01224 
01225                         // note that this is probably badly inefficient.
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 //#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
01238 #ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
01239                 if (!cudie) {
01240                         // If it's still not enough, lets dive deeper in the shit, and try
01241                         // to save the world again: for every compilation unit, we will
01242                         // load the corresponding .debug_line section, and see if we can
01243                         // find our address in it.
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                                         // ...but if we get a match, it might be a false positive
01253                                         // because our (address - bias) might as well be valid in a
01254                                         // different compilation unit. So we throw our last card on
01255                                         // the table and lookup for the address into the .eh_frame
01256                                         // section.
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; // this time we lost the game :/
01270                 }
01271 
01272                 // Now that we have a compilation unit DIE, this function will be able
01273                 // to load the corresponding section in .debug_line (if not already
01274                 // loaded) and hopefully find the source location mapped to our
01275                 // address.
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                         // fallback.
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         // defined here because in C++98, template function cannot take locally
01309         // defined types... grrr.
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                 // continuous range
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                 // non-continuous range.
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                                                 // let's be curious and look deeper in the tree,
01401                                                 // function are not necessarily at the first level, but
01402                                                 // might be nested inside a namespace, structure etc.
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                                 // let's be curious and look deeper in the tree, function are
01431                                 // not necessarily at the first level, but might be nested
01432                                 // inside a namespace, structure, a function, an inlined
01433                                 // function etc.
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 /*************** CODE SNIPPET ***************/
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                 // This function make uses of the dumbest algo ever:
01498                 //      1) seek(0)
01499                 //      2) read lines one by one and discard until line_start
01500                 //      3) read line one by one until line_start + line_count
01501                 //
01502                 // If you are getting snippets many time from the same file, it is
01503                 // somewhat a waste of CPU, feel free to benchmark and propose a
01504                 // better solution ;)
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                 // think of it like a lambda in C++98 ;)
01519                 // but look, I will reuse it two times!
01520                 // What a good boy am I.
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         // there is no find_if_not in C++98, lets do something crappy to
01555         // workaround.
01556         struct not_isspace {
01557                 bool operator()(char c) {
01558                         return !std::isspace(c);
01559                 }
01560         };
01561         // and define this one here because C++98 is not happy with local defined
01562         // struct passed to template functions, fuuuu.
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                 // some sort of poor man's move semantic.
01584                 swap(const_cast<SourceFile&>(from));
01585         }
01586         SourceFile& operator=(const SourceFile& from) {
01587                 // some sort of poor man's move semantic.
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 /*************** PRINTER ***************/
01665 
01666 #ifdef BACKWARD_SYSTEM_LINUX
01667 
01668 namespace Color {
01669         enum type {
01670                 yellow = 33,
01671                 purple = 35,
01672                 reset  = 39
01673         };
01674 } // namespace Color
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                 // I assume that the terminal can handle basic colors. Seriously I
01689                 // don't want to deal with all the termcap shit.
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 } // namespace Color
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 /*************** SIGNALS HANDLING ***************/
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                 // Signals for which the default action is "Core".
01873                 SIGABRT,    // Abort signal from abort(3)
01874                 SIGBUS,     // Bus error (bad memory access)
01875                 SIGFPE,     // Floating point exception
01876                 SIGILL,     // Illegal Instruction
01877                 SIGIOT,     // IOT trap. A synonym for SIGABRT
01878                 SIGQUIT,    // Quit from keyboard
01879                 SIGSEGV,    // Invalid memory reference
01880                 SIGSYS,     // Bad argument to routine (SVr4)
01881                 SIGTRAP,    // Trace/breakpoint trap
01882                 SIGUNUSED,  // Synonymous with SIGSYS
01883                 SIGXCPU,    // CPU time limit exceeded (4.2BSD)
01884                 SIGXFSZ,    // File size limit exceeded (4.2BSD)
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                 // try to forward the signal.
01966                 raise(info->si_signo);
01967 
01968                 // terminate the process immediately.
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 } // namespace backward
01988 
01989 #endif /* H_GUARD */


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:55