Index: include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFListTable.h" #include #include #include @@ -23,108 +24,35 @@ class Error; class raw_ostream; -/// 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 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 - /// 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; +/// A class representing a single range list entry. +struct RangeListEntry : public DWARFListEntryBase { + /// 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); + void dump(raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, + uint64_t &CurrentBase, DIDumpOptions DumpOpts) const; + bool isSentinel() const { return EntryKind == dwarf::DW_RLE_end_of_list; } +}; +/// A class representing a single rangelist. +class DWARFDebugRnglist : public DWARFListType { 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); /// 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. -/// 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. - uint32_t Length = 0; - /// The DWARF version number. - uint16_t Version; - /// The size in bytes of an address on the target architecture. For - /// segmented addressing, this is the size of the offset portion of the - /// address. - uint8_t AddrSize; - /// The size in bytes of a segment selector on the target architecture. - /// If the target system uses a flat address space, this value is 0. - uint8_t SegSize; - /// The number of offsets that follow the header before the range lists. - uint32_t OffsetEntryCount; - }; - -private: - dwarf::DwarfFormat Format; - uint32_t HeaderOffset; - Header HeaderData; - std::vector Offsets; - std::map Ranges; - +class DWARFDebugRnglistTable : public DWARFListTableBase { 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); - /// Look up a rangelist based on a given offset. Extract it and enter it into - /// the ranges map if necessary. - Expected 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 - /// parsed, or there was a problem in parsing). - uint32_t length() const; + DWARFDebugRnglistTable() + : DWARFListTableBase(/* SectionName = */ ".debug_rnglists", + /* HeaderString = */ "ranges:", + /* ListTypeString = */ "range") {} }; } // end namespace llvm Index: include/llvm/DebugInfo/DWARF/DWARFListTable.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFListTable.h +++ include/llvm/DebugInfo/DWARF/DWARFListTable.h @@ -0,0 +1,278 @@ +//===- DWARFListTable.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H +#define LLVM_DEBUGINFO_DWARFLISTTABLE_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +namespace llvm { + +/// A base class for DWARF list entries, such as range or location list +/// entries. +struct DWARFListEntryBase { + /// The offset at which the entry is located in the section. + uint32_t Offset; + /// The DWARF encoding (DW_RLE_* or DW_LLE_*). + uint8_t EntryKind; + /// The index of the section this entry belongs to. + uint64_t SectionIndex; +}; + +/// A base class for lists of entries that are extracted from a particular +/// section, such as range lists or location lists. +template class DWARFListType { + using EntryType = ListEntryType; + using ListEntries = std::vector; + +protected: + ListEntries Entries; + +public: + // FIXME: We need to consolidate the various verions of "createError" + // that are used in the DWARF consumer. Until then, this is a workaround. + Error createError(const char *, const char *, uint32_t); + + const ListEntries &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, const char *SectionName, + const char *ListStringName); +}; + +/// A class representing the header of a list table such as the range list +/// table in the .debug_rnglists section. +class DWARFListTableHeader { + struct Header { + /// The total length of the entries for this table, not including the length + /// field itself. + uint32_t Length = 0; + /// The DWARF version number. + uint16_t Version; + /// The size in bytes of an address on the target architecture. For + /// segmented addressing, this is the size of the offset portion of the + /// address. + uint8_t AddrSize; + /// The size in bytes of a segment selector on the target architecture. + /// If the target system uses a flat address space, this value is 0. + uint8_t SegSize; + /// The number of offsets that follow the header before the range lists. + uint32_t OffsetEntryCount; + }; + + Header HeaderData; + /// The offset table, which contains offsets to the individual list entries. + /// It is used by forms such as DW_FORM_rnglistx. + /// FIXME: Generate the table and use the appropriate forms. + std::vector Offsets; + /// The table's format, either DWARF32 or DWARF64. + dwarf::DwarfFormat Format; + /// The offset at which the header (and hence the table) is located within + /// its section. + uint32_t HeaderOffset; + /// The name of the section the list is located in. + const char *SectionName; + /// A characterization of the list for dumping purposes, e.g. "range" or + /// "location". + const char *ListTypeString; + +public: + DWARFListTableHeader(const char *SectionName, const char *ListTypeString) + : SectionName(SectionName), ListTypeString(ListTypeString) {} + + void clear() { + HeaderData = {}; + Offsets.clear(); + } + uint32_t getHeaderOffset() const { return HeaderOffset; } + uint8_t getAddrSize() const { return HeaderData.AddrSize; } + uint32_t getLength() const { return HeaderData.Length; } + const char *getSectionName() const { return SectionName; } + const char *getListTypeString() const { return ListTypeString; } + dwarf::DwarfFormat getFormat() const { return Format; } + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const; + Optional getOffsetEntry(uint32_t Index) const { + if (Index < Offsets.size()) + return Offsets[Index]; + return None; + } + + /// Extract the table header and the array of offsets. + Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + + /// Returns the length of the table, including the length field, or 0 if the + /// length has not been determined (e.g. because the table has not yet been + /// parsed, or there was a problem in parsing). + uint32_t length() const; +}; + +/// A class representing a table of lists as specified in the DWARF v5 +/// standard for location lists and range lists. The table consists of a header +/// followed by an array of offsets into a DWARF section, followed by zero or +/// more list entries. The list entries are kept in a map where the keys are +/// the lists' section offsets. +template class DWARFListTableBase { + DWARFListTableHeader Header; + /// A mapping between file offsets and lists. It is used to find a particular + /// list based on an offset (obtained from DW_AT_ranges, for example). + std::map ListMap; + /// This string is displayed as a heading before the list is dumped + /// (e.g. "ranges:"). + const char *HeaderString; + +protected: + DWARFListTableBase(const char *SectionName, const char *HeaderString, + const char *ListTypeString) + : Header(SectionName, ListTypeString), HeaderString(HeaderString) {} + +public: + void clear() { + Header.clear(); + ListMap.clear(); + } + /// Extract the table header and the array of offsets. + Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr) { + return Header.extract(Data, OffsetPtr); + } + /// Extract an entire table, including all list entries. + Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + /// Look up a list based on a given offset. Extract it and enter it into the + /// list map if necessary. + Expected findList(DWARFDataExtractor Data, uint32_t Offset); + + uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); } + uint8_t getAddrSize() const { return Header.getAddrSize(); } + + 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 { + return Header.getOffsetEntry(Index); + } + /// 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 (Header.getFormat()) { + case dwarf::DwarfFormat::DWARF32: + return 12; + case dwarf::DwarfFormat::DWARF64: + return 20; + } + llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64"); + } + + uint32_t length() { return Header.length(); } +}; + +template +Error DWARFListTableBase::extract(DWARFDataExtractor Data, + uint32_t *OffsetPtr) { + clear(); + if (Error E = extractHeaderAndOffsets(Data, OffsetPtr)) + return E; + + Data.setAddressSize(Header.getAddrSize()); + uint32_t End = getHeaderOffset() + Header.length(); + while (*OffsetPtr < End) { + DWARFListType CurrentList; + uint32_t Off = *OffsetPtr; + if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr, + Header.getSectionName(), + Header.getListTypeString())) + return E; + ListMap[Off] = CurrentList; + } + + assert(*OffsetPtr == End && + "mismatch between expected length of table and length " + "of extracted data"); + return Error::success(); +} + +template +Error DWARFListType::extract(DWARFDataExtractor Data, + uint32_t HeaderOffset, uint32_t End, + uint32_t *OffsetPtr, + const char *SectionName, + const char *ListTypeString) { + if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End) + return createError("invalid %s list offset 0x%" PRIx32, + ListTypeString, *OffsetPtr); + Entries.clear(); + while (*OffsetPtr < End) { + ListEntryType Entry; + if (Error E = Entry.extract(Data, End, OffsetPtr)) + return E; + Entries.push_back(Entry); + if (Entry.isSentinel()) + return Error::success(); + } + return createError("no end of list marker detected at end of %s table " + "starting at offset 0x%" PRIx32, + SectionName, HeaderOffset); +} + +template +void DWARFListTableBase::dump(raw_ostream &OS, + DIDumpOptions DumpOpts) const { + Header.dump(OS, DumpOpts); + OS << HeaderString << "\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 : ListMap) + for (const auto &Entry : List.second.getEntries()) + MaxEncodingStringLength = + std::max(MaxEncodingStringLength, + dwarf::RangeListEncodingString(Entry.EntryKind).size()); + } + + uint64_t CurrentBase = 0; + for (const auto &List : ListMap) + for (const auto &Entry : List.second.getEntries()) + Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase, + DumpOpts); +} + +template +Expected +DWARFListTableBase::findList(DWARFDataExtractor Data, + uint32_t Offset) { + auto Entry = ListMap.find(Offset); + if (Entry != ListMap.end()) + return Entry->second; + + // Extract the list from the section and enter it into the list map. + DWARFListType List; + uint32_t End = getHeaderOffset() + Header.length(); + uint32_t StartingOffset = Offset; + if (Error E = + List.extract(Data, getHeaderOffset(), End, &Offset, + Header.getSectionName(), Header.getListTypeString())) + return std::move(E); + ListMap[StartingOffset] = List; + return List; +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H Index: lib/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- lib/DebugInfo/DWARF/CMakeLists.txt +++ lib/DebugInfo/DWARF/CMakeLists.txt @@ -20,6 +20,7 @@ DWARFExpression.cpp DWARFFormValue.cpp DWARFGdbIndex.cpp + DWARFListTable.cpp DWARFTypeUnit.cpp DWARFUnitIndex.cpp DWARFUnit.cpp Index: lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -16,12 +16,6 @@ using namespace llvm; -void DWARFDebugRnglistTable::clear() { - HeaderData = {}; - Offsets.clear(); - Ranges.clear(); -} - template static Error createError(char const *Fmt, const Ts &... Vals) { std::string Buffer; @@ -30,66 +24,14 @@ return make_error(Stream.str(), inconvertibleErrorCode()); } -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 " - ".debug_rnglists table length at offset 0x%" PRIx32, - *OffsetPtr); - // TODO: Add support for DWARF64. - HeaderData.Length = Data.getU32(OffsetPtr); - if (HeaderData.Length == 0xffffffffu) - 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 - ") to contain a complete header", - HeaderOffset, length()); - uint32_t End = HeaderOffset + length(); - if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) - return createError( - "section is not large enough to contain a .debug_rnglists table " - "of length 0x%" PRIx32 " at offset 0x%" PRIx32, - length(), HeaderOffset); - - HeaderData.Version = Data.getU16(OffsetPtr); - HeaderData.AddrSize = Data.getU8(OffsetPtr); - HeaderData.SegSize = Data.getU8(OffsetPtr); - HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); - - // Perform basic validation of the remaining header fields. - if (HeaderData.Version != 5) - return createError("unrecognised .debug_rnglists table version %" PRIu16 - " in table at offset 0x%" PRIx32, - HeaderData.Version, HeaderOffset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) - return createError(".debug_rnglists table at offset 0x%" PRIx32 - " has unsupported address size %hhu", - HeaderOffset, HeaderData.AddrSize); - if (HeaderData.SegSize != 0) - return createError(".debug_rnglists table at offset 0x%" PRIx32 - " has unsupported segment selector size %" PRIu8, - HeaderOffset, HeaderData.SegSize); - if (End < HeaderOffset + sizeof(HeaderData) + - HeaderData.OffsetEntryCount * sizeof(uint32_t)) - return createError(".debug_rnglists table at offset 0x%" PRIx32 - " 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(); +template <> +Error DWARFListType::createError(const char *Fmt, const char *s, + uint32_t Val) { + return ::createError(Fmt, s, Val); } -Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data, - uint32_t End, - uint32_t *OffsetPtr) { +Error 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 @@ -206,53 +148,10 @@ return Res; } -Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset, - uint32_t End, uint32_t *OffsetPtr) { - if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End) - return createError("invalid range list offset 0x%" PRIx32, *OffsetPtr); - Entries.clear(); - while (*OffsetPtr < End) { - RangeListEntry Entry{0, 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, - DWARFDebugRnglist::RangeListEntry Entry, - uint8_t AddrSize, uint8_t MaxEncodingStringLength, - uint64_t &CurrentBase, DIDumpOptions DumpOpts) { - auto PrintRawEntry = [](raw_ostream &OS, - DWARFDebugRnglist::RangeListEntry Entry, +void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize, + uint8_t MaxEncodingStringLength, + uint64_t &CurrentBase, DIDumpOptions DumpOpts) const { + auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, uint8_t AddrSize, DIDumpOptions DumpOpts) { if (DumpOpts.Verbose) { DumpOpts.DisplayRawContents = true; @@ -264,108 +163,41 @@ if (DumpOpts.Verbose) { // Print the section offset in verbose mode. - OS << format("0x%8.8" PRIx32 ":", Entry.Offset); - auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind); + 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 (Entry.EntryKind != dwarf::DW_RLE_end_of_list) + if (EntryKind != dwarf::DW_RLE_end_of_list) OS << ": "; } - switch (Entry.EntryKind) { + switch (EntryKind) { case dwarf::DW_RLE_end_of_list: OS << (DumpOpts.Verbose ? "" : ""); break; case dwarf::DW_RLE_base_address: // In non-verbose mode we do not print anything for this entry. - CurrentBase = Entry.Value0; + CurrentBase = Value0; if (!DumpOpts.Verbose) return; - OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0); + OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0); break; case dwarf::DW_RLE_start_length: - PrintRawEntry(OS, Entry, AddrSize, DumpOpts); - DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1) - .dump(OS, AddrSize, DumpOpts); + PrintRawEntry(OS, *this, AddrSize, DumpOpts); + DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); break; case dwarf::DW_RLE_offset_pair: - PrintRawEntry(OS, Entry, AddrSize, DumpOpts); - DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase) + PrintRawEntry(OS, *this, AddrSize, DumpOpts); + DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) .dump(OS, AddrSize, DumpOpts); break; case dwarf::DW_RLE_start_end: - DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts); + DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); break; default: llvm_unreachable("Unsupported range list encoding"); } OS << "\n"; } - -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 - ", version = 0x%4.4" PRIx16 ", " - "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 - ", offset_entry_count = " - "0x%8.8" PRIx32 "\n", - HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, - HeaderData.SegSize, HeaderData.OffsetEntryCount); - - if (HeaderData.OffsetEntryCount > 0) { - OS << "Offsets: ["; - for (const auto &Off : Offsets) { - OS << format("\n0x%8.8" PRIx32, Off); - if (DumpOpts.Verbose) - OS << format(" => 0x%8.8" PRIx32, - Off + HeaderOffset + sizeof(HeaderData)); - } - OS << "\n]\n"; - } - 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.second.getEntries()) - dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength, - CurrentBase, DumpOpts); -} - -uint32_t DWARFDebugRnglistTable::length() const { - if (HeaderData.Length == 0) - return 0; - // TODO: DWARF64 support. - return HeaderData.Length + sizeof(uint32_t); -} - -Expected -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)) - return std::move(E); - Ranges[StartingOffset] = RngList; - return RngList; -} Index: lib/DebugInfo/DWARF/DWARFListTable.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFListTable.cpp +++ lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -0,0 +1,109 @@ +//===- DWARFListTable.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/DWARFListTable.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +template +static Error createError(char const *Fmt, const Ts &... Vals) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + return make_error(Stream.str(), inconvertibleErrorCode()); +} + +Error DWARFListTableHeader::extract(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 " + "%s table length at offset 0x%" PRIx32, + SectionName, *OffsetPtr); + // TODO: Add support for DWARF64. + HeaderData.Length = Data.getU32(OffsetPtr); + if (HeaderData.Length == 0xffffffffu) + return createError("DWARF64 is not supported in %s at offset 0x%" PRIx32, + SectionName, HeaderOffset); + Format = dwarf::DwarfFormat::DWARF32; + if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) + return createError("%s table at offset 0x%" PRIx32 + " has too small length (0x%" PRIx32 + ") to contain a complete header", + SectionName, HeaderOffset, length()); + uint32_t End = HeaderOffset + length(); + if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) + return createError("section is not large enough to contain a %s table " + "of length 0x%" PRIx32 " at offset 0x%" PRIx32, + SectionName, length(), HeaderOffset); + + HeaderData.Version = Data.getU16(OffsetPtr); + HeaderData.AddrSize = Data.getU8(OffsetPtr); + HeaderData.SegSize = Data.getU8(OffsetPtr); + HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); + + // Perform basic validation of the remaining header fields. + if (HeaderData.Version != 5) + return createError("unrecognised %s table version %" PRIu16 + " in table at offset 0x%" PRIx32, + SectionName, HeaderData.Version, HeaderOffset); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createError("%s table at offset 0x%" PRIx32 + " has unsupported address size %hhu", + SectionName, HeaderOffset, HeaderData.AddrSize); + if (HeaderData.SegSize != 0) + return createError("%s table at offset 0x%" PRIx32 + " has unsupported segment selector size %" PRIu8, + SectionName, HeaderOffset, HeaderData.SegSize); + if (End < HeaderOffset + sizeof(HeaderData) + + HeaderData.OffsetEntryCount * sizeof(uint32_t)) + return createError( + "%s table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32 + ") than there is space for", + SectionName, 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(); +} + +void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { + if (DumpOpts.Verbose) + OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); + OS << format( + "%s list header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", " + "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 + ", offset_entry_count = " + "0x%8.8" PRIx32 "\n", + ListTypeString, HeaderData.Length, HeaderData.Version, + HeaderData.AddrSize, HeaderData.SegSize, HeaderData.OffsetEntryCount); + + if (HeaderData.OffsetEntryCount > 0) { + OS << "offsets: ["; + for (const auto &Off : Offsets) { + OS << format("\n0x%8.8" PRIx32, Off); + if (DumpOpts.Verbose) + OS << format(" => 0x%8.8" PRIx32, + Off + HeaderOffset + sizeof(HeaderData)); + } + OS << "\n]\n"; + } +} + +uint32_t DWARFListTableHeader::length() const { + if (HeaderData.Length == 0) + return 0; + // TODO: DWARF64 support. + return HeaderData.Length + sizeof(uint32_t); +} Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -408,7 +408,7 @@ if (RngListTable) { DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, isLittleEndian, RngListTable->getAddrSize()); - auto RangeListOrError = RngListTable->findRangeList(RangesData, Offset); + auto RangeListOrError = RngListTable->findList(RangesData, Offset); if (RangeListOrError) return RangeListOrError.get().getAbsoluteRanges(getBaseAddress()); return RangeListOrError.takeError(); Index: test/DebugInfo/X86/fission-ranges.ll =================================================================== --- test/DebugInfo/X86/fission-ranges.ll +++ test/DebugInfo/X86/fission-ranges.ll @@ -55,9 +55,9 @@ ; V5RNGLISTS-NOT: DW_TAG ; V5RNGLISTS: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) ; V5RNGLISTS: .debug_rnglists contents: -; V5RNGLISTS-NEXT: 0x00000000: Range List Header: length = 0x00000014, version = 0x0005, +; V5RNGLISTS-NEXT: 0x00000000: range list header: length = 0x00000014, version = 0x0005, ; V5RNGLISTS-SAME: addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -; V5RNGLISTS-NEXT: Ranges: +; V5RNGLISTS-NEXT: ranges: ; V5RNGLISTS-NEXT: 0x0000000c: [DW_RLE_offset_pair]: ; V5RNGLISTS-NEXT: 0x0000000f: [DW_RLE_offset_pair]: ; V5RNGLISTS: 0x{{[0-9a-f]+}}: [DW_RLE_end_of_list] Index: test/DebugInfo/X86/rnglists-nobase.ll =================================================================== --- test/DebugInfo/X86/rnglists-nobase.ll +++ test/DebugInfo/X86/rnglists-nobase.ll @@ -21,9 +21,9 @@ ; Compile with clang -O1 -gdwarf-5 -S -emit-llvm ; ; CHECK: .debug_rnglists contents: -; CHECK-NEXT: 0x00000000: Range List Header: length = 0x00000027, version = 0x0005, +; CHECK-NEXT: 0x00000000: range list header: length = 0x00000027, version = 0x0005, ; CHECK-SAME: addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -; CHECK-NEXT: Ranges: +; CHECK-NEXT: ranges: ; CHECK-NEXT: 0x0000000c: [DW_RLE_start_length]: ; CHECK-NEXT: 0x00000016: [DW_RLE_start_length]: ; CHECK-NEXT: 0x00000020: [DW_RLE_start_length]: Index: test/tools/llvm-dwarfdump/X86/debug_rnglists.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists.s @@ -4,12 +4,12 @@ # RUN: llvm-dwarfdump -v --debug-rnglists %t.o 2> %t.err | FileCheck %s --check-prefixes=VERBOSE,BOTH # BOTH: .debug_rnglists contents: -# TERSE-NEXT: Range List Header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# TERSE-NEXT: range list header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 # VERBOSE-NEXT: 0x{{[0-9a-f]*}}: -# VERBOSE-SAME: Range List Header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# VERBOSE-SAME: range list header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -# BOTH-NEXT: Ranges: +# BOTH-NEXT: ranges: # TERSE-NEXT: [0x0000000000000010, 0x0000000000000020) # TERSE-NEXT: [0x0000000000000025, 0x00000000000000a5) # TERSE-NEXT: @@ -23,18 +23,18 @@ # VERBOSE-NEXT: 0x00000029: [DW_RLE_start_end ]: [0x0000000000000100, 0x0000000000000200) # VERBOSE-NEXT: 0x0000003a: [DW_RLE_end_of_list ] -# TERSE-NEXT: Range List Header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 +# TERSE-NEXT: range list header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 # VERBOSE-NEXT: 0x{{[0-9a-f]*}}: -# VERBOSE-SAME: Range List Header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 +# VERBOSE-SAME: range list header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 -# BOTH-NEXT: Offsets: [ +# BOTH-NEXT: offsets: [ # BOTH-NEXT: 0x00000008 # VERBOSE-SAME: => 0x0000004f # BOTH-NEXT: 0x0000001b # VERBOSE-SAME: => 0x00000062 # BOTH-NEXT: ] -# BOTH-NEXT: Ranges: +# BOTH-NEXT: ranges: # TERSE-NEXT: [0x00000000, 0x00000000) # TERSE-NEXT: [0x00000002, 0x00000006) @@ -48,21 +48,21 @@ # VERBOSE-NEXT: 0x00000062: [DW_RLE_start_length]: 0x00000036, 0x00000100 => [0x00000036, 0x00000136) # VERBOSE-NEXT: 0x00000069: [DW_RLE_end_of_list ] -# TERSE-NEXT: Range List Header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# TERSE-NEXT: range list header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 # VERBOSE-NEXT: 0x{{[0-9a-f]*}}: -# VERBOSE-SAME: Range List Header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# VERBOSE-SAME: range list header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -# BOTH-NOT: Offsets: -# BOTH: Ranges: +# BOTH-NOT: offsets: +# BOTH: ranges: # BOTH-NOT: [ -# TERSE-NEXT: Range List Header: length = 0x0000000e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# TERSE-NEXT: range list header: length = 0x0000000e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 # VERBOSE-NEXT: 0x{{[0-9a-f]*}}: -# VERBOSE-SAME: Range List Header: length = 0x0000000e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# VERBOSE-SAME: range list header: length = 0x0000000e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -# BOTH-NEXT: Ranges: +# BOTH-NEXT: ranges: # TERSE-NEXT: [0x0000000000000800, 0x0000000000001000) # TERSE-NEXT: @@ -70,12 +70,12 @@ # VERBOSE-SAME: [0x0000000000000800, 0x0000000000001000) # VERBOSE-NEXT: 0x000000b6: [DW_RLE_end_of_list] -# TERSE-NEXT: Range List Header: length = 0x00000017, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# TERSE-NEXT: range list header: length = 0x00000017, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 # VERBOSE-NEXT: 0x{{[0-9a-f]*}}: -# VERBOSE-SAME: Range List Header: length = 0x00000017, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# VERBOSE-SAME: range list header: length = 0x00000017, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -# BOTH-NEXT: Ranges: +# BOTH-NEXT: ranges: # TERSE-NEXT: [0x0000000000001800, 0x0000000000002000) # TERSE-NEXT: @@ -84,7 +84,7 @@ # VERBOSE-SAME: [0x0000000000001800, 0x0000000000002000) # VERBOSE-NEXT: 0x000000d1: [DW_RLE_end_of_list ] -# BOTH-NOT: Range List Header: +# BOTH-NOT: range list header: # ERR-NOT: error: # ERR: error: unsupported rnglists encoding DW_RLE_base_addressx at offset 0x82 Index: test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -1,9 +1,9 @@ # RUN: llvm-mc %S/Inputs/debug_rnglists_short_section.s -filetype obj -triple x86_64-pc-linux -o - | \ # RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=SHORT # SHORT-NOT: error: -# SHORT-NOT: Range List Header +# SHORT-NOT: range list header # SHORT: error: section is not large enough to contain a .debug_rnglists table length at offset 0 -# SHORT-NOT: Range List Header +# SHORT-NOT: range list header # SHORT-NOT: error: # RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ @@ -11,18 +11,18 @@ # RUN: FileCheck %s --input-file %t.err # GOOD: .debug_rnglists contents: -# GOOD-NEXT: Range List Header: length = 0x0000001e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000001 -# GOOD-NEXT: Offsets: [ +# GOOD-NEXT: range list header: length = 0x0000001e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000001 +# GOOD-NEXT: offsets: [ # GOOD-NEXT: 0x00000004 # GOOD-NEXT: ] -# GOOD-NEXT: Ranges: +# GOOD-NEXT: ranges: # GOOD-NEXT: [0x0000000000000010, 0x0000000000000020) # GOOD-NEXT: -# GOOD-NEXT: Range List Header: length = 0x0000001a, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 -# GOOD-NEXT: Ranges: +# GOOD-NEXT: range list header: length = 0x0000001a, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# GOOD-NEXT: ranges: # GOOD-NEXT: [0x0000000000000030, 0x0000000000000040) # GOOD-NEXT: -# GOOD-NOT: Range List Header +# GOOD-NOT: range list header # CHECK-NOT: error: # CHECK: error: .debug_rnglists table at offset 0x22 has too small length (0xb) to contain a complete header