forked from OSchip/llvm-project
DebugInfo: Use loclistx for DWARFv5 location lists to reduce the number of relocations
This only implements the non-dwo part, but loclistx is necessary to use location lists in DWARFv5, so it's a precursor to that work - and generally reduces relocations (only using one reloc, then indexes/relative offsets for all location list references) in non-split DWARF.
This commit is contained in:
parent
97c742e6b7
commit
77cfcd7509
|
@ -188,6 +188,7 @@ public:
|
|||
///
|
||||
/// \returns anm optional absolute section offset value for the attribute.
|
||||
Optional<uint64_t> getRangesBaseAttribute() const;
|
||||
Optional<uint64_t> getLocBaseAttribute() const;
|
||||
|
||||
/// Get the DW_AT_high_pc attribute value as an address.
|
||||
///
|
||||
|
|
|
@ -200,6 +200,8 @@ class DWARFUnit {
|
|||
const DWARFDebugAbbrev *Abbrev;
|
||||
const DWARFSection *RangeSection;
|
||||
uint64_t RangeSectionBase;
|
||||
const DWARFSection *LocSection;
|
||||
uint64_t LocSectionBase;
|
||||
|
||||
/// Location table of this unit.
|
||||
std::unique_ptr<DWARFLocationTable> LocTable;
|
||||
|
@ -219,6 +221,7 @@ class DWARFUnit {
|
|||
|
||||
/// A table of range lists (DWARF v5 and later).
|
||||
Optional<DWARFDebugRnglistTable> RngListTable;
|
||||
Optional<DWARFListTableHeader> LoclistTableHeader;
|
||||
|
||||
mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
|
||||
llvm::Optional<object::SectionedAddress> BaseAddr;
|
||||
|
@ -305,6 +308,14 @@ public:
|
|||
RangeSection = RS;
|
||||
RangeSectionBase = Base;
|
||||
}
|
||||
void setLocSection(const DWARFSection *LS, uint64_t Base) {
|
||||
LocSection = LS;
|
||||
LocSectionBase = Base;
|
||||
}
|
||||
|
||||
uint64_t getLocSectionBase() const {
|
||||
return LocSectionBase;
|
||||
}
|
||||
|
||||
Optional<object::SectionedAddress>
|
||||
getAddrOffsetSectionItem(uint32_t Index) const;
|
||||
|
@ -421,6 +432,11 @@ public:
|
|||
return None;
|
||||
}
|
||||
|
||||
Optional<uint64_t> getLoclistOffset(uint32_t Index) {
|
||||
if (LoclistTableHeader)
|
||||
return LoclistTableHeader->getOffsetEntry(Index);
|
||||
return None;
|
||||
}
|
||||
Expected<DWARFAddressRangesVector> collectAddressRanges();
|
||||
|
||||
/// Returns subprogram DIE with address range encompassing the provided
|
||||
|
|
|
@ -798,6 +798,8 @@ void DIEBlock::print(raw_ostream &O) const {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
if (Form == dwarf::DW_FORM_loclistx)
|
||||
return getULEB128Size(Index);
|
||||
if (Form == dwarf::DW_FORM_data4)
|
||||
return 4;
|
||||
if (Form == dwarf::DW_FORM_sec_offset)
|
||||
|
@ -808,6 +810,10 @@ unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
|||
/// EmitValue - Emit label value.
|
||||
///
|
||||
void DIELocList::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
if (Form == dwarf::DW_FORM_loclistx) {
|
||||
AP->EmitULEB128(Index);
|
||||
return;
|
||||
}
|
||||
DwarfDebug *DD = AP->getDwarfDebug();
|
||||
MCSymbol *Label = DD->getDebugLocs().getList(Index).Label;
|
||||
AP->emitDwarfSymbolReference(Label, /*ForceOffset*/ DD->useSplitDwarf());
|
||||
|
|
|
@ -1220,8 +1220,11 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
|
|||
/// Add a Dwarf loclistptr attribute data and value.
|
||||
void DwarfCompileUnit::addLocationList(DIE &Die, dwarf::Attribute Attribute,
|
||||
unsigned Index) {
|
||||
dwarf::Form Form = DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset
|
||||
: dwarf::DW_FORM_data4;
|
||||
dwarf::Form Form = dwarf::DW_FORM_data4;
|
||||
if (DD->getDwarfVersion() == 4)
|
||||
Form =dwarf::DW_FORM_sec_offset;
|
||||
if (DD->getDwarfVersion() >= 5)
|
||||
Form =dwarf::DW_FORM_loclistx;
|
||||
Die.addValue(DIEValueAllocator, Attribute, Form, DIELocList(Index));
|
||||
}
|
||||
|
||||
|
|
|
@ -2323,9 +2323,12 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm,
|
|||
// FIXME: Generate the offsets table and use DW_FORM_loclistx with the
|
||||
// DW_AT_loclists_base attribute. Until then set the number of offsets to 0.
|
||||
Asm->OutStreamer->AddComment("Offset entry count");
|
||||
Asm->emitInt32(0);
|
||||
Asm->emitInt32(DebugLocs.getLists().size());
|
||||
Asm->OutStreamer->EmitLabel(DebugLocs.getSym());
|
||||
|
||||
for (const auto &List : DebugLocs.getLists())
|
||||
Asm->EmitLabelDifference(List.Label, DebugLocs.getSym(), 4);
|
||||
|
||||
return TableEnd;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,13 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
|
|||
|
||||
uint64_t Offset = *FormValue.getAsSectionOffset();
|
||||
|
||||
if (FormValue.getForm() == DW_FORM_loclistx) {
|
||||
FormValue.dump(OS, DumpOpts);
|
||||
if (auto LoclistOffset = U->getLoclistOffset(Offset))
|
||||
Offset = *LoclistOffset + U->getLocSectionBase();
|
||||
else
|
||||
return;
|
||||
}
|
||||
U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(),
|
||||
MRI, U, LLDumpOpts, Indent);
|
||||
return;
|
||||
|
@ -409,6 +416,10 @@ Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
|
|||
return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
|
||||
}
|
||||
|
||||
Optional<uint64_t> DWARFDie::getLocBaseAttribute() const {
|
||||
return toSectionOffset(find(DW_AT_loclists_base));
|
||||
}
|
||||
|
||||
Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
|
||||
if (auto FormValue = find(DW_AT_high_pc)) {
|
||||
if (auto Address = FormValue->getAsAddress()) {
|
||||
|
|
|
@ -312,6 +312,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
|
|||
case DW_FORM_udata:
|
||||
case DW_FORM_ref_udata:
|
||||
case DW_FORM_rnglistx:
|
||||
case DW_FORM_loclistx:
|
||||
Value.uval = Data.getULEB128(OffsetPtr);
|
||||
break;
|
||||
case DW_FORM_string:
|
||||
|
@ -551,6 +552,10 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
|
|||
OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
|
||||
break;
|
||||
|
||||
case DW_FORM_loclistx:
|
||||
OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue);
|
||||
break;
|
||||
|
||||
// Should be formatted to 64-bit for DWARF64.
|
||||
case DW_FORM_sec_offset:
|
||||
AddrOS << format("0x%08x", (uint32_t)UValue);
|
||||
|
|
|
@ -352,6 +352,7 @@ void DWARFUnit::clear() {
|
|||
Abbrevs = nullptr;
|
||||
BaseAddr.reset();
|
||||
RangeSectionBase = 0;
|
||||
LocSectionBase = 0;
|
||||
AddrOffsetSectionBase = 0;
|
||||
clearDIEs(false);
|
||||
DWO.reset();
|
||||
|
@ -442,11 +443,13 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
|
|||
if (!IsDWO) {
|
||||
assert(AddrOffsetSectionBase == 0);
|
||||
assert(RangeSectionBase == 0);
|
||||
assert(LocSectionBase == 0);
|
||||
AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0);
|
||||
if (!AddrOffsetSectionBase)
|
||||
AddrOffsetSectionBase =
|
||||
toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
|
||||
RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
|
||||
LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
|
||||
}
|
||||
|
||||
// In general, in DWARF v5 and beyond we derive the start of the unit's
|
||||
|
@ -498,6 +501,28 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
|
|||
if (IsDWO && RngListTable)
|
||||
RangeSectionBase = RngListTable->getHeaderSize();
|
||||
}
|
||||
|
||||
// FIXME: add loclists.dwo support
|
||||
setLocSection(&Context.getDWARFObj().getLoclistsSection(),
|
||||
toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0));
|
||||
|
||||
if (LocSection->Data.size()) {
|
||||
LoclistTableHeader.emplace(".debug_loclists", "locations");
|
||||
uint64_t Offset = LocSectionBase;
|
||||
uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Header.getFormat());
|
||||
DWARFDataExtractor Data(Context.getDWARFObj(), *LocSection,
|
||||
isLittleEndian, getAddressByteSize());
|
||||
if (Offset < HeaderSize)
|
||||
return createStringError(errc::invalid_argument,
|
||||
"did not detect a valid"
|
||||
" list table with base = 0x%" PRIx64 "\n",
|
||||
Offset);
|
||||
Offset -= HeaderSize;
|
||||
if (Error E = LoclistTableHeader->extract(Data, &Offset))
|
||||
return createStringError(errc::invalid_argument,
|
||||
"parsing a loclist table: " +
|
||||
toString(std::move(E)));
|
||||
}
|
||||
}
|
||||
|
||||
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
|
||||
|
|
|
@ -2,32 +2,36 @@
|
|||
; RUN: llvm-dwarfdump -v -debug-info -debug-loclists %t | FileCheck %s
|
||||
|
||||
; CHECK: DW_TAG_variable
|
||||
; FIXME: Use DW_FORM_loclistx to reduce relocations
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000000c
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) loclist = 0x00000018:
|
||||
; CHECK-NEXT: [0x0000000000000000, 0x0000000000000003): DW_OP_consts +3, DW_OP_stack_value
|
||||
; CHECK-NEXT: [0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value)
|
||||
; CHECK-NEXT: DW_AT_name {{.*}} "y"
|
||||
|
||||
; CHECK: DW_TAG_variable
|
||||
; FIXME: Use DW_FORM_loclistx to reduce relocations
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x0000001d
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x1) loclist = 0x00000029:
|
||||
; CHECK-NEXT: [0x0000000000000000, 0x0000000000000003): DW_OP_consts +5, DW_OP_stack_value)
|
||||
; CHECK-NEXT: DW_AT_name {{.*}} "x"
|
||||
|
||||
; CHECK: DW_TAG_variable
|
||||
; FIXME: Use DW_FORM_loclistx to reduce relocations
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000025
|
||||
; CHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x2) loclist = 0x00000031:
|
||||
; CHECK-NEXT: [0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX)
|
||||
; CHECK-NEXT: DW_AT_name {{.*}} "r"
|
||||
|
||||
; CHECK: .debug_loclists contents:
|
||||
; CHECK-NEXT: 0x00000000: locations list header: length = 0x00000029, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
|
||||
; CHECK-NEXT: 0x00000000: locations list header: length = 0x00000035, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000003
|
||||
|
||||
; CHECK-NEXT: offsets: [
|
||||
; CHECK-NEXT: 0x0000000c => 0x00000018
|
||||
; CHECK-NEXT: 0x0000001d => 0x00000029
|
||||
; CHECK-NEXT: 0x00000025 => 0x00000031
|
||||
; CHECK-NEXT: ]
|
||||
|
||||
; Don't use startx_length if there's more than one entry, because the shared
|
||||
; base address will be useful for both the range that does start at the start of
|
||||
; the function, and the one that doesn't.
|
||||
|
||||
; CHECK-NEXT: 0x0000000c:
|
||||
; CHECK-NEXT: 0x00000018:
|
||||
; CHECK-NEXT: DW_LLE_base_addressx (0x0000000000000000)
|
||||
; CHECK-NEXT: DW_LLE_offset_pair (0x0000000000000000, 0x0000000000000003): DW_OP_consts +3, DW_OP_stack_value
|
||||
; CHECK-NEXT: DW_LLE_offset_pair (0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value
|
||||
|
@ -35,14 +39,14 @@
|
|||
|
||||
; Show that startx_length can be used when the address range starts at the start of the function.
|
||||
|
||||
; CHECK: 0x0000001d:
|
||||
; CHECK: 0x00000029:
|
||||
; CHECK-NEXT: DW_LLE_startx_length (0x0000000000000000, 0x0000000000000003): DW_OP_consts +5, DW_OP_stack_value
|
||||
; CHECK-NEXT: DW_LLE_end_of_list ()
|
||||
|
||||
; And use a base address when the range doesn't start at an existing/useful
|
||||
; address in the pool.
|
||||
|
||||
; CHECK: 0x00000025:
|
||||
; CHECK: 0x00000031:
|
||||
; CHECK-NEXT: DW_LLE_base_addressx (0x0000000000000000)
|
||||
; CHECK-NEXT: DW_LLE_offset_pair (0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX
|
||||
; CHECK-NEXT: DW_LLE_end_of_list ()
|
||||
|
|
Loading…
Reference in New Issue