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 74 #if defined(BACKWARD_SYSTEM_LINUX) 97 # if BACKWARD_HAS_UNWIND == 1 98 # elif BACKWARD_HAS_BACKTRACE == 1 100 # undef BACKWARD_HAS_UNWIND 101 # define BACKWARD_HAS_UNWIND 1 102 # undef BACKWARD_HAS_BACKTRACE 103 # define BACKWARD_HAS_BACKTRACE 0 143 # if BACKWARD_HAS_DW == 1 144 # elif BACKWARD_HAS_BFD == 1 145 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 147 # undef BACKWARD_HAS_DW 148 # define BACKWARD_HAS_DW 0 149 # undef BACKWARD_HAS_BFD 150 # define BACKWARD_HAS_BFD 0 151 # undef BACKWARD_HAS_BACKTRACE_SYMBOL 152 # define BACKWARD_HAS_BACKTRACE_SYMBOL 1 156 # if BACKWARD_HAS_UNWIND == 1 171 #ifdef __CLANG_UNWIND_H 174 # include <inttypes.h> 175 extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*,
int*);
183 # include <sys/stat.h> 184 # include <syscall.h> 188 # if BACKWARD_HAS_BFD == 1 195 # ifndef PACKAGE_VERSION 196 # define PACKAGE_VERSION 208 # if BACKWARD_HAS_DW == 1 209 # include <elfutils/libdw.h> 210 # include <elfutils/libdwfl.h> 214 # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) 216 # include <execinfo.h> 219 #endif // defined(BACKWARD_SYSTEM_LINUX) 221 #ifdef BACKWARD_ATLEAST_CXX11 222 # include <unordered_map> 226 template <
typename K,
typename V>
228 typedef std::unordered_map<K, V>
type;
233 #else // NOT BACKWARD_ATLEAST_CXX11 237 template <
typename K,
typename V>
241 template <
typename T>
242 const T&
move(
const T& v) {
return v; }
243 template <
typename T>
247 #endif // BACKWARD_ATLEAST_CXX11 251 namespace system_tag {
256 #if defined(BACKWARD_SYSTEM_LINUX) 258 #elif defined(BACKWARD_SYSTEM_UNKNOWN) 261 # error "May I please get my system defines?" 266 namespace trace_resolver_tag {
267 #ifdef BACKWARD_SYSTEM_LINUX 270 struct backtrace_symbol;
272 # if BACKWARD_HAS_DW == 1 273 typedef libdw current;
274 # elif BACKWARD_HAS_BFD == 1 275 typedef libbfd current;
276 # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 277 typedef backtrace_symbol current;
279 # error "You shall not pass, until you know what you want." 281 #endif // BACKWARD_SYSTEM_LINUX 287 template <
typename T>
290 template <
typename T>
293 template <
typename T>
296 template <
typename R,
typename T, R (*F)(T)>
298 template <
typename U>
304 template <
typename T>
311 template <
typename T,
typename Deleter = deleter<
void,
void*, &::free> >
317 #ifdef BACKWARD_ATLEAST_CXX11 329 explicit handle(): _val(), _empty(true) {}
330 explicit handle(T val): _val(val), _empty(false) {}
332 #ifdef BACKWARD_ATLEAST_CXX11 342 swap(const_cast<handle&>(from));
346 swap(const_cast<handle&>(from));
return *
this;
354 operator const dummy*()
const {
358 return reinterpret_cast<const dummy*
>(_val);
391 template <
typename TAG>
393 static std::string
demangle(
const char* funcname) {
398 #ifdef BACKWARD_SYSTEM_LINUX 404 std::string demangle(
const char* funcname) {
405 using namespace details;
406 _demangle_buffer.reset(
407 abi::__cxa_demangle(funcname, _demangle_buffer.release(),
408 &_demangle_buffer_length, 0)
410 if (_demangle_buffer) {
411 return _demangle_buffer.get();
418 size_t _demangle_buffer_length;
421 #endif // BACKWARD_SYSTEM_LINUX 437 explicit Trace(
void* addr,
size_t idx):
438 addr(addr), idx(idx) {}
444 std::string
function;
459 return !(*
this == b);
491 template <
typename TAG>
494 size_t size()
const {
return 0; }
502 #ifdef BACKWARD_SYSTEM_LINUX 504 class StackTraceLinuxImplBase {
506 StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
508 unsigned thread_id()
const {
512 void skip_n_firsts(
size_t n) { _skip = n; }
515 void load_thread_info() {
516 _thread_id = syscall(SYS_gettid);
517 if (_thread_id == (
size_t) getpid()) {
524 size_t skip_n_firsts()
const {
return _skip; }
531 class StackTraceLinuxImplHolder:
public StackTraceLinuxImplBase {
533 size_t size()
const {
534 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
536 Trace operator[](
size_t idx) {
540 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
544 return &_stacktrace[skip_n_firsts()];
550 std::vector<void*> _stacktrace;
554 #if BACKWARD_HAS_UNWIND == 1 558 template <
typename F>
561 size_t operator()(F&
f,
size_t depth) {
565 _Unwind_Backtrace(&this->backtrace_trampoline,
this);
574 static _Unwind_Reason_Code backtrace_trampoline(
575 _Unwind_Context* ctx,
void *
self) {
576 return ((Unwinder*)
self)->backtrace(ctx);
579 _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
580 if (_index >= 0 && static_cast<size_t>(_index) >= _depth)
581 return _URC_END_OF_STACK;
583 int ip_before_instruction = 0;
584 uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
586 if (!ip_before_instruction) {
591 (*_f)(_index, (
void*)ip);
594 return _URC_NO_REASON;
598 template <
typename F>
599 size_t unwind(F
f,
size_t depth) {
600 Unwinder<F> unwinder;
601 return unwinder(f, depth);
608 class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
611 size_t load_here(
size_t depth=32) {
616 _stacktrace.resize(depth);
617 size_t trace_cnt = details::unwind(callback(*
this), depth);
618 _stacktrace.resize(trace_cnt);
622 size_t load_from(
void* addr,
size_t depth=32) {
623 load_here(depth + 8);
625 for (
size_t i = 0;
i < _stacktrace.size(); ++
i) {
626 if (_stacktrace[
i] == addr) {
632 _stacktrace.resize(std::min(_stacktrace.size(),
633 skip_n_firsts() + depth));
642 void operator()(
size_t idx,
void* addr) {
643 self._stacktrace[idx] = addr;
649 #else // BACKWARD_HAS_UNWIND == 0 652 class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
655 size_t load_here(
size_t depth=32) {
660 _stacktrace.resize(depth + 1);
661 size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
662 _stacktrace.resize(trace_cnt);
667 size_t load_from(
void* addr,
size_t depth=32) {
668 load_here(depth + 8);
670 for (
size_t i = 0;
i < _stacktrace.size(); ++
i) {
671 if (_stacktrace[
i] == addr) {
673 _stacktrace[
i] = (
void*)( (uintptr_t)_stacktrace[
i] + 1);
678 _stacktrace.resize(std::min(_stacktrace.size(),
679 skip_n_firsts() + depth));
684 #endif // BACKWARD_HAS_UNWIND 685 #endif // BACKWARD_SYSTEM_LINUX 692 template <
typename TAG>
695 #ifdef BACKWARD_SYSTEM_UNKNOWN 709 #ifdef BACKWARD_SYSTEM_LINUX 711 class TraceResolverLinuxImplBase {
713 std::string demangle(
const char* funcname) {
714 return _demangler.demangle(funcname);
721 template <
typename STACKTRACE_TAG>
722 class TraceResolverLinuxImpl;
724 #if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 727 class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
728 public TraceResolverLinuxImplBase {
731 void load_stacktrace(ST& st) {
732 using namespace details;
733 if (st.size() == 0) {
737 backtrace_symbols(st.begin(), st.size())
743 char* funcname = filename;
744 while (*funcname && *funcname !=
'(') {
748 char* funcname_end = funcname;
749 while (*funcname_end && *funcname_end !=
')' && *funcname_end !=
'+') {
752 *funcname_end =
'\0';
762 #endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1 764 #if BACKWARD_HAS_BFD == 1 767 class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
768 public TraceResolverLinuxImplBase {
770 TraceResolverLinuxImpl(): _bfd_loaded(
false) {}
773 void load_stacktrace(ST&) {}
781 if (!dladdr(trace.
addr, &symbol_info)) {
796 if (symbol_info.dli_sname) {
800 if (!symbol_info.dli_fname) {
805 bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
811 find_sym_result* details_selected;
818 find_sym_result details_call_site = find_symbol_details(fobj,
819 trace.
addr, symbol_info.dli_fbase);
820 details_selected = &details_call_site;
822 #if BACKWARD_HAS_UNWIND == 0 830 find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
831 (
void*) (uintptr_t(trace.
addr) - 1),
832 symbol_info.dli_fbase);
835 if (details_call_site.found && details_adjusted_call_site.found) {
837 details_selected = &details_adjusted_call_site;
838 trace.
addr = (
void*) (uintptr_t(trace.
addr) - 1);
841 if (details_selected == &details_call_site && details_call_site.found) {
845 details_call_site = find_symbol_details(fobj, trace.
addr,
846 symbol_info.dli_fbase);
848 #endif // BACKWARD_HAS_UNWIND 850 if (details_selected->found) {
851 if (details_selected->filename) {
856 if (details_selected->funcname) {
864 if (!symbol_info.dli_sname) {
875 trace.
inliners = backtrace_inliners(fobj, *details_selected);
897 if (symbol_info.dli_saddr) {
898 find_sym_result details = find_symbol_details(fobj,
899 symbol_info.dli_saddr,
900 symbol_info.dli_fbase);
904 diy_inliner.
line = details.line;
905 if (details.filename) {
906 diy_inliner.
filename = details.filename;
908 if (details.funcname) {
909 diy_inliner.
function = demangle(details.funcname);
913 if (diy_inliner != trace.
source) {
914 trace.
inliners.push_back(diy_inliner);
935 struct bfd_fileobject {
939 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 {
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);
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&) {}
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);
1199 const char* sym_name = dwfl_module_addrname(mod, trace_addr);
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);
1283 int line = 0, col = 0;
1284 dwarf_lineno(srcloc, &line);
1285 dwarf_linecol(srcloc, &col);
1290 deep_first_search_by_pc(cudie, trace_addr - mod_bias,
1291 inliners_search_cb(trace));
1305 dwfl_handle_t _dwfl_handle;
1306 bool _dwfl_handle_initialized;
1310 struct inliners_search_cb {
1311 void operator()(Dwarf_Die* die) {
1312 switch (dwarf_tag(die)) {
1314 case DW_TAG_subprogram:
1315 if ((name = dwarf_diename(die))) {
1320 case DW_TAG_inlined_subroutine:
1322 Dwarf_Attribute attr_mem;
1324 if ((name = dwarf_diename(die))) {
1327 if ((name = die_call_file(die))) {
1331 Dwarf_Word line = 0, col = 0;
1332 dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
1334 dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
1348 static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1349 Dwarf_Addr low, high;
1352 if (dwarf_hasattr(die, DW_AT_low_pc) &&
1353 dwarf_hasattr(die, DW_AT_high_pc)) {
1354 if (dwarf_lowpc(die, &low) != 0) {
1357 if (dwarf_highpc(die, &high) != 0) {
1358 Dwarf_Attribute attr_mem;
1359 Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
1361 if (dwarf_formudata(attr, &value) != 0) {
1366 return pc >= low && pc < high;
1371 ptrdiff_t offset = 0;
1372 while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
1373 if (pc >= low && pc < high) {
1380 static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
1381 Dwarf_Die* result) {
1382 if (dwarf_child(parent_die, result) != 0) {
1386 Dwarf_Die* die = result;
1388 switch (dwarf_tag(die)) {
1389 case DW_TAG_subprogram:
1390 case DW_TAG_inlined_subroutine:
1391 if (die_has_pc(die, pc)) {
1395 bool declaration =
false;
1396 Dwarf_Attribute attr_mem;
1397 dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
1398 &attr_mem), &declaration);
1404 Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
1411 }
while (dwarf_siblingof(die, result) == 0);
1415 template <
typename CB>
1416 static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
1417 Dwarf_Addr pc, CB cb) {
1419 if (dwarf_child(parent_die, &die_mem) != 0) {
1423 bool branch_has_pc =
false;
1424 Dwarf_Die* die = &die_mem;
1426 bool declaration =
false;
1427 Dwarf_Attribute attr_mem;
1428 dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
1434 branch_has_pc = deep_first_search_by_pc(die, pc, cb);
1436 if (!branch_has_pc) {
1437 branch_has_pc = die_has_pc(die, pc);
1439 if (branch_has_pc) {
1442 }
while (dwarf_siblingof(die, &die_mem) == 0);
1443 return branch_has_pc;
1446 static const char* die_call_file(Dwarf_Die *die) {
1447 Dwarf_Attribute attr_mem;
1448 Dwarf_Sword file_idx = 0;
1450 dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
1453 if (file_idx == 0) {
1458 Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
1463 Dwarf_Files* files = 0;
1465 dwarf_getsrcfiles(cudie, &files, &nfiles);
1470 return dwarf_filesrc(files, file_idx, 0, 0);
1474 #endif // BACKWARD_HAS_DW == 1 1478 public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1480 #endif // BACKWARD_SYSTEM_LINUX 1489 typedef std::vector<std::pair<unsigned, std::string> >
lines_t;
1495 lines_t&
get_lines(
unsigned line_start,
unsigned line_count, lines_t& lines) {
1496 using namespace std;
1511 for (line_idx = 1; line_idx < line_start; ++line_idx) {
1512 std::getline(*_file, line);
1522 bool operator()(
char c) {
1523 return std::isspace(c);
1527 bool started =
false;
1528 for (; line_idx < line_start + line_count; ++line_idx) {
1529 getline(*_file, line);
1534 if (std::find_if(line.begin(), line.end(),
1539 lines.push_back(make_pair(line_idx, line));
1543 std::find_if(lines.rbegin(), lines.rend(),
1549 lines_t
get_lines(
unsigned line_start,
unsigned line_count) {
1551 return get_lines(line_start, line_count, lines);
1558 return !std::isspace(c);
1565 return !(std::find_if(p.second.begin(), p.second.end(),
1571 _file.swap(b.
_file);
1574 #ifdef BACKWARD_ATLEAST_CXX11 1584 swap(const_cast<SourceFile&>(from));
1588 swap(const_cast<SourceFile&>(from));
return *
this;
1597 #ifdef BACKWARD_ATLEAST_CXX11 1608 unsigned line_start,
unsigned context_size) {
1610 SourceFile& src_file = get_src_file(filename);
1611 unsigned start = line_start - context_size / 2;
1612 return src_file.
get_lines(start, context_size);
1616 const std::string& filename_a,
unsigned line_a,
1617 const std::string& filename_b,
unsigned line_b,
1618 unsigned context_size) {
1619 SourceFile& src_file_a = get_src_file(filename_a);
1620 SourceFile& src_file_b = get_src_file(filename_b);
1622 lines_t lines = src_file_a.
get_lines(line_a - context_size / 4,
1624 src_file_b.
get_lines(line_b - context_size / 4, context_size / 2,
1630 unsigned line_a,
unsigned line_b,
unsigned context_size) {
1631 SourceFile& src_file = get_src_file(filename);
1633 using std::min;
using std::max;
1634 unsigned a =
min(line_a, line_b);
1635 unsigned b = max(line_a, line_b);
1637 if ((b - a) < (context_size / 3)) {
1638 return src_file.
get_lines((a + b - context_size + 1) / 2,
1642 lines_t lines = src_file.
get_lines(a - context_size / 4,
1644 src_file.
get_lines(b - context_size / 4, context_size / 2, lines);
1654 src_files_t::iterator it = _src_files.find(filename);
1655 if (it != _src_files.end()) {
1658 SourceFile& new_src_file = _src_files[filename];
1660 return new_src_file;
1666 #ifdef BACKWARD_SYSTEM_LINUX 1679 _os(os), _reset(
false), _istty(
false) {}
1682 _istty = isatty(fileno(_os));
1686 if (!_istty)
return;
1690 fprintf(_os,
"\033[%im", static_cast<int>(ccode));
1706 #else // ndef BACKWARD_SYSTEM_LINUX 1724 #endif // BACKWARD_SYSTEM_LINUX 1740 inliner_context_size(5),
1741 trace_context_size(7)
1744 template <
typename ST>
1745 FILE*
print(ST& st, FILE* os = stderr) {
1750 print_header(os, st.thread_id());
1751 _resolver.load_stacktrace(st);
1752 for (
size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1753 print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize);
1758 template <
typename IT>
1759 FILE*
print(IT begin, IT end, FILE* os = stderr,
size_t thread_id = 0) {
1764 print_header(os, thread_id);
1765 for (; begin != end; ++begin) {
1766 print_trace(os, *begin, colorize);
1775 fprintf(os,
"Stack trace (most recent call last)");
1777 fprintf(os,
" in thread %u:\n", thread_id);
1785 fprintf(os,
"#%-2u", trace.
idx);
1786 bool already_indented =
true;
1789 fprintf(os,
" Object \"%s\", at %p, in %s\n",
1792 already_indented =
false;
1795 for (
size_t inliner_idx = trace.
inliners.size();
1796 inliner_idx > 0; --inliner_idx) {
1797 if (!already_indented) {
1802 print_source_loc(os,
" | ", inliner_loc);
1804 print_snippet(os,
" | ", inliner_loc,
1807 already_indented =
false;
1811 if (!already_indented) {
1814 print_source_loc(os,
" ", trace.
source, trace.
addr);
1816 print_snippet(os,
" ", trace.
source,
1827 using namespace std;
1831 source_loc.
line, context_size);
1833 for (lines_t::const_iterator it = lines.begin();
1834 it != lines.end(); ++it) {
1835 if (it-> first == source_loc.
line) {
1837 fprintf(os,
"%s>", indent);
1839 fprintf(os,
"%s ", indent);
1841 fprintf(os,
"%4u: %s\n", it->first, it->second.c_str());
1842 if (it-> first == source_loc.
line) {
1851 fprintf(os,
"%sSource \"%s\", line %i, in %s",
1852 indent, source_loc.
filename.c_str(), (int)source_loc.
line,
1855 if (address && addr != 0) {
1856 fprintf(os,
" [%p]\n", addr);
1865 #ifdef BACKWARD_SYSTEM_LINUX 1870 static std::vector<int> make_default_signals() {
1871 const int posix_signals[] = {
1885 return std::vector<int>(posix_signals, posix_signals +
sizeof posix_signals /
sizeof posix_signals[0] );
1888 SignalHandling(
const std::vector<int>& posix_signals = make_default_signals()):
1890 bool success =
true;
1892 const size_t stack_size = 1024 * 1024 * 8;
1893 _stack_content.reset((
char*)malloc(stack_size));
1894 if (_stack_content) {
1896 ss.ss_sp = _stack_content.get();
1897 ss.ss_size = stack_size;
1899 if (sigaltstack(&ss, 0) < 0) {
1906 for (
size_t i = 0;
i < posix_signals.size(); ++
i) {
1907 struct sigaction action;
1908 memset(&action, 0,
sizeof action);
1909 action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1911 sigfillset(&action.sa_mask);
1912 sigdelset(&action.sa_mask, posix_signals[
i]);
1913 action.sa_sigaction = &sig_handler;
1915 int r = sigaction(posix_signals[i], &action, 0);
1916 if (r < 0) success =
false;
1922 bool loaded()
const {
return _loaded; }
1931 static void sig_handler(
int, siginfo_t* info,
void* _ctx) {
1932 ucontext_t *uctx = (ucontext_t*) _ctx;
1935 void* error_addr = 0;
1936 #ifdef REG_RIP // x86_64 1937 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_RIP]);
1938 #elif defined(REG_EIP) // x86_32 1939 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_EIP]);
1940 #elif defined(__arm__) 1941 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.arm_pc);
1942 #elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) 1943 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.regs->nip);
1945 # warning ":/ sorry, ain't know no nothing none not of your architecture!" 1956 printer.
color =
true;
1958 printer.
print(st, stderr);
1960 #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L 1965 raise(info->si_signo);
1969 _exit(EXIT_FAILURE);
1973 #endif // BACKWARD_SYSTEM_LINUX 1975 #ifdef BACKWARD_SYSTEM_UNKNOWN 1984 #endif // BACKWARD_SYSTEM_UNKNOWN
void swap(any &x, any &y) any_noexcept
const_ref_t operator*() const
std::vector< std::pair< unsigned, std::string > > lines_t
SourceFile::lines_t lines_t
std::string object_filename
const T operator->() const
ResolvedTrace resolve(ResolvedTrace t)
lines_t & get_lines(unsigned line_start, unsigned line_count, lines_t &lines)
lines_t get_lines(unsigned line_start, unsigned line_count)
void print_source_loc(FILE *os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, void *addr=0)
ref_t operator[](size_t idx)
ROSCPP_DECL std::string resolve(const std::string &name, bool remap=true)
void load_stacktrace(ST &)
void operator()(U &ptr) const
rm_ptr< T >::type & ref_t
lines_t get_coalesced_snippet(const std::string &filename, unsigned line_a, unsigned line_b, unsigned context_size)
FILE * print(IT begin, IT end, FILE *os=stderr, size_t thread_id=0)
handle & operator=(const handle &from)
bool operator()(const lines_t::value_type &p)
void operator()(T &ptr) const
details::hashtable< std::string, SourceFile >::type src_files_t
void set_color(Color::type)
void print_snippet(FILE *os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, Colorize &colorize, Color::type color_code, int context_size)
std::string object_function
lines_t get_combined_snippet(const std::string &filename_a, unsigned line_a, const std::string &filename_b, unsigned line_b, unsigned context_size)
FILE * print(ST &st, FILE *os=stderr)
ResolvedTrace(const Trace &mini_trace)
std::vector< SourceLoc > source_locs_t
SourceFile(const SourceFile &from)
const T & move(const T &v)
bool operator!=(const SourceLoc &b) const
size_t load_here(size_t=0)
unsigned thread_id() const
Trace(void *addr, size_t idx)
void print_header(FILE *os, unsigned thread_id)
lines_t get_snippet(const std::string &filename, unsigned line_start, unsigned context_size)
SourceFile & get_src_file(const std::string &filename)
SourceFile(const std::string &path)
void print_trace(FILE *os, const ResolvedTrace &trace, Colorize &colorize)
static std::string demangle(const char *funcname)
SignalHandling(const std::vector< int > &=std::vector< int >())
size_t load_from(void *, size_t=0)
details::handle< std::ifstream *, details::default_delete< std::ifstream * > > _file
handle(const handle &from)
bool operator==(const SourceLoc &b) const
empty_struct data[sizeof(T)/sizeof(empty_struct)]
void skip_n_firsts(size_t)
SourceFile & operator=(const SourceFile &from)
const rm_ptr< T >::type & const_ref_t
tf::tfVector4 __attribute__