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 @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include +#include #include namespace llvm { @@ -21,8 +22,43 @@ class Error; class raw_ostream; -class DWARFDebugRnglists { +/// A class representing a single rangelist. +class DWARFDebugRnglist { +public: + struct RangeListEntry { + /// The offset at which the entry is located in the section. + uint32_t Offset; + /// The DWARF encoding (DW_RLE_*). + uint8_t EntryKind; + /// 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 + /// values are semantically undefined, but initialized to 0. + uint64_t Value0; + uint64_t Value1; + + Error extract(DWARFDataExtractor Data, uint32_t End, uint32_t *OffsetPtr); + }; + + using RngListEntries = std::vector; + private: + RngListEntries Entries; + +public: + const RngListEntries &getEntries() const { return Entries; } + bool empty() const { return Entries.empty(); } + void clear() { Entries.clear(); } + Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End, + uint32_t *OffsetPtr); +}; + +/// A class representing a table of range lists as specified in DWARF v5. +/// The table consists of a header followed by an array of offsets into the +/// .debug_rnglists section, followed by one or more rangelists. The rangelists +/// are kept in a map where the keys are the lists' section offsets. +class DWARFDebugRnglistTable { +public: struct Header { /// The total length of the entries for this table, not including the length /// field itself. @@ -40,32 +76,17 @@ uint32_t OffsetEntryCount; }; -public: - struct RangeListEntry { - /// The offset at which the entry is located in the section. - const uint32_t Offset; - /// The DWARF encoding (DW_RLE_*). - const uint8_t EntryKind; - /// 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 - /// values are semantically undefined, but initialized to 0. - const uint64_t Value0; - const uint64_t Value1; - }; - - using DWARFRangeList = std::vector; - private: uint32_t HeaderOffset; Header HeaderData; std::vector Offsets; - std::vector Ranges; - // The length of the longest encoding string we encountered during parsing. - uint8_t MaxEncodingStringLength = 0; + std::map Ranges; public: void clear(); + /// Extract the table header and the array of offsets. + Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr); + /// Extract an entire table, including all rangelists. Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); uint32_t getHeaderOffset() const { return HeaderOffset; } void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const; Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -499,7 +499,7 @@ isLittleEndian(), 0); uint32_t Offset = 0; while (rnglistData.isValidOffset(Offset)) { - DWARFDebugRnglists Rnglists; + DWARFDebugRnglistTable Rnglists; uint32_t TableOffset = Offset; if (Error Err = Rnglists.extract(rnglistData, &Offset)) { errs() << "error: " + toString(std::move(Err)) << '\n'; Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -16,7 +16,7 @@ using namespace llvm; -void DWARFDebugRnglists::clear() { +void DWARFDebugRnglistTable::clear() { HeaderData = {}; Offsets.clear(); Ranges.clear(); @@ -30,11 +30,9 @@ return make_error(Stream.str(), inconvertibleErrorCode()); } -Error DWARFDebugRnglists::extract(DWARFDataExtractor Data, - uint32_t *OffsetPtr) { - clear(); +Error DWARFDebugRnglistTable::extractHeaderAndOffsets(DWARFDataExtractor Data, + uint32_t *OffsetPtr) { HeaderOffset = *OffsetPtr; - // Read and verify the length field. if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) return createError("section is not large enough to contain a " @@ -82,113 +80,132 @@ " has more offset entries (%" PRIu32 ") than there is space for", HeaderOffset, HeaderData.OffsetEntryCount); - Data.setAddressSize(HeaderData.AddrSize); - for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) Offsets.push_back(Data.getU32(OffsetPtr)); + return Error::success(); +} - DWARFRangeList CurrentRanges; - while (*OffsetPtr < End) { - uint32_t EntryOffset = *OffsetPtr; - uint8_t Encoding = Data.getU8(OffsetPtr); - MaxEncodingStringLength = - std::max(MaxEncodingStringLength, - (uint8_t)dwarf::RangeListEncodingString(Encoding).size()); - switch (Encoding) { - case dwarf::DW_RLE_end_of_list: - CurrentRanges.push_back(RangeListEntry{ EntryOffset, Encoding, 0, 0 }); - Ranges.insert(Ranges.end(), std::move(CurrentRanges)); - CurrentRanges.clear(); - break; - // TODO: Support other encodings. - case dwarf::DW_RLE_base_addressx: - return createError("unsupported rnglists encoding DW_RLE_base_addressx " - "at offset 0x%" PRIx32, - *OffsetPtr - 1); - case dwarf::DW_RLE_startx_endx: - return createError("unsupported rnglists encoding DW_RLE_startx_endx at " - "offset 0x%" PRIx32, +Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data, + uint32_t End, + uint32_t *OffsetPtr) { + Offset = *OffsetPtr; + // 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); + + switch (Encoding) { + case dwarf::DW_RLE_end_of_list: + Value0 = Value1 = 0; + break; + // TODO: Support other encodings. + case dwarf::DW_RLE_base_addressx: + return createError("unsupported rnglists encoding DW_RLE_base_addressx " + "at offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_startx_endx: + return createError("unsupported rnglists encoding DW_RLE_startx_endx at " + "offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_startx_length: + return createError("unsupported rnglists encoding DW_RLE_startx_length " + "at offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_offset_pair: { + uint32_t PreviousOffset = *OffsetPtr - 1; + Value0 = Data.getULEB128(OffsetPtr); + Value1 = Data.getULEB128(OffsetPtr); + if (End < *OffsetPtr) + return createError("read past end of table when reading " + "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, + PreviousOffset); + break; + } + case dwarf::DW_RLE_base_address: { + if ((End - *OffsetPtr) < Data.getAddressSize()) + return createError("insufficient space remaining in table for " + "DW_RLE_base_address encoding at offset 0x%" PRIx32, *OffsetPtr - 1); - case dwarf::DW_RLE_startx_length: - return createError("unsupported rnglists encoding DW_RLE_startx_length " + Value0 = Data.getAddress(OffsetPtr); + break; + } + case dwarf::DW_RLE_start_end: { + if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2)) + return createError("insufficient space remaining in table for " + "DW_RLE_start_end encoding " "at offset 0x%" PRIx32, *OffsetPtr - 1); - case dwarf::DW_RLE_offset_pair: { - uint32_t PreviousOffset = *OffsetPtr - 1; - uint64_t StartingOffset = Data.getULEB128(OffsetPtr); - uint64_t EndingOffset = Data.getULEB128(OffsetPtr); - if (End < *OffsetPtr) - return createError("read past end of table when reading " - "DW_RLE_offset_pair encoding at offset 0x%" PRIx32, - PreviousOffset); - CurrentRanges.push_back( - RangeListEntry{EntryOffset, Encoding, StartingOffset, EndingOffset}); - break; - } - case dwarf::DW_RLE_base_address: { - if ((End - *OffsetPtr) < HeaderData.AddrSize) - return createError("insufficient space remaining in table for " - "DW_RLE_base_address encoding at offset 0x%" PRIx32, - *OffsetPtr - 1); - uint64_t Base = Data.getAddress(OffsetPtr); - CurrentRanges.push_back(RangeListEntry{EntryOffset, Encoding, Base, 0}); - break; - } - case dwarf::DW_RLE_start_end: { - if ((End - *OffsetPtr) < unsigned(HeaderData.AddrSize * 2)) - return createError("insufficient space remaining in table for " - "DW_RLE_start_end encoding " - "at offset 0x%" PRIx32, - *OffsetPtr - 1); - uint64_t Start = Data.getAddress(OffsetPtr); - uint64_t End = Data.getAddress(OffsetPtr); - CurrentRanges.push_back( - RangeListEntry{EntryOffset, Encoding, Start, End}); - break; - } - case dwarf::DW_RLE_start_length: { - uint32_t PreviousOffset = *OffsetPtr - 1; - uint64_t Start = Data.getAddress(OffsetPtr); - uint64_t Length = Data.getULEB128(OffsetPtr); - if (End < *OffsetPtr) - return createError("read past end of table when reading " - "DW_RLE_start_length encoding at offset 0x%" PRIx32, - PreviousOffset); - CurrentRanges.push_back( - RangeListEntry{EntryOffset, Encoding, Start, Length}); - break; - } - default: - Ranges.insert(Ranges.end(), std::move(CurrentRanges)); - return createError("unknown rnglists encoding 0x%" PRIx32 - " at offset 0x%" PRIx32, - uint32_t(Encoding), *OffsetPtr - 1); - } + Value0 = Data.getAddress(OffsetPtr); + Value1 = Data.getAddress(OffsetPtr); + break; + } + case dwarf::DW_RLE_start_length: { + uint32_t PreviousOffset = *OffsetPtr - 1; + Value0 = Data.getAddress(OffsetPtr); + Value1 = Data.getULEB128(OffsetPtr); + if (End < *OffsetPtr) + return createError("read past end of table when reading " + "DW_RLE_start_length encoding at offset 0x%" PRIx32, + PreviousOffset); + break; + } + default: + return createError("unknown rnglists encoding 0x%" PRIx32 + " at offset 0x%" PRIx32, + uint32_t(Encoding), *OffsetPtr - 1); } - // If OffsetPtr does not indicate the End offset, then either the above loop - // terminated prematurely, or we encountered a malformed encoding, but did not - // report an error when we should have done. - assert(*OffsetPtr == End && - "did not detect malformed data or loop ended unexpectedly"); + EntryKind = Encoding; + return Error::success(); +} - // If CurrentRanges is not empty, we have a malformed section, because we did - // not find a DW_RLE_end_of_list marker at the end of the last list. - if (!CurrentRanges.empty()) - return createError( - "no end of list marker detected at end of .debug_rnglists table " - "starting at offset 0x%" PRIx32, - HeaderOffset); +Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset, + uint32_t End, uint32_t *OffsetPtr) { + Entries.clear(); + while (*OffsetPtr < End) { + RangeListEntry Entry{0, 0, 0, 0}; + if (Error E = Entry.extract(Data, End, OffsetPtr)) + return E; + Entries.push_back(Entry); + if (Entry.EntryKind == dwarf::DW_RLE_end_of_list) + return Error::success(); + } + return createError( + "no end of list marker detected at end of .debug_rnglists table " + "starting at offset 0x%" PRIx32, + HeaderOffset); +} + +Error DWARFDebugRnglistTable::extract(DWARFDataExtractor Data, + uint32_t *OffsetPtr) { + clear(); + if (Error E = extractHeaderAndOffsets(Data, OffsetPtr)) + return E; + + Data.setAddressSize(HeaderData.AddrSize); + uint32_t End = HeaderOffset + length(); + while (*OffsetPtr < End) { + DWARFDebugRnglist CurrentRangeList; + uint32_t Off = *OffsetPtr; + if (Error E = CurrentRangeList.extract(Data, HeaderOffset, End, OffsetPtr)) + return E; + Ranges[Off] = CurrentRangeList; + } + + assert(*OffsetPtr == End && + "mismatch between expected length of .debug_rnglists table and length " + "of extracted data"); return Error::success(); } static void dumpRangeEntry(raw_ostream &OS, - DWARFDebugRnglists::RangeListEntry Entry, + DWARFDebugRnglist::RangeListEntry Entry, uint8_t AddrSize, uint8_t MaxEncodingStringLength, uint64_t &CurrentBase, DIDumpOptions DumpOpts) { auto PrintRawEntry = [](raw_ostream &OS, - DWARFDebugRnglists::RangeListEntry Entry, + DWARFDebugRnglist::RangeListEntry Entry, uint8_t AddrSize, DIDumpOptions DumpOpts) { if (DumpOpts.Verbose) { DumpOpts.DisplayRawContents = true; @@ -240,7 +257,8 @@ OS << "\n"; } -void DWARFDebugRnglists::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { +void DWARFDebugRnglistTable::dump(raw_ostream &OS, + DIDumpOptions DumpOpts) const { if (DumpOpts.Verbose) OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); OS << format("Range List Header: length = 0x%8.8" PRIx32 @@ -263,14 +281,25 @@ } OS << "Ranges:\n"; + // Determine the length of the longest encoding string we have in the table, + // so we can align the output properly. We only need this in verbose mode. + size_t MaxEncodingStringLength = 0; + if (DumpOpts.Verbose) { + for (const auto &List : Ranges) + for (const auto &Entry : List.second.getEntries()) + MaxEncodingStringLength = + std::max(MaxEncodingStringLength, + dwarf::RangeListEncodingString(Entry.EntryKind).size()); + } + uint64_t CurrentBase = 0; for (const auto &List : Ranges) - for (const auto &Entry : List) + for (const auto &Entry : List.second.getEntries()) dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength, CurrentBase, DumpOpts); } -uint32_t DWARFDebugRnglists::length() const { +uint32_t DWARFDebugRnglistTable::length() const { if (HeaderData.Length == 0) return 0; // TODO: DWARF64 support.