Dwarf_Die find_die()

in src/backward.h [3145:3244]


    Dwarf_Die find_die(dwarf_fileobject& fobj, Dwarf_Addr addr)
    {
        // Let's get to work! First see if we have a debug_aranges section so
        // we can speed up the search

        Dwarf_Debug dwarf = fobj.dwarf_handle.get();
        Dwarf_Error error = DW_DLE_NE;
        Dwarf_Arange* aranges;
        Dwarf_Signed arange_count;

        Dwarf_Die returnDie;
        bool found = false;
        if (dwarf_get_aranges(dwarf, &aranges, &arange_count, &error) != DW_DLV_OK) {
            aranges = NULL;
        }

        if (aranges) {
            // We have aranges. Get the one where our address is.
            Dwarf_Arange arange;
            if (dwarf_get_arange(aranges, arange_count, addr, &arange, &error) == DW_DLV_OK) {

                // We found our address. Get the compilation-unit DIE offset
                // represented by the given address range.
                Dwarf_Off cu_die_offset;
                if (dwarf_get_cu_die_offset(arange, &cu_die_offset, &error) == DW_DLV_OK) {
                    // Get the DIE at the offset returned by the aranges search.
                    // We set is_info to 1 to specify that the offset is from
                    // the .debug_info section (and not .debug_types)
                    int dwarf_result = dwarf_offdie_b(dwarf, cu_die_offset, 1, &returnDie, &error);

                    found = dwarf_result == DW_DLV_OK;
                }
                dwarf_dealloc(dwarf, arange, DW_DLA_ARANGE);
            }
        }

        if (found)
            return returnDie; // The caller is responsible for freeing the die

        // The search for aranges failed. Try to find our address by scanning
        // all compilation units.
        Dwarf_Unsigned next_cu_header;
        Dwarf_Half tag = 0;
        returnDie = 0;

        while (!found &&
               dwarf_next_cu_header_d(dwarf, 1, 0, 0, 0, 0, 0, 0, 0, 0, &next_cu_header, 0, &error) == DW_DLV_OK) {

            if (returnDie)
                dwarf_dealloc(dwarf, returnDie, DW_DLA_DIE);

            if (dwarf_siblingof(dwarf, 0, &returnDie, &error) == DW_DLV_OK) {
                if ((dwarf_tag(returnDie, &tag, &error) == DW_DLV_OK) && tag == DW_TAG_compile_unit) {
                    if (die_has_pc(fobj, returnDie, addr)) {
                        found = true;
                    }
                }
            }
        }

        if (found) {
            while (dwarf_next_cu_header_d(dwarf, 1, 0, 0, 0, 0, 0, 0, 0, 0, &next_cu_header, 0, &error) == DW_DLV_OK) {
                // Reset the cu header state. Libdwarf's next_cu_header API
                // keeps its own iterator per Dwarf_Debug that can't be reset.
                // We need to keep fetching elements until the end.
            }
        }

        if (found)
            return returnDie;

        // We couldn't find any compilation units with ranges or a high/low pc.
        // Try again by looking at all DIEs in all compilation units.
        Dwarf_Die cudie;
        while (dwarf_next_cu_header_d(dwarf, 1, 0, 0, 0, 0, 0, 0, 0, 0, &next_cu_header, 0, &error) == DW_DLV_OK) {
            if (dwarf_siblingof(dwarf, 0, &cudie, &error) == DW_DLV_OK) {
                Dwarf_Die die_mem = 0;
                Dwarf_Die resultDie = find_fundie_by_pc(fobj, cudie, addr, die_mem);

                if (resultDie) {
                    found = true;
                    break;
                }
            }
        }

        if (found) {
            while (dwarf_next_cu_header_d(dwarf, 1, 0, 0, 0, 0, 0, 0, 0, 0, &next_cu_header, 0, &error) == DW_DLV_OK) {
                // Reset the cu header state. Libdwarf's next_cu_header API
                // keeps its own iterator per Dwarf_Debug that can't be reset.
                // We need to keep fetching elements until the end.
            }
        }

        if (found)
            return cudie;

        // We failed.
        return NULL;
    }