diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 56 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp | 96 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp | 97 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp | 72 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 99 |
7 files changed, 201 insertions, 221 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt index b4770e561f7..437c845718d 100644 --- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt @@ -15,7 +15,6 @@ add_llvm_library(LLVMDebugInfoDWARF DWARFDebugLoc.cpp DWARFDebugMacro.cpp DWARFDebugPubTable.cpp - DWARFDebugRangeList.cpp DWARFDebugRnglists.cpp DWARFDie.cpp DWARFExpression.cpp diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index a5c31a56fad..be0192cdeda 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -25,7 +25,6 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.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" @@ -267,24 +266,29 @@ static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData, } } -// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5). -static void dumpRnglistsSection(raw_ostream &OS, - DWARFDataExtractor &rnglistData, - DIDumpOptions DumpOpts) { +// Dump a section that contains a sequence of tables of lists, such as range +// or location list tables. In DWARF v5 we expect to find properly formatted +// tables with headers. In DWARF v4 and earlier we simply expect a sequence of +// lists, which we treat, mutatis mutandis, like DWARF v5 tables. +template <typename ListTable> +static void dumpListSection(raw_ostream &OS, DWARFContext *C, + StringRef SectionName, uint16_t MaxVersion, + DWARFDataExtractor &ListData, + DIDumpOptions DumpOpts, bool isDWO = false) { uint32_t Offset = 0; - while (rnglistData.isValidOffset(Offset)) { - llvm::DWARFDebugRnglistTable Rnglists; - uint32_t TableOffset = Offset; - if (Error Err = Rnglists.extract(rnglistData, &Offset)) { + while (ListData.isValidOffset(Offset)) { + ListTable Table(C, SectionName, isDWO); + if (Error Err = Table.extract(ListData, MaxVersion, &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) + // If table extraction set Offset to 0, it indicates that we cannot + // continue to read the section. + if (Offset == 0) break; - Offset = TableOffset + Length; + // In DWARF v4 and earlier, dump as much of the lists as we can. + if (MaxVersion < 5) + Table.dump(OS, DumpOpts); } else { - Rnglists.dump(OS, DumpOpts); + Table.dump(OS, DumpOpts); } } } @@ -484,29 +488,25 @@ void DWARFContext::dump( uint8_t savedAddressByteSize = getCUAddrSize(); DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(), isLittleEndian(), savedAddressByteSize); - uint32_t offset = 0; - DWARFDebugRangeList rangeList; - while (rangesData.isValidOffset(offset)) { - if (Error E = rangeList.extract(rangesData, &offset)) { - WithColor::error() << toString(std::move(E)) << '\n'; - break; - } - rangeList.dump(OS); - } + dumpListSection<DWARFDebugRnglistTable>( + OS, this, ".debug_ranges", /* MaxVersion = */ 4, rangesData, DumpOpts); } if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists, DObj->getRnglistsSection().Data)) { DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(), - isLittleEndian(), 0); - dumpRnglistsSection(OS, RnglistData, DumpOpts); + isLittleEndian(), getCUAddrSize()); + dumpListSection<DWARFDebugRnglistTable>( + OS, this, ".debug_rnglists", getMaxVersion(5), 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); + isLittleEndian(), getCUAddrSize()); + dumpListSection<DWARFDebugRnglistTable>(OS, this, ".debug_rnglists.dwo", + getMaxVersion(5), RnglistData, + DumpOpts); } if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp deleted file mode 100644 index 84e3c634f54..00000000000 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ /dev/null @@ -1,96 +0,0 @@ -//===- DWARFDebugRangesList.cpp -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cinttypes> -#include <cstdint> - -using namespace llvm; - -void DWARFDebugRangeList::clear() { - Offset = -1U; - AddressSize = 0; - Entries.clear(); -} - -Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data, - uint32_t *offset_ptr) { - clear(); - if (!data.isValidOffset(*offset_ptr)) - return createStringError(errc::invalid_argument, - "invalid range list offset 0x%" PRIx32, *offset_ptr); - - AddressSize = data.getAddressSize(); - if (AddressSize != 4 && AddressSize != 8) - return createStringError(errc::invalid_argument, - "invalid address size: %" PRIu8, AddressSize); - Offset = *offset_ptr; - while (true) { - RangeListEntry Entry; - Entry.SectionIndex = -1ULL; - - uint32_t prev_offset = *offset_ptr; - Entry.StartAddress = data.getRelocatedAddress(offset_ptr); - Entry.EndAddress = - data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex); - - // Check that both values were extracted correctly. - if (*offset_ptr != prev_offset + 2 * AddressSize) { - clear(); - return createStringError(errc::invalid_argument, - "invalid range list entry at offset 0x%" PRIx32, - prev_offset); - } - if (Entry.isEndOfListEntry()) - break; - Entries.push_back(Entry); - } - return Error::success(); -} - -void DWARFDebugRangeList::dump(raw_ostream &OS) const { - for (const RangeListEntry &RLE : Entries) { - const char *format_str = (AddressSize == 4 - ? "%08x %08" PRIx64 " %08" PRIx64 "\n" - : "%08x %016" PRIx64 " %016" PRIx64 "\n"); - OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress); - } - OS << format("%08x <End of list>\n", Offset); -} - -DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges( - llvm::Optional<BaseAddress> BaseAddr) const { - DWARFAddressRangesVector Res; - for (const RangeListEntry &RLE : Entries) { - if (RLE.isBaseAddressSelectionEntry(AddressSize)) { - BaseAddr = {RLE.EndAddress, RLE.SectionIndex}; - continue; - } - - DWARFAddressRange E; - E.LowPC = RLE.StartAddress; - E.HighPC = RLE.EndAddress; - E.SectionIndex = RLE.SectionIndex; - // Base address of a range list entry is determined by the closest preceding - // base address selection entry in the same range list. It defaults to the - // base address of the compilation unit if there is no such entry. - if (BaseAddr) { - E.LowPC += BaseAddr->Address; - E.HighPC += BaseAddr->Address; - if (E.SectionIndex == -1ULL) - E.SectionIndex = BaseAddr->SectionIndex; - } - Res.push_back(E); - } - return Res; -} diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp index eeb85edf5b2..0b0133304c3 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -13,19 +13,30 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End, - uint32_t *OffsetPtr) { + uint16_t Version, StringRef /* SectionName */, + uint32_t *OffsetPtr, bool /* isDWO */) { 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 && - "not enough space to extract a rangelist encoding"); - uint8_t Encoding = Data.getU8(OffsetPtr); + + assert((Data.getAddressSize() == 4 || Data.getAddressSize() == 8) && + "Unsupported address size"); + + // We model a DWARF v4 range list entry like DWARF v5 DW_RLE_offset_pair, + // since it is subject to base adjustment. + uint8_t Encoding = dwarf::DW_RLE_offset_pair; + if (Version > 4) { + // The caller should guarantee that we have at least 1 byte available, so + // we just assert instead of revalidate. + assert(*OffsetPtr < End && + "not enough space to extract a rangelist encoding"); + Encoding = Data.getU8(OffsetPtr); + } switch (Encoding) { case dwarf::DW_RLE_end_of_list: @@ -48,6 +59,23 @@ Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End, "at offset 0x%" PRIx32, *OffsetPtr - 1); case dwarf::DW_RLE_offset_pair: { + if (Version < 5) { + if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2)) + return createStringError( + errc::illegal_byte_sequence, + "invalid range list entry at offset 0x%" PRIx32, *OffsetPtr); + Value0 = Data.getRelocatedAddress(OffsetPtr); + Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); + // Adjust the EntryKind for end-of-list and base_address based on the + // contents. + if (Value0 == maxUIntN(Data.getAddressSize() * 8)) { + Encoding = dwarf::DW_RLE_base_address; + Value0 = Value1; + Value1 = 0; + } else if (Value0 == 0 && Value1 == 0) + Encoding = dwarf::DW_RLE_end_of_list; + break; + } uint32_t PreviousOffset = *OffsetPtr - 1; Value0 = Data.getULEB128(OffsetPtr); Value1 = Data.getULEB128(OffsetPtr); @@ -58,7 +86,7 @@ Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End, PreviousOffset); break; } - case dwarf::DW_RLE_base_address: { + case dwarf::DW_RLE_base_address: if ((End - *OffsetPtr) < Data.getAddressSize()) return createStringError(errc::invalid_argument, "insufficient space remaining in table for " @@ -66,18 +94,16 @@ Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End, *OffsetPtr - 1); Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); break; - } - case dwarf::DW_RLE_start_end: { + case dwarf::DW_RLE_start_end: if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2)) return createStringError(errc::invalid_argument, "insufficient space remaining in table for " "DW_RLE_start_end encoding " "at offset 0x%" PRIx32, *OffsetPtr - 1); - Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); - Value1 = Data.getRelocatedAddress(OffsetPtr); + Value0 = Data.getRelocatedAddress(OffsetPtr); + Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); break; - } case dwarf::DW_RLE_start_length: { uint32_t PreviousOffset = *OffsetPtr - 1; Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex); @@ -143,9 +169,10 @@ DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( return Res; } -void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize, - uint8_t MaxEncodingStringLength, - uint64_t &CurrentBase, DIDumpOptions DumpOpts) const { +void RangeListEntry::dump(raw_ostream &OS, DWARFContext *, uint8_t AddrSize, + uint64_t &CurrentBase, unsigned Indent, + uint16_t Version, uint8_t MaxEncodingStringLength, + DIDumpOptions DumpOpts) const { auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, uint8_t AddrSize, DIDumpOptions DumpOpts) { if (DumpOpts.Verbose) { @@ -156,27 +183,49 @@ void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize, } }; + // Output indentations before we print the actual entry. We only print + // anything for DW_RLE_base_address when we are in verbose mode. + if (DumpOpts.Verbose || !isBaseAddressSelectionEntry()) + OS.indent(Indent); + if (DumpOpts.Verbose) { // Print the section offset in verbose mode. OS << format("0x%8.8" PRIx32 ":", Offset); - auto EncodingString = dwarf::RangeListEncodingString(EntryKind); - // Unsupported encodings should have been reported during parsing. - assert(!EncodingString.empty() && "Unknown range entry encoding"); - OS << format(" [%s%*c", EncodingString.data(), - MaxEncodingStringLength - EncodingString.size() + 1, ']'); - if (EntryKind != dwarf::DW_RLE_end_of_list) - OS << ": "; + if (Version > 4) { + auto EncodingString = dwarf::RangeListEncodingString(EntryKind); + // Unsupported encodings should have been reported during parsing. + assert(!EncodingString.empty() && "Unknown range entry encoding"); + OS << format(" [%s%*c", EncodingString.data(), + MaxEncodingStringLength - EncodingString.size() + 1, ']'); + if (!isEndOfList()) + OS << ": "; + } } switch (EntryKind) { case dwarf::DW_RLE_end_of_list: - OS << (DumpOpts.Verbose ? "" : "<End of list>"); + if (DumpOpts.Verbose) { + // For DWARF v4 and earlier, we print the raw entry, i.e. 2 zeros. + if (Version < 5) { + OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); + OS << format(", 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value1); + } + break; + } + OS << "<End of list>"; break; case dwarf::DW_RLE_base_address: - // In non-verbose mode we do not print anything for this entry. + // In non-verbose mode, we do not print anything for this entry. CurrentBase = Value0; if (!DumpOpts.Verbose) return; + if (Version < 5) { + // Dump the entry in pre-DWARF v5 format, i.e. with a -1 as Value0. + uint64_t allOnes = maxUIntN(AddrSize * 8); + OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, allOnes); + OS << format(", 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); + break; + } OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); break; case dwarf::DW_RLE_start_length: diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 35567d0f67a..25457781e8c 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -15,7 +15,6 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp index 462c036d73a..835f7279e26 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -20,30 +20,43 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data, uint32_t *OffsetPtr) { HeaderOffset = *OffsetPtr; // Read and verify the length field. - if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) + if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) { + // By setting *OffsetPtr to 0, we indicate to the caller that + // we could not detemine the length of the table. + *OffsetPtr = 0; return createStringError(errc::invalid_argument, "section is not large enough to contain a " "%s table length at offset 0x%" PRIx32, - SectionName.data(), *OffsetPtr); + SectionName.data(), HeaderOffset); + } // TODO: Add support for DWARF64. HeaderData.Length = Data.getU32(OffsetPtr); - if (HeaderData.Length == 0xffffffffu) + if (HeaderData.Length == 0xffffffffu) { + *OffsetPtr = 0; return createStringError(errc::not_supported, "DWARF64 is not supported in %s at offset 0x%" PRIx32, SectionName.data(), HeaderOffset); + } + + uint32_t TableLength = HeaderData.Length + sizeof(uint32_t); + uint32_t End = HeaderOffset + TableLength; Format = dwarf::DwarfFormat::DWARF32; - if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) - return createStringError(errc::invalid_argument, - "%s table at offset 0x%" PRIx32 - " has too small length (0x%" PRIx32 - ") to contain a complete header", - SectionName.data(), HeaderOffset, length()); - uint32_t End = HeaderOffset + length(); - if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) - return createStringError(errc::invalid_argument, - "section is not large enough to contain a %s table " - "of length 0x%" PRIx32 " at offset 0x%" PRIx32, - SectionName.data(), length(), HeaderOffset); + if (TableLength < sizeof(Header)) { + *OffsetPtr = End; + return createStringError( + errc::invalid_argument, + "%s table at offset 0x%" PRIx32 " has too small length (0x%" PRIx32 + ") to contain a complete header", + SectionName.data(), HeaderOffset, TableLength); + } + if (!Data.isValidOffsetForDataOfSize(HeaderOffset, TableLength)) { + *OffsetPtr = 0; // No recovery if the length exceeds the section size. + return createStringError( + errc::invalid_argument, + "section is not large enough to contain a %s table " + "of length 0x%" PRIx32 " at offset 0x%" PRIx32, + SectionName.data(), TableLength, HeaderOffset); + } HeaderData.Version = Data.getU16(OffsetPtr); HeaderData.AddrSize = Data.getU8(OffsetPtr); @@ -51,27 +64,36 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data, HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); // Perform basic validation of the remaining header fields. - if (HeaderData.Version != 5) + if (HeaderData.Version != 5) { + *OffsetPtr = End; return createStringError(errc::invalid_argument, - "unrecognised %s table version %" PRIu16 - " in table at offset 0x%" PRIx32, - SectionName.data(), HeaderData.Version, HeaderOffset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + "unrecognised %s table version %" PRIu16 + " in table at offset 0x%" PRIx32, + SectionName.data(), HeaderData.Version, + HeaderOffset); + } + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) { + *OffsetPtr = End; return createStringError(errc::not_supported, "%s table at offset 0x%" PRIx32 " has unsupported address size %" PRIu8, SectionName.data(), HeaderOffset, HeaderData.AddrSize); - if (HeaderData.SegSize != 0) + } + if (HeaderData.SegSize != 0) { + *OffsetPtr = End; return createStringError(errc::not_supported, "%s table at offset 0x%" PRIx32 " has unsupported segment selector size %" PRIu8, SectionName.data(), HeaderOffset, HeaderData.SegSize); + } if (End < HeaderOffset + sizeof(HeaderData) + - HeaderData.OffsetEntryCount * sizeof(uint32_t)) + HeaderData.OffsetEntryCount * sizeof(uint32_t)) { + *OffsetPtr = End; return createStringError(errc::invalid_argument, "%s table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32 ") than there is space for", SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount); + } Data.setAddressSize(HeaderData.AddrSize); for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) Offsets.push_back(Data.getU32(OffsetPtr)); @@ -101,9 +123,11 @@ void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { } } -uint32_t DWARFListTableHeader::length() const { +uint32_t DWARFListTableHeader::getTableLength() const { if (HeaderData.Length == 0) return 0; + assert(HeaderData.Version > 0 && + "No DWARF version in header when using getTableLength()"); // TODO: DWARF64 support. - return HeaderData.Length + sizeof(uint32_t); + return HeaderData.Length + (HeaderData.Version > 4) * sizeof(uint32_t); } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index b2bc2c8fa32..38dfe67f299 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -264,13 +264,16 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, return true; } -// Parse the rangelist table header, including the optional array of offsets +// Parse a list table header, including the optional array of offsets // following it (DWARF v5 and later). -static Expected<DWARFDebugRnglistTable> -parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) { +template <typename DWARFListTable> +static Expected<DWARFListTable> +parseListTableHeader(DWARFDataExtractor DA, DWARFContext *C, + StringRef SectionName, uint32_t Offset, bool isDWO) { // 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. + DWARFListTable Table(C, SectionName, isDWO); if (Offset > 0) { if (Offset < 12U) return createStringError(errc::invalid_argument, "Did not detect a valid" @@ -278,20 +281,46 @@ parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) { Offset); Offset -= 12U; } - llvm::DWARFDebugRnglistTable Table; if (Error E = Table.extractHeaderAndOffsets(DA, &Offset)) return std::move(E); return Table; } -Error DWARFUnit::extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const { - // Require that compile unit is extracted. - assert(!DieArray.empty()); - DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, - isLittleEndian, getAddressByteSize()); - uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; - return RangeList.extract(RangesData, &ActualRangeListOffset); +// Parse a DWARF v5 list table (e.g. either a rangelist table or a location +// list table). For DWARF units with version 4 or earlier, we instead create +// the table artifically by giving it a size that equals the section size. +template <typename DWARFListTable> +static Optional<DWARFListTable> +setupListTable(DWARFUnit *U, const DWARFSection *Section, StringRef SectionName, + uint32_t &Base, bool isDWO, bool isLittleEndian) { + if (!Section->Data.size()) + return None; + DWARFContext &Ctx = U->getContext(); + DWARFListTable Table(&Ctx, SectionName, isDWO); + // Parse the list table header. Individual lists are extracted lazily. + DWARFDataExtractor DA(Ctx.getDWARFObj(), *Section, isLittleEndian, + U->getAddressByteSize()); + if (U->getVersion() < 5) { + Base = 0; + Table.setHeaderData(Section->Data.size(), U->getVersion(), + DA.getAddressSize()); + return Table; + } + if (auto TableOrError = parseListTableHeader<DWARFListTable>( + DA, &Ctx, SectionName, Base, isDWO)) + Table = TableOrError.get(); + else { + WithColor::error() << "parsing a " << Table.getListTypeString().data() + << " list table: " << toString(TableOrError.takeError()) + << '\n'; + return None; + } + // In a split dwarf unit, there are no attributes like DW_AT_rnglists_base or + // DW_AT_loclists_base that describe the table base. Adjust Base to point past + // the table header which is expected to start at offset 0. + if (isDWO) + Base = Table.getHeaderSize(); + return Table; } void DWARFUnit::clear() { @@ -411,31 +440,20 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to // describe address ranges. + StringRef RangeSectionName = ".debug_ranges"; if (getVersion() >= 5) { - if (isDWO) + if (isDWO) { + RangeSectionName = ".debug_rnglists.dwo"; setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0); - else + } else { + RangeSectionName = ".debug_rnglists"; setRangesSection(&Context.getDWARFObj().getRnglistsSection(), toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0)); - if (RangeSection->Data.size()) { - // 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(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(); } } + RngListTable = setupListTable<DWARFDebugRnglistTable>( + this, RangeSection, RangeSectionName, RangeSectionBase, isDWO, + isLittleEndian); // 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. @@ -477,16 +495,9 @@ bool DWARFUnit::parseDWO() { DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); 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(TableOrError.takeError()) - << '\n'; - if (DWO->RngListTable) - DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize(); + DWO->RngListTable = setupListTable<DWARFDebugRnglistTable>( + DWOCU, DWO->RangeSection, ".debug_rnglists.dwo", DWO->RangeSectionBase, + /* isDWO =*/true, isLittleEndian); } else { auto DWORangesBase = UnitDie.getRangesBaseAttribute(); DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); @@ -504,12 +515,6 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) { Expected<DWARFAddressRangesVector> DWARFUnit::findRnglistFromOffset(uint32_t Offset) { - if (getVersion() <= 4) { - DWARFDebugRangeList RangeList; - if (Error E = extractRangeList(Offset, RangeList)) - return std::move(E); - return RangeList.getAbsoluteRanges(getBaseAddress()); - } if (RngListTable) { DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, isLittleEndian, RngListTable->getAddrSize()); |