[llvm] r332759 - [DWARF v5] Improved support for .debug_rnglists (consumer). Enables any consumer to
Wolfgang Pieb via llvm-commits
llvm-commits at lists.llvm.org
Fri May 18 13:12:55 PDT 2018
Author: wolfgangp
Date: Fri May 18 13:12:54 2018
New Revision: 332759
URL: http://llvm.org/viewvc/llvm-project?rev=332759&view=rev
Log:
[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
Added:
llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s
Modified:
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h
llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h Fri May 18 13:12:54 2018
@@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
@@ -30,6 +31,8 @@ public:
uint32_t Offset;
/// The DWARF encoding (DW_RLE_*).
uint8_t EntryKind;
+ /// The index of the section this range belongs to.
+ uint64_t SectionIndex;
/// The values making up the range list entry. Most represent a range with
/// a start and end address or a start address and a length. Others are
/// single value base addresses or end-of-list with no values. The unneeded
@@ -51,6 +54,9 @@ public:
void clear() { Entries.clear(); }
Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
uint32_t *OffsetPtr);
+ /// Build a DWARFAddressRangesVector from a rangelist.
+ DWARFAddressRangesVector
+ getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const;
};
/// A class representing a table of range lists as specified in DWARF v5.
@@ -77,6 +83,7 @@ public:
};
private:
+ dwarf::DwarfFormat Format;
uint32_t HeaderOffset;
Header HeaderData;
std::vector<uint32_t> Offsets;
@@ -88,8 +95,31 @@ public:
Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr);
/// Extract an entire table, including all rangelists.
Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
+ /// Look up a rangelist based on a given offset. Extract it and enter it into
+ /// the ranges map if necessary.
+ Optional<DWARFDebugRnglist> findRangeList(DWARFDataExtractor Data,
+ uint32_t Offset);
uint32_t getHeaderOffset() const { return HeaderOffset; }
+ uint8_t getAddrSize() const { return HeaderData.AddrSize; }
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const;
+ /// Return the contents of the offset entry designated by a given index.
+ Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
+ if (Index < Offsets.size())
+ return Offsets[Index];
+ return None;
+ }
+ /// Return the size of the table header including the length but not including
+ /// the offsets. This is dependent on the table format, which is unambiguously
+ /// derived from parsing the table.
+ uint8_t getHeaderSize() const {
+ switch (Format) {
+ case dwarf::DwarfFormat::DWARF32:
+ return 12;
+ case dwarf::DwarfFormat::DWARF64:
+ return 20;
+ }
+ llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
+ }
/// Returns the length of this table, including the length field, or 0 if the
/// length has not been determined (e.g. because the table has not yet been
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h Fri May 18 13:12:54 2018
@@ -63,6 +63,7 @@ public:
return Dummy;
}
virtual const DWARFSection &getRangeDWOSection() const { return Dummy; }
+ virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; }
virtual const DWARFSection &getAddrSection() const { return Dummy; }
virtual const DWARFSection &getAppleNamesSection() const { return Dummy; }
virtual const DWARFSection &getAppleTypesSection() const { return Dummy; }
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h Fri May 18 13:12:54 2018
@@ -18,6 +18,7 @@
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
@@ -261,6 +262,9 @@ class DWARFUnit {
/// offsets table (DWARF v5).
Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution;
+ /// A table of range lists (DWARF v5 and later).
+ Optional<DWARFDebugRnglistTable> RngListTable;
+
mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
llvm::Optional<BaseAddress> BaseAddr;
/// The compile unit debug information entry items.
@@ -430,6 +434,24 @@ public:
const char *getCompilationDir();
Optional<uint64_t> getDWOId();
+ /// Return a vector of address ranges resulting from a (possibly encoded)
+ /// range list starting at a given offset in the appropriate ranges section.
+ DWARFAddressRangesVector findRnglistFromOffset(uint32_t Offset);
+
+ /// Return a vector of address ranges retrieved from an encoded range
+ /// list whose offset is found via a table lookup given an index (DWARF v5
+ /// and later).
+ DWARFAddressRangesVector findRnglistFromIndex(uint32_t Index);
+
+ /// Return a rangelist's offset based on an index. The index designates
+ /// an entry in the rangelist table's offset array and is supplied by
+ /// DW_FORM_rnglistx.
+ Optional<uint32_t> getRnglistOffset(uint32_t Index) {
+ if (RngListTable)
+ return RngListTable->getOffsetEntry(Index);
+ return None;
+ }
+
void collectAddressRanges(DWARFAddressRangesVector &CURanges);
/// Returns subprogram DIE with address range encompassing the provided
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Fri May 18 13:12:54 2018
@@ -248,6 +248,28 @@ static void dumpStringOffsetsSection(
}
}
+// 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 @@ void DWARFContext::dump(
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 @@ class DWARFObjInMemory final : public DW
DWARFSectionMap LocDWOSection;
DWARFSectionMap StringOffsetDWOSection;
DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap RnglistsDWOSection;
DWARFSectionMap AddrSection;
DWARFSectionMap AppleNamesSection;
DWARFSectionMap AppleTypesSection;
@@ -1192,6 +1207,7 @@ class DWARFObjInMemory final : public DW
.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 @@ public:
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; }
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp Fri May 18 13:12:54 2018
@@ -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 @@ Error DWARFDebugRnglistTable::extractHea
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 @@ Error DWARFDebugRnglist::RangeListEntry:
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 @@ Error DWARFDebugRnglist::RangeListEntry:
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 @@ Error DWARFDebugRnglist::RangeListEntry:
"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 @@ Error DWARFDebugRnglist::RangeListEntry:
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 @@ uint32_t DWARFDebugRnglistTable::length(
// 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;
+}
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp Fri May 18 13:12:54 2018
@@ -257,6 +257,16 @@ static void dumpAttribute(raw_ostream &O
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 @@ DWARFAddressRangesVector DWARFDie::getAd
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();
}
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp Fri May 18 13:12:54 2018
@@ -280,6 +280,7 @@ bool DWARFFormValue::extractValue(const
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 @@ void DWARFFormValue::dump(raw_ostream &O
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);
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp Fri May 18 13:12:54 2018
@@ -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 @@ bool DWARFUnitHeader::extract(DWARFConte
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 @@ size_t DWARFUnit::extractDIEsIfNeeded(bo
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 @@ bool DWARFUnit::parseDWO() {
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 @@ void DWARFUnit::clearDIEs(bool KeepCUDie
}
}
+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)
Added: llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s?rev=332759&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s (added)
+++ llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s Fri May 18 13:12:54 2018
@@ -0,0 +1,192 @@
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o
+# RUN: llvm-dwarfdump -v -debug-info %t.o 2> %t.err | FileCheck %s
+# RUN: FileCheck %s --input-file %t.err --check-prefix=ERR
+
+# Test object to verify dwarfdump handles v5 range lists.
+# We use very simplified compile unit dies.
+# There are 2 full CUs with DW_AT_rnglists_base, one with a DW_AT_ranges
+# attribute using DW_FORM_sec_offset, the other with DW_AT_ranges using
+# DW_FORM_rnglistx.
+
+ .section .debug_abbrev,"", at progbits
+ .byte 0x01 # Abbrev code
+ .byte 0x11 # DW_TAG_compile_unit
+ .byte 0x00 # DW_CHILDREN_no
+ .byte 0x74 # DW_AT_rnglists_base
+ .byte 0x17 # DW_FORM_sec_offset
+ .byte 0x55 # DW_AT_ranges
+ .byte 0x17 # DW_FORM_sec_offset
+ .byte 0x00 # EOM(1)
+ .byte 0x00 # EOM(2)
+ .byte 0x02 # Abbrev code
+ .byte 0x11 # DW_TAG_compile_unit
+ .byte 0x00 # DW_CHILDREN_no
+ .byte 0x74 # DW_AT_rnglists_base
+ .byte 0x17 # DW_FORM_sec_offset
+ .byte 0x55 # DW_AT_ranges
+ .byte 0x23 # DW_FORM_rnglistx
+ .byte 0x00 # EOM(1)
+ .byte 0x00 # EOM(2)
+ .byte 0x00 # EOM(3)
+
+# The split CU uses DW_FORM_rnglistx (the only correct option).
+# There is no DW_AT_rnglists_base in split units.
+ .section .debug_abbrev.dwo,"", at progbits
+ .byte 0x01 # Abbrev code
+ .byte 0x11 # DW_TAG_compile_unit
+ .byte 0x00 # DW_CHILDREN_no
+ .byte 0x55 # DW_AT_ranges
+ .byte 0x23 # DW_FORM_rnglistx
+ .byte 0x00 # EOM(1)
+ .byte 0x00 # EOM(2)
+ .byte 0x00 # EOM(3)
+
+ .section .debug_info,"", at progbits
+# DWARF v5 CU header.
+ .long CU1_5_end-CU1_5_version # Length of Unit
+CU1_5_version:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+ .byte 1 # Abbreviation code
+ .long Rnglist_Table0_base # DW_AT_rnglists_base
+ .long Rnglist_Table0_Rnglist0 # DW_AT_ranges
+ .byte 0 # NULL
+ .byte 0 # NULL
+CU1_5_end:
+
+# DWARF v5 CU header
+ .long CU2_5_end-CU2_5_version # Length of Unit
+CU2_5_version:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+ .byte 2 # Abbreviation code
+ .long Rnglist_Table0_base # DW_AT_rnglists_base
+ .uleb128 1 # DW_AT_ranges
+ .byte 0 # NULL
+CU2_5_end:
+# A CU with an invalid DW_AT_rnglists_base attribute
+ .long CU3_5_end-CU3_5_version # Length of Unit
+CU3_5_version:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+ .byte 2 # Abbreviation code
+ .long 0x8 # DW_AT_rnglists_base
+ .long 0 # DW_AT_ranges
+ .byte 0 # NULL
+CU3_5_end:
+
+ .section .debug_info.dwo,"", at progbits
+
+# DWARF v5 split CU header.
+ .long CU_split_5_end-CU_split_5_version # Length of Unit
+CU_split_5_version:
+ .short 5 # DWARF version number
+ .byte 5 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long 0 # Offset Into Abbrev Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+ .byte 1 # Abbreviation code
+ .uleb128 1 # DW_AT_ranges
+ .byte 0 # NULL
+CU_split_5_end:
+
+ .section .debug_rnglists,"", at progbits
+# A rnglist table with 2 range lists. The first one uses DW_RLE_start_end
+# and DW_RLE_start_length. The second one uses DW_RLE_base_address and
+# DW_RLE_offset_pair. The range lists have entries in the offset table.
+ .long Rnglist_Table0_end - Rnglist_Table0 # table length
+Rnglist_Table0:
+ .short 5 # version
+ .byte 4 # address size
+ .byte 0 # segment selector size
+ .long 2 # offset entry count
+Rnglist_Table0_base:
+# 2 offset entries which can be used by DW_FORM_rnglistx.
+ .long Rnglist_Table0_Rnglist0 - Rnglist_Table0_base
+ .long Rnglist_Table0_Rnglist1 - Rnglist_Table0_base
+Rnglist_Table0_Rnglist0:
+ .byte 6 # DW_RLE_start_end
+ .long Range0_start
+ .long Range0_end
+ .byte 7 # DW_RLE_start_length
+ .long Range1_start
+ .uleb128 Range1_end - Range1_start
+ .byte 0 # DW_RLE_end_of_list
+Rnglist_Table0_Rnglist1:
+ .byte 5 # DW_RLE_base_address
+ .long Range0_start
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 Range1_start - Range0_start
+ .uleb128 Range1_end - Range0_start
+ .byte 0 # DW_RLE_end_of_list
+Rnglist_Table0_end:
+
+# A rnglist table for the split unit with an empty rangelist and one that
+# uses DW_RLE_base_address and DW_RLE_offset_pair. The ranges have entries
+# in the offset table. We use the empty range list so we can test
+# DW_FORM_rnglistx with an index other than 0.
+ .section .debug_rnglists.dwo,"", at progbits
+ .long Rnglist_Table0_dwo_end - Rnglist_Table0_dwo # table length
+Rnglist_Table0_dwo:
+ .short 5 # version
+ .byte 4 # address size
+ .byte 0 # segment selector size
+ .long 2 # offset entry count
+Rnglist_Table0_base_dwo:
+# 2 offset entries which can be used by DW_FORM_rnglistx.
+ .long Rnglist_Table0_Rnglist0_dwo - Rnglist_Table0_base_dwo
+ .long Rnglist_Table0_Rnglist1_dwo - Rnglist_Table0_base_dwo
+Rnglist_Table0_Rnglist0_dwo:
+ .byte 0 # DW_RLE_start_end
+Rnglist_Table0_Rnglist1_dwo:
+ .byte 5 # DW_RLE_base_address
+ .long Range0_start - .text
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 Range1_start - Range0_start
+ .uleb128 Range1_end - Range0_start
+ .byte 0 # DW_RLE_end_of_list
+Rnglist_Table0_dwo_end:
+
+.text
+ .space 20
+Range0_start: # Range0: 0x14 - 0x1c
+ .space 10
+Range0_end:
+ .space 12
+Range1_start: # Range1: 0x2a - 0x34
+ .space 10
+Range1_end:
+
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK-NOT: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000014
+# CHECK-NEXT: [0x00000014, 0x0000001e) ".text"
+# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
+
+# CHECK: Compile Unit:
+# CHECK-NOT: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000018
+# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
+
+# CHECK: .debug_info.dwo contents:
+# CHECK: Compile Unit:
+# CHECK-NOT: contents:
+# CHECK: DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000009
+# CHECK-NEXT: [0x0000002a, 0x00000034))
+
+#ERR: error: parsing a range list table: Did not detect a valid range list table with base = 0x8
More information about the llvm-commits
mailing list