Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -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 @@ 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 @@ 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 BaseAddr) const; }; /// A class representing a table of range lists as specified in DWARF v5. @@ -77,6 +83,7 @@ }; private: + dwarf::DwarfFormat Format; uint32_t HeaderOffset; Header HeaderData; std::vector Offsets; @@ -88,8 +95,31 @@ 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 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 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 Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -63,6 +63,7 @@ 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; } Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -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 @@ /// offsets table (DWARF v5). Optional StringOffsetsTableContribution; + /// A table of range lists (DWARF v5 and later). + Optional RngListTable; + mutable const DWARFAbbreviationDeclarationSet *Abbrevs; llvm::Optional BaseAddr; /// The compile unit debug information entry items. @@ -430,6 +434,24 @@ const char *getCompilationDir(); Optional 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 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 Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/trunk/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, 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; } Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ llvm/trunk/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 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 +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; +} Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/trunk/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 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 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(); } Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ llvm/trunk/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); Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/trunk/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 +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(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(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) Index: llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s =================================================================== --- llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s +++ llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s @@ -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