26#ifdef OGDF_EXTERNAL_BACKWARD
28#elif !defined(H_6B9572DA_A64B_49E6_B234_051480991C89)
29#define H_6B9572DA_A64B_49E6_B234_051480991C89
32# error "It's not going to compile without a C++ compiler..."
35#if defined(BACKWARD_CXX11)
36#elif defined(BACKWARD_CXX98)
38# if __cplusplus >= 201103L
39# define BACKWARD_CXX11
40# define BACKWARD_ATLEAST_CXX11
41# define BACKWARD_ATLEAST_CXX98
43# define BACKWARD_CXX98
44# define BACKWARD_ATLEAST_CXX98
56#if defined(BACKWARD_SYSTEM_LINUX)
57#elif defined(BACKWARD_SYSTEM_UNKNOWN)
60# define BACKWARD_SYSTEM_LINUX
62# define BACKWARD_SYSTEM_UNKNOWN
79#if defined(BACKWARD_SYSTEM_LINUX)
102# if BACKWARD_HAS_UNWIND == 1
103# elif BACKWARD_HAS_BACKTRACE == 1
105# undef BACKWARD_HAS_UNWIND
106# define BACKWARD_HAS_UNWIND 1
107# undef BACKWARD_HAS_BACKTRACE
108# define BACKWARD_HAS_BACKTRACE 0
148# if BACKWARD_HAS_DW == 1
149# elif BACKWARD_HAS_BFD == 1
150# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
152# undef BACKWARD_HAS_DW
153# define BACKWARD_HAS_DW 0
154# undef BACKWARD_HAS_BFD
155# define BACKWARD_HAS_BFD 0
156# undef BACKWARD_HAS_BACKTRACE_SYMBOL
157# define BACKWARD_HAS_BACKTRACE_SYMBOL 1
161# if BACKWARD_HAS_UNWIND == 1
176#ifdef __CLANG_UNWIND_H
180extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*,
int*);
188# include <sys/stat.h>
193# if BACKWARD_HAS_BFD == 1
200# ifndef PACKAGE_VERSION
201# define PACKAGE_VERSION
213# if BACKWARD_HAS_DW == 1
214# include <elfutils/libdw.h>
215# include <elfutils/libdwfl.h>
219# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1)
221# include <execinfo.h>
226#ifdef BACKWARD_ATLEAST_CXX11
227# include <unordered_map>
231 template <
typename K,
typename V>
233 using type = std::unordered_map<K, V>;
242 template <
typename K,
typename V>
246 template <
typename T>
247 const T&
move(
const T& v) {
return v; }
248 template <
typename T>
256namespace system_tag {
261#if defined(BACKWARD_SYSTEM_LINUX)
263#elif defined(BACKWARD_SYSTEM_UNKNOWN)
266# error "May I please get my system defines?"
271namespace trace_resolver_tag {
272#ifdef BACKWARD_SYSTEM_LINUX
275 struct backtrace_symbol;
277# if BACKWARD_HAS_DW == 1
278 using current = libdw;
279# elif BACKWARD_HAS_BFD == 1
280 using current = libbfd;
281# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1
282 using current = backtrace_symbol;
284# error "You shall not pass, until you know what you want."
301template <
typename R,
typename T, R (*F)(T)>
303 template <
typename U>
316template <
typename T,
typename Deleter = deleter<
void,
void*, &::free> >
322#ifdef BACKWARD_ATLEAST_CXX11
337#ifdef BACKWARD_ATLEAST_CXX11
342 swap(from);
return *
this;
351 swap(
const_cast<handle&
>(from));
return *
this;
359 operator const dummy*()
const {
363 return reinterpret_cast<const dummy*
>(
_val);
396template <
typename TAG>
398 static std::string
demangle(
const char* funcname) {
403#ifdef BACKWARD_SYSTEM_LINUX
406struct demangler_impl<system_tag::current_tag> {
407 demangler_impl(): _demangle_buffer_length(0) {}
409 std::string
demangle(
const char* funcname) {
410 using namespace details;
411 _demangle_buffer.reset(
412 abi::__cxa_demangle(funcname, NULL,
413 &_demangle_buffer_length, 0)
415 if (_demangle_buffer) {
416 return _demangle_buffer.get();
422 details::handle<char*> _demangle_buffer;
423 size_t _demangle_buffer_length;
442 explicit Trace(
void* _addr,
size_t _idx):
464 return !(*
this == b);
496template <
typename TAG>
499 size_t size()
const {
return 0; }
507#ifdef BACKWARD_SYSTEM_LINUX
509class StackTraceLinuxImplBase {
511 StackTraceLinuxImplBase(): _thread_id(0), _skip(0) {}
513 unsigned thread_id()
const {
517 void skip_n_firsts(
size_t n) { _skip = n; }
520 void load_thread_info() {
521 _thread_id = syscall(SYS_gettid);
522 if (_thread_id == (
size_t) getpid()) {
529 size_t skip_n_firsts()
const {
return _skip; }
536class StackTraceLinuxImplHolder:
public StackTraceLinuxImplBase {
538 size_t size()
const {
539 return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
541 Trace operator[](
size_t idx) {
545 return Trace(_stacktrace[idx + skip_n_firsts()], idx);
549 return &_stacktrace[skip_n_firsts()];
555 std::vector<void*> _stacktrace;
559#if BACKWARD_HAS_UNWIND == 1
566 size_t operator()(F& f,
size_t depth) {
570 _Unwind_Backtrace(&this->backtrace_trampoline,
this);
579 static _Unwind_Reason_Code backtrace_trampoline(
580 _Unwind_Context* ctx,
void *self) {
581 return ((Unwinder*)self)->backtrace(ctx);
584 _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) {
585 if (_index >= 0 &&
static_cast<size_t>(_index) >= _depth)
586 return _URC_END_OF_STACK;
588 int ip_before_instruction = 0;
589 uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction);
591 if (!ip_before_instruction) {
596 (*_f)(_index, (
void*)ip);
599 return _URC_NO_REASON;
604size_t unwind(F f,
size_t depth) {
605 Unwinder<F> unwinder;
606 return unwinder(f, depth);
613class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
615 __attribute__ ((noinline))
621 _stacktrace.resize(depth);
622 size_t trace_cnt = details::unwind(callback(*
this), depth);
623 _stacktrace.resize(trace_cnt);
627 size_t load_from(
void* addr,
size_t depth=32) {
630 for (
size_t i = 0; i < _stacktrace.size(); ++i) {
631 if (_stacktrace[i] == addr) {
637 _stacktrace.resize(std::min(_stacktrace.size(),
644 StackTraceImpl& self;
645 callback(StackTraceImpl& _self): self(_self) {}
647 void operator()(
size_t idx,
void* addr) {
648 self._stacktrace[idx] = addr;
657class StackTraceImpl<system_tag::linux_tag>:
public StackTraceLinuxImplHolder {
659 __attribute__ ((noinline))
665 _stacktrace.resize(depth + 1);
666 size_t trace_cnt = backtrace(&_stacktrace[0], _stacktrace.size());
667 _stacktrace.resize(trace_cnt);
672 size_t load_from(
void* addr,
size_t depth=32) {
675 for (
size_t i = 0; i < _stacktrace.size(); ++i) {
676 if (_stacktrace[i] == addr) {
678 _stacktrace[i] = (
void*)( (uintptr_t)_stacktrace[i] + 1);
683 _stacktrace.resize(std::min(_stacktrace.size(),
697template <
typename TAG>
700#ifdef BACKWARD_SYSTEM_UNKNOWN
714#ifdef BACKWARD_SYSTEM_LINUX
716class TraceResolverLinuxImplBase {
718 std::string demangle(
const char* funcname) {
719 return _demangler.demangle(funcname);
723 details::demangler _demangler;
726template <
typename STACKTRACE_TAG>
727class TraceResolverLinuxImpl;
729#if BACKWARD_HAS_BACKTRACE_SYMBOL == 1
732class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>:
733 public TraceResolverLinuxImplBase {
736 void load_stacktrace(ST& st) {
737 using namespace details;
738 if (st.size() == 0) {
742 backtrace_symbols(st.begin(), st.size())
746 ResolvedTrace resolve(ResolvedTrace trace) {
747 char* filename = _symbols[trace.idx];
748 char* funcname = filename;
749 while (*funcname && *funcname !=
'(') {
753 char* funcname_end = funcname;
754 while (*funcname_end && *funcname_end !=
')' && *funcname_end !=
'+') {
757 *funcname_end =
'\0';
758 trace.object_function = this->demangle(funcname);
759 trace.source.function = trace.object_function;
764 details::handle<char**> _symbols;
769#if BACKWARD_HAS_BFD == 1
772class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>:
773 public TraceResolverLinuxImplBase {
775 TraceResolverLinuxImpl(): _bfd_loaded(false) {}
778 void load_stacktrace(ST&) {}
780 ResolvedTrace resolve(ResolvedTrace trace) {
786 if (!dladdr(trace.addr, &symbol_info)) {
801 if (symbol_info.dli_sname) {
802 trace.object_function = demangle(symbol_info.dli_sname);
805 if (!symbol_info.dli_fname) {
809 trace.object_filename = symbol_info.dli_fname;
810 bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname);
816 find_sym_result* details_selected;
823 find_sym_result details_call_site = find_symbol_details(fobj,
824 trace.addr, symbol_info.dli_fbase);
825 details_selected = &details_call_site;
827#if BACKWARD_HAS_UNWIND == 0
835 find_sym_result details_adjusted_call_site = find_symbol_details(fobj,
836 (
void*) (uintptr_t(trace.addr) - 1),
837 symbol_info.dli_fbase);
840 if (details_call_site.found && details_adjusted_call_site.found) {
842 details_selected = &details_adjusted_call_site;
843 trace.addr = (
void*) (uintptr_t(trace.addr) - 1);
846 if (details_selected == &details_call_site && details_call_site.found) {
850 details_call_site = find_symbol_details(fobj, trace.addr,
851 symbol_info.dli_fbase);
855 if (details_selected->found) {
856 if (details_selected->filename) {
857 trace.source.filename = details_selected->filename;
859 trace.source.line = details_selected->line;
861 if (details_selected->funcname) {
867 trace.source.function = demangle(details_selected->funcname);
869 if (!symbol_info.dli_sname) {
873 trace.object_function = trace.source.function;
880 trace.inliners = backtrace_inliners(fobj, *details_selected);
883 if (trace.inliners.size() == 0) {
902 if (symbol_info.dli_saddr) {
903 find_sym_result details = find_symbol_details(fobj,
904 symbol_info.dli_saddr,
905 symbol_info.dli_fbase);
908 ResolvedTrace::SourceLoc diy_inliner;
909 diy_inliner.line = details.line;
910 if (details.filename) {
911 diy_inliner.filename = details.filename;
913 if (details.funcname) {
914 diy_inliner.function = demangle(details.funcname);
916 diy_inliner.function = trace.source.function;
918 if (diy_inliner != trace.source) {
919 trace.inliners.push_back(diy_inliner);
933 using bfd_handle_t = details::handle<bfd*,
934 details::deleter<bfd_boolean, bfd*, &bfd_close>
937 using bfd_symtab_t = details::handle<asymbol**>;
940 struct bfd_fileobject {
944 bfd_symtab_t dynamic_symtab;
947 using fobj_bfd_map_t = details::hashtable<std::string, bfd_fileobject>::type;
948 fobj_bfd_map_t _fobj_bfd_map;
950 bfd_fileobject& load_object_with_bfd(
const std::string& filename_object) {
951 using namespace details;
954 using namespace details;
959 fobj_bfd_map_t::iterator it =
960 _fobj_bfd_map.find(filename_object);
961 if (it != _fobj_bfd_map.end()) {
966 bfd_fileobject&
r = _fobj_bfd_map[filename_object];
969 bfd_handle_t bfd_handle;
971 int fd = open(filename_object.c_str(), O_RDONLY);
973 bfd_fdopenr(filename_object.c_str(),
"default", fd)
980 if (!bfd_check_format(bfd_handle.get(), bfd_object)) {
984 if ((bfd_get_file_flags(bfd_handle.get()) & HAS_SYMS) == 0) {
988 ssize_t symtab_storage_size =
989 bfd_get_symtab_upper_bound(bfd_handle.get());
991 ssize_t dyn_symtab_storage_size =
992 bfd_get_dynamic_symtab_upper_bound(bfd_handle.get());
994 if (symtab_storage_size <= 0 && dyn_symtab_storage_size <= 0) {
998 bfd_symtab_t symtab, dynamic_symtab;
999 ssize_t symcount = 0, dyn_symcount = 0;
1001 if (symtab_storage_size > 0) {
1003 (bfd_symbol**) malloc(symtab_storage_size)
1005 symcount = bfd_canonicalize_symtab(
1006 bfd_handle.get(), symtab.get()
1010 if (dyn_symtab_storage_size > 0) {
1011 dynamic_symtab.reset(
1012 (bfd_symbol**) malloc(dyn_symtab_storage_size)
1014 dyn_symcount = bfd_canonicalize_dynamic_symtab(
1015 bfd_handle.get(), dynamic_symtab.get()
1020 if (symcount <= 0 && dyn_symcount <= 0) {
1024 r.handle =
move(bfd_handle);
1025 r.symtab =
move(symtab);
1026 r.dynamic_symtab =
move(dynamic_symtab);
1030 struct find_sym_result {
1032 const char* filename;
1033 const char* funcname;
1037 struct find_sym_context {
1038 TraceResolverLinuxImpl* self;
1039 bfd_fileobject* fobj;
1042 find_sym_result result;
1045 find_sym_result find_symbol_details(bfd_fileobject& fobj,
void* addr,
1047 find_sym_context context;
1048 context.self =
this;
1049 context.fobj = &fobj;
1050 context.addr = addr;
1051 context.base_addr = base_addr;
1052 context.result.found =
false;
1053 bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
1055 return context.result;
1058 static void find_in_section_trampoline(bfd*, asection* section,
1060 find_sym_context* context =
static_cast<find_sym_context*
>(data);
1061 context->self->find_in_section(
1062 reinterpret_cast<bfd_vma
>(context->addr),
1063 reinterpret_cast<bfd_vma
>(context->base_addr),
1065 section, context->result
1069 void find_in_section(bfd_vma addr, bfd_vma base_addr,
1070 bfd_fileobject& fobj, asection* section, find_sym_result& result)
1072 if (result.found)
return;
1074 if ((bfd_get_section_flags(fobj.handle.get(), section)
1078 bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
1079 bfd_size_type
size = bfd_get_section_size(section);
1082 if (addr < sec_addr || addr >= sec_addr + size) {
1084 if (addr < sec_addr || addr >= sec_addr + size) {
1089 if (!result.found && fobj.symtab) {
1090 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1091 fobj.symtab.get(), addr - sec_addr, &result.filename,
1092 &result.funcname, &result.line);
1095 if (!result.found && fobj.dynamic_symtab) {
1096 result.found = bfd_find_nearest_line(fobj.handle.get(), section,
1097 fobj.dynamic_symtab.get(), addr - sec_addr,
1098 &result.filename, &result.funcname, &result.line);
1103 ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj,
1104 find_sym_result previous_result) {
1107 ResolvedTrace::source_locs_t results;
1108 while (previous_result.found) {
1109 find_sym_result result;
1110 result.found = bfd_find_inliner_info(fobj.handle.get(),
1111 &result.filename, &result.funcname, &result.line);
1118 ResolvedTrace::SourceLoc src_loc;
1119 src_loc.line = result.line;
1120 if (result.filename) {
1121 src_loc.filename = result.filename;
1123 if (result.funcname) {
1124 src_loc.function = demangle(result.funcname);
1126 results.push_back(src_loc);
1128 previous_result = result;
1133 bool cstrings_eq(
const char* a,
const char* b) {
1137 return strcmp(a, b) == 0;
1143#if BACKWARD_HAS_DW == 1
1146class TraceResolverLinuxImpl<trace_resolver_tag::libdw>:
1147 public TraceResolverLinuxImplBase {
1149 TraceResolverLinuxImpl(): _dwfl_handle_initialized(false) {}
1152 void load_stacktrace(ST&) {}
1154 ResolvedTrace resolve(ResolvedTrace trace) {
1155 using namespace details;
1157 Dwarf_Addr trace_addr = (Dwarf_Addr) trace.addr;
1159 if (!_dwfl_handle_initialized) {
1161 _dwfl_cb.reset(
new Dwfl_Callbacks);
1162 _dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
1163 _dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
1164 _dwfl_cb->debuginfo_path = 0;
1166 _dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
1167 _dwfl_handle_initialized =
true;
1169 if (!_dwfl_handle) {
1174 dwfl_report_begin(_dwfl_handle.get());
1175 int r = dwfl_linux_proc_report (_dwfl_handle.get(), getpid());
1176 dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
1182 if (!_dwfl_handle) {
1189 Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
1193 const char* module_name = dwfl_module_info (mod,
1194 0, 0, 0, 0, 0, 0, 0);
1196 trace.object_filename = module_name;
1203 const char* sym_name = dwfl_module_addrname(mod, trace_addr);
1205 trace.object_function = demangle(sym_name);
1215 Dwarf_Addr mod_bias = 0;
1216 Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
1230 while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
1232 Dwarf_Die* fundie = find_fundie_by_pc(cudie,
1233 trace_addr - mod_bias, &die_mem);
1242#ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
1249 Dwarf_Addr cfi_bias;
1250 Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
1253 while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
1254 if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
1262 handle<Dwarf_Frame*> frame;
1263 dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
1280 Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
1283 const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
1285 trace.source.filename = srcfile;
1287 int line = 0, col = 0;
1288 dwarf_lineno(srcloc, &line);
1289 dwarf_linecol(srcloc, &col);
1290 trace.source.line = line;
1291 trace.source.col = col;
1294 deep_first_search_by_pc(cudie, trace_addr - mod_bias,
1295 inliners_search_cb(trace));
1296 if (trace.source.function.size() == 0) {
1298 trace.source.function = trace.object_function;
1305 using dwfl_handle_t = details::handle<Dwfl*, details::deleter<void, Dwfl*, &dwfl_end>>;
1306 details::handle<Dwfl_Callbacks*, details::default_delete<Dwfl_Callbacks*> >
1308 dwfl_handle_t _dwfl_handle;
1309 bool _dwfl_handle_initialized;
1313 struct inliners_search_cb {
1314 void operator()(Dwarf_Die* die) {
1315 switch (dwarf_tag(die)) {
1317 case DW_TAG_subprogram:
1318 if ((name = dwarf_diename(die))) {
1319 trace.source.function = name;
1323 case DW_TAG_inlined_subroutine:
1324 ResolvedTrace::SourceLoc sloc;
1325 Dwarf_Attribute attr_mem;
1327 if ((name = dwarf_diename(die))) {
1328 sloc.function = name;
1330 if ((name = die_call_file(die))) {
1331 sloc.filename = name;
1334 Dwarf_Word line = 0, col = 0;
1335 dwarf_formudata(dwarf_attr(die, DW_AT_call_line,
1337 dwarf_formudata(dwarf_attr(die, DW_AT_call_column,
1342 trace.inliners.push_back(sloc);
1346 ResolvedTrace& trace;
1347 inliners_search_cb(ResolvedTrace& t): trace(t) {}
1351 static bool die_has_pc(Dwarf_Die* die, Dwarf_Addr pc) {
1352 Dwarf_Addr low, high;
1355 if (dwarf_hasattr(die, DW_AT_low_pc) and
1356 dwarf_hasattr(die, DW_AT_high_pc)) {
1357 if (dwarf_lowpc(die, &low) != 0) {
1360 if (dwarf_highpc(die, &high) != 0) {
1361 Dwarf_Attribute attr_mem;
1362 Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_high_pc, &attr_mem);
1364 if (dwarf_formudata(attr, &value) != 0) {
1369 return pc >= low && pc < high;
1374 ptrdiff_t offset = 0;
1375 while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
1376 if (pc >= low && pc < high) {
1383 static Dwarf_Die* find_fundie_by_pc(Dwarf_Die* parent_die, Dwarf_Addr pc,
1384 Dwarf_Die* result) {
1385 if (dwarf_child(parent_die, result) != 0) {
1389 Dwarf_Die* die = result;
1391 switch (dwarf_tag(die)) {
1392 case DW_TAG_subprogram:
1393 case DW_TAG_inlined_subroutine:
1394 if (die_has_pc(die, pc)) {
1398 bool declaration =
false;
1399 Dwarf_Attribute attr_mem;
1400 dwarf_formflag(dwarf_attr(die, DW_AT_declaration,
1401 &attr_mem), &declaration);
1407 Dwarf_Die* indie = find_fundie_by_pc(die, pc, &die_mem);
1413 }
while (dwarf_siblingof(die, result) == 0);
1417 template <
typename CB>
1418 static bool deep_first_search_by_pc(Dwarf_Die* parent_die,
1419 Dwarf_Addr pc, CB cb) {
1421 if (dwarf_child(parent_die, &die_mem) != 0) {
1425 bool branch_has_pc =
false;
1426 Dwarf_Die* die = &die_mem;
1428 bool declaration =
false;
1429 Dwarf_Attribute attr_mem;
1430 dwarf_formflag(dwarf_attr(die, DW_AT_declaration, &attr_mem), &declaration);
1436 branch_has_pc = deep_first_search_by_pc(die, pc, cb);
1438 if (!branch_has_pc) {
1439 branch_has_pc = die_has_pc(die, pc);
1441 if (branch_has_pc) {
1444 }
while (dwarf_siblingof(die, &die_mem) == 0);
1445 return branch_has_pc;
1448 static const char* die_call_file(Dwarf_Die *die) {
1449 Dwarf_Attribute attr_mem;
1450 Dwarf_Sword file_idx = 0;
1452 dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem),
1455 if (file_idx == 0) {
1460 Dwarf_Die* cudie = dwarf_diecu(die, &die_mem, 0, 0);
1465 Dwarf_Files* files = 0;
1467 dwarf_getsrcfiles(cudie, &files, &nfiles);
1472 return dwarf_filesrc(files, file_idx, 0, 0);
1479class TraceResolverImpl<system_tag::linux_tag>:
1480 public TraceResolverLinuxImpl<trace_resolver_tag::current> {};
1491 using lines_t = std::vector<std::pair<unsigned, std::string>>;
1498 using namespace std;
1513 for (line_idx = 1; line_idx < line_start; ++line_idx) {
1514 std::getline(*
_file, line);
1524 bool operator()(
char c) {
1525 return std::isspace(c);
1529 bool started =
false;
1530 for (; line_idx < line_start + line_count; ++line_idx) {
1531 getline(*
_file, line);
1536 if (std::find_if(line.begin(), line.end(),
1541 lines.push_back(make_pair(line_idx, line));
1545 std::find_if(lines.rbegin(), lines.rend(),
1553 return get_lines(line_start, line_count, lines);
1560 return !std::isspace(c);
1567 return !(std::find_if(p.second.begin(), p.second.end(),
1576#ifdef BACKWARD_ATLEAST_CXX11
1581 swap(from);
return *
this;
1599#ifdef BACKWARD_ATLEAST_CXX11
1610 unsigned line_start,
unsigned context_size) {
1613 unsigned start = line_start - context_size / 2;
1614 return src_file.
get_lines(start, context_size);
1618 const std::string& filename_a,
unsigned line_a,
1619 const std::string& filename_b,
unsigned line_b,
1620 unsigned context_size) {
1626 src_file_b.
get_lines(line_b - context_size / 4, context_size / 2,
1632 unsigned line_a,
unsigned line_b,
unsigned context_size) {
1635 using std::min;
using std::max;
1636 unsigned a = min(line_a, line_b);
1637 unsigned b = max(line_a, line_b);
1639 if ((b - a) < (context_size / 3)) {
1640 return src_file.
get_lines((a + b - context_size + 1) / 2,
1646 src_file.
get_lines(b - context_size / 4, context_size / 2, lines);
1656 src_files_t::iterator it =
_src_files.find(filename);
1662 return new_src_file;
1668#ifdef BACKWARD_SYSTEM_LINUX
1681 _os(os), _reset(false), _use_colors(false) {}
1690 if (isatty(fileno(desc))) {
1696 if (!_use_colors)
return;
1700 _os <<
"\033[" <<
static_cast<int>(ccode) <<
"m";
1755 template <
typename ST>
1756 FILE*
print(ST& st, FILE* os = stderr) {
1757 std::stringstream ss;
1760 colorize.activate_if_tty(os);
1762 print(st, ss, colorize);
1763 fprintf(os,
"%s", ss.str().c_str());
1767 template <
typename ST>
1771 colorize.activate();
1773 print(st, os, colorize);
1776 template <
typename IT>
1777 FILE*
print(IT begin, IT end, FILE* os = stderr,
size_t thread_id = 0) {
1778 std::stringstream ss;
1781 colorize.activate_if_tty(os);
1783 print(begin, end, ss, thread_id, colorize);
1784 fprintf(os,
"%s", ss.str().c_str());
1788 template <
typename IT>
1789 void print(IT begin, IT end, std::ostream& os,
size_t thread_id = 0) {
1792 colorize.activate();
1794 print(begin, end, os, thread_id, colorize);
1801 template <
typename ST>
1805 for (
size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
1810 template <
typename IT>
1811 void print(IT begin, IT end, std::ostream& os,
size_t thread_id,
Colorize& colorize) {
1813 for (; begin != end; ++begin) {
1819 os <<
"Stack trace (most recent call last)";
1821 os <<
" in thread " << thread_id;
1829 << std::left << std::setw(2) << trace.
idx
1831 bool already_indented =
true;
1841 already_indented =
false;
1844 for (
size_t inliner_idx = trace.
inliners.size();
1845 inliner_idx > 0; --inliner_idx) {
1846 if (!already_indented) {
1856 already_indented =
false;
1860 if (!already_indented) {
1876 using namespace std;
1880 source_loc.
line, context_size);
1882 for (lines_t::const_iterator it = lines.begin();
1883 it != lines.end(); ++it) {
1884 if (it-> first == source_loc.
line) {
1885 colorize.set_color(color_code);
1886 os << indent <<
">";
1888 os << indent <<
" ";
1890 os << std::setw(4) << it->first
1894 if (it-> first == source_loc.
line) {
1912 os <<
" [" << addr <<
"]";
1920#ifdef BACKWARD_SYSTEM_LINUX
1923class SignalHandling {
1925 static std::vector<int> make_default_signals() {
1926 const int posix_signals[] = {
1955 return std::vector<int>(posix_signals, posix_signals +
sizeof posix_signals /
sizeof posix_signals[0] );
1958 SignalHandling(
const std::vector<int>& posix_signals = make_default_signals()):
1960 bool success =
true;
1962 const size_t stack_size = 1024 * 1024 * 8;
1963 _stack_content.reset((
char*)malloc(stack_size));
1964 if (_stack_content) {
1966 ss.ss_sp = _stack_content.get();
1967 ss.ss_size = stack_size;
1969 if (sigaltstack(&ss, 0) < 0) {
1976 for (
size_t i = 0; i < posix_signals.size(); ++i) {
1977 struct sigaction action;
1978 memset(&action, 0,
sizeof action);
1979 action.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_NODEFER |
1981 sigfillset(&action.sa_mask);
1982 sigdelset(&action.sa_mask, posix_signals[i]);
1983 action.sa_sigaction = &sig_handler;
1985 int r = sigaction(posix_signals[i], &action, 0);
1986 if (
r < 0) success =
false;
1992 bool loaded()
const {
return _loaded; }
1995 details::handle<char*> _stack_content;
1998 static void sig_handler(
int, siginfo_t* info,
void* _ctx) {
1999 ucontext_t *uctx = (ucontext_t*) _ctx;
2002 void* error_addr = 0;
2004 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_RIP]);
2005#elif defined(REG_EIP)
2006 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.gregs[REG_EIP]);
2007#elif defined(__arm__)
2008 error_addr =
reinterpret_cast<void*
>(uctx->uc_mcontext.arm_pc);
2010# warning ":/ sorry, ain't know no nothing none not of your architecture!"
2013 st.load_from(error_addr, 32);
2019 printer.address =
true;
2020 printer.print(st, stderr);
2022#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
2027 raise(info->si_signo);
2031 _exit(EXIT_FAILURE);
2037#ifdef BACKWARD_SYSTEM_UNKNOWN
void set_color(Color::type)
void print_header(std::ostream &os, unsigned thread_id)
void print_source_loc(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, void *addr=0)
FILE * print(ST &st, FILE *os=stderr)
void print(IT begin, IT end, std::ostream &os, size_t thread_id, Colorize &colorize)
void print(IT begin, IT end, std::ostream &os, size_t thread_id=0)
FILE * print(IT begin, IT end, FILE *os=stderr, size_t thread_id=0)
void print(ST &st, std::ostream &os, Colorize &colorize)
void print(ST &st, std::ostream &os)
void print_trace(std::ostream &os, const ResolvedTrace &trace, Colorize &colorize)
void print_snippet(std::ostream &os, const char *indent, const ResolvedTrace::SourceLoc &source_loc, Colorize &colorize, Color::type color_code, int context_size)
SignalHandling(const std::vector< int > &=std::vector< int >())
SourceFile & get_src_file(const std::string &filename)
SourceFile::lines_t lines_t
lines_t get_coalesced_snippet(const std::string &filename, unsigned line_a, unsigned line_b, unsigned context_size)
lines_t get_snippet(const std::string &filename, unsigned line_start, unsigned context_size)
details::hashtable< std::string, SourceFile >::type src_files_t
lines_t get_combined_snippet(const std::string &filename_a, unsigned line_a, const std::string &filename_b, unsigned line_b, unsigned context_size)
lines_t get_lines(unsigned line_start, unsigned line_count)
std::vector< std::pair< unsigned, std::string > > lines_t
SourceFile & operator=(const SourceFile &from)
SourceFile(const SourceFile &from)
lines_t & get_lines(unsigned line_start, unsigned line_count, lines_t &lines)
details::handle< std::ifstream *, details::default_delete< std::ifstream * > > _file
SourceFile(const std::string &path)
size_t load_from(void *, size_t=0)
size_t load_here(size_t=0)
void skip_n_firsts(size_t)
unsigned thread_id() const
void load_stacktrace(ST &)
ResolvedTrace resolve(ResolvedTrace t)
handle(const handle &from)
const typename rm_ptr< T >::type & const_ref_t
handle & operator=(const handle &from)
ref_t operator[](size_t idx)
const_ref_t operator*() const
typename rm_ptr< T >::type & ref_t
const T operator->() const
Basic configuration file.
const T & move(const T &v)
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
bool operator==(const SourceLoc &b) const
bool operator!=(const SourceLoc &b) const
ResolvedTrace(const Trace &mini_trace)
std::vector< SourceLoc > source_locs_t
std::string object_filename
std::string object_function
bool operator()(const lines_t::value_type &p)
Trace(void *_addr, size_t _idx)
void operator()(T &ptr) const
void operator()(U &ptr) const
static std::string demangle(const char *funcname)