ResolvedTrace resolve()

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;
    }