in folly/experimental/symbolizer/DwarfUtil.cpp [272:448]
Attribute readAttribute(
const CompilationUnit& cu,
const Die& die,
AttributeSpec spec,
folly::StringPiece& info) {
// DWARF 5 introduces new FORMs whose values are relative to some base attrs:
// DW_AT_str_offsets_base, DW_AT_rnglists_base, DW_AT_addr_base.
// Debug Fission DWARF 4 uses GNU DW_AT_GNU_ranges_base & DW_AT_GNU_addr_base.
//
// The order in which attributes appear in a CU is not defined.
// The DW_AT_*_base attrs may appear after attributes that need them.
// The DW_AT_*_base attrs are CU specific; so we read them just after
// reading the CU header. During this first pass return empty values
// when encountering a FORM that depends on DW_AT_*_base.
auto getStringUsingOffsetTable = [&](uint64_t index) {
if (!cu.strOffsetsBase.has_value()) {
return folly::StringPiece();
}
// DWARF 5: 7.26 String Offsets Table
// The DW_AT_str_offsets_base attribute points to the first entry following
// the header. The entries are indexed sequentially from this base entry,
// starting from 0.
auto sp = cu.debugSections.debugStrOffsets.subpiece(
*cu.strOffsetsBase +
index * (cu.is64Bit ? sizeof(uint64_t) : sizeof(uint32_t)));
uint64_t strOffset = readOffset(sp, cu.is64Bit);
return getStringFromStringSection(cu.debugSections.debugStr, strOffset);
};
auto readDebugAddr = [&](uint64_t index) {
if (!cu.addrBase.has_value()) {
return uint64_t(0);
}
// DWARF 5: 7.27 Address Table
// The DW_AT_addr_base attribute points to the first entry following the
// header. The entries are indexed sequentially from this base entry,
// starting from 0.
auto sp = cu.debugSections.debugAddr.subpiece(
*cu.addrBase + index * sizeof(uint64_t));
return read<uint64_t>(sp);
};
switch (spec.form) {
case DW_FORM_addr:
return {spec, die, read<uintptr_t>(info)};
case DW_FORM_block1:
return {spec, die, readBytes(info, read<uint8_t>(info))};
case DW_FORM_block2:
return {spec, die, readBytes(info, read<uint16_t>(info))};
case DW_FORM_block4:
return {spec, die, readBytes(info, read<uint32_t>(info))};
case DW_FORM_block:
FOLLY_FALLTHROUGH;
case DW_FORM_exprloc:
return {spec, die, readBytes(info, readULEB(info))};
case DW_FORM_data1:
FOLLY_FALLTHROUGH;
case DW_FORM_ref1:
return {spec, die, read<uint8_t>(info)};
case DW_FORM_data2:
FOLLY_FALLTHROUGH;
case DW_FORM_ref2:
return {spec, die, read<uint16_t>(info)};
case DW_FORM_data4:
FOLLY_FALLTHROUGH;
case DW_FORM_ref4:
return {spec, die, read<uint32_t>(info)};
case DW_FORM_data8:
FOLLY_FALLTHROUGH;
case DW_FORM_ref8:
FOLLY_FALLTHROUGH;
case DW_FORM_ref_sig8:
return {spec, die, read<uint64_t>(info)};
case DW_FORM_sdata:
return {spec, die, readSLEB(info)};
case DW_FORM_udata:
FOLLY_FALLTHROUGH;
case DW_FORM_ref_udata:
return {spec, die, readULEB(info)};
case DW_FORM_flag:
return {spec, die, read<uint8_t>(info)};
case DW_FORM_flag_present:
return {spec, die, 1};
case DW_FORM_sec_offset:
FOLLY_FALLTHROUGH;
case DW_FORM_ref_addr:
return {spec, die, readOffset(info, die.is64Bit)};
case DW_FORM_string:
return {spec, die, readNullTerminated(info)};
case DW_FORM_strp:
return {
spec,
die,
getStringFromStringSection(
cu.debugSections.debugStr, readOffset(info, die.is64Bit))};
case DW_FORM_indirect: // form is explicitly specified
// Update spec with the actual FORM.
spec.form = readULEB(info);
return readAttribute(cu, die, spec, info);
// DWARF 5:
case DW_FORM_implicit_const: // form is explicitly specified
// For attributes with this form, the attribute specification contains a
// third part, which is a signed LEB128 number. The value of this number
// is used as the value of the attribute, and no value is stored in the
// .debug_info section.
return {spec, die, spec.implicitConst};
case DW_FORM_addrx:
return {spec, die, readDebugAddr(readULEB(info))};
case DW_FORM_addrx1:
return {spec, die, readDebugAddr(readU64<1>(info))};
case DW_FORM_addrx2:
return {spec, die, readDebugAddr(readU64<2>(info))};
case DW_FORM_addrx3:
return {spec, die, readDebugAddr(readU64<3>(info))};
case DW_FORM_addrx4:
return {spec, die, readDebugAddr(readU64<4>(info))};
case DW_FORM_line_strp:
return {
spec,
die,
getStringFromStringSection(
cu.debugSections.debugLineStr, readOffset(info, die.is64Bit))};
case DW_FORM_strx:
return {spec, die, getStringUsingOffsetTable(readULEB(info))};
case DW_FORM_strx1:
return {spec, die, getStringUsingOffsetTable(readU64<1>(info))};
case DW_FORM_strx2:
return {spec, die, getStringUsingOffsetTable(readU64<2>(info))};
case DW_FORM_strx3:
return {spec, die, getStringUsingOffsetTable(readU64<3>(info))};
case DW_FORM_strx4:
return {spec, die, getStringUsingOffsetTable(readU64<4>(info))};
case DW_FORM_rnglistx: {
auto index = readULEB(info);
if (!cu.rnglistsBase.has_value()) {
return {spec, die, 0};
}
const uint64_t offsetSize =
cu.is64Bit ? sizeof(uint64_t) : sizeof(uint32_t);
auto sp = cu.debugSections.debugRnglists.subpiece(
*cu.rnglistsBase + index * offsetSize);
auto offset = readOffset(sp, cu.is64Bit);
return {spec, die, *cu.rnglistsBase + offset};
} break;
case DW_FORM_loclistx: {
auto index = readULEB(info);
if (!cu.loclistsBase.has_value()) {
return {spec, die, 0};
}
const uint64_t offsetSize =
cu.is64Bit ? sizeof(uint64_t) : sizeof(uint32_t);
auto sp = cu.debugSections.debugLoclists.subpiece(
*cu.loclistsBase + index * offsetSize);
auto offset = readOffset(sp, cu.is64Bit);
return {spec, die, *cu.loclistsBase + offset};
} break;
case DW_FORM_data16:
return {spec, die, readBytes(info, 16)};
case DW_FORM_ref_sup4:
case DW_FORM_ref_sup8:
case DW_FORM_strp_sup:
FOLLY_SAFE_CHECK(
false, "Unexpected DWARF5 supplimentary object files: ", spec.form);
default:
FOLLY_SAFE_CHECK(false, "invalid attribute form: ", spec.form);
}
return {spec, die, 0};
}