1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

[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
This commit is contained in:
Wolfgang Pieb 2018-05-18 20:12:54 +00:00
parent ef40796261
commit fd2b373e39
9 changed files with 459 additions and 30 deletions

View File

@ -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

View File

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

View File

@ -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

View File

@ -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 DWARFObject {
DWARFSectionMap LocDWOSection;
DWARFSectionMap StringOffsetDWOSection;
DWARFSectionMap RangeDWOSection;
DWARFSectionMap RnglistsDWOSection;
DWARFSectionMap AddrSection;
DWARFSectionMap AppleNamesSection;
DWARFSectionMap AppleTypesSection;
@ -1192,6 +1207,7 @@ class DWARFObjInMemory final : public DWARFObject {
.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; }

View File

@ -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::extractHeaderAndOffsets(DWARFDataExtractor Data,
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::extract(DWARFDataExtractor Data,
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::extract(DWARFDataExtractor Data,
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::extract(DWARFDataExtractor Data,
"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::extract(DWARFDataExtractor Data,
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() const {
// 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;
}

View File

@ -257,6 +257,16 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
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::getAddressRanges() const {
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();
}

View File

@ -280,6 +280,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
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 &OS, DIDumpOptions DumpOpts) const {
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);

View File

@ -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(DWARFContext &Context,
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(bool CUDieOnly) {
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)

View File

@ -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,"",@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,"",@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,"",@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,"",@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,"",@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,"",@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