static bool die_has_pc()

in src/backward.h [2453:2536]


    static bool die_has_pc(dwarf_fileobject& fobj, Dwarf_Die die, Dwarf_Addr pc)
    {
        Dwarf_Addr low_pc = 0, high_pc = 0;
        Dwarf_Half high_pc_form = 0;
        Dwarf_Form_Class return_class;
        Dwarf_Error error = DW_DLE_NE;
        Dwarf_Debug dwarf = fobj.dwarf_handle.get();
        bool has_lowpc = false;
        bool has_highpc = false;
        bool has_ranges = false;

        if (dwarf_lowpc(die, &low_pc, &error) == DW_DLV_OK) {
            // If we have a low_pc check if there is a high pc.
            // If we don't have a high pc this might mean we have a base
            // address for the ranges list or just an address.
            has_lowpc = true;

            if (dwarf_highpc_b(die, &high_pc, &high_pc_form, &return_class, &error) == DW_DLV_OK) {
                // We do have a high pc. In DWARF 4+ this is an offset from the
                // low pc, but in earlier versions it's an absolute address.

                has_highpc = true;
                // In DWARF 2/3 this would be a DW_FORM_CLASS_ADDRESS
                if (return_class == DW_FORM_CLASS_CONSTANT) {
                    high_pc = low_pc + high_pc;
                }

                // We have low and high pc, check if our address
                // is in that range
                return pc >= low_pc && pc < high_pc;
            }
        }
        else {
            // Reset the low_pc, in case dwarf_lowpc failing set it to some
            // undefined value.
            low_pc = 0;
        }

        // Check if DW_AT_ranges is present and search for the PC in the
        // returned ranges list. We always add the low_pc, as it not set it will
        // be 0, in case we had a DW_AT_low_pc and DW_AT_ranges pair
        bool result = false;

        Dwarf_Attribute attr;
        if (dwarf_attr(die, DW_AT_ranges, &attr, &error) == DW_DLV_OK) {

            Dwarf_Off offset;
            if (dwarf_global_formref(attr, &offset, &error) == DW_DLV_OK) {
                Dwarf_Ranges* ranges;
                Dwarf_Signed ranges_count = 0;
                Dwarf_Unsigned byte_count = 0;

                if (dwarf_get_ranges_a(dwarf, offset, die, &ranges, &ranges_count, &byte_count, &error) == DW_DLV_OK) {
                    has_ranges = ranges_count != 0;
                    for (int i = 0; i < ranges_count; i++) {
                        if (ranges[i].dwr_addr1 != 0 && pc >= ranges[i].dwr_addr1 + low_pc &&
                            pc < ranges[i].dwr_addr2 + low_pc) {
                            result = true;
                            break;
                        }
                    }
                    dwarf_ranges_dealloc(dwarf, ranges, ranges_count);
                }
            }
        }

        // Last attempt. We might have a single address set as low_pc.
        if (!result && low_pc != 0 && pc == low_pc) {
            result = true;
        }

        // If we don't have lowpc, highpc and ranges maybe this DIE is a
        // declaration that relies on a DW_AT_specification DIE that happens
        // later. Use the specification cache we filled when we loaded this CU.
        if (!result && (!has_lowpc && !has_highpc && !has_ranges)) {
            Dwarf_Die spec_die = get_spec_die(fobj, die);
            if (spec_die) {
                result = die_has_pc(fobj, spec_die, pc);
                dwarf_dealloc(dwarf, spec_die, DW_DLA_DIE);
            }
        }

        return result;
    }