in src/backward.h [1902:2040]
ResolvedTrace resolve(ResolvedTrace trace)
{
// trace.addr is a virtual address in memory pointing to some code.
// Let's try to find from which loaded object it comes from.
// The loaded object can be yourself btw.
Dl_info symbol_info;
int dladdr_result = 0;
# if defined(__GLIBC__)
link_map* link_map;
// We request the link map so we can get information about offsets
dladdr_result = dladdr1(trace.addr, &symbol_info, reinterpret_cast<void**>(&link_map), RTLD_DL_LINKMAP);
# else
// Android doesn't have dladdr1. Don't use the linker map.
dladdr_result = dladdr(trace.addr, &symbol_info);
# endif
if (!dladdr_result) {
return trace; // dat broken trace...
}
// Now we get in symbol_info:
// .dli_fname:
// pathname of the shared object that contains the address.
// .dli_fbase:
// where the object is loaded in memory.
// .dli_sname:
// the name of the nearest symbol to trace.addr, we expect a
// function name.
// .dli_saddr:
// the exact address corresponding to .dli_sname.
//
// And in link_map:
// .l_addr:
// difference between the address in the ELF file and the address
// in memory
// l_name:
// absolute pathname where the object was found
if (symbol_info.dli_sname) {
trace.object_function = demangle(symbol_info.dli_sname);
}
if (!symbol_info.dli_fname) {
return trace;
}
trace.object_filename = resolve_exec_path(symbol_info);
dwarf_fileobject& fobj = load_object_with_dwarf(symbol_info.dli_fname);
if (!fobj.dwarf_handle) {
return trace; // sad, we couldn't load the object :(
}
# if defined(__GLIBC__)
// Convert the address to a module relative one by looking at
// the module's loading address in the link map
Dwarf_Addr address = reinterpret_cast<uintptr_t>(trace.addr) - reinterpret_cast<uintptr_t>(link_map->l_addr);
# else
Dwarf_Addr address = reinterpret_cast<uintptr_t>(trace.addr);
# endif
if (trace.object_function.empty()) {
symbol_cache_t::iterator it = fobj.symbol_cache.lower_bound(address);
if (it != fobj.symbol_cache.end()) {
if (it->first != address) {
if (it != fobj.symbol_cache.begin()) {
--it;
}
}
trace.object_function = demangle(it->second.c_str());
}
}
// Get the Compilation Unit DIE for the address
Dwarf_Die die = find_die(fobj, address);
if (!die) {
return trace; // this time we lost the game :/
}
// libdwarf doesn't give us direct access to its objects, it always
// allocates a copy for the caller. We keep that copy alive in a cache
// and we deallocate it later when it's no longer required.
die_cache_entry& die_object = get_die_cache(fobj, die);
if (die_object.isEmpty())
return trace; // We have no line section for this DIE
die_linemap_t::iterator it = die_object.line_section.lower_bound(address);
if (it != die_object.line_section.end()) {
if (it->first != address) {
if (it == die_object.line_section.begin()) {
// If we are on the first item of the line section
// but the address does not match it means that
// the address is below the range of the DIE. Give up.
return trace;
}
else {
--it;
}
}
}
else {
return trace; // We didn't find the address.
}
// Get the Dwarf_Line that the address points to and call libdwarf
// to get source file, line and column info.
Dwarf_Line line = die_object.line_buffer[it->second];
Dwarf_Error error = DW_DLE_NE;
char* filename;
if (dwarf_linesrc(line, &filename, &error) == DW_DLV_OK) {
trace.source.filename = std::string(filename);
dwarf_dealloc(fobj.dwarf_handle.get(), filename, DW_DLA_STRING);
}
Dwarf_Unsigned number = 0;
if (dwarf_lineno(line, &number, &error) == DW_DLV_OK) {
trace.source.line = number;
}
else {
trace.source.line = 0;
}
if (dwarf_lineoff_b(line, &number, &error) == DW_DLV_OK) {
trace.source.col = number;
}
else {
trace.source.col = 0;
}
std::vector<std::string> namespace_stack;
deep_first_search_by_pc(fobj, die, address, namespace_stack, inliners_search_cb(trace, fobj, die));
dwarf_dealloc(fobj.dwarf_handle.get(), die, DW_DLA_DIE);
return trace;
}