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