diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /include/llvm/DebugInfo/DWARF | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'include/llvm/DebugInfo/DWARF')
20 files changed, 1574 insertions, 300 deletions
diff --git a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 0bade10f6201..1d448728338f 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H #define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" @@ -20,18 +21,76 @@ namespace llvm { class raw_ostream; +class ScopedPrinter; + +/// The accelerator tables are designed to allow efficient random access +/// (using a symbol name as a key) into debug info by providing an index of the +/// debug info DIEs. This class implements the common functionality of Apple and +/// DWARF 5 accelerator tables. +/// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it +/// to this class. +class DWARFAcceleratorTable { +protected: + DWARFDataExtractor AccelSection; + DataExtractor StringSection; + +public: + /// An abstract class representing a single entry in the accelerator tables. + class Entry { + protected: + SmallVector<DWARFFormValue, 3> Values; + + Entry() = default; + + // Make these protected so only (final) subclasses can be copied around. + Entry(const Entry &) = default; + Entry(Entry &&) = default; + Entry &operator=(const Entry &) = default; + Entry &operator=(Entry &&) = default; + ~Entry() = default; + + + public: + /// Returns the Offset of the Compilation Unit associated with this + /// Accelerator Entry or None if the Compilation Unit offset is not recorded + /// in this Accelerator Entry. + virtual Optional<uint64_t> getCUOffset() const = 0; + + /// Returns the Tag of the Debug Info Entry associated with this + /// Accelerator Entry or None if the Tag is not recorded in this + /// Accelerator Entry. + virtual Optional<dwarf::Tag> getTag() const = 0; + + /// Returns the raw values of fields in the Accelerator Entry. In general, + /// these can only be interpreted with the help of the metadata in the + /// owning Accelerator Table. + ArrayRef<DWARFFormValue> getValues() const { return Values; } + }; + + DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : AccelSection(AccelSection), StringSection(StringSection) {} + virtual ~DWARFAcceleratorTable(); + + virtual llvm::Error extract() = 0; + virtual void dump(raw_ostream &OS) const = 0; + + DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete; + void operator=(const DWARFAcceleratorTable &) = delete; +}; /// This implements the Apple accelerator table format, a precursor of the /// DWARF 5 accelerator table format. -/// TODO: Factor out a common base class for both formats. -class DWARFAcceleratorTable { +class AppleAcceleratorTable : public DWARFAcceleratorTable { struct Header { uint32_t Magic; uint16_t Version; uint16_t HashFunction; - uint32_t NumBuckets; - uint32_t NumHashes; + uint32_t BucketCount; + uint32_t HashCount; uint32_t HeaderDataLength; + + void dump(ScopedPrinter &W) const; }; struct HeaderData { @@ -40,22 +99,51 @@ class DWARFAcceleratorTable { uint32_t DIEOffsetBase; SmallVector<std::pair<AtomType, Form>, 3> Atoms; + + Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const; }; struct Header Hdr; struct HeaderData HdrData; - DWARFDataExtractor AccelSection; - DataExtractor StringSection; bool IsValid = false; + /// Returns true if we should continue scanning for entries or false if we've + /// reached the last (sentinel) entry of encountered a parsing error. + bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms, + uint32_t *DataOffset) const; + public: - /// An iterator for the entries associated with one key. Each entry can have - /// multiple DWARFFormValues. - class ValueIterator : public std::iterator<std::input_iterator_tag, - ArrayRef<DWARFFormValue>> { - const DWARFAcceleratorTable *AccelTable = nullptr; - SmallVector<DWARFFormValue, 3> AtomForms; ///< The decoded data entry. + /// Apple-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const HeaderData *HdrData = nullptr; + + Entry(const HeaderData &Data); + Entry() = default; + + void extract(const AppleAcceleratorTable &AccelTable, uint32_t *Offset); + + public: + Optional<uint64_t> getCUOffset() const override; + + /// Returns the Section Offset of the Debug Info Entry associated with this + /// Accelerator Entry or None if the DIE offset is not recorded in this + /// Accelerator Entry. The returned offset is relative to the start of the + /// Section containing the DIE. + Optional<uint64_t> getDIESectionOffset() const; + Optional<dwarf::Tag> getTag() const override; + + /// Returns the value of the Atom in this Accelerator Entry, if the Entry + /// contains such Atom. + Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const; + + friend class AppleAcceleratorTable; + friend class ValueIterator; + }; + + class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> { + const AppleAcceleratorTable *AccelTable = nullptr; + Entry Current; ///< The current entry. unsigned DataOffset = 0; ///< Offset into the section. unsigned Data = 0; ///< Current data entry. unsigned NumData = 0; ///< Number of data entries. @@ -64,13 +152,11 @@ public: void Next(); public: /// Construct a new iterator for the entries at \p DataOffset. - ValueIterator(const DWARFAcceleratorTable &AccelTable, unsigned DataOffset); + ValueIterator(const AppleAcceleratorTable &AccelTable, unsigned DataOffset); /// End marker. ValueIterator() = default; - const ArrayRef<DWARFFormValue> operator*() const { - return AtomForms; - } + const Entry &operator*() const { return Current; } ValueIterator &operator++() { Next(); return *this; } ValueIterator operator++(int) { ValueIterator I = *this; @@ -85,16 +171,18 @@ public: } }; - - DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, + AppleAcceleratorTable(const DWARFDataExtractor &AccelSection, DataExtractor StringSection) - : AccelSection(AccelSection), StringSection(StringSection) {} + : DWARFAcceleratorTable(AccelSection, StringSection) {} - llvm::Error extract(); + llvm::Error extract() override; uint32_t getNumBuckets(); uint32_t getNumHashes(); uint32_t getSizeHdr(); uint32_t getHeaderDataLength(); + + /// Return the Atom description, which can be used to interpret the raw values + /// of the Accelerator Entries in this table. ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc(); bool validateForms(); @@ -107,10 +195,404 @@ public: /// related to the input hash data offset. /// DieTag is the tag of the DIE std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset); - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS) const override; + + /// Look up all entries in the accelerator table matching \c Key. + iterator_range<ValueIterator> equal_range(StringRef Key) const; +}; + +/// .debug_names section consists of one or more units. Each unit starts with a +/// header, which is followed by a list of compilation units, local and foreign +/// type units. +/// +/// These may be followed by an (optional) hash lookup table, which consists of +/// an array of buckets and hashes similar to the apple tables above. The only +/// difference is that the hashes array is 1-based, and consequently an empty +/// bucket is denoted by 0 and not UINT32_MAX. +/// +/// Next is the name table, which consists of an array of names and array of +/// entry offsets. This is different from the apple tables, which store names +/// next to the actual entries. +/// +/// The structure of the entries is described by an abbreviations table, which +/// comes after the name table. Unlike the apple tables, which have a uniform +/// entry structure described in the header, each .debug_names entry may have +/// different index attributes (DW_IDX_???) attached to it. +/// +/// The last segment consists of a list of entries, which is a 0-terminated list +/// referenced by the name table and interpreted with the help of the +/// abbreviation table. +class DWARFDebugNames : public DWARFAcceleratorTable { + /// The fixed-size part of a Dwarf 5 Name Index header + struct HeaderPOD { + uint32_t UnitLength; + uint16_t Version; + uint16_t Padding; + uint32_t CompUnitCount; + uint32_t LocalTypeUnitCount; + uint32_t ForeignTypeUnitCount; + uint32_t BucketCount; + uint32_t NameCount; + uint32_t AbbrevTableSize; + uint32_t AugmentationStringSize; + }; + +public: + class NameIndex; + class NameIterator; + class ValueIterator; + + /// Dwarf 5 Name Index header. + struct Header : public HeaderPOD { + SmallString<8> AugmentationString; + + Error extract(const DWARFDataExtractor &AS, uint32_t *Offset); + void dump(ScopedPrinter &W) const; + }; + + /// Index attribute and its encoding. + struct AttributeEncoding { + dwarf::Index Index; + dwarf::Form Form; + + constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form) + : Index(Index), Form(Form) {} + + friend bool operator==(const AttributeEncoding &LHS, + const AttributeEncoding &RHS) { + return LHS.Index == RHS.Index && LHS.Form == RHS.Form; + } + }; + + /// Abbreviation describing the encoding of Name Index entries. + struct Abbrev { + uint32_t Code; ///< Abbreviation code + dwarf::Tag Tag; ///< Dwarf Tag of the described entity. + std::vector<AttributeEncoding> Attributes; ///< List of index attributes. + + Abbrev(uint32_t Code, dwarf::Tag Tag, + std::vector<AttributeEncoding> Attributes) + : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {} + + void dump(ScopedPrinter &W) const; + }; + + /// DWARF v5-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const NameIndex *NameIdx; + const Abbrev *Abbr; + + Entry(const NameIndex &NameIdx, const Abbrev &Abbr); + + public: + Optional<uint64_t> getCUOffset() const override; + Optional<dwarf::Tag> getTag() const override { return tag(); } + + /// Returns the Index into the Compilation Unit list of the owning Name + /// Index or None if this Accelerator Entry does not have an associated + /// Compilation Unit. It is up to the user to verify that the returned Index + /// is valid in the owning NameIndex (or use getCUOffset(), which will + /// handle that check itself). Note that entries in NameIndexes which index + /// just a single Compilation Unit are implicitly associated with that unit, + /// so this function will return 0 even without an explicit + /// DW_IDX_compile_unit attribute. + Optional<uint64_t> getCUIndex() const; + + /// .debug_names-specific getter, which always succeeds (DWARF v5 index + /// entries always have a tag). + dwarf::Tag tag() const { return Abbr->Tag; } + + /// Returns the Offset of the DIE within the containing CU or TU. + Optional<uint64_t> getDIEUnitOffset() const; + + /// Return the Abbreviation that can be used to interpret the raw values of + /// this Accelerator Entry. + const Abbrev &getAbbrev() const { return *Abbr; } + + /// Returns the value of the Index Attribute in this Accelerator Entry, if + /// the Entry contains such Attribute. + Optional<DWARFFormValue> lookup(dwarf::Index Index) const; + + void dump(ScopedPrinter &W) const; + + friend class NameIndex; + friend class ValueIterator; + }; + + /// Error returned by NameIndex::getEntry to report it has reached the end of + /// the entry list. + class SentinelError : public ErrorInfo<SentinelError> { + public: + static char ID; + + void log(raw_ostream &OS) const override { OS << "Sentinel"; } + std::error_code convertToErrorCode() const override; + }; + +private: + /// DenseMapInfo for struct Abbrev. + struct AbbrevMapInfo { + static Abbrev getEmptyKey(); + static Abbrev getTombstoneKey(); + static unsigned getHashValue(uint32_t Code) { + return DenseMapInfo<uint32_t>::getHashValue(Code); + } + static unsigned getHashValue(const Abbrev &Abbr) { + return getHashValue(Abbr.Code); + } + static bool isEqual(uint32_t LHS, const Abbrev &RHS) { + return LHS == RHS.Code; + } + static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) { + return LHS.Code == RHS.Code; + } + }; + +public: + /// A single entry in the Name Table (Dwarf 5 sect. 6.1.1.4.6) of the Name + /// Index. + class NameTableEntry { + DataExtractor StrData; + + uint32_t Index; + uint32_t StringOffset; + uint32_t EntryOffset; + + public: + NameTableEntry(const DataExtractor &StrData, uint32_t Index, + uint32_t StringOffset, uint32_t EntryOffset) + : StrData(StrData), Index(Index), StringOffset(StringOffset), + EntryOffset(EntryOffset) {} + + /// Return the index of this name in the parent Name Index. + uint32_t getIndex() const { return Index; } + + /// Returns the offset of the name of the described entities. + uint32_t getStringOffset() const { return StringOffset; } + + /// Return the string referenced by this name table entry or nullptr if the + /// string offset is not valid. + const char *getString() const { + uint32_t Off = StringOffset; + return StrData.getCStr(&Off); + } + + /// Returns the offset of the first Entry in the list. + uint32_t getEntryOffset() const { return EntryOffset; } + }; + + /// Represents a single accelerator table within the Dwarf 5 .debug_names + /// section. + class NameIndex { + DenseSet<Abbrev, AbbrevMapInfo> Abbrevs; + struct Header Hdr; + const DWARFDebugNames &Section; + + // Base of the whole unit and of various important tables, as offsets from + // the start of the section. + uint32_t Base; + uint32_t CUsBase; + uint32_t BucketsBase; + uint32_t HashesBase; + uint32_t StringOffsetsBase; + uint32_t EntryOffsetsBase; + uint32_t EntriesBase; + + void dumpCUs(ScopedPrinter &W) const; + void dumpLocalTUs(ScopedPrinter &W) const; + void dumpForeignTUs(ScopedPrinter &W) const; + void dumpAbbreviations(ScopedPrinter &W) const; + bool dumpEntry(ScopedPrinter &W, uint32_t *Offset) const; + void dumpName(ScopedPrinter &W, const NameTableEntry &NTE, + Optional<uint32_t> Hash) const; + void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const; + + Expected<AttributeEncoding> extractAttributeEncoding(uint32_t *Offset); + + Expected<std::vector<AttributeEncoding>> + extractAttributeEncodings(uint32_t *Offset); + + Expected<Abbrev> extractAbbrev(uint32_t *Offset); + + public: + NameIndex(const DWARFDebugNames &Section, uint32_t Base) + : Section(Section), Base(Base) {} + + /// Reads offset of compilation unit CU. CU is 0-based. + uint32_t getCUOffset(uint32_t CU) const; + uint32_t getCUCount() const { return Hdr.CompUnitCount; } + + /// Reads offset of local type unit TU, TU is 0-based. + uint32_t getLocalTUOffset(uint32_t TU) const; + uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; } + + /// Reads signature of foreign type unit TU. TU is 0-based. + uint64_t getForeignTUSignature(uint32_t TU) const; + uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; } + + /// Reads an entry in the Bucket Array for the given Bucket. The returned + /// value is a (1-based) index into the Names, StringOffsets and + /// EntryOffsets arrays. The input Bucket index is 0-based. + uint32_t getBucketArrayEntry(uint32_t Bucket) const; + uint32_t getBucketCount() const { return Hdr.BucketCount; } + + /// Reads an entry in the Hash Array for the given Index. The input Index + /// is 1-based. + uint32_t getHashArrayEntry(uint32_t Index) const; + + /// Reads an entry in the Name Table for the given Index. The Name Table + /// consists of two arrays -- String Offsets and Entry Offsets. The returned + /// offsets are relative to the starts of respective sections. Input Index + /// is 1-based. + NameTableEntry getNameTableEntry(uint32_t Index) const; + + uint32_t getNameCount() const { return Hdr.NameCount; } + + const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const { + return Abbrevs; + } + + Expected<Entry> getEntry(uint32_t *Offset) const; + + /// Look up all entries in this Name Index matching \c Key. + iterator_range<ValueIterator> equal_range(StringRef Key) const; + + NameIterator begin() const { return NameIterator(this, 1); } + NameIterator end() const { return NameIterator(this, getNameCount() + 1); } + + llvm::Error extract(); + uint32_t getUnitOffset() const { return Base; } + uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; } + void dump(ScopedPrinter &W) const; + + friend class DWARFDebugNames; + }; + + class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> { + + /// The Name Index we are currently iterating through. The implementation + /// relies on the fact that this can also be used as an iterator into the + /// "NameIndices" vector in the Accelerator section. + const NameIndex *CurrentIndex = nullptr; + + /// Whether this is a local iterator (searches in CurrentIndex only) or not + /// (searches all name indices). + bool IsLocal; + + Optional<Entry> CurrentEntry; + unsigned DataOffset = 0; ///< Offset into the section. + std::string Key; ///< The Key we are searching for. + Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed. + + bool getEntryAtCurrentOffset(); + Optional<uint32_t> findEntryOffsetInCurrentIndex(); + bool findInCurrentIndex(); + void searchFromStartOfCurrentIndex(); + void next(); + + /// Set the iterator to the "end" state. + void setEnd() { *this = ValueIterator(); } + + public: + /// Create a "begin" iterator for looping over all entries in the + /// accelerator table matching Key. The iterator will run through all Name + /// Indexes in the section in sequence. + ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key); + + /// Create a "begin" iterator for looping over all entries in a specific + /// Name Index. Other indices in the section will not be visited. + ValueIterator(const NameIndex &NI, StringRef Key); + + /// End marker. + ValueIterator() = default; + + const Entry &operator*() const { return *CurrentEntry; } + ValueIterator &operator++() { + next(); + return *this; + } + ValueIterator operator++(int) { + ValueIterator I = *this; + next(); + return I; + } + + friend bool operator==(const ValueIterator &A, const ValueIterator &B) { + return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset; + } + friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { + return !(A == B); + } + }; + + class NameIterator { + + /// The Name Index we are iterating through. + const NameIndex *CurrentIndex; + + /// The current name in the Name Index. + uint32_t CurrentName; + + void next() { + assert(CurrentName <= CurrentIndex->getNameCount()); + ++CurrentName; + } + + public: + using iterator_category = std::input_iterator_tag; + using value_type = NameTableEntry; + using difference_type = uint32_t; + using pointer = NameTableEntry *; + using reference = NameTableEntry; // We return entries by value. + + /// Creates an iterator whose initial position is name CurrentName in + /// CurrentIndex. + NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName) + : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {} + + NameTableEntry operator*() const { + return CurrentIndex->getNameTableEntry(CurrentName); + } + NameIterator &operator++() { + next(); + return *this; + } + NameIterator operator++(int) { + NameIterator I = *this; + next(); + return I; + } + + friend bool operator==(const NameIterator &A, const NameIterator &B) { + return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName; + } + friend bool operator!=(const NameIterator &A, const NameIterator &B) { + return !(A == B); + } + }; + +private: + SmallVector<NameIndex, 0> NameIndices; + DenseMap<uint32_t, const NameIndex *> CUToNameIndex; + +public: + DWARFDebugNames(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : DWARFAcceleratorTable(AccelSection, StringSection) {} + + llvm::Error extract() override; + void dump(raw_ostream &OS) const override; /// Look up all entries in the accelerator table matching \c Key. iterator_range<ValueIterator> equal_range(StringRef Key) const; + + using const_iterator = SmallVector<NameIndex, 0>::const_iterator; + const_iterator begin() const { return NameIndices.begin(); } + const_iterator end() const { return NameIndices.end(); } + + /// Return the Name Index covering the compile unit at CUOffset, or nullptr if + /// there is no Name Index covering that unit. + const NameIndex *getCUNameIndex(uint32_t CUOffset); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h b/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h new file mode 100644 index 000000000000..5a7df5c353e8 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h @@ -0,0 +1,68 @@ +//===- DWARFAddressRange.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_DWARF_DWARFADDRESSRANGE_H +#define LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H + +#include "llvm/DebugInfo/DIContext.h" +#include <cstdint> +#include <tuple> +#include <vector> + +namespace llvm { + +class raw_ostream; + +struct DWARFAddressRange { + uint64_t LowPC; + uint64_t HighPC; + uint64_t SectionIndex; + + DWARFAddressRange() = default; + + /// Used for unit testing. + DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) + : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} + + /// Returns true if LowPC is smaller or equal to HighPC. This accounts for + /// dead-stripped ranges. + bool valid() const { return LowPC <= HighPC; } + + /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). + bool intersects(const DWARFAddressRange &RHS) const { + assert(valid() && RHS.valid()); + // Empty ranges can't intersect. + if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) + return false; + return LowPC < RHS.HighPC && RHS.LowPC < HighPC; + } + + /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). + bool contains(const DWARFAddressRange &RHS) const { + assert(valid() && RHS.valid()); + return LowPC <= RHS.LowPC && RHS.HighPC <= HighPC; + } + + void dump(raw_ostream &OS, uint32_t AddressSize, + DIDumpOptions DumpOpts = {}) const; +}; + +static inline bool operator<(const DWARFAddressRange &LHS, + const DWARFAddressRange &RHS) { + return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); +} + +raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); + +/// DWARFAddressRangesVector - represents a set of absolute address ranges. +using DWARFAddressRangesVector = std::vector<DWARFAddressRange>; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index a18adf87bf8e..c219ca75e640 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -18,13 +18,13 @@ namespace llvm { class DWARFCompileUnit : public DWARFUnit { public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, - bool IsDWO, const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + bool IsDWO, const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} // VTable anchor. ~DWARFCompileUnit() override; diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index 2ddbc4b91ba2..fe7430c9f04c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -34,6 +34,7 @@ #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Error.h" #include "llvm/Support/Host.h" #include <cstdint> @@ -43,7 +44,6 @@ namespace llvm { -class DataExtractor; class MCRegisterInfo; class MemoryBuffer; class raw_ostream; @@ -69,10 +69,11 @@ class DWARFContext : public DIContext { std::unique_ptr<DWARFDebugFrame> DebugFrame; std::unique_ptr<DWARFDebugFrame> EHFrame; std::unique_ptr<DWARFDebugMacro> Macro; - std::unique_ptr<DWARFAcceleratorTable> AppleNames; - std::unique_ptr<DWARFAcceleratorTable> AppleTypes; - std::unique_ptr<DWARFAcceleratorTable> AppleNamespaces; - std::unique_ptr<DWARFAcceleratorTable> AppleObjC; + std::unique_ptr<DWARFDebugNames> Names; + std::unique_ptr<AppleAcceleratorTable> AppleNames; + std::unique_ptr<AppleAcceleratorTable> AppleTypes; + std::unique_ptr<AppleAcceleratorTable> AppleNamespaces; + std::unique_ptr<AppleAcceleratorTable> AppleObjC; DWARFUnitSection<DWARFCompileUnit> DWOCUs; std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; @@ -204,6 +205,9 @@ public: DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); + /// Return the compile unit that includes an offset (relative to .debug_info). + DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); + /// Get a DIE given an exact offset. DWARFDie getDIEForOffset(uint32_t Offset); @@ -243,19 +247,36 @@ public: const DWARFDebugMacro *getDebugMacro(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleNames(); + const DWARFDebugNames &getDebugNames(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleTypes(); + const AppleAcceleratorTable &getAppleNames(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleNamespaces(); + const AppleAcceleratorTable &getAppleTypes(); /// Get a reference to the parsed accelerator table object. - const DWARFAcceleratorTable &getAppleObjC(); + const AppleAcceleratorTable &getAppleNamespaces(); + + /// Get a reference to the parsed accelerator table object. + const AppleAcceleratorTable &getAppleObjC(); + + /// Get a pointer to a parsed line table corresponding to a compile unit. + /// Report any parsing issues as warnings on stderr. + const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U); /// Get a pointer to a parsed line table corresponding to a compile unit. - const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *cu); + /// Report any recoverable parsing problems using the callback. + Expected<const DWARFDebugLine::LineTable *> + getLineTableForUnit(DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback); + + DataExtractor getStringExtractor() const { + return DataExtractor(DObj->getStringSection(), false, 0); + } + DataExtractor getLineStringExtractor() const { + return DataExtractor(DObj->getLineStringSection(), false, 0); + } /// Wraps the returned DIEs for a given address. struct DIEsForAddress { @@ -303,9 +324,6 @@ public: Error loadRegisterInfo(const object::ObjectFile &Obj); private: - /// Return the compile unit that includes an offset (relative to .debug_info). - DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); - /// Return the compile unit which contains instruction with provided /// address. DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); diff --git a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index a379d9c85b38..10e146b70ec7 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -44,6 +44,13 @@ public: uint64_t getRelocatedAddress(uint32_t *Off, uint64_t *SecIx = nullptr) const { return getRelocatedValue(getAddressSize(), Off, SecIx); } + + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. + /// There is a DWARF encoding that uses a PC-relative adjustment. + /// For these values, \p AbsPosOffset is used to fix them, which should + /// reflect the absolute address of this pointer. + Optional<uint64_t> getEncodedPointer(uint32_t *Offset, uint8_t Encoding, + uint64_t AbsPosOffset = 0) const; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h index dfbbb95076e8..ab46fac39f7c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -43,6 +43,7 @@ public: uint64_t Length; uint64_t getEndAddress() const { return Address + Length; } + void dump(raw_ostream &OS, uint32_t AddressSize) const; }; private: diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index a711fb295444..ff1c7fb38389 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -10,40 +10,290 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H -#include "llvm/Support/DataExtractor.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/Support/Error.h" #include <memory> #include <vector> namespace llvm { -class FrameEntry; class raw_ostream; -/// \brief A parsed .debug_frame or .eh_frame section -/// +namespace dwarf { + +/// Represent a sequence of Call Frame Information instructions that, when read +/// in order, construct a table mapping PC to frame state. This can also be +/// referred to as "CFI rules" in DWARF literature to avoid confusion with +/// computer programs in the broader sense, and in this context each instruction +/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5 +/// manual, "6.4.1 Structure of Call Frame Information". +class CFIProgram { +public: + typedef SmallVector<uint64_t, 2> Operands; + + /// An instruction consists of a DWARF CFI opcode and an optional sequence of + /// operands. If it refers to an expression, then this expression has its own + /// sequence of operations and operands handled separately by DWARFExpression. + struct Instruction { + Instruction(uint8_t Opcode) : Opcode(Opcode) {} + + uint8_t Opcode; + Operands Ops; + // Associated DWARF expression in case this instruction refers to one + Optional<DWARFExpression> Expression; + }; + + using InstrList = std::vector<Instruction>; + using iterator = InstrList::iterator; + using const_iterator = InstrList::const_iterator; + + iterator begin() { return Instructions.begin(); } + const_iterator begin() const { return Instructions.begin(); } + iterator end() { return Instructions.end(); } + const_iterator end() const { return Instructions.end(); } + + unsigned size() const { return (unsigned)Instructions.size(); } + bool empty() const { return Instructions.empty(); } + + CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor) + : CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor) {} + + /// Parse and store a sequence of CFI instructions from Data, + /// starting at *Offset and ending at EndOffset. *Offset is updated + /// to EndOffset upon successful parsing, or indicates the offset + /// where a problem occurred in case an error is returned. + Error parse(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset); + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, + unsigned IndentLevel = 1) const; + +private: + std::vector<Instruction> Instructions; + const uint64_t CodeAlignmentFactor; + const int64_t DataAlignmentFactor; + + /// Convenience method to add a new instruction with the given opcode. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + /// Add a new single-operand instruction. + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + /// Add a new instruction that has two operands. + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } + + /// Types of operands to CFI instructions + /// In DWARF, this type is implicitly tied to a CFI instruction opcode and + /// thus this type doesn't need to be explictly written to the file (this is + /// not a DWARF encoding). The relationship of instrs to operand types can + /// be obtained from getOperandTypes() and is only used to simplify + /// instruction printing. + enum OperandType { + OT_Unset, + OT_None, + OT_Address, + OT_Offset, + OT_FactoredCodeOffset, + OT_SignedFactDataOffset, + OT_UnsignedFactDataOffset, + OT_Register, + OT_Expression + }; + + /// Retrieve the array describing the types of operands according to the enum + /// above. This is indexed by opcode. + static ArrayRef<OperandType[2]> getOperandTypes(); + + /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. + void printOperand(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, + const Instruction &Instr, unsigned OperandIdx, + uint64_t Operand) const; +}; + +/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an +/// FDE. +class FrameEntry { +public: + enum FrameKind { FK_CIE, FK_FDE }; + + FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign, + int64_t DataAlign) + : Kind(K), Offset(Offset), Length(Length), CFIs(CodeAlign, DataAlign) {} + + virtual ~FrameEntry() {} + + FrameKind getKind() const { return Kind; } + uint64_t getOffset() const { return Offset; } + uint64_t getLength() const { return Length; } + const CFIProgram &cfis() const { return CFIs; } + CFIProgram &cfis() { return CFIs; } + + /// Dump the instructions in this CFI fragment + virtual void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const = 0; + +protected: + const FrameKind Kind; + + /// Offset of this entry in the section. + const uint64_t Offset; + + /// Entry length as specified in DWARF. + const uint64_t Length; + + CFIProgram CFIs; +}; + +/// DWARF Common Information Entry (CIE) +class CIE : public FrameEntry { +public: + // CIEs (and FDEs) are simply container classes, so the only sensible way to + // create them is by providing the full parsed contents in the constructor. + CIE(uint64_t Offset, uint64_t Length, uint8_t Version, + SmallString<8> Augmentation, uint8_t AddressSize, + uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor, + int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister, + SmallString<8> AugmentationData, uint32_t FDEPointerEncoding, + uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality, + Optional<uint32_t> PersonalityEnc) + : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor, + DataAlignmentFactor), + Version(Version), Augmentation(std::move(Augmentation)), + AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize), + CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister), + AugmentationData(std::move(AugmentationData)), + FDEPointerEncoding(FDEPointerEncoding), + LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality), + PersonalityEnc(PersonalityEnc) {} + + static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; } + + StringRef getAugmentationString() const { return Augmentation; } + uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } + int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } + uint8_t getVersion() const { return Version; } + uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; } + Optional<uint64_t> getPersonalityAddress() const { return Personality; } + Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; } + + uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; } + + uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; } + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const override; + +private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v4 + const uint8_t Version; + const SmallString<8> Augmentation; + const uint8_t AddressSize; + const uint8_t SegmentDescriptorSize; + const uint64_t CodeAlignmentFactor; + const int64_t DataAlignmentFactor; + const uint64_t ReturnAddressRegister; + + // The following are used when the CIE represents an EH frame entry. + const SmallString<8> AugmentationData; + const uint32_t FDEPointerEncoding; + const uint32_t LSDAPointerEncoding; + const Optional<uint64_t> Personality; + const Optional<uint32_t> PersonalityEnc; +}; + +/// DWARF Frame Description Entry (FDE) +class FDE : public FrameEntry { +public: + // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with + // an offset to the CIE (provided by parsing the FDE header). The CIE itself + // is obtained lazily once it's actually required. + FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, + uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie, + Optional<uint64_t> LSDAAddress) + : FrameEntry(FK_FDE, Offset, Length, + Cie ? Cie->getCodeAlignmentFactor() : 0, + Cie ? Cie->getDataAlignmentFactor() : 0), + LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation), + AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {} + + ~FDE() override = default; + + const CIE *getLinkedCIE() const { return LinkedCIE; } + uint64_t getInitialLocation() const { return InitialLocation; } + uint64_t getAddressRange() const { return AddressRange; } + Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; } + + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + bool IsEH) const override; + + static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; } + +private: + /// The following fields are defined in section 6.4.1 of the DWARF standard v3 + const uint64_t LinkedCIEOffset; + const uint64_t InitialLocation; + const uint64_t AddressRange; + const CIE *LinkedCIE; + const Optional<uint64_t> LSDAAddress; +}; + +} // end namespace dwarf + +/// A parsed .debug_frame or .eh_frame section class DWARFDebugFrame { // True if this is parsing an eh_frame section. - bool IsEH; + const bool IsEH; + // Not zero for sane pointer values coming out of eh_frame + const uint64_t EHFrameAddress; + + std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries; + using iterator = pointee_iterator<decltype(Entries)::const_iterator>; + + /// Return the entry at the given offset or nullptr. + dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const; public: - DWARFDebugFrame(bool IsEH); + // If IsEH is true, assume it is a .eh_frame section. Otherwise, + // it is a .debug_frame section. EHFrameAddress should be different + // than zero for correct parsing of .eh_frame addresses when they + // use a PC-relative encoding. + DWARFDebugFrame(bool IsEH = false, uint64_t EHFrameAddress = 0); ~DWARFDebugFrame(); /// Dump the section data into the given stream. - void dump(raw_ostream &OS, Optional<uint64_t> Offset) const; + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + Optional<uint64_t> Offset) const; - /// \brief Parse the section from raw data. - /// data is assumed to be pointing to the beginning of the section. - void parse(DataExtractor Data); + /// Parse the section from raw data. \p Data is assumed to contain the whole + /// frame section contents to be parsed. + void parse(DWARFDataExtractor Data); /// Return whether the section has any entries. bool empty() const { return Entries.empty(); } - /// Return the entry at the given offset or nullptr. - FrameEntry *getEntryAtOffset(uint64_t Offset) const; + /// DWARF Frame entries accessors + iterator begin() const { return Entries.begin(); } + iterator end() const { return Entries.end(); } + iterator_range<iterator> entries() const { + return iterator_range<iterator>(Entries.begin(), Entries.end()); + } -private: - std::vector<std::unique_ptr<FrameEntry>> Entries; + uint64_t getEHFrameAddress() const { return EHFrameAddress; } }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index de8ad4e5ef3c..5b2af34bbcf5 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -10,11 +10,14 @@ #ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H #define LLVM_DEBUGINFO_DWARFDEBUGLINE_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" #include "llvm/Support/MD5.h" #include <cstdint> #include <map> @@ -31,11 +34,30 @@ public: struct FileNameEntry { FileNameEntry() = default; - StringRef Name; + DWARFFormValue Name; uint64_t DirIdx = 0; uint64_t ModTime = 0; uint64_t Length = 0; MD5::MD5Result Checksum; + DWARFFormValue Source; + }; + + /// Tracks which optional content types are present in a DWARF file name + /// entry format. + struct ContentTypeTracker { + ContentTypeTracker() = default; + + /// Whether filename entries provide a modification timestamp. + bool HasModTime = false; + /// Whether filename entries provide a file size. + bool HasLength = false; + /// For v5, whether filename entries provide an MD5 checksum. + bool HasMD5 = false; + /// For v5, whether filename entries provide source text. + bool HasSource = false; + + /// Update tracked content types with \p ContentType. + void trackContentType(dwarf::LineNumberEntryFormat ContentType); }; struct Prologue { @@ -47,7 +69,7 @@ public: /// Version, address size (starting in v5), and DWARF32/64 format; these /// parameters affect interpretation of forms (used in the directory and /// file tables starting with v5). - DWARFFormParams FormParams; + dwarf::FormParams FormParams; /// The number of bytes following the prologue_length field to the beginning /// of the first byte of the statement program itself. uint64_t PrologueLength; @@ -68,13 +90,13 @@ public: uint8_t LineRange; /// The number assigned to the first special opcode. uint8_t OpcodeBase; - /// For v5, whether filename entries provide an MD5 checksum. - bool HasMD5; + /// This tracks which optional file format content types are present. + ContentTypeTracker ContentTypes; std::vector<uint8_t> StandardOpcodeLengths; - std::vector<StringRef> IncludeDirectories; + std::vector<DWARFFormValue> IncludeDirectories; std::vector<FileNameEntry> FileNames; - const DWARFFormParams getFormParams() const { return FormParams; } + const dwarf::FormParams getFormParams() const { return FormParams; } uint16_t getVersion() const { return FormParams.Version; } uint8_t getAddressSize() const { return FormParams.AddrSize; } bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; } @@ -83,6 +105,8 @@ public: uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; } + bool totalLengthIsValid() const; + /// Length of the prologue in bytes. uint32_t getLength() const { return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) + @@ -99,9 +123,9 @@ public: } void clear(); - void dump(raw_ostream &OS) const; - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - const DWARFUnit *U = nullptr); + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; + Error parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U = nullptr); }; /// Standard .debug_line state machine structure. @@ -219,12 +243,14 @@ public: DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const; - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; void clear(); /// Parse prologue and all rows. - bool parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - const DWARFUnit *U, raw_ostream *OS = nullptr); + Error parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback = warn, + raw_ostream *OS = nullptr); using RowVector = std::vector<Row>; using RowIter = RowVector::const_iterator; @@ -238,11 +264,75 @@ public: private: uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq, uint64_t Address) const; + Optional<StringRef> + getSourceByIndex(uint64_t FileIndex, + DILineInfoSpecifier::FileLineInfoKind Kind) const; }; const LineTable *getLineTable(uint32_t Offset) const; - const LineTable *getOrParseLineTable(DWARFDataExtractor &DebugLineData, - uint32_t Offset, const DWARFUnit *U); + Expected<const LineTable *> getOrParseLineTable( + DWARFDataExtractor &DebugLineData, uint32_t Offset, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback = warn); + + /// Helper to allow for parsing of an entire .debug_line section in sequence. + class SectionParser { + public: + using cu_range = DWARFUnitSection<DWARFCompileUnit>::iterator_range; + using tu_range = + iterator_range<std::deque<DWARFUnitSection<DWARFTypeUnit>>::iterator>; + using LineToUnitMap = std::map<uint64_t, DWARFUnit *>; + + SectionParser(DWARFDataExtractor &Data, const DWARFContext &C, cu_range CUs, + tu_range TUs); + + /// Get the next line table from the section. Report any issues via the + /// callbacks. + /// + /// \param RecoverableErrorCallback - any issues that don't prevent further + /// parsing of the table will be reported through this callback. + /// \param UnrecoverableErrorCallback - any issues that prevent further + /// parsing of the table will be reported through this callback. + /// \param OS - if not null, the parser will print information about the + /// table as it parses it. + LineTable + parseNext(function_ref<void(Error)> RecoverableErrorCallback = warn, + function_ref<void(Error)> UnrecoverableErrorCallback = warn, + raw_ostream *OS = nullptr); + + /// Skip the current line table and go to the following line table (if + /// present) immediately. + /// + /// \param ErrorCallback - report any prologue parsing issues via this + /// callback. + void skip(function_ref<void(Error)> ErrorCallback = warn); + + /// Indicates if the parser has parsed as much as possible. + /// + /// \note Certain problems with the line table structure might mean that + /// parsing stops before the end of the section is reached. + bool done() const { return Done; } + + /// Get the offset the parser has reached. + uint32_t getOffset() const { return Offset; } + + private: + DWARFUnit *prepareToParse(uint32_t Offset); + void moveToNextTable(uint32_t OldOffset, const Prologue &P); + + LineToUnitMap LineToUnit; + + DWARFDataExtractor &DebugLineData; + const DWARFContext &Context; + uint32_t Offset = 0; + bool Done = false; + }; + + /// Helper function for DWARFDebugLine parse functions, to report issues + /// identified during parsing. + /// + /// \param Err The Error to report. + static void warn(Error Err); private: struct ParsingState { diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index a6d319a90457..9a73745fb6b4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -42,7 +42,8 @@ public: SmallVector<Entry, 2> Entries; /// Dump this list on OS. void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, - const MCRegisterInfo *MRI, unsigned Indent) const; + const MCRegisterInfo *MRI, uint64_t BaseAddress, + unsigned Indent) const; }; private: diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h index 761871dc6255..cae4804e61d3 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -32,7 +32,7 @@ public: /// The name of the object as given by the DW_AT_name attribute of the /// referenced DIE. - const char *Name; + StringRef Name; }; /// Each table consists of sets of variable length entries. Each set describes diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h index f9ec96366a53..ce7436d9faa3 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -10,8 +10,8 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include <cassert> #include <cstdint> #include <vector> @@ -21,47 +21,6 @@ namespace llvm { struct BaseAddress; class raw_ostream; -struct DWARFAddressRange { - uint64_t LowPC; - uint64_t HighPC; - uint64_t SectionIndex; - - DWARFAddressRange() = default; - - /// Used for unit testing. - DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) - : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} - - /// Returns true if LowPC is smaller or equal to HighPC. This accounts for - /// dead-stripped ranges. - bool valid() const { return LowPC <= HighPC; } - - /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). - bool intersects(const DWARFAddressRange &RHS) const { - // Empty ranges can't intersect. - if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) - return false; - return (LowPC < RHS.HighPC) && (HighPC > RHS.LowPC); - } - - /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). - bool contains(const DWARFAddressRange &RHS) const { - if (LowPC <= RHS.LowPC && RHS.LowPC <= HighPC) - return LowPC <= RHS.HighPC && RHS.HighPC <= HighPC; - return false; - } -}; - -static inline bool operator<(const DWARFAddressRange &LHS, - const DWARFAddressRange &RHS) { - return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); -} - -raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); - -/// DWARFAddressRangesVector - represents a set of absolute address ranges. -using DWARFAddressRangesVector = std::vector<DWARFAddressRange>; - class DWARFDebugRangeList { public: struct RangeListEntry { @@ -112,7 +71,7 @@ public: void clear(); void dump(raw_ostream &OS) const; - bool extract(const DWARFDataExtractor &data, uint32_t *offset_ptr); + Error extract(const DWARFDataExtractor &data, uint32_t *offset_ptr); const std::vector<RangeListEntry> &getEntries() { return Entries; } /// getAbsoluteRanges - Returns absolute address ranges defined by this range diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h new file mode 100644 index 000000000000..e2e8ab5ed219 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -0,0 +1,60 @@ +//===- DWARFDebugRnglists.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_DWARFDEBUGRNGLISTS_H +#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFListTable.h" +#include <cstdint> +#include <map> +#include <vector> + +namespace llvm { + +class Error; +class raw_ostream; + +/// 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: + /// Build a DWARFAddressRangesVector from a rangelist. + DWARFAddressRangesVector + getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const; +}; + +class DWARFDebugRnglistTable : public DWARFListTableBase<DWARFDebugRnglist> { +public: + DWARFDebugRnglistTable() + : DWARFListTableBase(/* SectionName = */ ".debug_rnglists", + /* HeaderString = */ "ranges:", + /* ListTypeString = */ "range") {} +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H diff --git a/include/llvm/DebugInfo/DWARF/DWARFDie.h b/include/llvm/DebugInfo/DWARF/DWARFDie.h index 75fc5995c5b2..6e6b57cbcbd4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -16,9 +16,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include <cassert> #include <cstdint> #include <iterator> @@ -104,12 +104,24 @@ public: /// invalid DWARFDie instance if it doesn't. DWARFDie getSibling() const; + /// Get the previous sibling of this DIE object. + /// + /// \returns a valid DWARFDie instance if this object has a sibling or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getPreviousSibling() const; + /// Get the first child of this DIE object. /// /// \returns a valid DWARFDie instance if this object has children or an /// invalid DWARFDie instance if it doesn't. DWARFDie getFirstChild() const; + /// Get the last child of this DIE object. + /// + /// \returns a valid null DWARFDie instance if this object has children or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getLastChild() const; + /// Dump the DIE and all of its attributes to the supplied stream. /// /// \param OS the stream to use for output. @@ -207,7 +219,7 @@ public: /// /// \returns a address range vector that might be empty if no address range /// information is available. - DWARFAddressRangesVector getAddressRanges() const; + Expected<DWARFAddressRangesVector> getAddressRanges() const; /// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any /// of its children. @@ -288,6 +300,7 @@ public: explicit attribute_iterator(DWARFDie D, bool End); attribute_iterator &operator++(); + attribute_iterator &operator--(); explicit operator bool() const { return AttrValue.isValid(); } const DWARFAttribute &operator*() const { return AttrValue; } bool operator==(const attribute_iterator &X) const { return Index == X.Index; } @@ -306,26 +319,23 @@ inline bool operator<(const DWARFDie &LHS, const DWARFDie &RHS) { return LHS.getOffset() < RHS.getOffset(); } -class DWARFDie::iterator : public iterator_facade_base<iterator, - std::forward_iterator_tag, - const DWARFDie> { +class DWARFDie::iterator + : public iterator_facade_base<iterator, std::bidirectional_iterator_tag, + const DWARFDie> { DWARFDie Die; - void skipNull() { - if (Die && Die.isNULL()) - Die = DWARFDie(); - } public: iterator() = default; explicit iterator(DWARFDie D) : Die(D) { - // If we start out with only a Null DIE then invalidate. - skipNull(); } iterator &operator++() { Die = Die.getSibling(); - // Don't include the NULL die when iterating. - skipNull(); + return *this; + } + + iterator &operator--() { + Die = Die.getPreviousSibling(); return *this; } @@ -341,7 +351,7 @@ inline DWARFDie::iterator DWARFDie::begin() const { } inline DWARFDie::iterator DWARFDie::end() const { - return iterator(); + return iterator(getLastChild()); } inline iterator_range<DWARFDie::iterator> DWARFDie::children() const { diff --git a/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/include/llvm/DebugInfo/DWARF/DWARFExpression.h index dcd486f3fb13..3fad68a9b48b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFExpression.h +++ b/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -93,12 +93,13 @@ public: /// An iterator to go through the expression operations. class iterator - : public iterator_facade_base<iterator, std::forward_iterator_tag, Operation> { + : public iterator_facade_base<iterator, std::forward_iterator_tag, + Operation> { friend class DWARFExpression; - DWARFExpression *Expr; + const DWARFExpression *Expr; uint32_t Offset; Operation Op; - iterator(DWARFExpression *Expr, uint32_t Offset) + iterator(const DWARFExpression *Expr, uint32_t Offset) : Expr(Expr), Offset(Offset) { Op.Error = Offset >= Expr->Data.getData().size() || @@ -127,10 +128,11 @@ public: assert(AddressSize == 8 || AddressSize == 4); } - iterator begin() { return iterator(this, 0); } - iterator end() { return iterator(this, Data.getData().size()); } + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, Data.getData().size()); } - void print(raw_ostream &OS, const MCRegisterInfo *RegInfo); + void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, + bool IsEH = false) const; private: DataExtractor Data; diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index d32053519ec4..1b5f71c946f9 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -20,38 +20,10 @@ namespace llvm { +class DWARFContext; class DWARFUnit; class raw_ostream; -/// A helper struct for DWARFFormValue methods, providing information that -/// allows it to know the byte size of DW_FORM values that vary in size -/// depending on the DWARF version, address byte size, or DWARF32/DWARF64. -struct DWARFFormParams { - uint16_t Version; - uint8_t AddrSize; - dwarf::DwarfFormat Format; - - /// The definition of the size of form DW_FORM_ref_addr depends on the - /// version. In DWARF v2 it's the size of an address; after that, it's the - /// size of a reference. - uint8_t getRefAddrByteSize() const { - if (Version == 2) - return AddrSize; - return getDwarfOffsetByteSize(); - } - - /// The size of a reference is determined by the DWARF 32/64-bit format. - uint8_t getDwarfOffsetByteSize() const { - switch (Format) { - case dwarf::DwarfFormat::DWARF32: - return 4; - case dwarf::DwarfFormat::DWARF64: - return 8; - } - llvm_unreachable("Invalid Format value"); - } -}; - class DWARFFormValue { public: enum FormClass { @@ -83,7 +55,7 @@ private: dwarf::Form Form; /// Form for this value. ValueType Value; /// Contains all data for the form. const DWARFUnit *U = nullptr; /// Remember the DWARFUnit at extract time. - + const DWARFContext *C = nullptr; /// Context for extract time. public: DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} @@ -106,10 +78,17 @@ public: /// Extracts a value in \p Data at offset \p *OffsetPtr. The information /// in \p FormParams is needed to interpret some forms. The optional - /// \p Unit allows extracting information if the form refers to other - /// sections (e.g., .debug_str). + /// \p Context and \p Unit allows extracting information if the form refers + /// to other sections (e.g., .debug_str). bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, - DWARFFormParams FormParams, const DWARFUnit *U = nullptr); + dwarf::FormParams FormParams, + const DWARFContext *Context = nullptr, + const DWARFUnit *Unit = nullptr); + + bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, + dwarf::FormParams FormParams, const DWARFUnit *U) { + return extractValue(Data, OffsetPtr, FormParams, nullptr, U); + } bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; @@ -127,19 +106,6 @@ public: Optional<uint64_t> getAsCStringOffset() const; Optional<uint64_t> getAsReferenceUVal() const; - /// Get the fixed byte size for a given form. - /// - /// If the form has a fixed byte size, then an Optional with a value will be - /// returned. If the form is always encoded using a variable length storage - /// format (ULEB or SLEB numbers or blocks) then None will be returned. - /// - /// \param Form DWARF form to get the fixed byte size for. - /// \param FormParams DWARF parameters to help interpret forms. - /// \returns Optional<uint8_t> value with the fixed byte size or None if - /// \p Form doesn't have a fixed byte size. - static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, - const DWARFFormParams FormParams); - /// Skip a form's value in \p DebugInfoData at the offset specified by /// \p OffsetPtr. /// @@ -150,7 +116,7 @@ public: /// \param Params DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. bool skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, - const DWARFFormParams Params) const { + const dwarf::FormParams Params) const { return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params); } @@ -165,7 +131,8 @@ public: /// \param FormParams DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, const DWARFFormParams FormParams); + uint32_t *OffsetPtr, + const dwarf::FormParams FormParams); private: void dumpString(raw_ostream &OS) const; diff --git a/include/llvm/DebugInfo/DWARF/DWARFListTable.h b/include/llvm/DebugInfo/DWARF/DWARFListTable.h new file mode 100644 index 000000000000..ab12f3bc08b0 --- /dev/null +++ b/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 <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 diff --git a/include/llvm/DebugInfo/DWARF/DWARFObject.h b/include/llvm/DebugInfo/DWARF/DWARFObject.h index 167eb2da5ba0..6e8f370f4aea 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ b/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -42,8 +42,10 @@ public: virtual StringRef getDebugFrameSection() const { return ""; } virtual StringRef getEHFrameSection() const { return ""; } virtual const DWARFSection &getLineSection() const { return Dummy; } + virtual StringRef getLineStringSection() const { return ""; } virtual StringRef getStringSection() const { return ""; } virtual const DWARFSection &getRangeSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsSection() const { return Dummy; } virtual StringRef getMacinfoSection() const { return ""; } virtual StringRef getPubNamesSection() const { return ""; } virtual StringRef getPubTypesSection() const { return ""; } @@ -61,12 +63,14 @@ public: return Dummy; } virtual const DWARFSection &getRangeDWOSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; } virtual const DWARFSection &getAddrSection() const { return Dummy; } virtual const DWARFSection &getAppleNamesSection() const { return Dummy; } virtual const DWARFSection &getAppleTypesSection() const { return Dummy; } virtual const DWARFSection &getAppleNamespacesSection() const { return Dummy; } + virtual const DWARFSection &getDebugNamesSection() const { return Dummy; } virtual const DWARFSection &getAppleObjCSection() const { return Dummy; } virtual StringRef getCUIndexSection() const { return ""; } virtual StringRef getGdbIndexSection() const { return ""; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index a7842454f435..cb5a78ee3dbf 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -24,29 +24,21 @@ struct DWARFSection; class raw_ostream; class DWARFTypeUnit : public DWARFUnit { -private: - uint64_t TypeHash; - uint32_t TypeOffset; - public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, - UnitSection, Entry) {} + const DWARFUnitSectionBase &UnitSection) + : DWARFUnit(Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection) {} - uint32_t getHeaderSize() const override { - return DWARFUnit::getHeaderSize() + 12; - } + uint64_t getTypeHash() const { return getHeader().getTypeHash(); } + uint32_t getTypeOffset() const { return getHeader().getTypeOffset(); } void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}); static const DWARFSectionKind Section = DW_SECT_TYPES; - -protected: - bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) override; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 3cec58383f87..988a7958184c 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -18,6 +18,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" @@ -40,6 +41,66 @@ class DWARFContext; class DWARFDebugAbbrev; class DWARFUnit; +/// Base class describing the header of any kind of "unit." Some information +/// is specific to certain unit types. We separate this class out so we can +/// parse the header before deciding what specific kind of unit to construct. +class DWARFUnitHeader { + // Offset within section. + uint32_t Offset = 0; + // Version, address size, and DWARF format. + dwarf::FormParams FormParams; + uint32_t Length = 0; + uint64_t AbbrOffset = 0; + + // For DWO units only. + const DWARFUnitIndex::Entry *IndexEntry = nullptr; + + // For type units only. + uint64_t TypeHash = 0; + uint32_t TypeOffset = 0; + + // For v5 split or skeleton compile units only. + Optional<uint64_t> DWOId; + + // Unit type as parsed, or derived from the section kind. + uint8_t UnitType = 0; + + // Size as parsed. uint8_t for compactness. + uint8_t Size = 0; + +public: + /// Parse a unit header from \p debug_info starting at \p offset_ptr. + bool extract(DWARFContext &Context, const DWARFDataExtractor &debug_info, + uint32_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO, + const DWARFUnitIndex *Index = nullptr); + uint32_t getOffset() const { return Offset; } + const dwarf::FormParams &getFormParams() const { return FormParams; } + uint16_t getVersion() const { return FormParams.Version; } + dwarf::DwarfFormat getFormat() const { return FormParams.Format; } + uint8_t getAddressByteSize() const { return FormParams.AddrSize; } + uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return FormParams.getDwarfOffsetByteSize(); + } + uint32_t getLength() const { return Length; } + uint64_t getAbbrOffset() const { return AbbrOffset; } + Optional<uint64_t> getDWOId() const { return DWOId; } + void setDWOId(uint64_t Id) { + assert((!DWOId || *DWOId == Id) && "setting DWOId to a different value"); + DWOId = Id; + } + const DWARFUnitIndex::Entry *getIndexEntry() const { return IndexEntry; } + uint64_t getTypeHash() const { return TypeHash; } + uint32_t getTypeOffset() const { return TypeOffset; } + uint8_t getUnitType() const { return UnitType; } + bool isTypeUnit() const { + return UnitType == dwarf::DW_UT_type || UnitType == dwarf::DW_UT_split_type; + } + uint8_t getSize() const { return Size; } + // FIXME: Support DWARF64. + uint32_t getNextUnitOffset() const { return Offset + Length + 4; } +}; + /// Base class for all DWARFUnitSection classes. This provides the /// functionality common to all unit types. class DWARFUnitSectionBase { @@ -56,7 +117,8 @@ public: protected: ~DWARFUnitSectionBase() = default; - virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, + virtual void parseImpl(DWARFContext &Context, const DWARFObject &Obj, + const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, @@ -116,14 +178,14 @@ public: } private: - void parseImpl(DWARFContext &Context, const DWARFSection &Section, - const DWARFDebugAbbrev *DA, const DWARFSection *RS, - StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, - const DWARFSection &LS, bool LE, bool IsDWO, - bool Lazy) override { + void parseImpl(DWARFContext &Context, const DWARFObject &Obj, + const DWARFSection &Section, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, + bool IsDWO, bool Lazy) override { if (Parsed) return; - DataExtractor Data(Section.Data, LE, 0); + DWARFDataExtractor Data(Obj, Section, LE, 0); if (!Parser) { const DWARFUnitIndex *Index = nullptr; if (IsDWO) @@ -132,11 +194,12 @@ private: &LS](uint32_t Offset) -> std::unique_ptr<UnitType> { if (!Data.isValidOffset(Offset)) return nullptr; - auto U = llvm::make_unique<UnitType>( - Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, *this, - Index ? Index->getFromOffset(Offset) : nullptr); - if (!U->extract(Data, &Offset)) + DWARFUnitHeader Header; + if (!Header.extract(Context, Data, &Offset, UnitType::Section, Index)) return nullptr; + auto U = llvm::make_unique<UnitType>( + Context, Section, Header, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + *this); return U; }; } @@ -168,9 +231,10 @@ struct BaseAddress { /// Represents a unit's contribution to the string offsets table. struct StrOffsetsContributionDescriptor { uint64_t Base = 0; + /// The contribution size not including the header. uint64_t Size = 0; /// Format and version. - DWARFFormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; + dwarf::FormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size, uint8_t Version, dwarf::DwarfFormat Format) @@ -193,6 +257,7 @@ class DWARFUnit { /// Section containing this DWARFUnit. const DWARFSection &InfoSection; + DWARFUnitHeader Header; const DWARFDebugAbbrev *Abbrev; const DWARFSection *RangeSection; uint32_t RangeSectionBase; @@ -205,63 +270,28 @@ class DWARFUnit { bool isDWO; const DWARFUnitSectionBase &UnitSection; - // Version, address size, and DWARF format. - DWARFFormParams FormParams; /// Start, length, and DWARF format of the unit's contribution to the string /// offsets table (DWARF v5). Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution; - uint32_t Offset; - uint32_t Length; + /// A table of range lists (DWARF v5 and later). + Optional<DWARFDebugRnglistTable> RngListTable; + mutable const DWARFAbbreviationDeclarationSet *Abbrevs; - uint64_t AbbrOffset; - uint8_t UnitType; llvm::Optional<BaseAddress> BaseAddr; /// The compile unit debug information entry items. std::vector<DWARFDebugInfoEntry> DieArray; - /// The vector of inlined subroutine DIEs that we can map directly to from - /// their subprogram below. - std::vector<DWARFDie> InlinedSubroutineDIEs; - - /// A type representing a subprogram DIE and a map (built using a sorted - /// vector) into that subprogram's inlined subroutine DIEs. - struct SubprogramDIEAddrInfo { - DWARFDie SubprogramDIE; - - uint64_t SubprogramBasePC; - - /// A vector sorted to allow mapping from a relative PC to the inlined - /// subroutine DIE with the most specific address range covering that PC. - /// - /// The PCs are relative to the `SubprogramBasePC`. - /// - /// The vector is sorted in ascending order of the first int which - /// represents the relative PC for an interval in the map. The second int - /// represents the index into the `InlinedSubroutineDIEs` vector of the DIE - /// that interval maps to. An index of '-1` indicates an empty mapping. The - /// interval covered is from the `.first` relative PC to the next entry's - /// `.first` relative PC. - std::vector<std::pair<uint32_t, int32_t>> InlinedSubroutineDIEAddrMap; - }; - - /// Vector of the subprogram DIEs and their subroutine address maps. - std::vector<SubprogramDIEAddrInfo> SubprogramDIEAddrInfos; - - /// A vector sorted to allow mapping from a PC to the subprogram DIE (and - /// associated addr map) index. Subprograms with overlapping PC ranges aren't - /// supported here. Nothing will crash, but the mapping may be inaccurate. - /// This vector may also contain "empty" ranges marked by an address with - /// a DIE index of '-1'. - std::vector<std::pair<uint64_t, int64_t>> SubprogramDIEAddrMap; + /// Map from range's start address to end address and corresponding DIE. + /// IntervalMap does not support range removal, as a result, we use the + /// std::map::upper_bound for address range lookup. + std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap; using die_iterator_range = iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>; std::shared_ptr<DWARFUnit> DWO; - const DWARFUnitIndex::Entry *IndexEntry; - uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) { auto First = DieArray.data(); assert(Die >= First && Die < First + DieArray.size()); @@ -269,10 +299,10 @@ class DWARFUnit { } protected: - virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); + const DWARFUnitHeader &getHeader() const { return Header; } - /// Size in bytes of the unit header. - virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } + /// Size in bytes of the parsed unit header. + uint32_t getHeaderSize() const { return Header.getSize(); } /// Find the unit's contribution to the string offsets table and determine its /// length and form. The given offset is expected to be derived from the unit @@ -291,16 +321,28 @@ protected: public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - const DWARFUnitSectionBase &UnitSection, - const DWARFUnitIndex::Entry *IndexEntry = nullptr); + const DWARFUnitSectionBase &UnitSection); virtual ~DWARFUnit(); DWARFContext& getContext() const { return Context; } - + uint32_t getOffset() const { return Header.getOffset(); } + const dwarf::FormParams &getFormParams() const { + return Header.getFormParams(); + } + uint16_t getVersion() const { return Header.getVersion(); } + uint8_t getAddressByteSize() const { return Header.getAddressByteSize(); } + uint8_t getRefAddrByteSize() const { return Header.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return Header.getDwarfOffsetByteSize(); + } + uint32_t getLength() const { return Header.getLength(); } + uint8_t getUnitType() const { return Header.getUnitType(); } + uint32_t getNextUnitOffset() const { return Header.getNextUnitOffset(); } const DWARFSection &getLineSection() const { return LineSection; } StringRef getStringSection() const { return StringSection; } const DWARFSection &getStringOffsetSection() const { @@ -312,6 +354,9 @@ public: AddrOffsetSectionBase = Base; } + /// Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + void setRangesSection(const DWARFSection *RS, uint32_t Base) { RangeSection = RS; RangeSectionBase = Base; @@ -326,31 +371,18 @@ public: return DataExtractor(StringSection, false, 0); } - - bool extract(DataExtractor debug_info, uint32_t* offset_ptr); - - /// extractRangeList - extracts the range list referenced by this compile - /// unit from .debug_ranges section. Returns true on success. - /// Requires that compile unit is already extracted. - bool extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const; + /// Extract the range list referenced by this compile unit from the + /// .debug_ranges section. If the extraction is unsuccessful, an error + /// is returned. Successful extraction requires that the compile unit + /// has already been extracted. + Error extractRangeList(uint32_t RangeListOffset, + DWARFDebugRangeList &RangeList) const; void clear(); - uint32_t getOffset() const { return Offset; } - uint32_t getNextUnitOffset() const { return Offset + Length + 4; } - uint32_t getLength() const { return Length; } const Optional<StrOffsetsContributionDescriptor> & getStringOffsetsTableContribution() const { return StringOffsetsTableContribution; } - const DWARFFormParams &getFormParams() const { return FormParams; } - uint16_t getVersion() const { return FormParams.Version; } - dwarf::DwarfFormat getFormat() const { return FormParams.Format; } - uint8_t getAddressByteSize() const { return FormParams.AddrSize; } - uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } - uint8_t getDwarfOffsetByteSize() const { - return FormParams.getDwarfOffsetByteSize(); - } uint8_t getDwarfStringOffsetsByteSize() const { assert(StringOffsetsTableContribution); @@ -364,8 +396,6 @@ public: const DWARFAbbreviationDeclarationSet *getAbbreviations() const; - uint8_t getUnitType() const { return UnitType; } - static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { switch (UnitType) { case dwarf::DW_UT_compile: @@ -383,7 +413,7 @@ public: return false; } - /// \brief Return the number of bytes for the header of a unit of + /// Return the number of bytes for the header of a unit of /// UnitType type. /// /// This function must be called with a valid unit type which in @@ -403,9 +433,7 @@ public: llvm_unreachable("Invalid UnitType."); } - llvm::Optional<BaseAddress> getBaseAddress() const { return BaseAddr; } - - void setBaseAddress(BaseAddress BaseAddr) { this->BaseAddr = BaseAddr; } + llvm::Optional<BaseAddress> getBaseAddress(); DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { extractDIEsIfNeeded(ExtractUnitDIEOnly); @@ -415,7 +443,29 @@ public: } const char *getCompilationDir(); - Optional<uint64_t> getDWOId(); + Optional<uint64_t> getDWOId() { + extractDIEsIfNeeded(/*CUDieOnly*/ true); + return getHeader().getDWOId(); + } + void setDWOId(uint64_t NewID) { Header.setDWOId(NewID); } + + /// Return a vector of address ranges resulting from a (possibly encoded) + /// range list starting at a given offset in the appropriate ranges section. + Expected<DWARFAddressRangesVector> findRnglistFromOffset(uint32_t Offset); + + /// Return a vector of address ranges retrieved from an encoded range + /// list whose offset is found via a table lookup given an index (DWARF v5 + /// and later). + Expected<DWARFAddressRangesVector> findRnglistFromIndex(uint32_t Index); + + /// Return a rangelist's offset based on an index. The index designates + /// an entry in the rangelist table's offset array and is supplied by + /// DW_FORM_rnglistx. + Optional<uint32_t> getRnglistOffset(uint32_t Index) { + if (RngListTable) + return RngListTable->getOffsetEntry(Index); + return None; + } void collectAddressRanges(DWARFAddressRangesVector &CURanges); @@ -433,14 +483,14 @@ public: /// getUnitSection - Return the DWARFUnitSection containing this unit. const DWARFUnitSectionBase &getUnitSection() const { return UnitSection; } - /// \brief Returns the number of DIEs in the unit. Parses the unit + /// Returns the number of DIEs in the unit. Parses the unit /// if necessary. unsigned getNumDIEs() { extractDIEsIfNeeded(false); return DieArray.size(); } - /// \brief Return the index of a DIE inside the unit's DIE vector. + /// Return the index of a DIE inside the unit's DIE vector. /// /// It is illegal to call this method with a DIE that hasn't be /// created by this unit. In other word, it's illegal to call this @@ -450,7 +500,7 @@ public: return getDIEIndex(D.getDebugInfoEntry()); } - /// \brief Return the DIE object at the given index. + /// Return the DIE object at the given index. DWARFDie getDIEAtIndex(unsigned Index) { assert(Index < DieArray.size()); return DWARFDie(this, &DieArray[Index]); @@ -458,9 +508,11 @@ public: DWARFDie getParent(const DWARFDebugInfoEntry *Die); DWARFDie getSibling(const DWARFDebugInfoEntry *Die); + DWARFDie getPreviousSibling(const DWARFDebugInfoEntry *Die); DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die); + DWARFDie getLastChild(const DWARFDebugInfoEntry *Die); - /// \brief Return the DIE object for a given offset inside the + /// Return the DIE object for a given offset inside the /// unit's DIE vector. /// /// The unit needs to have its DIEs extracted for this method to work. @@ -478,7 +530,7 @@ public: } uint32_t getLineTableOffset() const { - if (IndexEntry) + if (auto IndexEntry = Header.getIndexEntry()) if (const auto *Contrib = IndexEntry->getOffset(DW_SECT_LINE)) return Contrib->Offset; return 0; @@ -491,7 +543,9 @@ public: private: /// Size in bytes of the .debug_info data associated with this compile unit. - size_t getDebugInfoSize() const { return Length + 4 - getHeaderSize(); } + size_t getDebugInfoSize() const { + return Header.getLength() + 4 - getHeaderSize(); + } /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it /// hasn't already been done. Returns the number of DIEs parsed at this call. @@ -507,9 +561,6 @@ private: /// parseDWO - Parses .dwo file for current compile unit. Returns true if /// it was actually constructed. bool parseDWO(); - - void buildSubprogramDIEAddrMap(); - void buildInlinedSubroutineDIEAddrMap(SubprogramDIEAddrInfo &SPInfo); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index 0d920abe3231..a829510a219d 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -11,7 +11,8 @@ #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H #include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include <cstdint> @@ -24,7 +25,7 @@ struct DWARFAttribute; class DWARFContext; class DWARFDie; class DWARFUnit; -class DWARFAcceleratorTable; +class DWARFCompileUnit; class DWARFDataExtractor; class DWARFDebugAbbrev; class DataExtractor; @@ -109,7 +110,7 @@ private: /// \param Abbrev Pointer to the abbreviations section we are verifying /// Abbrev can be a pointer to either .debug_abbrev or debug_abbrev.dwo. /// - /// \returns The number of errors that occured during verification. + /// \returns The number of errors that occurred during verification. unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev); /// Verifies the header of a unit in the .debug_info section. @@ -151,14 +152,14 @@ private: /// type of the unit DIE. /// /// \returns true if the content is verified successfully, false otherwise. - bool verifyUnitContents(DWARFUnit Unit, uint8_t UnitType = 0); + bool verifyUnitContents(DWARFUnit &Unit, uint8_t UnitType = 0); /// Verify that all Die ranges are valid. /// /// This function currently checks for: /// - cases in which lowPC >= highPC /// - /// \returns Number of errors that occured during verification. + /// \returns Number of errors that occurred during verification. unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI); /// Verifies the attribute's DWARF attribute and its value. @@ -170,7 +171,7 @@ private: /// \param Die The DWARF DIE that owns the attribute value /// \param AttrValue The DWARF attribute value to check /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// attributes' values in a .debug_info section unit unsigned verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue); @@ -185,7 +186,7 @@ private: /// \param Die The DWARF DIE that owns the attribute value /// \param AttrValue The DWARF attribute value to check /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// attributes' forms in a .debug_info section unit unsigned verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue); @@ -197,11 +198,11 @@ private: /// around, that it doesn't create invalid references by failing to relocate /// CU relative and absolute references. /// - /// \returns NumErrors The number of errors occured during verification of + /// \returns NumErrors The number of errors occurred during verification of /// references for the .debug_info section unsigned verifyDebugInfoReferences(); - /// Verify the the DW_AT_stmt_list encoding and value and ensure that no + /// Verify the DW_AT_stmt_list encoding and value and ensure that no /// compile units that have the same DW_AT_stmt_list value. void verifyDebugLineStmtOffsets(); @@ -228,9 +229,42 @@ private: /// \param StrData pointer to the string section /// \param SectionName the name of the table we're verifying /// - /// \returns The number of errors occured during verification - unsigned verifyAccelTable(const DWARFSection *AccelSection, - DataExtractor *StrData, const char *SectionName); + /// \returns The number of errors occurred during verification + unsigned verifyAppleAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, + const char *SectionName); + + unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable); + unsigned verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, + const DataExtractor &StrData); + unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI); + unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI, + const DWARFDebugNames::Abbrev &Abbr, + DWARFDebugNames::AttributeEncoding AttrEnc); + unsigned verifyNameIndexEntries(const DWARFDebugNames::NameIndex &NI, + const DWARFDebugNames::NameTableEntry &NTE); + unsigned verifyNameIndexCompleteness(const DWARFDie &Die, + const DWARFDebugNames::NameIndex &NI); + + /// Verify that the DWARF v5 accelerator table is valid. + /// + /// This function currently checks that: + /// - Headers individual Name Indices fit into the section and can be parsed. + /// - Abbreviation tables can be parsed and contain valid index attributes + /// with correct form encodings. + /// - The CU lists reference existing compile units. + /// - The buckets have a valid index, or they are empty. + /// - All names are reachable via the hash table (they have the correct hash, + /// and the hash is in the correct bucket). + /// - Information in the index entries is complete (all required entries are + /// present) and consistent with the debug_info section DIEs. + /// + /// \param AccelSection section containing the acceleration table + /// \param StrData string section + /// + /// \returns The number of errors occurred during verification + unsigned verifyDebugNames(const DWARFSection &AccelSection, + const DataExtractor &StrData); public: DWARFVerifier(raw_ostream &S, DWARFContext &D, |
