in src/backward.h [1573:1719]
ResolvedTrace resolve(ResolvedTrace trace)
{
using namespace details;
Dwarf_Addr trace_addr = (Dwarf_Addr)trace.addr;
if (!_dwfl_handle_initialized) {
// initialize dwfl...
_dwfl_cb.reset(new Dwfl_Callbacks);
_dwfl_cb->find_elf = &dwfl_linux_proc_find_elf;
_dwfl_cb->find_debuginfo = &dwfl_standard_find_debuginfo;
_dwfl_cb->debuginfo_path = 0;
_dwfl_handle.reset(dwfl_begin(_dwfl_cb.get()));
_dwfl_handle_initialized = true;
if (!_dwfl_handle) {
return trace;
}
// ...from the current process.
dwfl_report_begin(_dwfl_handle.get());
int r = dwfl_linux_proc_report(_dwfl_handle.get(), getpid());
dwfl_report_end(_dwfl_handle.get(), NULL, NULL);
if (r < 0) {
return trace;
}
}
if (!_dwfl_handle) {
return trace;
}
// find the module (binary object) that contains the trace's address.
// This is not using any debug information, but the addresses ranges of
// all the currently loaded binary object.
Dwfl_Module* mod = dwfl_addrmodule(_dwfl_handle.get(), trace_addr);
if (mod) {
// now that we found it, lets get the name of it, this will be the
// full path to the running binary or one of the loaded library.
const char* module_name = dwfl_module_info(mod, 0, 0, 0, 0, 0, 0, 0);
if (module_name) {
trace.object_filename = module_name;
}
// We also look after the name of the symbol, equal or before this
// address. This is found by walking the symtab. We should get the
// symbol corresponding to the function (mangled) containing the
// address. If the code corresponding to the address was inlined,
// this is the name of the out-most inliner function.
const char* sym_name = dwfl_module_addrname(mod, trace_addr);
if (sym_name) {
trace.object_function = demangle(sym_name);
}
}
// now let's get serious, and find out the source location (file and
// line number) of the address.
// This function will look in .debug_aranges for the address and map it
// to the location of the compilation unit DIE in .debug_info and
// return it.
Dwarf_Addr mod_bias = 0;
Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias);
# if 1
if (!cudie) {
// Sadly clang does not generate the section .debug_aranges, thus
// dwfl_module_addrdie will fail early. Clang doesn't either set
// the lowpc/highpc/range info for every compilation unit.
//
// So in order to save the world:
// for every compilation unit, we will iterate over every single
// DIEs. Normally functions should have a lowpc/highpc/range, which
// we will use to infer the compilation unit.
// note that this is probably badly inefficient.
while ((cudie = dwfl_module_nextcu(mod, cudie, &mod_bias))) {
Dwarf_Die die_mem;
Dwarf_Die* fundie = find_fundie_by_pc(cudie, trace_addr - mod_bias, &die_mem);
if (fundie) {
break;
}
}
}
# endif
//#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
# ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
if (!cudie) {
// If it's still not enough, lets dive deeper in the shit, and try
// to save the world again: for every compilation unit, we will
// load the corresponding .debug_line section, and see if we can
// find our address in it.
Dwarf_Addr cfi_bias;
Dwarf_CFI* cfi_cache = dwfl_module_eh_cfi(mod, &cfi_bias);
Dwarf_Addr bias;
while ((cudie = dwfl_module_nextcu(mod, cudie, &bias))) {
if (dwarf_getsrc_die(cudie, trace_addr - bias)) {
// ...but if we get a match, it might be a false positive
// because our (address - bias) might as well be valid in a
// different compilation unit. So we throw our last card on
// the table and lookup for the address into the .eh_frame
// section.
handle<Dwarf_Frame*> frame;
dwarf_cfi_addrframe(cfi_cache, trace_addr - cfi_bias, &frame);
if (frame) {
break;
}
}
}
}
# endif
if (!cudie) {
return trace; // this time we lost the game :/
}
// Now that we have a compilation unit DIE, this function will be able
// to load the corresponding section in .debug_line (if not already
// loaded) and hopefully find the source location mapped to our
// address.
Dwarf_Line* srcloc = dwarf_getsrc_die(cudie, trace_addr - mod_bias);
if (srcloc) {
const char* srcfile = dwarf_linesrc(srcloc, 0, 0);
if (srcfile) {
trace.source.filename = srcfile;
}
int line = 0, col = 0;
dwarf_lineno(srcloc, &line);
dwarf_linecol(srcloc, &col);
trace.source.line = line;
trace.source.col = col;
}
deep_first_search_by_pc(cudie, trace_addr - mod_bias, inliners_search_cb(trace));
if (trace.source.function.size() == 0) {
// fallback.
trace.source.function = trace.object_function;
}
return trace;
}