[DWARF v5] Improved support for .debug_rnglists (consumer). Enables any consumer to
extract DWARF v5 encoded rangelists.
Reviewer: JDevlieghere
Differential Revision: https://reviews.llvm.org/D45549
llvm-svn: 332759
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 8488fe8..08c77a0 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -248,6 +248,28 @@
}
}
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void dumpRnglistsSection(raw_ostream &OS,
+ DWARFDataExtractor &rnglistData,
+ DIDumpOptions DumpOpts) {
+ uint32_t Offset = 0;
+ while (rnglistData.isValidOffset(Offset)) {
+ llvm::DWARFDebugRnglistTable Rnglists;
+ uint32_t TableOffset = Offset;
+ if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
+ WithColor::error() << toString(std::move(Err)) << '\n';
+ uint64_t Length = Rnglists.length();
+ // Keep going after an error, if we can, assuming that the length field
+ // could be read. If it couldn't, stop reading the section.
+ if (Length == 0)
+ break;
+ Offset = TableOffset + Length;
+ } else {
+ Rnglists.dump(OS, DumpOpts);
+ }
+ }
+}
+
void DWARFContext::dump(
raw_ostream &OS, DIDumpOptions DumpOpts,
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
@@ -455,24 +477,16 @@
if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
DObj->getRnglistsSection().Data)) {
- DWARFDataExtractor rnglistData(*DObj, DObj->getRnglistsSection(),
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
isLittleEndian(), 0);
- uint32_t Offset = 0;
- while (rnglistData.isValidOffset(Offset)) {
- DWARFDebugRnglistTable Rnglists;
- uint32_t TableOffset = Offset;
- if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
- WithColor::error() << toString(std::move(Err)) << '\n';
- uint64_t Length = Rnglists.length();
- // Keep going after an error, if we can, assuming that the length field
- // could be read. If it couldn't, stop reading the section.
- if (Length == 0)
- break;
- Offset = TableOffset + Length;
- } else {
- Rnglists.dump(OS, DumpOpts);
- }
- }
+ dumpRnglistsSection(OS, RnglistData, DumpOpts);
+ }
+
+ if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsDWOSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, DumpOpts);
}
if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
@@ -1173,6 +1187,7 @@
DWARFSectionMap LocDWOSection;
DWARFSectionMap StringOffsetDWOSection;
DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap RnglistsDWOSection;
DWARFSectionMap AddrSection;
DWARFSectionMap AppleNamesSection;
DWARFSectionMap AppleTypesSection;
@@ -1192,6 +1207,7 @@
.Case("debug_loc.dwo", &LocDWOSection)
.Case("debug_line.dwo", &LineDWOSection)
.Case("debug_names", &DebugNamesSection)
+ .Case("debug_rnglists.dwo", &RnglistsDWOSection)
.Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
.Case("debug_addr", &AddrSection)
.Case("apple_names", &AppleNamesSection)
@@ -1450,6 +1466,9 @@
const DWARFSection &getRangeDWOSection() const override {
return RangeDWOSection;
}
+ const DWARFSection &getRnglistsDWOSection() const override {
+ return RnglistsDWOSection;
+ }
const DWARFSection &getAddrSection() const override { return AddrSection; }
StringRef getCUIndexSection() const override { return CUIndexSection; }
StringRef getGdbIndexSection() const override { return GdbIndexSection; }
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
index 3a273f8..0c2bb32 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
-
#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -44,6 +44,7 @@
return createError(
"DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32,
HeaderOffset);
+ Format = dwarf::DwarfFormat::DWARF32;
if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
return createError(".debug_rnglists table at offset 0x%" PRIx32
" has too small length (0x%" PRIx32
@@ -90,6 +91,7 @@
uint32_t End,
uint32_t *OffsetPtr) {
Offset = *OffsetPtr;
+ SectionIndex = -1ULL;
// The caller should guarantee that we have at least 1 byte available, so
// we just assert instead of revalidate.
assert(*OffsetPtr < End &&
@@ -128,7 +130,7 @@
return createError("insufficient space remaining in table for "
"DW_RLE_base_address encoding at offset 0x%" PRIx32,
*OffsetPtr - 1);
- Value0 = Data.getAddress(OffsetPtr);
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
break;
}
case dwarf::DW_RLE_start_end: {
@@ -137,13 +139,13 @@
"DW_RLE_start_end encoding "
"at offset 0x%" PRIx32,
*OffsetPtr - 1);
- Value0 = Data.getAddress(OffsetPtr);
- Value1 = Data.getAddress(OffsetPtr);
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+ Value1 = Data.getRelocatedAddress(OffsetPtr);
break;
}
case dwarf::DW_RLE_start_length: {
uint32_t PreviousOffset = *OffsetPtr - 1;
- Value0 = Data.getAddress(OffsetPtr);
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
Value1 = Data.getULEB128(OffsetPtr);
if (End < *OffsetPtr)
return createError("read past end of table when reading "
@@ -161,6 +163,49 @@
return Error::success();
}
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+ llvm::Optional<BaseAddress> BaseAddr) const {
+ DWARFAddressRangesVector Res;
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
+ break;
+ if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
+ BaseAddr = {RLE.Value0, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.SectionIndex = RLE.SectionIndex;
+ if (BaseAddr && E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
+
+ switch (RLE.EntryKind) {
+ case dwarf::DW_RLE_offset_pair:
+ E.LowPC = RLE.Value0;
+ E.HighPC = RLE.Value1;
+ if (BaseAddr) {
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ }
+ break;
+ case dwarf::DW_RLE_start_end:
+ E.LowPC = RLE.Value0;
+ E.HighPC = RLE.Value1;
+ break;
+ case dwarf::DW_RLE_start_length:
+ E.LowPC = RLE.Value0;
+ E.HighPC = E.LowPC + RLE.Value1;
+ break;
+ default:
+ // Unsupported encodings should have been reported during extraction,
+ // so we should not run into any here.
+ llvm_unreachable("Unsupported range list encoding");
+ }
+ Res.push_back(E);
+ }
+ return Res;
+}
+
Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
uint32_t End, uint32_t *OffsetPtr) {
Entries.clear();
@@ -305,3 +350,22 @@
// TODO: DWARF64 support.
return HeaderData.Length + sizeof(uint32_t);
}
+
+Optional<DWARFDebugRnglist>
+DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
+ uint32_t Offset) {
+ auto Entry = Ranges.find(Offset);
+ if (Entry != Ranges.end())
+ return Entry->second;
+
+ // Extract the rangelist from the section and enter it into the ranges map.
+ DWARFDebugRnglist RngList;
+ uint32_t End = HeaderOffset + length();
+ uint32_t StartingOffset = Offset;
+ if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset)) {
+ llvm::consumeError(std::move(E));
+ return None;
+ }
+ Ranges[StartingOffset] = RngList;
+ return RngList;
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 0d045c5..33cb00d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -257,6 +257,16 @@
dumpApplePropertyAttribute(OS, *OptVal);
} else if (Attr == DW_AT_ranges) {
const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+ // For DW_FORM_rnglistx we need to dump the offset separately, since
+ // we have only dumped the index so far.
+ Optional<DWARFFormValue> Value = Die.find(DW_AT_ranges);
+ if (Value && Value->getForm() == DW_FORM_rnglistx)
+ if (auto RangeListOffset =
+ U->getRnglistOffset(*Value->getAsSectionOffset())) {
+ DWARFFormValue FV(dwarf::DW_FORM_sec_offset);
+ FV.setUValue(*RangeListOffset);
+ FV.dump(OS, DumpOpts);
+ }
dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
sizeof(BaseIndent) + Indent + 4, DumpOpts);
}
@@ -380,12 +390,11 @@
if (getLowAndHighPC(LowPC, HighPC, Index))
return {{LowPC, HighPC, Index}};
- // Multiple ranges from .debug_ranges section.
- auto RangesOffset = toSectionOffset(find(DW_AT_ranges));
- if (RangesOffset) {
- DWARFDebugRangeList RangeList;
- if (U->extractRangeList(*RangesOffset, RangeList))
- return RangeList.getAbsoluteRanges(U->getBaseAddress());
+ Optional<DWARFFormValue> Value = find(DW_AT_ranges);
+ if (Value) {
+ if (Value->getForm() == DW_FORM_rnglistx)
+ return U->findRnglistFromIndex(*Value->getAsSectionOffset());
+ return U->findRnglistFromOffset(*Value->getAsSectionOffset());
}
return DWARFAddressRangesVector();
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index b3ecf8e..1aa43c6 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -280,6 +280,7 @@
break;
case DW_FORM_udata:
case DW_FORM_ref_udata:
+ case DW_FORM_rnglistx:
Value.uval = Data.getULEB128(OffsetPtr);
break;
case DW_FORM_string:
@@ -483,6 +484,10 @@
OS << "DW_FORM_indirect";
break;
+ case DW_FORM_rnglistx:
+ OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
+ break;
+
// Should be formatted to 64-bit for DWARF64.
case DW_FORM_sec_offset:
AddrOS << format("0x%08x", (uint32_t)UValue);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 6fa604c..11cec59 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -14,6 +14,7 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Support/DataExtractor.h"
@@ -150,6 +151,29 @@
return true;
}
+// Parse the rangelist table header, including the optional array of offsets
+// following it (DWARF v5 and later).
+static Expected<DWARFDebugRnglistTable>
+parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
+ // TODO: Support DWARF64
+ // We are expected to be called with Offset 0 or pointing just past the table
+ // header, which is 12 bytes long for DWARF32.
+ if (Offset > 0) {
+ if (Offset < 12U) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(
+ "Did not detect a valid range list table with base = 0x%x", Offset);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+ }
+ Offset -= 12U;
+ }
+ llvm::DWARFDebugRnglistTable Table;
+ if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
+ return E;
+ return Table;
+}
+
bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
DWARFDebugRangeList &RangeList) const {
// Require that compile unit is extracted.
@@ -281,6 +305,32 @@
StringOffsetsTableContribution = determineStringOffsetsTableContribution(
DA, StringOffsetsContributionBase);
+ // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
+ // describe address ranges.
+ if (getVersion() >= 5) {
+ if (isDWO)
+ setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+ else
+ setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
+ toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
+ // Parse the range list table header. Individual range lists are
+ // extracted lazily.
+ DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, 0);
+ if (auto TableOrError =
+ parseRngListTableHeader(RangesDA, RangeSectionBase))
+ RngListTable = TableOrError.get();
+ else
+ WithColor::error() << "parsing a range list table: "
+ << toString(std::move(TableOrError.takeError()))
+ << '\n';
+
+ // In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
+ // Adjust RangeSectionBase to point past the table header.
+ if (isDWO && RngListTable)
+ RangeSectionBase = RngListTable->getHeaderSize();
+ }
+
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
}
@@ -319,8 +369,23 @@
DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
// Share .debug_addr and .debug_ranges section with compile unit in .dwo
DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
- auto DWORangesBase = UnitDie.getRangesBaseAttribute();
- DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+ if (getVersion() >= 5) {
+ DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+ DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, 0);
+ if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase))
+ DWO->RngListTable = TableOrError.get();
+ else
+ WithColor::error() << "parsing a range list table: "
+ << toString(std::move(TableOrError.takeError()))
+ << '\n';
+ if (DWO->RngListTable)
+ DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
+ } else {
+ auto DWORangesBase = UnitDie.getRangesBaseAttribute();
+ DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+ }
+
return true;
}
@@ -331,6 +396,28 @@
}
}
+DWARFAddressRangesVector DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
+ if (getVersion() <= 4) {
+ DWARFDebugRangeList RangeList;
+ if (extractRangeList(Offset, RangeList))
+ return RangeList.getAbsoluteRanges(getBaseAddress());
+ return DWARFAddressRangesVector();
+ }
+ if (RngListTable) {
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, RngListTable->getAddrSize());
+ if (auto RangeList = RngListTable->findRangeList(RangesData, Offset))
+ return RangeList->getAbsoluteRanges(getBaseAddress());
+ }
+ return DWARFAddressRangesVector();
+}
+
+DWARFAddressRangesVector DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+ if (auto Offset = getRnglistOffset(Index))
+ return findRnglistFromOffset(*Offset + RangeSectionBase);
+ return DWARFAddressRangesVector();
+}
+
void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
DWARFDie UnitDie = getUnitDIE();
if (!UnitDie)