24 #ifndef H_6B9572DA_A64B_49E6_B234_051480991C89
25 #define H_6B9572DA_A64B_49E6_B234_051480991C89
28 # error "It's not going to compile without a C++ compiler..."
31 #if defined(BACKWARD_CXX11)
32 #elif defined(BACKWARD_CXX98)
34 # if __cplusplus >= 201103L
35 # define BACKWARD_CXX11
36 # define BACKWARD_ATLEAST_CXX11
37 # define BACKWARD_ATLEAST_CXX98
39 # define BACKWARD_CXX98
40 # define BACKWARD_ATLEAST_CXX98
52 #if defined(BACKWARD_SYSTEM_LINUX)
53 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
56 # define BACKWARD_SYSTEM_LINUX
58 # define BACKWARD_SYSTEM_UNKNOWN
75 #if defined(BACKWARD_SYSTEM_LINUX)
98 # if BACKWARD_HAS_UNWIND == 1
99 # elif BACKWARD_HAS_BACKTRACE == 1
101 # undef BACKWARD_HAS_UNWIND
102 # define BACKWARD_HAS_UNWIND 1
103 # undef BACKWARD_HAS_BACKTRACE
104 # define BACKWARD_HAS_BACKTRACE 0
144 # if BACKWARD_HAS_DW == 1
145 # elif BACKWARD_HAS_BFD == 1
146 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
148 # undef BACKWARD_HAS_DW
149 # define BACKWARD_HAS_DW 0
150 # undef BACKWARD_HAS_BFD
151 # define BACKWARD_HAS_BFD 0
152 # undef BACKWARD_HAS_BACKTRACE_SYMBOL
153 # define BACKWARD_HAS_BACKTRACE_SYMBOL 1
157 # if BACKWARD_HAS_UNWIND == 1
172 #ifdef __CLANG_UNWIND_H
176 extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*,
int*);
184 # include <sys/stat.h>
185 # include <syscall.h>
189 # if BACKWARD_HAS_BFD == 1
196 # ifndef PACKAGE_VERSION
197 # define PACKAGE_VERSION
209 # if BACKWARD_HAS_DW == 1
210 # include <elfutils/libdw.h>
211 # include <elfutils/libdwfl.h>
215 # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
217 # include <execinfo.h>
220 #endif // defined(BACKWARD_SYSTEM_LINUX)
222 #ifdef BACKWARD_ATLEAST_CXX11
223 # include <unordered_map>
227 template <
typename K,
typename V>
229 using type = std::unordered_map<K, V>;
234 #else // NOT BACKWARD_ATLEAST_CXX11
238 template <
typename K,
typename V>
242 template <
typename T>
243 const T&
move(
const T& v) {
return v; }
244 template <
typename T>
248 #endif // BACKWARD_ATLEAST_CXX11
252 namespace system_tag {
257 #if defined(BACKWARD_SYSTEM_LINUX)
259 #elif defined(BACKWARD_SYSTEM_UNKNOWN)
262 # error "May I please get my system defines?"
267 namespace trace_resolver_tag {
268 #ifdef BACKWARD_SYSTEM_LINUX
271 struct backtrace_symbol;
273 # if BACKWARD_HAS_DW == 1
274 using current = libdw;
275 # elif BACKWARD_HAS_BFD == 1
276 using current = libbfd;
277 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
278 using current = backtrace_symbol;
280 # error "You shall not pass, until you know what you want."
282 #endif // BACKWARD_SYSTEM_LINUX
288 template <
typename T>
291 template <
typename T>
294 template <
typename T>
297 template <
typename R,
typename T, R (*F)(T)>
299 template <
typename U>
305 template <
typename T>
312 template <
typename T,
typename Deleter = deleter<
void,
void*, &::free> >
318 #ifdef BACKWARD_ATLEAST_CXX11
333 #ifdef BACKWARD_ATLEAST_CXX11
338 swap(from);
return *
this;
347 swap(
const_cast<handle&
>(from));
return *
this;
355 operator const dummy*()
const {
359 return reinterpret_cast<const dummy*
>(
_val);
392 template <
typename TAG>
394 static std::string
demangle(
const char* funcname) {
399 #ifdef BACKWARD_SYSTEM_LINUX
403 demangler_impl(): _demangle_buffer_length(0) {}
405 std::string
demangle(
const char* funcname) {
406 using namespace details;
407 _demangle_buffer.reset(
408 abi::__cxa_demangle(funcname, NULL,
409 &_demangle_buffer_length, 0)
411 if (_demangle_buffer) {
412 return _demangle_buffer.get();
418 details::handle<char*> _demangle_buffer;
419 size_t _demangle_buffer_length;
422 #endif // BACKWARD_SYSTEM_LINUX
438 explicit Trace(
void* _addr,
size_t _idx):
439 addr(_addr), idx(_idx) {}
445 std::string
function;
460 return !(*
this == b);
492 template <
typename TAG>
495 size_t size()
const {
return 0; }
503 #ifdef BACKWARD_SYSTEM_LINUX
505 class StackTraceLinuxImplBase {
507 StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
509 unsigned thread_id()
const {
513 void skip_n_firsts(
size_t n) { _skip = n; }
516 void load_thread_info() {
517 _thread_id = syscall(SYS_gettid);
518 if (_thread_id == (
size_t) getpid()) {
525 size_t skip_n_firsts()
const {
return _skip; }
532 class StackTraceLinuxImplHolder:
public StackTraceLinuxImplBase {
534 size_t size()
const {
535 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
537 Trace operator[](
size_t idx) {
541 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
545 return &_stacktrace[skip_n_firsts()];
551 std::vector<void*> _stacktrace;
555 #if BACKWARD_HAS_UNWIND == 1
559 template <
typename F>
562 size_t operator()(F& f,
size_t depth) {
566 _Unwind_Backtrace(&this->backtrace_trampoline,
this);
575 static _Unwind_Reason_Code backtrace_trampoline(
576 _Unwind_Context* ctx,
void *
self) {
577 return ((Unwinder*)
self)->backtrace(ctx);
580 _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
581 if (_index >= 0 &&
static_cast<size_t>(_index) >= _depth)
582 return _URC_END_OF_STACK;
584 int ip_before_instruction = 0;
585 uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
587 if (!ip_before_instruction) {
592 (*_f)(_index, (
void*)ip);
595 return _URC_NO_REASON;
599 template <
typename F>
600 size_t unwind(F f,
size_t depth) {
601 Unwinder<F> unwinder;
602 return unwinder(f, depth);
609 class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
611 __attribute__ ((noinline))
612 size_t load_here(
size_t depth=32) {
617 _stacktrace.resize(depth);
618 size_t trace_cnt = details::unwind(callback(*
this), depth);
619 _stacktrace.resize(trace_cnt);
623 size_t load_from(
void* addr,
size_t depth=32) {
624 load_here(depth + 8);
626 for (
size_t i = 0; i < _stacktrace.size(); ++i) {
627 if (_stacktrace[i] == addr) {
633 _stacktrace.resize(std::min(_stacktrace.size(),
634 skip_n_firsts() + depth));
640 StackTraceImpl&
self;
641 callback(StackTraceImpl& _self): self(_self) {}
643 void operator()(
size_t idx,
void* addr) {
644 self._stacktrace[idx] = addr;
650 #else // BACKWARD_HAS_UNWIND == 0
653 class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
655 __attribute__ ((noinline))
656 size_t load_here(
size_t depth=32) {
661 _stacktrace.resize(depth + 1);
662 size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
663 _stacktrace.resize(trace_cnt);
668 size_t load_from(
void* addr,
size_t depth=32) {
669 load_here(depth + 8);
671 for (
size_t i = 0; i < _stacktrace.size(); ++i) {
672 if (_stacktrace[i] == addr) {
674 _stacktrace[i] = (
void*)( (uintptr_t)_stacktrace[i] + 1);
679 _stacktrace.resize(std::min(_stacktrace.size(),
680 skip_n_firsts() + depth));
685 #endif // BACKWARD_HAS_UNWIND
686 #endif // BACKWARD_SYSTEM_LINUX
693 template <
typename TAG>
696 #ifdef BACKWARD_SYSTEM_UNKNOWN
710 #ifdef BACKWARD_SYSTEM_LINUX
712 class TraceResolverLinuxImplBase {
714 std::string demangle(
const char* funcname) {
715 return _demangler.demangle(funcname);
719 details::demangler _demangler;
722 template <
typename STACKTRACE_TAG>
723 class TraceResolverLinuxImpl;
725 #if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
728 class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
729 public TraceResolverLinuxImplBase {
732 void load_stacktrace(ST& st) {
733 using namespace details;
734 if (st.size() == 0) {
738 backtrace_symbols(st.begin(), st.size())
742 ResolvedTrace resolve(ResolvedTrace trace) {
743 char* filename = _symbols[trace.idx];
744 char* funcname = filename;
745 while (*funcname && *funcname !=
'(') {
749 char* funcname_end = funcname;
750 while (*funcname_end && *funcname_end !=
')' && *funcname_end !=
'+') {
753 *funcname_end =
'\0';
754 trace.object_function = this->demangle(funcname);
755 trace.source.function = trace.object_function;
760 details::handle<char**> _symbols;
763 #endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1
765 #if BACKWARD_HAS_BFD == 1
768 class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
769 public TraceResolverLinuxImplBase {
771 TraceResolverLinuxImpl(): _bfd_loaded(false) {}
774 void load_stacktrace(ST&) {}
776 ResolvedTrace resolve(ResolvedTrace trace) {
782 if (!dladdr(trace.addr, &symbol_info)) {
797 if (symbol_info.dli_sname) {
798 trace.object_function = demangle(symbol_info.dli_sname);
801 if (!symbol_info.dli_fname) {
805 trace.object_filename = symbol_info.dli_fname;
806 bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
812 find_sym_result* details_selected;
819 find_sym_result details_call_site = find_symbol_details(fobj,
820 trace.addr, symbol_info.dli_fbase);
821 details_selected = &details_call_site;
823 #if BACKWARD_HAS_UNWIND == 0
831 find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
832 (
void*) (uintptr_t(trace.addr) - 1),
833 symbol_info.dli_fbase);
836 if (details_call_site.found && details_adjusted_call_site.found) {
838 details_selected = &details_adjusted_call_site;
839 trace.addr = (
void*) (uintptr_t(trace.addr) - 1);
842 if (details_selected == &details_call_site && details_call_site.found) {
846 details_call_site = find_symbol_details(fobj, trace.addr,
847 symbol_info.dli_fbase);
849 #endif // BACKWARD_HAS_UNWIND
851 if (details_selected->found) {
852 if (details_selected->filename) {
853 trace.source.filename = details_selected->filename;
855 trace.source.line = details_selected->line;
857 if (details_selected->funcname) {
863 trace.source.function = demangle(details_selected->funcname);
865 if (!symbol_info.dli_sname) {
869 trace.object_function = trace.source.function;
876 trace.inliners = backtrace_inliners(fobj, *details_selected);
879 if (trace.inliners.size() == 0) {
898 if (symbol_info.dli_saddr) {
899 find_sym_result details = find_symbol_details(fobj,
900 symbol_info.dli_saddr,
901 symbol_info.dli_fbase);
904 ResolvedTrace::SourceLoc diy_inliner;
905 diy_inliner.line = details.line;
906 if (details.filename) {
907 diy_inliner.filename = details.filename;
909 if (details.funcname) {
910 diy_inliner.function = demangle(details.funcname);
912 diy_inliner.function = trace.source.function;
914 if (diy_inliner != trace.source) {
915 trace.inliners.push_back(diy_inliner);
929 using bfd_handle_t = details::handle<bfd*,
930 details::deleter<bfd_boolean, bfd*, &bfd_close>
933 using bfd_symtab_t = details::handle<asymbol**>;
936 struct bfd_fileobject {
940 bfd_symtab_t dynamic_symtab;
944 fobj_bfd_map_t _fobj_bfd_map;
946 bfd_fileobject& load_object_with_bfd(
const std::string& filename_object) {
947 using namespace details;
950 using namespace details;
955 fobj_bfd_map_t::iterator it =
956 _fobj_bfd_map.find(filename_object);
957 if (it != _fobj_bfd_map.end()) {
962 bfd_fileobject&
r = _fobj_bfd_map[filename_object];
965 bfd_handle_t bfd_handle;
967 int fd = open(filename_object.c_str(), O_RDONLY);
969 bfd_fdopenr(filename_object.c_str(),
"default", fd)
976 if (!bfd_check_format(bfd_handle.get(), bfd_object)) {
980 if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
984 ssize_t symtab_storage_size =
985 bfd_get_symtab_upper_bound(bfd_handle.get());
987 ssize_t dyn_symtab_storage_size =
988 bfd_get_dynamic_symtab_upper_bound(bfd_handle.get());
990 if (symtab_storage_size <= 0 && dyn_symtab_storage_size <= 0) {
994 bfd_symtab_t symtab, dynamic_symtab;
995 ssize_t symcount = 0, dyn_symcount = 0;
997 if (symtab_storage_size > 0) {
999 (bfd_symbol**) malloc(symtab_storage_size)
1001 symcount = bfd_canonicalize_symtab(
1002 bfd_handle.get(), symtab.get()
1006 if (dyn_symtab_storage_size > 0) {
1007 dynamic_symtab.reset(
1008 (bfd_symbol**) malloc(dyn_symtab_storage_size)
1010 dyn_symcount = bfd_canonicalize_dynamic_symtab(
1011 bfd_handle.get(), dynamic_symtab.get()
1016 if (symcount <= 0 && dyn_symcount <= 0) {
1020 r.handle =
move(bfd_handle);
1021 r.symtab =
move(symtab);
1022 r.dynamic_symtab =
move(dynamic_symtab);
1026 struct find_sym_result {
1028 const char* filename;
1029 const char* funcname;
1033 struct find_sym_context {
1034 TraceResolverLinuxImpl*
self;
1035 bfd_fileobject* fobj;
1038 find_sym_result result;
1041 find_sym_result find_symbol_details(bfd_fileobject& fobj,
void* addr,
1043 find_sym_context context;
1044 context.self =
this;
1045 context.fobj = &fobj;
1046 context.addr = addr;
1047 context.base_addr = base_addr;
1048 context.result.found =
false;
1049 bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
1051 return context.result;
1054 static void find_in_section_trampoline(bfd*, asection* section,
1056 find_sym_context* context =
static_cast<find_sym_context*
>(data);
1057 context->self->find_in_section(
1058 reinterpret_cast<bfd_vma
>(context->addr),
1059 reinterpret_cast<bfd_vma
>(context->base_addr),
1061 section, context->result
1065 void find_in_section(bfd_vma addr, bfd_vma base_addr,
1066 bfd_fileobject& fobj, asection* section, find_sym_result& result)
1068 if (result.found)
return;
1070 if ((bfd_get_section_flags(fobj.handle.get(), section)
1074 bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
1075 bfd_size_type
size = bfd_get_section_size(section);
1078 if (addr < sec_addr || addr >= sec_addr + size) {
1080 if (addr < sec_addr || addr >= sec_addr + size) {
1085 if (!result.found && fobj.symtab) {
1086 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1087 fobj.symtab.get(), addr - sec_addr, &result.filename,
1088 &result.funcname, &result.line);
1091 if (!result.found && fobj.dynamic_symtab) {
1092 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1093 fobj.dynamic_symtab.get(), addr - sec_addr,
1094 &result.filename, &result.funcname, &result.line);
1100 find_sym_result previous_result) {
1104 while (previous_result.found) {
1105 find_sym_result result;
1106 result.found = bfd_find_inliner_info(fobj.handle.get(),
1107 &result.filename, &result.funcname, &result.line);
1114 ResolvedTrace::SourceLoc src_loc;
1115 src_loc.line = result.line;
1116 if (result.filename) {
1117 src_loc.filename = result.filename;
1119 if (result.funcname) {
1120 src_loc.function = demangle(result.funcname);
1122 results.push_back(src_loc);
1124 previous_result = result;
1129 bool cstrings_eq(
const char* a,
const char* b) {
1133 return strcmp(a, b) == 0;
1137 #endif // BACKWARD_HAS_BFD == 1
1139 #if BACKWARD_HAS_DW == 1
1142 class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
1143 public TraceResolverLinuxImplBase {
1145 TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
1148 void load_stacktrace(ST&) {}
1150 ResolvedTrace resolve(ResolvedTrace trace) {
1151 using namespace details;
1153 Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr;
1155 if (!_dwfl_handle_initialized) {
1157 _dwfl_cb.reset(
new Dwfl_Callbacks);
1158 _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
1159 _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
1160 _dwfl_cb->debuginfo_path = 0;
1162 _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
1163 _dwfl_handle_initialized =
true;
1165 if (!_dwfl_handle) {
1170 dwfl_report_begin(_dwfl_handle.get());
1171 int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid());
1172 dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
1178 if (!_dwfl_handle) {
1185 Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
1189 const char* module_name = dwfl_module_info (mod,
1190 0, 0, 0, 0, 0, 0, 0);
1192 trace.object_filename = module_name;
1199 const char* sym_name = dwfl_module_addrname(mod, trace_addr);
1201 trace.object_function = demangle(sym_name);
1211 Dwarf_Addr mod_bias = 0;
1212 Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
1226 while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
1228 Dwarf_Die* fundie = find_fundie_by_pc(cudie,
1229 trace_addr - mod_bias, &die_mem);
1238 #ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
1245 Dwarf_Addr cfi_bias;
1246 Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
1249 while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
1250 if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
1258 handle<Dwarf_Frame*> frame;
1259 dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
1276 Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
1279 const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
1281 trace.source.filename = srcfile;
1283 int line = 0, col = 0;
1284 dwarf_lineno(srcloc, &line);
1285 dwarf_linecol(srcloc, &col);
1286 trace.source.line = line;
1287 trace.source.col = col;
1290 deep_first_search_by_pc(cudie, trace_addr - mod_bias,
1291 inliners_search_cb(trace));
1292 if (trace.source.function.size() == 0) {
1294 trace.source.function = trace.object_function;
1301 using dwfl_handle_t = details::handle<Dwfl*, details::deleter<void, Dwfl*, &dwfl_end>>;
1302 details::handle<Dwfl_Callbacks*, details::default_delete<Dwfl_Callbacks*> >
1304 dwfl_handle_t _dwfl_handle;
1305 bool _dwfl_handle_initialized;
1309 struct inliners_search_cb {
1310 void operator()(Dwarf_Die* die) {
1311 switch (dwarf_tag(die)) {
1313 case DW_TAG_subprogram:
1314 if ((name = dwarf_diename(die))) {
1315 trace.source.function = name;
1319 case DW_TAG_inlined_subroutine:
1320 ResolvedTrace::SourceLoc sloc;
1321 Dwarf_Attribute attr_mem;
1323 if ((name = dwarf_diename(die))) {
1324 sloc.function = name;
1326 if ((name = die_call_file(die))) {
1327 sloc.filename = name;
1330 Dwarf_Word line = 0, col = 0;
1331 dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
1333 dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
1338 trace.inliners.push_back(sloc);
1342 ResolvedTrace& trace;
1343 inliners_search_cb(ResolvedTrace& t): trace(t) {}
1347 static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1348 Dwarf_Addr low, high;
1351 if (dwarf_hasattr(die, DW_AT_low_pc) and
1352 dwarf_hasattr(die, DW_AT_high_pc)) {
1353 if (dwarf_lowpc(die, &low) != 0) {
1356 if (dwarf_highpc(die, &high) != 0) {
1357 Dwarf_Attribute attr_mem;
1358 Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
1360 if (dwarf_formudata(attr, &value) != 0) {
1365 return pc >= low && pc < high;
1370 ptrdiff_t offset = 0;
1371 while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
1372 if (pc >= low && pc < high) {
1379 static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
1380 Dwarf_Die* result) {
1381 if (dwarf_child(parent_die, result) != 0) {
1385 Dwarf_Die* die = result;
1387 switch (dwarf_tag(die)) {
1388 case DW_TAG_subprogram:
1389 case DW_TAG_inlined_subroutine:
1390 if (die_has_pc(die, pc)) {
1394 bool declaration =
false;
1395 Dwarf_Attribute attr_mem;
1396 dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
1397 &attr_mem), &declaration);
1403 Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
1409 }
while (dwarf_siblingof(die, result) == 0);
1413 template <
typename CB>
1414 static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
1415 Dwarf_Addr pc, CB cb) {
1417 if (dwarf_child(parent_die, &die_mem) != 0) {
1421 bool branch_has_pc =
false;
1422 Dwarf_Die* die = &die_mem;
1424 bool declaration =
false;
1425 Dwarf_Attribute attr_mem;
1426 dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
1432 branch_has_pc = deep_first_search_by_pc(die, pc, cb);
1434 if (!branch_has_pc) {
1435 branch_has_pc = die_has_pc(die, pc);
1437 if (branch_has_pc) {
1440 }
while (dwarf_siblingof(die, &die_mem) == 0);
1441 return branch_has_pc;
1444 static const char* die_call_file(Dwarf_Die *die) {
1445 Dwarf_Attribute attr_mem;
1446 Dwarf_Sword file_idx = 0;
1448 dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
1451 if (file_idx == 0) {
1456 Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
1461 Dwarf_Files* files = 0;
1463 dwarf_getsrcfiles(cudie, &files, &nfiles);
1468 return dwarf_filesrc(files, file_idx, 0, 0);
1472 #endif // BACKWARD_HAS_DW == 1
1475 class TraceResolverImpl<system_tag::linux_tag>:
1476 public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1478 #endif // BACKWARD_SYSTEM_LINUX
1487 using lines_t = std::vector<std::pair<unsigned, std::string>>;
1494 using namespace std;
1509 for (line_idx = 1; line_idx < line_start; ++line_idx) {
1510 std::getline(*_file, line);
1520 bool operator()(
char c) {
1521 return std::isspace(c);
1525 bool started =
false;
1526 for (; line_idx < line_start + line_count; ++line_idx) {
1527 getline(*_file, line);
1532 if (std::find_if(line.begin(), line.end(),
1537 lines.push_back(make_pair(line_idx, line));
1541 std::find_if(lines.rbegin(), lines.rend(),
1549 return get_lines(line_start, line_count, lines);
1556 return !std::isspace(c);
1563 return !(std::find_if(p.second.begin(), p.second.end(),
1569 _file.swap(b.
_file);
1572 #ifdef BACKWARD_ATLEAST_CXX11
1576 SourceFile& operator=(SourceFile&& from) {
1577 swap(from);
return *
this;
1586 swap(
const_cast<SourceFile&
>(from));
return *
this;
1595 #ifdef BACKWARD_ATLEAST_CXX11
1606 unsigned line_start,
unsigned context_size) {
1608 SourceFile& src_file = get_src_file(filename);
1609 unsigned start = line_start - context_size / 2;
1610 return src_file.
get_lines(start, context_size);
1614 const std::string& filename_a,
unsigned line_a,
1615 const std::string& filename_b,
unsigned line_b,
1616 unsigned context_size) {
1617 SourceFile& src_file_a = get_src_file(filename_a);
1618 SourceFile& src_file_b = get_src_file(filename_b);
1622 src_file_b.
get_lines(line_b - context_size / 4, context_size / 2,
1628 unsigned line_a,
unsigned line_b,
unsigned context_size) {
1629 SourceFile& src_file = get_src_file(filename);
1631 using std::min;
using std::max;
1632 unsigned a = min(line_a, line_b);
1633 unsigned b = max(line_a, line_b);
1635 if ((b - a) < (context_size / 3)) {
1636 return src_file.
get_lines((a + b - context_size + 1) / 2,
1642 src_file.
get_lines(b - context_size / 4, context_size / 2, lines);
1652 src_files_t::iterator it = _src_files.find(filename);
1653 if (it != _src_files.end()) {
1656 SourceFile& new_src_file = _src_files[filename];
1658 return new_src_file;
1664 #ifdef BACKWARD_SYSTEM_LINUX
1676 Colorize(std::ostream& os):
1677 _os(os), _reset(false), _use_colors(false) {}
1685 void activate_if_tty(std::FILE *desc) {
1686 if (isatty(fileno(desc))) {
1692 if (!_use_colors)
return;
1696 _os <<
"\033[" <<
static_cast<int>(ccode) <<
"m";
1712 #else // ndef BACKWARD_SYSTEM_LINUX
1731 #endif // BACKWARD_SYSTEM_LINUX
1747 inliner_context_size(5),
1748 trace_context_size(7)
1751 template <
typename ST>
1752 FILE*
print(ST& st, FILE* os = stderr) {
1753 std::stringstream ss;
1756 colorize.activate_if_tty(os);
1758 print(st, ss, colorize);
1759 fprintf(os,
"%s", ss.str().c_str());
1763 template <
typename ST>
1767 colorize.activate();
1769 print(st, os, colorize);
1772 template <
typename IT>
1774 std::stringstream ss;
1777 colorize.activate_if_tty(os);
1780 fprintf(os,
"%s", ss.str().c_str());
1784 template <
typename IT>
1788 colorize.activate();
1797 template <
typename ST>
1799 print_header(os, st.thread_id());
1800 _resolver.load_stacktrace(st);
1801 for (
size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1802 print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize);
1806 template <
typename IT>
1808 print_header(os, thread_id);
1810 print_trace(os, *
begin, colorize);
1815 os <<
"Stack trace (most recent call last)";
1817 os <<
" in thread " << thread_id;
1825 << std::left << std::setw(2) << trace.
idx
1827 bool already_indented =
true;
1837 already_indented =
false;
1840 for (
size_t inliner_idx = trace.
inliners.size();
1841 inliner_idx > 0; --inliner_idx) {
1842 if (!already_indented) {
1847 print_source_loc(os,
" | ", inliner_loc);
1849 print_snippet(os,
" | ", inliner_loc,
1852 already_indented =
false;
1856 if (!already_indented) {
1859 print_source_loc(os,
" ", trace.
source, trace.
addr);
1861 print_snippet(os,
" ", trace.
source,
1872 using namespace std;
1876 source_loc.
line, context_size);
1878 for (lines_t::const_iterator it = lines.begin();
1879 it != lines.end(); ++it) {
1880 if (it-> first == source_loc.
line) {
1881 colorize.set_color(color_code);
1882 os << indent <<
">";
1884 os << indent <<
" ";
1886 os << std::setw(4) << it->first
1890 if (it-> first == source_loc.
line) {
1907 if (address && addr != 0) {
1908 os <<
" [" << addr <<
"]";
1916 #ifdef BACKWARD_SYSTEM_LINUX
1919 class SignalHandling {
1921 static std::vector<int> make_default_signals() {
1922 const int posix_signals[] = {
1951 return std::vector<int>(posix_signals, posix_signals +
sizeof posix_signals /
sizeof posix_signals[0] );
1954 SignalHandling(
const std::vector<int>& posix_signals = make_default_signals()):
1956 bool success =
true;
1958 const size_t stack_size = 1024 * 1024 * 8;
1959 _stack_content.reset((
char*)malloc(stack_size));
1960 if (_stack_content) {
1962 ss.ss_sp = _stack_content.get();
1963 ss.ss_size = stack_size;
1965 if (sigaltstack(&ss, 0) < 0) {
1972 for (
size_t i = 0; i < posix_signals.size(); ++i) {
1973 struct sigaction action;
1974 memset(&action, 0,
sizeof action);
1975 action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1977 sigfillset(&action.sa_mask);
1978 sigdelset(&action.sa_mask, posix_signals[i]);
1979 action.sa_sigaction = &sig_handler;
1981 int r = sigaction(posix_signals[i], &action, 0);
1982 if (
r < 0) success =
false;
1988 bool loaded()
const {
return _loaded; }
1991 details::handle<char*> _stack_content;
1994 static void sig_handler(
int, siginfo_t* info,
void* _ctx) {
1995 ucontext_t *uctx = (ucontext_t*) _ctx;
1998 void* error_addr = 0;
1999 #ifdef REG_RIP // x86_64
2000 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_RIP]);
2001 #elif defined(REG_EIP) // x86_32
2002 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_EIP]);
2003 #elif defined(__arm__)
2004 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.arm_pc);
2006 # warning ":/ sorry, ain't know no nothing none not of your architecture!"
2009 st.load_from(error_addr, 32);
2015 printer.address =
true;
2016 printer.print(st, stderr);
2018 #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
2023 raise(info->si_signo);
2027 _exit(EXIT_FAILURE);
2031 #endif // BACKWARD_SYSTEM_LINUX
2033 #ifdef BACKWARD_SYSTEM_UNKNOWN
2042 #endif // BACKWARD_SYSTEM_UNKNOWN