#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFListTable.h"
#include <cstdint>
#include <map>
#include <vector>
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<RangeListEntry>;
-
-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<RangeListEntry> {
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<BaseAddress> 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 {
+class DWARFDebugRnglistTable : public DWARFListTableBase<DWARFDebugRnglist> {
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<uint32_t> Offsets;
- std::map<uint32_t, DWARFDebugRnglist> 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);
- /// Look up a rangelist based on a given offset. Extract it and enter it into
- /// the ranges map if necessary.
- Expected<DWARFDebugRnglist> findRangeList(DWARFDataExtractor Data,
- uint32_t Offset);
- uint32_t getHeaderOffset() const { return HeaderOffset; }
- uint8_t getAddrSize() const { return HeaderData.AddrSize; }
- void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const;
- /// Return the contents of the offset entry designated by a given index.
- Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
- if (Index < Offsets.size())
- return Offsets[Index];
- return None;
- }
- /// Return the size of the table header including the length but not including
- /// the offsets. This is dependent on the table format, which is unambiguously
- /// derived from parsing the table.
- uint8_t getHeaderSize() const {
- switch (Format) {
- case dwarf::DwarfFormat::DWARF32:
- return 12;
- case dwarf::DwarfFormat::DWARF64:
- return 20;
- }
- llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
- }
-
- /// Returns the length of this table, including the length field, or 0 if the
- /// length has not been determined (e.g. because the table has not yet been
- /// parsed, or there was a problem in parsing).
- uint32_t length() const;
+ DWARFDebugRnglistTable()
+ : DWARFListTableBase(/* SectionName = */ ".debug_rnglists",
+ /* HeaderString = */ "ranges:",
+ /* ListTypeString = */ "range") {}
};
} // end namespace llvm
--- /dev/null
+//===- 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 <cstdint>
+#include <map>
+#include <vector>
+
+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 <typename ListEntryType> class DWARFListType {
+ using EntryType = ListEntryType;
+ using ListEntries = std::vector<EntryType>;
+
+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, StringRef SectionName,
+ StringRef 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<uint32_t> 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.
+ StringRef SectionName;
+ /// A characterization of the list for dumping purposes, e.g. "range" or
+ /// "location".
+ StringRef ListTypeString;
+
+public:
+ DWARFListTableHeader(StringRef SectionName, StringRef 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; }
+ StringRef getSectionName() const { return SectionName; }
+ StringRef getListTypeString() const { return ListTypeString; }
+ dwarf::DwarfFormat getFormat() const { return Format; }
+
+ void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
+ Optional<uint32_t> 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 <typename DWARFListType> 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<uint32_t, DWARFListType> ListMap;
+ /// This string is displayed as a heading before the list is dumped
+ /// (e.g. "ranges:").
+ StringRef HeaderString;
+
+protected:
+ DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
+ StringRef 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<DWARFListType> 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<uint32_t> 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 <typename DWARFListType>
+Error DWARFListTableBase<DWARFListType>::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 <typename ListEntryType>
+Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
+ uint32_t HeaderOffset, uint32_t End,
+ uint32_t *OffsetPtr,
+ StringRef SectionName,
+ StringRef ListTypeString) {
+ if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
+ return createError("invalid %s list offset 0x%" PRIx32,
+ ListTypeString.data(), *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.data(), HeaderOffset);
+}
+
+template <typename DWARFListType>
+void DWARFListTableBase<DWARFListType>::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 <typename DWARFListType>
+Expected<DWARFListType>
+DWARFListTableBase<DWARFListType>::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
DWARFExpression.cpp
DWARFFormValue.cpp
DWARFGdbIndex.cpp
+ DWARFListTable.cpp
DWARFTypeUnit.cpp
DWARFUnitIndex.cpp
DWARFUnit.cpp
using namespace llvm;
-void DWARFDebugRnglistTable::clear() {
- HeaderData = {};
- Offsets.clear();
- Ranges.clear();
-}
-
template <typename... Ts>
static Error createError(char const *Fmt, const Ts &... Vals) {
std::string Buffer;
return make_error<StringError>(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<RangeListEntry>::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
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;
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 ? "" : "<End of list>");
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<DWARFDebugRnglist>
-DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
- uint32_t Offset) {
- auto Entry = Ranges.find(Offset);
- if (Entry != Ranges.end())
- return Entry->second;
-
- // Extract the rangelist from the section and enter it into the ranges map.
- DWARFDebugRnglist RngList;
- uint32_t End = HeaderOffset + length();
- uint32_t StartingOffset = Offset;
- if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset))
- return std::move(E);
- Ranges[StartingOffset] = RngList;
- return RngList;
-}
--- /dev/null
+//===- 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 <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(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.data(), *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.data(), 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.data(), 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.data(), 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.data(), HeaderData.Version, HeaderOffset);
+ if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+ return createError("%s table at offset 0x%" PRIx32
+ " has unsupported address size %hhu",
+ SectionName.data(), HeaderOffset, HeaderData.AddrSize);
+ if (HeaderData.SegSize != 0)
+ return createError("%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))
+ return createError(
+ "%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));
+ 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.data(), 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);
+}
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();
; 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]
# 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: <End of list>
# 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)
# 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: <End of list>
# 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: <End of list>
# 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
# 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 - | \
# 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: <End of list>
-# 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: <End of list>
-# 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