diff options
Diffstat (limited to 'third_party/llvm-project/include/llvm/DebugInfo/DWARF')
31 files changed, 5375 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h new file mode 100644 index 000000000..39ae53c4e --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -0,0 +1,183 @@ +//===- DWARFAbbreviationDeclaration.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#define LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/DataExtractor.h" +#include <cassert> +#include <cstddef> +#include <cstdint> + +namespace llvm { + +class DWARFFormValue; +class DWARFUnit; +class raw_ostream; + +class DWARFAbbreviationDeclaration { +public: + struct AttributeSpec { + AttributeSpec(dwarf::Attribute A, dwarf::Form F, int64_t Value) + : Attr(A), Form(F), Value(Value) { + assert(isImplicitConst()); + } + AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional<uint8_t> ByteSize) + : Attr(A), Form(F) { + assert(!isImplicitConst()); + this->ByteSize.HasByteSize = ByteSize.hasValue(); + if (this->ByteSize.HasByteSize) + this->ByteSize.ByteSize = *ByteSize; + } + + dwarf::Attribute Attr; + dwarf::Form Form; + + private: + /// The following field is used for ByteSize for non-implicit_const + /// attributes and as value for implicit_const ones, indicated by + /// Form == DW_FORM_implicit_const. + /// The following cases are distinguished: + /// * Form != DW_FORM_implicit_const and HasByteSize is true: + /// ByteSize contains the fixed size in bytes for the Form in this + /// object. + /// * Form != DW_FORM_implicit_const and HasByteSize is false: + /// byte size of Form either varies according to the DWARFUnit + /// that it is contained in or the value size varies and must be + /// decoded from the debug information in order to determine its size. + /// * Form == DW_FORM_implicit_const: + /// Value contains value for the implicit_const attribute. + struct ByteSizeStorage { + bool HasByteSize; + uint8_t ByteSize; + }; + union { + ByteSizeStorage ByteSize; + int64_t Value; + }; + + public: + bool isImplicitConst() const { + return Form == dwarf::DW_FORM_implicit_const; + } + + int64_t getImplicitConstValue() const { + assert(isImplicitConst()); + return Value; + } + + /// Get the fixed byte size of this Form if possible. This function might + /// use the DWARFUnit to calculate the size of the Form, like for + /// DW_AT_address and DW_AT_ref_addr, so this isn't just an accessor for + /// the ByteSize member. + Optional<int64_t> getByteSize(const DWARFUnit &U) const; + }; + using AttributeSpecVector = SmallVector<AttributeSpec, 8>; + + DWARFAbbreviationDeclaration(); + + uint32_t getCode() const { return Code; } + uint8_t getCodeByteSize() const { return CodeByteSize; } + dwarf::Tag getTag() const { return Tag; } + bool hasChildren() const { return HasChildren; } + + using attr_iterator_range = + iterator_range<AttributeSpecVector::const_iterator>; + + attr_iterator_range attributes() const { + return attr_iterator_range(AttributeSpecs.begin(), AttributeSpecs.end()); + } + + dwarf::Form getFormByIndex(uint32_t idx) const { + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Form; + } + + size_t getNumAttributes() const { + return AttributeSpecs.size(); + } + + dwarf::Attribute getAttrByIndex(uint32_t idx) const { + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Attr; + } + + /// Get the index of the specified attribute. + /// + /// Searches the this abbreviation declaration for the index of the specified + /// attribute. + /// + /// \param attr DWARF attribute to search for. + /// \returns Optional index of the attribute if found, None otherwise. + Optional<uint32_t> findAttributeIndex(dwarf::Attribute attr) const; + + /// Extract a DWARF form value from a DIE specified by DIE offset. + /// + /// Extract an attribute value for a DWARFUnit given the DIE offset and the + /// attribute. + /// + /// \param DIEOffset the DIE offset that points to the ULEB128 abbreviation + /// code in the .debug_info data. + /// \param Attr DWARF attribute to search for. + /// \param U the DWARFUnit the contains the DIE. + /// \returns Optional DWARF form value if the attribute was extracted. + Optional<DWARFFormValue> getAttributeValue(const uint64_t DIEOffset, + const dwarf::Attribute Attr, + const DWARFUnit &U) const; + + bool extract(DataExtractor Data, uint64_t* OffsetPtr); + void dump(raw_ostream &OS) const; + + // Return an optional byte size of all attribute data in this abbreviation + // if a constant byte size can be calculated given a DWARFUnit. This allows + // DWARF parsing to be faster as many DWARF DIEs have a fixed byte size. + Optional<size_t> getFixedAttributesByteSize(const DWARFUnit &U) const; + +private: + void clear(); + + /// A helper structure that can quickly determine the size in bytes of an + /// abbreviation declaration. + struct FixedSizeInfo { + /// The fixed byte size for fixed size forms. + uint16_t NumBytes = 0; + /// Number of DW_FORM_address forms in this abbrevation declaration. + uint8_t NumAddrs = 0; + /// Number of DW_FORM_ref_addr forms in this abbrevation declaration. + uint8_t NumRefAddrs = 0; + /// Number of 4 byte in DWARF32 and 8 byte in DWARF64 forms. + uint8_t NumDwarfOffsets = 0; + + FixedSizeInfo() = default; + + /// Calculate the fixed size in bytes given a DWARFUnit. + /// + /// \param U the DWARFUnit to use when determing the byte size. + /// \returns the size in bytes for all attribute data in this abbreviation. + /// The returned size does not include bytes for the ULEB128 abbreviation + /// code + size_t getByteSize(const DWARFUnit &U) const; + }; + + uint32_t Code; + dwarf::Tag Tag; + uint8_t CodeByteSize; + bool HasChildren; + AttributeSpecVector AttributeSpecs; + /// If this abbreviation has a fixed byte size then FixedAttributeSize member + /// variable below will have a value. + Optional<FixedSizeInfo> FixedAttributeSize; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h new file mode 100644 index 000000000..c9042e593 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -0,0 +1,599 @@ +//===- DWARFAcceleratorTable.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include <cstdint> +#include <utility> + +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 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. +class AppleAcceleratorTable : public DWARFAcceleratorTable { + struct Header { + uint32_t Magic; + uint16_t Version; + uint16_t HashFunction; + uint32_t BucketCount; + uint32_t HashCount; + uint32_t HeaderDataLength; + + void dump(ScopedPrinter &W) const; + }; + + struct HeaderData { + using AtomType = uint16_t; + using Form = dwarf::Form; + + uint64_t DIEOffsetBase; + SmallVector<std::pair<AtomType, Form>, 3> Atoms; + + Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const; + }; + + struct Header Hdr; + struct HeaderData HdrData; + 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, + uint64_t *DataOffset) const; + +public: + /// 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, uint64_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. + uint64_t DataOffset = 0; ///< Offset into the section. + unsigned Data = 0; ///< Current data entry. + unsigned NumData = 0; ///< Number of data entries. + + /// Advance the iterator. + void Next(); + public: + /// Construct a new iterator for the entries at \p DataOffset. + ValueIterator(const AppleAcceleratorTable &AccelTable, uint64_t DataOffset); + /// End marker. + ValueIterator() = default; + + const Entry &operator*() const { return Current; } + 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.NumData == B.NumData && A.DataOffset == B.DataOffset; + } + friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { + return !(A == B); + } + }; + + AppleAcceleratorTable(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : DWARFAcceleratorTable(AccelSection, StringSection) {} + + 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(); + + /// Return information related to the DWARF DIE we're looking for when + /// performing a lookup by name. + /// + /// \param HashDataOffset an offset into the hash data table + /// \returns <DieOffset, DieTag> + /// DieOffset is the offset into the .debug_info section for the DIE + /// related to the input hash data offset. + /// DieTag is the tag of the DIE + std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset); + 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 v5 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 v5 Name Index header. + struct Header : public HeaderPOD { + SmallString<8> AugmentationString; + + Error extract(const DWARFDataExtractor &AS, uint64_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 v5 sect. 6.1.1.4.6) of the Name + /// Index. + class NameTableEntry { + DataExtractor StrData; + + uint32_t Index; + uint64_t StringOffset; + uint64_t EntryOffset; + + public: + NameTableEntry(const DataExtractor &StrData, uint32_t Index, + uint64_t StringOffset, uint64_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. + uint64_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 { + uint64_t Off = StringOffset; + return StrData.getCStr(&Off); + } + + /// Returns the offset of the first Entry in the list. + uint64_t getEntryOffset() const { return EntryOffset; } + }; + + /// Represents a single accelerator table within the DWARF v5 .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. + uint64_t Base; + uint64_t CUsBase; + uint64_t BucketsBase; + uint64_t HashesBase; + uint64_t StringOffsetsBase; + uint64_t EntryOffsetsBase; + uint64_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, uint64_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(uint64_t *Offset); + + Expected<std::vector<AttributeEncoding>> + extractAttributeEncodings(uint64_t *Offset); + + Expected<Abbrev> extractAbbrev(uint64_t *Offset); + + public: + NameIndex(const DWARFDebugNames &Section, uint64_t Base) + : Section(Section), Base(Base) {} + + /// Reads offset of compilation unit CU. CU is 0-based. + uint64_t getCUOffset(uint32_t CU) const; + uint32_t getCUCount() const { return Hdr.CompUnitCount; } + + /// Reads offset of local type unit TU, TU is 0-based. + uint64_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(uint64_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); } + + Error extract(); + uint64_t getUnitOffset() const { return Base; } + uint64_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; + uint64_t 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<uint64_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<uint64_t, const NameIndex *> CUToNameIndex; + +public: + DWARFDebugNames(const DWARFDataExtractor &AccelSection, + DataExtractor StringSection) + : DWARFAcceleratorTable(AccelSection, StringSection) {} + + 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(uint64_t CUOffset); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h new file mode 100644 index 000000000..2d5f9f3c7 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h @@ -0,0 +1,61 @@ +//===- DWARFAddressRange.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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; + } + + 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/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h new file mode 100644 index 000000000..dfc778346 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFAttribute.h @@ -0,0 +1,49 @@ +//===- DWARFAttribute.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFATTRIBUTE_H +#define LLVM_DEBUGINFO_DWARFATTRIBUTE_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include <cstdint> + +namespace llvm { + +//===----------------------------------------------------------------------===// +/// Encapsulates a DWARF attribute value and all of the data required to +/// describe the attribute value. +/// +/// This class is designed to be used by clients that want to iterate across all +/// attributes in a DWARFDie. +struct DWARFAttribute { + /// The debug info/types offset for this attribute. + uint64_t Offset = 0; + /// The debug info/types section byte size of the data for this attribute. + uint32_t ByteSize = 0; + /// The attribute enumeration of this attribute. + dwarf::Attribute Attr = dwarf::Attribute(0); + /// The form and value for this attribute. + DWARFFormValue Value; + + bool isValid() const { + return Offset != 0 && Attr != dwarf::Attribute(0); + } + + explicit operator bool() const { + return isValid(); + } + + /// Identifies DWARF attributes that may contain a reference to a + /// DWARF expression. + static bool mayHaveLocationDescription(dwarf::Attribute Attr); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFATTRIBUTE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h new file mode 100644 index 000000000..16b9bfb5d --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -0,0 +1,38 @@ +//===- DWARFCompileUnit.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H +#define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H + +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" + +namespace llvm { + +class DWARFCompileUnit : public DWARFUnit { +public: + DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, const DWARFSection *LocSection, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, + bool IsDWO, const DWARFUnitVector &UnitVector) + : DWARFUnit(Context, Section, Header, DA, RS, LocSection, SS, SOS, AOS, + LS, LE, IsDWO, UnitVector) {} + + /// VTable anchor. + ~DWARFCompileUnit() override; + /// Dump this compile unit to \p OS. + void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override; + /// Enable LLVM-style RTTI. + static bool classof(const DWARFUnit *U) { return !U->isTypeUnit(); } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h new file mode 100644 index 000000000..2dec107d1 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -0,0 +1,382 @@ +//===- DWARFContext.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H +#define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFObject.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#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> +#include <deque> +#include <map> +#include <memory> + +namespace llvm { + +class MCRegisterInfo; +class MemoryBuffer; +class raw_ostream; + +/// Used as a return value for a error callback passed to DWARF context. +/// Callback should return Halt if client application wants to stop +/// object parsing, or should return Continue otherwise. +enum class ErrorPolicy { Halt, Continue }; + +/// DWARFContext +/// This data structure is the top level entity that deals with dwarf debug +/// information parsing. The actual data is supplied through DWARFObj. +class DWARFContext : public DIContext { + DWARFUnitVector NormalUnits; + std::unique_ptr<DWARFUnitIndex> CUIndex; + std::unique_ptr<DWARFGdbIndex> GdbIndex; + std::unique_ptr<DWARFUnitIndex> TUIndex; + std::unique_ptr<DWARFDebugAbbrev> Abbrev; + std::unique_ptr<DWARFDebugLoc> Loc; + std::unique_ptr<DWARFDebugAranges> Aranges; + std::unique_ptr<DWARFDebugLine> Line; + std::unique_ptr<DWARFDebugFrame> DebugFrame; + std::unique_ptr<DWARFDebugFrame> EHFrame; + std::unique_ptr<DWARFDebugMacro> Macro; + 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; + + DWARFUnitVector DWOUnits; + std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO; + + /// The maximum DWARF version of all units. + unsigned MaxVersion = 0; + + struct DWOFile { + object::OwningBinary<object::ObjectFile> File; + std::unique_ptr<DWARFContext> Context; + }; + StringMap<std::weak_ptr<DWOFile>> DWOFiles; + std::weak_ptr<DWOFile> DWP; + bool CheckedForDWP = false; + std::string DWPName; + + std::unique_ptr<MCRegisterInfo> RegInfo; + + /// Read compile units from the debug_info section (if necessary) + /// and type units from the debug_types sections (if necessary) + /// and store them in NormalUnits. + void parseNormalUnits(); + + /// Read compile units from the debug_info.dwo section (if necessary) + /// and type units from the debug_types.dwo section (if necessary) + /// and store them in DWOUnits. + /// If \p Lazy is true, set up to parse but don't actually parse them. + enum { EagerParse = false, LazyParse = true }; + void parseDWOUnits(bool Lazy = false); + + std::unique_ptr<const DWARFObject> DObj; + +public: + DWARFContext(std::unique_ptr<const DWARFObject> DObj, + std::string DWPName = ""); + ~DWARFContext(); + + DWARFContext(DWARFContext &) = delete; + DWARFContext &operator=(DWARFContext &) = delete; + + const DWARFObject &getDWARFObj() const { return *DObj; } + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == CK_DWARF; + } + + /// Dump a textual representation to \p OS. If any \p DumpOffsets are present, + /// dump only the record at the specified offset. + void dump(raw_ostream &OS, DIDumpOptions DumpOpts, + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets); + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override { + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets; + dump(OS, DumpOpts, DumpOffsets); + } + + bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; + + using unit_iterator_range = DWARFUnitVector::iterator_range; + + /// Get units from .debug_info in this context. + unit_iterator_range info_section_units() { + parseNormalUnits(); + return unit_iterator_range(NormalUnits.begin(), + NormalUnits.begin() + + NormalUnits.getNumInfoUnits()); + } + + /// Get units from .debug_types in this context. + unit_iterator_range types_section_units() { + parseNormalUnits(); + return unit_iterator_range( + NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end()); + } + + /// Get compile units in this context. + unit_iterator_range compile_units() { return info_section_units(); } + + /// Get type units in this context. + unit_iterator_range type_units() { return types_section_units(); } + + /// Get all normal compile/type units in this context. + unit_iterator_range normal_units() { + parseNormalUnits(); + return unit_iterator_range(NormalUnits.begin(), NormalUnits.end()); + } + + /// Get units from .debug_info..dwo in the DWO context. + unit_iterator_range dwo_info_section_units() { + parseDWOUnits(); + return unit_iterator_range(DWOUnits.begin(), + DWOUnits.begin() + DWOUnits.getNumInfoUnits()); + } + + /// Get units from .debug_types.dwo in the DWO context. + unit_iterator_range dwo_types_section_units() { + parseDWOUnits(); + return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(), + DWOUnits.end()); + } + + /// Get compile units in the DWO context. + unit_iterator_range dwo_compile_units() { return dwo_info_section_units(); } + + /// Get type units in the DWO context. + unit_iterator_range dwo_type_units() { return dwo_types_section_units(); } + + /// Get all units in the DWO context. + unit_iterator_range dwo_units() { + parseDWOUnits(); + return unit_iterator_range(DWOUnits.begin(), DWOUnits.end()); + } + + /// Get the number of compile units in this context. + unsigned getNumCompileUnits() { + parseNormalUnits(); + return NormalUnits.getNumInfoUnits(); + } + + /// Get the number of type units in this context. + unsigned getNumTypeUnits() { + parseNormalUnits(); + return NormalUnits.getNumTypesUnits(); + } + + /// Get the number of compile units in the DWO context. + unsigned getNumDWOCompileUnits() { + parseDWOUnits(); + return DWOUnits.getNumInfoUnits(); + } + + /// Get the number of type units in the DWO context. + unsigned getNumDWOTypeUnits() { + parseDWOUnits(); + return DWOUnits.getNumTypesUnits(); + } + + /// Get the unit at the specified index. + DWARFUnit *getUnitAtIndex(unsigned index) { + parseNormalUnits(); + return NormalUnits[index].get(); + } + + /// Get the unit at the specified index for the DWO units. + DWARFUnit *getDWOUnitAtIndex(unsigned index) { + parseDWOUnits(); + return DWOUnits[index].get(); + } + + DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); + + /// Return the compile unit that includes an offset (relative to .debug_info). + DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset); + + /// Get a DIE given an exact offset. + DWARFDie getDIEForOffset(uint64_t Offset); + + unsigned getMaxVersion() { + // Ensure info units have been parsed to discover MaxVersion + info_section_units(); + return MaxVersion; + } + + unsigned getMaxDWOVersion() { + // Ensure DWO info units have been parsed to discover MaxVersion + dwo_info_section_units(); + return MaxVersion; + } + + void setMaxVersionIfGreater(unsigned Version) { + if (Version > MaxVersion) + MaxVersion = Version; + } + + const DWARFUnitIndex &getCUIndex(); + DWARFGdbIndex &getGdbIndex(); + const DWARFUnitIndex &getTUIndex(); + + /// Get a pointer to the parsed DebugAbbrev object. + const DWARFDebugAbbrev *getDebugAbbrev(); + + /// Get a pointer to the parsed DebugLoc object. + const DWARFDebugLoc *getDebugLoc(); + + /// Get a pointer to the parsed dwo abbreviations object. + const DWARFDebugAbbrev *getDebugAbbrevDWO(); + + /// Get a pointer to the parsed DebugAranges object. + const DWARFDebugAranges *getDebugAranges(); + + /// Get a pointer to the parsed frame information object. + const DWARFDebugFrame *getDebugFrame(); + + /// Get a pointer to the parsed eh frame information object. + const DWARFDebugFrame *getEHFrame(); + + /// Get a pointer to the parsed DebugMacro object. + const DWARFDebugMacro *getDebugMacro(); + + /// Get a reference to the parsed accelerator table object. + const DWARFDebugNames &getDebugNames(); + + /// Get a reference to the parsed accelerator table object. + const AppleAcceleratorTable &getAppleNames(); + + /// Get a reference to the parsed accelerator table object. + const AppleAcceleratorTable &getAppleTypes(); + + /// Get a reference to the parsed accelerator table object. + 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. + /// 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->getStrSection(), false, 0); + } + DataExtractor getLineStringExtractor() const { + return DataExtractor(DObj->getLineStrSection(), false, 0); + } + + /// Wraps the returned DIEs for a given address. + struct DIEsForAddress { + DWARFCompileUnit *CompileUnit = nullptr; + DWARFDie FunctionDIE; + DWARFDie BlockDIE; + explicit operator bool() const { return CompileUnit != nullptr; } + }; + + /// Get the compilation unit, the function DIE and lexical block DIE for the + /// given address where applicable. + /// TODO: change input parameter from "uint64_t Address" + /// into "SectionedAddress Address" + DIEsForAddress getDIEsForAddress(uint64_t Address); + + DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DIInliningInfo getInliningInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + + std::vector<DILocal> + getLocalsForAddress(object::SectionedAddress Address) override; + + bool isLittleEndian() const { return DObj->isLittleEndian(); } + static bool isSupportedVersion(unsigned version) { + return version == 2 || version == 3 || version == 4 || version == 5; + } + + std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath); + + const MCRegisterInfo *getRegisterInfo() const { return RegInfo.get(); } + + /// Function used to handle default error reporting policy. Prints a error + /// message and returns Continue, so DWARF context ignores the error. + static ErrorPolicy defaultErrorHandler(Error E); + static std::unique_ptr<DWARFContext> + create(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr, + function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler, + std::string DWPName = ""); + + static std::unique_ptr<DWARFContext> + create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost); + + /// Loads register info for the architecture of the provided object file. + /// Improves readability of dumped DWARF expressions. Requires the caller to + /// have initialized the relevant target descriptions. + Error loadRegisterInfo(const object::ObjectFile &Obj); + + /// Get address size from CUs. + /// TODO: refactor compile_units() to make this const. + uint8_t getCUAddrSize(); + + /// Dump Error as warning message to stderr. + static void dumpWarning(Error Warning); + + Triple::ArchType getArch() const { + return getDWARFObj().getFile()->getArch(); + } + +private: + /// Return the compile unit which contains instruction with provided + /// address. + /// TODO: change input parameter from "uint64_t Address" + /// into "SectionedAddress Address" + DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); + void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, + std::vector<DILocal> &Result); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h new file mode 100644 index 000000000..980724c52 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -0,0 +1,64 @@ +//===- DWARFDataExtractor.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H +#define LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H + +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/Support/DataExtractor.h" + +namespace llvm { +class DWARFObject; + +/// A DataExtractor (typically for an in-memory copy of an object-file section) +/// plus a relocation map for that section, if there is one. +class DWARFDataExtractor : public DataExtractor { + const DWARFObject *Obj = nullptr; + const DWARFSection *Section = nullptr; + +public: + /// Constructor for the normal case of extracting data from a DWARF section. + /// The DWARFSection's lifetime must be at least as long as the extractor's. + DWARFDataExtractor(const DWARFObject &Obj, const DWARFSection &Section, + bool IsLittleEndian, uint8_t AddressSize) + : DataExtractor(Section.Data, IsLittleEndian, AddressSize), Obj(&Obj), + Section(&Section) {} + + /// Constructor for cases when there are no relocations. + DWARFDataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize) + : DataExtractor(Data, IsLittleEndian, AddressSize) {} + + /// Extracts a value and applies a relocation to the result if + /// one exists for the given offset. + uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off, + uint64_t *SectionIndex = nullptr, + Error *Err = nullptr) const; + + /// Extracts an address-sized value and applies a relocation to the result if + /// one exists for the given offset. + uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const { + return getRelocatedValue(getAddressSize(), Off, SecIx); + } + uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const { + return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx, + &getError(C)); + } + + /// 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(uint64_t *Offset, uint8_t Encoding, + uint64_t AbsPosOffset = 0) const; + + size_t size() const { return Section == nullptr ? 0 : Section->Data.size(); } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDATAEXTRACTOR_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h new file mode 100644 index 000000000..1398e1625 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -0,0 +1,87 @@ +//===- DWARFDebugAbbrev.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGABBREV_H +#define LLVM_DEBUGINFO_DWARFDEBUGABBREV_H + +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> +#include <map> +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFAbbreviationDeclarationSet { + uint64_t Offset; + /// Code of the first abbreviation, if all abbreviations in the set have + /// consecutive codes. UINT32_MAX otherwise. + uint32_t FirstAbbrCode; + std::vector<DWARFAbbreviationDeclaration> Decls; + + using const_iterator = + std::vector<DWARFAbbreviationDeclaration>::const_iterator; + +public: + DWARFAbbreviationDeclarationSet(); + + uint64_t getOffset() const { return Offset; } + void dump(raw_ostream &OS) const; + bool extract(DataExtractor Data, uint64_t *OffsetPtr); + + const DWARFAbbreviationDeclaration * + getAbbreviationDeclaration(uint32_t AbbrCode) const; + + const_iterator begin() const { + return Decls.begin(); + } + + const_iterator end() const { + return Decls.end(); + } + +private: + void clear(); +}; + +class DWARFDebugAbbrev { + using DWARFAbbreviationDeclarationSetMap = + std::map<uint64_t, DWARFAbbreviationDeclarationSet>; + + mutable DWARFAbbreviationDeclarationSetMap AbbrDeclSets; + mutable DWARFAbbreviationDeclarationSetMap::const_iterator PrevAbbrOffsetPos; + mutable Optional<DataExtractor> Data; + +public: + DWARFDebugAbbrev(); + + const DWARFAbbreviationDeclarationSet * + getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const; + + void dump(raw_ostream &OS) const; + void parse() const; + void extract(DataExtractor Data); + + DWARFAbbreviationDeclarationSetMap::const_iterator begin() const { + parse(); + return AbbrDeclSets.begin(); + } + + DWARFAbbreviationDeclarationSetMap::const_iterator end() const { + return AbbrDeclSets.end(); + } + +private: + void clear(); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGABBREV_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h new file mode 100644 index 000000000..4539b9c9d --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h @@ -0,0 +1,97 @@ +//===- DWARFDebugAddr.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGADDR_H +#define LLVM_DEBUGINFO_DWARFDEBUGADDR_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <map> +#include <vector> + +namespace llvm { + +class Error; +class raw_ostream; + +/// A class representing an address table as specified in DWARF v5. +/// The table consists of a header followed by an array of address values from +/// .debug_addr section. +class DWARFDebugAddrTable { +public: + struct Header { + /// The total length of the entries for this table, not including the length + /// field itself. + uint32_t Length = 0; + /// The DWARF version number. + uint16_t Version = 5; + /// 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 = 0; + }; + +private: + dwarf::DwarfFormat Format; + uint64_t HeaderOffset; + Header HeaderData; + uint32_t DataSize = 0; + std::vector<uint64_t> Addrs; + +public: + void clear(); + + /// Extract an entire table, including all addresses. + Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr, + uint16_t Version, uint8_t AddrSize, + std::function<void(Error)> WarnCallback); + + uint64_t getHeaderOffset() const { return HeaderOffset; } + uint8_t getAddrSize() const { return HeaderData.AddrSize; } + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const; + + /// Return the address based on a given index. + Expected<uint64_t> getAddrEntry(uint32_t Index) const; + + /// Return the size of the table header including the length + /// but not including the addresses. + uint8_t getHeaderSize() const { + switch (Format) { + case dwarf::DwarfFormat::DWARF32: + return 8; // 4 + 2 + 1 + 1 + case dwarf::DwarfFormat::DWARF64: + return 16; // 12 + 2 + 1 + 1 + } + llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64)"); + } + + /// Returns the length of this table, including the length field, or 0 if the + /// length has not been determined (e.g. because the table has not yet been + /// parsed, or there was a problem in parsing). + uint32_t getLength() const; + + /// Verify that the given length is valid for this table. + bool hasValidLength() const { return getLength() != 0; } + + /// Invalidate Length field to stop further processing. + void invalidateLength() { HeaderData.Length = 0; } + + /// Returns the length of the array of addresses. + uint32_t getDataSize() const; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGADDR_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h new file mode 100644 index 000000000..ebe4ad6e2 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -0,0 +1,75 @@ +//===- DWARFDebugArangeSet.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugArangeSet { +public: + struct Header { + /// The total length of the entries for that set, not including the length + /// field itself. + uint32_t Length; + /// The offset from the beginning of the .debug_info section of the + /// compilation unit entry referenced by the table. + uint32_t CuOffset; + /// 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 descriptor on the target architecture. + /// If the target system uses a flat address space, this value is 0. + uint8_t SegSize; + }; + + struct Descriptor { + uint64_t Address; + uint64_t Length; + + uint64_t getEndAddress() const { return Address + Length; } + void dump(raw_ostream &OS, uint32_t AddressSize) const; + }; + +private: + using DescriptorColl = std::vector<Descriptor>; + using desc_iterator_range = iterator_range<DescriptorColl::const_iterator>; + + uint64_t Offset; + Header HeaderData; + DescriptorColl ArangeDescriptors; + +public: + DWARFDebugArangeSet() { clear(); } + + void clear(); + bool extract(DataExtractor data, uint64_t *offset_ptr); + void dump(raw_ostream &OS) const; + + uint32_t getCompileUnitDIEOffset() const { return HeaderData.CuOffset; } + + const Header &getHeader() const { return HeaderData; } + + desc_iterator_range descriptors() const { + return desc_iterator_range(ArangeDescriptors.begin(), + ArangeDescriptors.end()); + } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGESET_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h new file mode 100644 index 000000000..172f1d2c9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h @@ -0,0 +1,84 @@ +//===- DWARFDebugAranges.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGARANGES_H +#define LLVM_DEBUGINFO_DWARFDEBUGARANGES_H + +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> +#include <vector> + +namespace llvm { + +class DWARFContext; + +class DWARFDebugAranges { +public: + void generate(DWARFContext *CTX); + uint32_t findAddress(uint64_t Address) const; + +private: + void clear(); + void extract(DataExtractor DebugArangesData); + + /// Call appendRange multiple times and then call construct. + void appendRange(uint64_t CUOffset, uint64_t LowPC, uint64_t HighPC); + void construct(); + + struct Range { + explicit Range(uint64_t LowPC = -1ULL, uint64_t HighPC = -1ULL, + uint32_t CUOffset = -1U) + : LowPC(LowPC), Length(HighPC - LowPC), CUOffset(CUOffset) {} + + void setHighPC(uint64_t HighPC) { + if (HighPC == -1ULL || HighPC <= LowPC) + Length = 0; + else + Length = HighPC - LowPC; + } + + uint64_t HighPC() const { + if (Length) + return LowPC + Length; + return -1ULL; + } + + bool operator<(const Range &other) const { + return LowPC < other.LowPC; + } + + uint64_t LowPC; /// Start of address range. + uint32_t Length; /// End of address range (not including this address). + uint32_t CUOffset; /// Offset of the compile unit or die. + }; + + struct RangeEndpoint { + uint64_t Address; + uint64_t CUOffset; + bool IsRangeStart; + + RangeEndpoint(uint64_t Address, uint64_t CUOffset, bool IsRangeStart) + : Address(Address), CUOffset(CUOffset), IsRangeStart(IsRangeStart) {} + + bool operator<(const RangeEndpoint &Other) const { + return Address < Other.Address; + } + }; + + using RangeColl = std::vector<Range>; + using RangeCollIterator = RangeColl::const_iterator; + + std::vector<RangeEndpoint> Endpoints; + RangeColl Aranges; + DenseSet<uint64_t> ParsedCUOffsets; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGARANGES_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h new file mode 100644 index 000000000..c6539df0d --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -0,0 +1,308 @@ +//===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Triple.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 raw_ostream; + +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, + Triple::ArchType Arch) + : CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + Arch(Arch) {} + + /// 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(DWARFDataExtractor Data, uint64_t *Offset, uint64_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; + Triple::ArchType Arch; + + /// 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, Triple::ArchType Arch) + : Kind(K), Offset(Offset), Length(Length), + CFIs(CodeAlign, DataAlign, Arch) {} + + 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, Triple::ArchType Arch) + : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor, + DataAlignmentFactor, Arch), + 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, Triple::ArchType Arch) + : FrameEntry(FK_FDE, Offset, Length, + Cie ? Cie->getCodeAlignmentFactor() : 0, + Cie ? Cie->getDataAlignmentFactor() : 0, + Arch), + 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 { + const Triple::ArchType Arch; + // True if this is parsing an eh_frame section. + 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: + // 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(Triple::ArchType Arch, + bool IsEH = false, uint64_t EHFrameAddress = 0); + ~DWARFDebugFrame(); + + /// Dump the section data into the given stream. + void dump(raw_ostream &OS, const MCRegisterInfo *MRI, + Optional<uint64_t> Offset) const; + + /// 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(); } + + /// 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()); + } + + uint64_t getEHFrameAddress() const { return EHFrameAddress; } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h new file mode 100644 index 000000000..ded960337 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h @@ -0,0 +1,62 @@ +//===- DWARFDebugInfoEntry.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H +#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include <cstdint> + +namespace llvm { + +class DataExtractor; +class DWARFUnit; + +/// DWARFDebugInfoEntry - A DIE with only the minimum required data. +class DWARFDebugInfoEntry { + /// Offset within the .debug_info of the start of this entry. + uint64_t Offset = 0; + + /// The integer depth of this DIE within the compile unit DIEs where the + /// compile/type unit DIE has a depth of zero. + uint32_t Depth = 0; + + const DWARFAbbreviationDeclaration *AbbrevDecl = nullptr; + +public: + DWARFDebugInfoEntry() = default; + + /// Extracts a debug info entry, which is a child of a given unit, + /// starting at a given offset. If DIE can't be extracted, returns false and + /// doesn't change OffsetPtr. + bool extractFast(const DWARFUnit &U, uint64_t *OffsetPtr); + + /// High performance extraction should use this call. + bool extractFast(const DWARFUnit &U, uint64_t *OffsetPtr, + const DWARFDataExtractor &DebugInfoData, uint64_t UEndOffset, + uint32_t Depth); + + uint64_t getOffset() const { return Offset; } + uint32_t getDepth() const { return Depth; } + + dwarf::Tag getTag() const { + return AbbrevDecl ? AbbrevDecl->getTag() : dwarf::DW_TAG_null; + } + + bool hasChildren() const { return AbbrevDecl && AbbrevDecl->hasChildren(); } + + const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const { + return AbbrevDecl; + } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h new file mode 100644 index 000000000..c2be8304a --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -0,0 +1,392 @@ +//===- DWARFDebugLine.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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 "llvm/Support/Path.h" +#include <cstdint> +#include <map> +#include <string> +#include <vector> + +namespace llvm { + +class DWARFUnit; +class raw_ostream; + +class DWARFDebugLine { +public: + struct FileNameEntry { + FileNameEntry() = default; + + 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 { + Prologue(); + + /// The size in bytes of the statement information for this compilation unit + /// (not including the total_length field itself). + uint64_t TotalLength; + /// 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). + 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; + /// In v5, size in bytes of a segment selector. + uint8_t SegSelectorSize; + /// The size in bytes of the smallest target machine instruction. Statement + /// program opcodes that alter the address register first multiply their + /// operands by this value. + uint8_t MinInstLength; + /// The maximum number of individual operations that may be encoded in an + /// instruction. + uint8_t MaxOpsPerInst; + /// The initial value of theis_stmtregister. + uint8_t DefaultIsStmt; + /// This parameter affects the meaning of the special opcodes. See below. + int8_t LineBase; + /// This parameter affects the meaning of the special opcodes. See below. + uint8_t LineRange; + /// The number assigned to the first special opcode. + uint8_t OpcodeBase; + /// This tracks which optional file format content types are present. + ContentTypeTracker ContentTypes; + std::vector<uint8_t> StandardOpcodeLengths; + std::vector<DWARFFormValue> IncludeDirectories; + std::vector<FileNameEntry> FileNames; + + 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; } + + uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; } + + 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()) + + sizeofPrologueLength(); + } + + /// Length of the line table data in bytes (not including the prologue). + uint32_t getStatementTableLength() const { + return TotalLength + sizeofTotalLength() - getLength(); + } + + int32_t getMaxLineIncrementForSpecialOpcode() const { + return LineBase + (int8_t)LineRange - 1; + } + + /// Get DWARF-version aware access to the file name entry at the provided + /// index. + const llvm::DWARFDebugLine::FileNameEntry & + getFileNameEntry(uint64_t Index) const; + + bool hasFileAtIndex(uint64_t FileIndex) const; + + bool + getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, + DILineInfoSpecifier::FileLineInfoKind Kind, + std::string &Result, + sys::path::Style Style = sys::path::Style::native) const; + + void clear(); + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; + Error parse(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U = nullptr); + }; + + /// Standard .debug_line state machine structure. + struct Row { + explicit Row(bool DefaultIsStmt = false); + + /// Called after a row is appended to the matrix. + void postAppend(); + void reset(bool DefaultIsStmt); + void dump(raw_ostream &OS) const; + + static void dumpTableHeader(raw_ostream &OS); + + static bool orderByAddress(const Row &LHS, const Row &RHS) { + return std::tie(LHS.Address.SectionIndex, LHS.Address.Address) < + std::tie(RHS.Address.SectionIndex, RHS.Address.Address); + } + + /// The program-counter value corresponding to a machine instruction + /// generated by the compiler and section index pointing to the section + /// containg this PC. If relocation information is present then section + /// index is the index of the section which contains above address. + /// Otherwise this is object::SectionedAddress::Undef value. + object::SectionedAddress Address; + /// An unsigned integer indicating a source line number. Lines are numbered + /// beginning at 1. The compiler may emit the value 0 in cases where an + /// instruction cannot be attributed to any source line. + uint32_t Line; + /// An unsigned integer indicating a column number within a source line. + /// Columns are numbered beginning at 1. The value 0 is reserved to indicate + /// that a statement begins at the 'left edge' of the line. + uint16_t Column; + /// An unsigned integer indicating the identity of the source file + /// corresponding to a machine instruction. + uint16_t File; + /// An unsigned integer representing the DWARF path discriminator value + /// for this location. + uint32_t Discriminator; + /// An unsigned integer whose value encodes the applicable instruction set + /// architecture for the current instruction. + uint8_t Isa; + /// A boolean indicating that the current instruction is the beginning of a + /// statement. + uint8_t IsStmt : 1, + /// A boolean indicating that the current instruction is the + /// beginning of a basic block. + BasicBlock : 1, + /// A boolean indicating that the current address is that of the + /// first byte after the end of a sequence of target machine + /// instructions. + EndSequence : 1, + /// A boolean indicating that the current address is one (of possibly + /// many) where execution should be suspended for an entry breakpoint + /// of a function. + PrologueEnd : 1, + /// A boolean indicating that the current address is one (of possibly + /// many) where execution should be suspended for an exit breakpoint + /// of a function. + EpilogueBegin : 1; + }; + + /// Represents a series of contiguous machine instructions. Line table for + /// each compilation unit may consist of multiple sequences, which are not + /// guaranteed to be in the order of ascending instruction address. + struct Sequence { + Sequence(); + + /// Sequence describes instructions at address range [LowPC, HighPC) + /// and is described by line table rows [FirstRowIndex, LastRowIndex). + uint64_t LowPC; + uint64_t HighPC; + /// If relocation information is present then this is the index of the + /// section which contains above addresses. Otherwise this is + /// object::SectionedAddress::Undef value. + uint64_t SectionIndex; + unsigned FirstRowIndex; + unsigned LastRowIndex; + bool Empty; + + void reset(); + + static bool orderByHighPC(const Sequence &LHS, const Sequence &RHS) { + return std::tie(LHS.SectionIndex, LHS.HighPC) < + std::tie(RHS.SectionIndex, RHS.HighPC); + } + + bool isValid() const { + return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex); + } + + bool containsPC(object::SectionedAddress PC) const { + return SectionIndex == PC.SectionIndex && + (LowPC <= PC.Address && PC.Address < HighPC); + } + }; + + struct LineTable { + LineTable(); + + /// Represents an invalid row + const uint32_t UnknownRowIndex = UINT32_MAX; + + void appendRow(const DWARFDebugLine::Row &R) { Rows.push_back(R); } + + void appendSequence(const DWARFDebugLine::Sequence &S) { + Sequences.push_back(S); + } + + /// Returns the index of the row with file/line info for a given address, + /// or UnknownRowIndex if there is no such row. + uint32_t lookupAddress(object::SectionedAddress Address) const; + + bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size, + std::vector<uint32_t> &Result) const; + + bool hasFileAtIndex(uint64_t FileIndex) const { + return Prologue.hasFileAtIndex(FileIndex); + } + + /// Extracts filename by its index in filename table in prologue. + /// In Dwarf 4, the files are 1-indexed and the current compilation file + /// name is not represented in the list. In DWARF v5, the files are + /// 0-indexed and the primary source file has the index 0. + /// Returns true on success. + bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, + DILineInfoSpecifier::FileLineInfoKind Kind, + std::string &Result) const { + return Prologue.getFileNameByIndex(FileIndex, CompDir, Kind, Result); + } + + /// Fills the Result argument with the file and line information + /// corresponding to Address. Returns true on success. + bool getFileLineInfoForAddress(object::SectionedAddress Address, + const char *CompDir, + DILineInfoSpecifier::FileLineInfoKind Kind, + DILineInfo &Result) const; + + void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const; + void clear(); + + /// Parse prologue and all rows. + Error parse( + DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback, + raw_ostream *OS = nullptr); + + using RowVector = std::vector<Row>; + using RowIter = RowVector::const_iterator; + using SequenceVector = std::vector<Sequence>; + using SequenceIter = SequenceVector::const_iterator; + + struct Prologue Prologue; + RowVector Rows; + SequenceVector Sequences; + + private: + uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq, + object::SectionedAddress Address) const; + Optional<StringRef> + getSourceByIndex(uint64_t FileIndex, + DILineInfoSpecifier::FileLineInfoKind Kind) const; + + uint32_t lookupAddressImpl(object::SectionedAddress Address) const; + + bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size, + std::vector<uint32_t> &Result) const; + }; + + const LineTable *getLineTable(uint64_t Offset) const; + Expected<const LineTable *> getOrParseLineTable( + DWARFDataExtractor &DebugLineData, uint64_t Offset, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback); + + /// Helper to allow for parsing of an entire .debug_line section in sequence. + class SectionParser { + public: + using cu_range = DWARFUnitVector::iterator_range; + using tu_range = DWARFUnitVector::iterator_range; + 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, + function_ref<void(Error)> UnrecoverableErrorCallback, + 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); + + /// 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. + uint64_t getOffset() const { return Offset; } + + private: + DWARFUnit *prepareToParse(uint64_t Offset); + void moveToNextTable(uint64_t OldOffset, const Prologue &P); + + LineToUnitMap LineToUnit; + + DWARFDataExtractor &DebugLineData; + const DWARFContext &Context; + uint64_t Offset = 0; + bool Done = false; + }; + +private: + struct ParsingState { + ParsingState(struct LineTable *LT); + + void resetRowAndSequence(); + void appendRowToMatrix(); + + /// Line table we're currently parsing. + struct LineTable *LineTable; + struct Row Row; + struct Sequence Sequence; + }; + + using LineTableMapTy = std::map<uint64_t, LineTable>; + using LineTableIter = LineTableMapTy::iterator; + using LineTableConstIter = LineTableMapTy::const_iterator; + + LineTableMapTy LineTableMap; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGLINE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h new file mode 100644 index 000000000..25b771317 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -0,0 +1,121 @@ +//===- DWARFDebugLoc.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include <cstdint> + +namespace llvm { +class DWARFUnit; +class MCRegisterInfo; +class raw_ostream; + +class DWARFDebugLoc { +public: + /// A single location within a location list. + struct Entry { + /// The beginning address of the instruction range. + uint64_t Begin; + /// The ending address of the instruction range. + uint64_t End; + /// The location of the variable within the specified range. + SmallVector<uint8_t, 4> Loc; + }; + + /// A list of locations that contain one variable. + struct LocationList { + /// The beginning offset where this location list is stored in the debug_loc + /// section. + uint64_t Offset; + /// All the locations in which the variable is stored. + SmallVector<Entry, 2> Entries; + /// Dump this list on OS. + void dump(raw_ostream &OS, uint64_t BaseAddress, bool IsLittleEndian, + unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U, + DIDumpOptions DumpOpts, + unsigned Indent) const; + }; + +private: + using LocationLists = SmallVector<LocationList, 4>; + + /// A list of all the variables in the debug_loc section, each one describing + /// the locations in which the variable is stored. + LocationLists Locations; + + unsigned AddressSize; + + bool IsLittleEndian; + +public: + /// Print the location lists found within the debug_loc section. + void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, DIDumpOptions DumpOpts, + Optional<uint64_t> Offset) const; + + /// Parse the debug_loc section accessible via the 'data' parameter using the + /// address size also given in 'data' to interpret the address ranges. + void parse(const DWARFDataExtractor &data); + + /// Return the location list at the given offset or nullptr. + LocationList const *getLocationListAtOffset(uint64_t Offset) const; + + Expected<LocationList> + parseOneLocationList(const DWARFDataExtractor &Data, uint64_t *Offset); +}; + +class DWARFDebugLoclists { +public: + // Unconstructible. + DWARFDebugLoclists() = delete; + + struct Entry { + uint8_t Kind; + uint64_t Offset; + uint64_t Value0; + uint64_t Value1; + SmallVector<uint8_t, 4> Loc; + void dump(raw_ostream &OS, uint64_t &BaseAddr, bool IsLittleEndian, + unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U, + DIDumpOptions DumpOpts, unsigned Indent, size_t MaxEncodingStringLength) const; + }; + + /// Call the user-provided callback for each entry (including the end-of-list + /// entry) in the location list starting at \p Offset. The callback can return + /// false to terminate the iteration early. Returns an error if it was unable + /// to parse the entire location list correctly. Upon successful termination + /// \p Offset will be updated point past the end of the list. + static Error visitLocationList(const DWARFDataExtractor &Data, + uint64_t *Offset, uint16_t Version, + llvm::function_ref<bool(const Entry &)> F); + + /// Dump the location list at the given \p Offset. The function returns true + /// iff it has successfully reched the end of the list. This means that one + /// can attempt to parse another list after the current one (\p Offset will be + /// updated to point past the end of the current list). + static bool dumpLocationList(const DWARFDataExtractor &Data, uint64_t *Offset, + uint16_t Version, raw_ostream &OS, + uint64_t BaseAddr, const MCRegisterInfo *MRI, + DWARFUnit *U, DIDumpOptions DumpOpts, + unsigned Indent); + + /// Dump all location lists within the given range. + static void dumpRange(const DWARFDataExtractor &Data, uint64_t StartOffset, + uint64_t Size, uint16_t Version, raw_ostream &OS, + uint64_t BaseAddr, const MCRegisterInfo *MRI, + DIDumpOptions DumpOpts); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h new file mode 100644 index 000000000..7880bcdf6 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -0,0 +1,62 @@ +//===- DWARFDebugMacro.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugMacro { + /// A single macro entry within a macro list. + struct Entry { + /// The type of the macro entry. + uint32_t Type; + union { + /// The source line where the macro is defined. + uint64_t Line; + /// Vendor extension constant value. + uint64_t ExtConstant; + }; + + union { + /// The string (name, value) of the macro entry. + const char *MacroStr; + // An unsigned integer indicating the identity of the source file. + uint64_t File; + /// Vendor extension string. + const char *ExtStr; + }; + }; + + using MacroList = SmallVector<Entry, 4>; + + /// A list of all the macro entries in the debug_macinfo section. + std::vector<MacroList> MacroLists; + +public: + DWARFDebugMacro() = default; + + /// Print the macro list found within the debug_macinfo section. + void dump(raw_ostream &OS) const; + + /// Parse the debug_macinfo section accessible via the 'data' parameter. + void parse(DataExtractor data); + + /// Return whether the section has any entries. + bool empty() const { return MacroLists.empty(); } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h new file mode 100644 index 000000000..ae57306b9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -0,0 +1,80 @@ +//===- DWARFDebugPubTable.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H +#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFObject.h" +#include <cstdint> +#include <vector> + +namespace llvm { + +class raw_ostream; + +/// Represents structure for holding and parsing .debug_pub* tables. +class DWARFDebugPubTable { +public: + struct Entry { + /// Section offset from the beginning of the compilation unit. + uint64_t SecOffset; + + /// An entry of the various gnu_pub* debug sections. + dwarf::PubIndexEntryDescriptor Descriptor; + + /// The name of the object as given by the DW_AT_name attribute of the + /// referenced DIE. + StringRef Name; + }; + + /// Each table consists of sets of variable length entries. Each set describes + /// the names of global objects and functions, or global types, respectively, + /// whose definitions are represented by debugging information entries owned + /// by a single compilation unit. + struct Set { + /// The total length of the entries for that set, not including the length + /// field itself. + uint32_t Length; + + /// This number is specific to the name lookup table and is independent of + /// the DWARF version number. + uint16_t Version; + + /// The offset from the beginning of the .debug_info section of the + /// compilation unit header referenced by the set. + uint64_t Offset; + + /// The size in bytes of the contents of the .debug_info section generated + /// to represent that compilation unit. + uint32_t Size; + + std::vector<Entry> Entries; + }; + +private: + std::vector<Set> Sets; + + /// gnu styled tables contains additional information. + /// This flag determines whether or not section we parse is debug_gnu* table. + bool GnuStyle; + +public: + DWARFDebugPubTable(const DWARFObject &Obj, const DWARFSection &Sec, + bool LittleEndian, bool GnuStyle); + + void dump(raw_ostream &OS) const; + + ArrayRef<Set> getData() { return Sets; } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGPUBTABLE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h new file mode 100644 index 000000000..2f72c642a --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -0,0 +1,83 @@ +//===- DWARFDebugRangeList.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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 <cassert> +#include <cstdint> +#include <vector> + +namespace llvm { + +class raw_ostream; + +class DWARFDebugRangeList { +public: + struct RangeListEntry { + /// A beginning address offset. This address offset has the size of an + /// address and is relative to the applicable base address of the + /// compilation unit referencing this range list. It marks the beginning + /// of an address range. + uint64_t StartAddress; + /// An ending address offset. This address offset again has the size of + /// an address and is relative to the applicable base address of the + /// compilation unit referencing this range list. It marks the first + /// address past the end of the address range. The ending address must + /// be greater than or equal to the beginning address. + uint64_t EndAddress; + /// A section index this range belongs to. + uint64_t SectionIndex; + + /// The end of any given range list is marked by an end of list entry, + /// which consists of a 0 for the beginning address offset + /// and a 0 for the ending address offset. + bool isEndOfListEntry() const { + return (StartAddress == 0) && (EndAddress == 0); + } + + /// A base address selection entry consists of: + /// 1. The value of the largest representable address offset + /// (for example, 0xffffffff when the size of an address is 32 bits). + /// 2. An address, which defines the appropriate base address for + /// use in interpreting the beginning and ending address offsets of + /// subsequent entries of the location list. + bool isBaseAddressSelectionEntry(uint8_t AddressSize) const { + assert(AddressSize == 4 || AddressSize == 8); + if (AddressSize == 4) + return StartAddress == -1U; + return StartAddress == -1ULL; + } + }; + +private: + /// Offset in .debug_ranges section. + uint64_t Offset; + uint8_t AddressSize; + std::vector<RangeListEntry> Entries; + +public: + DWARFDebugRangeList() { clear(); } + + void clear(); + void dump(raw_ostream &OS) const; + Error extract(const DWARFDataExtractor &data, uint64_t *offset_ptr); + const std::vector<RangeListEntry> &getEntries() { return Entries; } + + /// getAbsoluteRanges - Returns absolute address ranges defined by this range + /// list. Has to be passed base address of the compile unit referencing this + /// range list. + DWARFAddressRangesVector + getAbsoluteRanges(llvm::Optional<object::SectionedAddress> BaseAddr) const; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h new file mode 100644 index 000000000..952c41e18 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -0,0 +1,64 @@ +//===- DWARFDebugRnglists.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H +#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H + +#include "llvm/ADT/Optional.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; +class DWARFUnit; + +/// 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, uint64_t End, uint64_t *OffsetPtr); + void dump(raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, + uint64_t &CurrentBase, DIDumpOptions DumpOpts, + llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress) 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<object::SectionedAddress> BaseAddr, + DWARFUnit &U) 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/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h new file mode 100644 index 000000000..f7f08b4a4 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -0,0 +1,468 @@ +//===- DWARFDie.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFDIE_H +#define LLVM_DEBUGINFO_DWARFDIE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/iterator.h" +#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 <cassert> +#include <cstdint> +#include <iterator> + +namespace llvm { + +class DWARFUnit; +class raw_ostream; + +//===----------------------------------------------------------------------===// +/// Utility class that carries the DWARF compile/type unit and the debug info +/// entry in an object. +/// +/// When accessing information from a debug info entry we always need to DWARF +/// compile/type unit in order to extract the info correctly as some information +/// is relative to the compile/type unit. Prior to this class the DWARFUnit and +/// the DWARFDebugInfoEntry was passed around separately and there was the +/// possibility for error if the wrong DWARFUnit was used to extract a unit +/// relative offset. This class helps to ensure that this doesn't happen and +/// also simplifies the attribute extraction calls by not having to specify the +/// DWARFUnit for each call. +class DWARFDie { + DWARFUnit *U = nullptr; + const DWARFDebugInfoEntry *Die = nullptr; + +public: + DWARFDie() = default; + DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry *D) : U(Unit), Die(D) {} + + bool isValid() const { return U && Die; } + explicit operator bool() const { return isValid(); } + const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; } + DWARFUnit *getDwarfUnit() const { return U; } + + /// Get the abbreviation declaration for this DIE. + /// + /// \returns the abbreviation declaration or NULL for null tags. + const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const { + assert(isValid() && "must check validity prior to calling"); + return Die->getAbbreviationDeclarationPtr(); + } + + /// Get the absolute offset into the debug info or types section. + /// + /// \returns the DIE offset or -1U if invalid. + uint64_t getOffset() const { + assert(isValid() && "must check validity prior to calling"); + return Die->getOffset(); + } + + dwarf::Tag getTag() const { + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) + return AbbrevDecl->getTag(); + return dwarf::DW_TAG_null; + } + + bool hasChildren() const { + assert(isValid() && "must check validity prior to calling"); + return Die->hasChildren(); + } + + /// Returns true for a valid DIE that terminates a sibling chain. + bool isNULL() const { return getAbbreviationDeclarationPtr() == nullptr; } + + /// Returns true if DIE represents a subprogram (not inlined). + bool isSubprogramDIE() const; + + /// Returns true if DIE represents a subprogram or an inlined subroutine. + bool isSubroutineDIE() const; + + /// Get the parent of this DIE object. + /// + /// \returns a valid DWARFDie instance if this object has a parent or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getParent() const; + + /// Get the 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 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. + /// \param indent the number of characters to indent each line that is output. + void dump(raw_ostream &OS, unsigned indent = 0, + DIDumpOptions DumpOpts = DIDumpOptions()) const; + + /// Convenience zero-argument overload for debugging. + LLVM_DUMP_METHOD void dump() const; + + /// Extract the specified attribute from this DIE. + /// + /// Extract an attribute value from this DIE only. This call doesn't look + /// for the attribute value in any DW_AT_specification or + /// DW_AT_abstract_origin referenced DIEs. + /// + /// \param Attr the attribute to extract. + /// \returns an optional DWARFFormValue that will have the form value if the + /// attribute was successfully extracted. + Optional<DWARFFormValue> find(dwarf::Attribute Attr) const; + + /// Extract the first value of any attribute in Attrs from this DIE. + /// + /// Extract the first attribute that matches from this DIE only. This call + /// doesn't look for the attribute value in any DW_AT_specification or + /// DW_AT_abstract_origin referenced DIEs. The attributes will be searched + /// linearly in the order they are specified within Attrs. + /// + /// \param Attrs an array of DWARF attribute to look for. + /// \returns an optional that has a valid DWARFFormValue for the first + /// matching attribute in Attrs, or None if none of the attributes in Attrs + /// exist in this DIE. + Optional<DWARFFormValue> find(ArrayRef<dwarf::Attribute> Attrs) const; + + /// Extract the first value of any attribute in Attrs from this DIE and + /// recurse into any DW_AT_specification or DW_AT_abstract_origin referenced + /// DIEs. + /// + /// \param Attrs an array of DWARF attribute to look for. + /// \returns an optional that has a valid DWARFFormValue for the first + /// matching attribute in Attrs, or None if none of the attributes in Attrs + /// exist in this DIE or in any DW_AT_specification or DW_AT_abstract_origin + /// DIEs. + Optional<DWARFFormValue> + findRecursively(ArrayRef<dwarf::Attribute> Attrs) const; + + /// Extract the specified attribute from this DIE as the referenced DIE. + /// + /// Regardless of the reference type, return the correct DWARFDie instance if + /// the attribute exists. The returned DWARFDie object might be from another + /// DWARFUnit, but that is all encapsulated in the new DWARFDie object. + /// + /// Extract an attribute value from this DIE only. This call doesn't look + /// for the attribute value in any DW_AT_specification or + /// DW_AT_abstract_origin referenced DIEs. + /// + /// \param Attr the attribute to extract. + /// \returns a valid DWARFDie instance if the attribute exists, or an invalid + /// DWARFDie object if it doesn't. + DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const; + DWARFDie getAttributeValueAsReferencedDie(const DWARFFormValue &V) const; + + /// Extract the range base attribute from this DIE as absolute section offset. + /// + /// This is a utility function that checks for either the DW_AT_rnglists_base + /// or DW_AT_GNU_ranges_base attribute. + /// + /// \returns anm optional absolute section offset value for the attribute. + Optional<uint64_t> getRangesBaseAttribute() const; + + /// Get the DW_AT_high_pc attribute value as an address. + /// + /// In DWARF version 4 and later the high PC can be encoded as an offset from + /// the DW_AT_low_pc. This function takes care of extracting the value as an + /// address or offset and adds it to the low PC if needed and returns the + /// value as an optional in case the DIE doesn't have a DW_AT_high_pc + /// attribute. + /// + /// \param LowPC the low PC that might be needed to calculate the high PC. + /// \returns an optional address value for the attribute. + Optional<uint64_t> getHighPC(uint64_t LowPC) const; + + /// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU. + /// Returns true if both attributes are present. + bool getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, + uint64_t &SectionIndex) const; + + /// Get the address ranges for this DIE. + /// + /// Get the hi/low PC range if both attributes are available or exrtracts the + /// non-contiguous address ranges from the DW_AT_ranges attribute. + /// + /// Extracts the range information from this DIE only. This call doesn't look + /// for the range in any DW_AT_specification or DW_AT_abstract_origin DIEs. + /// + /// \returns a address range vector that might be empty if no address range + /// information is available. + Expected<DWARFAddressRangesVector> getAddressRanges() const; + + /// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any + /// of its children. + /// + /// Get the hi/low PC range if both attributes are available or exrtracts the + /// non-contiguous address ranges from the DW_AT_ranges attribute for this DIE + /// and all children. + /// + /// \param Ranges the addres range vector to fill in. + void collectChildrenAddressRanges(DWARFAddressRangesVector &Ranges) const; + + bool addressRangeContainsAddress(const uint64_t Address) const; + + /// If a DIE represents a subprogram (or inlined subroutine), returns its + /// mangled name (or short name, if mangled is missing). This name may be + /// fetched from specification or abstract origin for this subprogram. + /// Returns null if no name is found. + const char *getSubroutineName(DINameKind Kind) const; + + /// Return the DIE name resolving DW_AT_sepcification or DW_AT_abstract_origin + /// references if necessary. Returns null if no name is found. + const char *getName(DINameKind Kind) const; + + /// Returns the declaration line (start line) for a DIE, assuming it specifies + /// a subprogram. This may be fetched from specification or abstract origin + /// for this subprogram by resolving DW_AT_sepcification or + /// DW_AT_abstract_origin references if necessary. + uint64_t getDeclLine() const; + + /// Retrieves values of DW_AT_call_file, DW_AT_call_line and DW_AT_call_column + /// from DIE (or zeroes if they are missing). This function looks for + /// DW_AT_call attributes in this DIE only, it will not resolve the attribute + /// values in any DW_AT_specification or DW_AT_abstract_origin DIEs. + /// \param CallFile filled in with non-zero if successful, zero if there is no + /// DW_AT_call_file attribute in this DIE. + /// \param CallLine filled in with non-zero if successful, zero if there is no + /// DW_AT_call_line attribute in this DIE. + /// \param CallColumn filled in with non-zero if successful, zero if there is + /// no DW_AT_call_column attribute in this DIE. + /// \param CallDiscriminator filled in with non-zero if successful, zero if + /// there is no DW_AT_GNU_discriminator attribute in this DIE. + void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, + uint32_t &CallColumn, uint32_t &CallDiscriminator) const; + + class attribute_iterator; + + /// Get an iterator range to all attributes in the current DIE only. + /// + /// \returns an iterator range for the attributes of the current DIE. + iterator_range<attribute_iterator> attributes() const; + + class iterator; + + iterator begin() const; + iterator end() const; + + std::reverse_iterator<iterator> rbegin() const; + std::reverse_iterator<iterator> rend() const; + + iterator_range<iterator> children() const; +}; + +class DWARFDie::attribute_iterator + : public iterator_facade_base<attribute_iterator, std::forward_iterator_tag, + const DWARFAttribute> { + /// The DWARF DIE we are extracting attributes from. + DWARFDie Die; + /// The value vended to clients via the operator*() or operator->(). + DWARFAttribute AttrValue; + /// The attribute index within the abbreviation declaration in Die. + uint32_t Index; + + friend bool operator==(const attribute_iterator &LHS, + const attribute_iterator &RHS); + + /// Update the attribute index and attempt to read the attribute value. If the + /// attribute is able to be read, update AttrValue and the Index member + /// variable. If the attribute value is not able to be read, an appropriate + /// error will be set if the Err member variable is non-NULL and the iterator + /// will be set to the end value so iteration stops. + void updateForIndex(const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I); + +public: + attribute_iterator() = delete; + 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; } +}; + +inline bool operator==(const DWARFDie::attribute_iterator &LHS, + const DWARFDie::attribute_iterator &RHS) { + return LHS.Index == RHS.Index; +} + +inline bool operator!=(const DWARFDie::attribute_iterator &LHS, + const DWARFDie::attribute_iterator &RHS) { + return !(LHS == RHS); +} + +inline bool operator==(const DWARFDie &LHS, const DWARFDie &RHS) { + return LHS.getDebugInfoEntry() == RHS.getDebugInfoEntry() && + LHS.getDwarfUnit() == RHS.getDwarfUnit(); +} + +inline bool operator!=(const DWARFDie &LHS, const DWARFDie &RHS) { + return !(LHS == RHS); +} + +inline bool operator<(const DWARFDie &LHS, const DWARFDie &RHS) { + return LHS.getOffset() < RHS.getOffset(); +} + +class DWARFDie::iterator + : public iterator_facade_base<iterator, std::bidirectional_iterator_tag, + const DWARFDie> { + DWARFDie Die; + + friend std::reverse_iterator<llvm::DWARFDie::iterator>; + friend bool operator==(const DWARFDie::iterator &LHS, + const DWARFDie::iterator &RHS); + +public: + iterator() = default; + + explicit iterator(DWARFDie D) : Die(D) {} + + iterator &operator++() { + Die = Die.getSibling(); + return *this; + } + + iterator &operator--() { + Die = Die.getPreviousSibling(); + return *this; + } + + const DWARFDie &operator*() const { return Die; } +}; + +inline bool operator==(const DWARFDie::iterator &LHS, + const DWARFDie::iterator &RHS) { + return LHS.Die == RHS.Die; +} + +inline bool operator!=(const DWARFDie::iterator &LHS, + const DWARFDie::iterator &RHS) { + return !(LHS == RHS); +} + +// These inline functions must follow the DWARFDie::iterator definition above +// as they use functions from that class. +inline DWARFDie::iterator DWARFDie::begin() const { + return iterator(getFirstChild()); +} + +inline DWARFDie::iterator DWARFDie::end() const { + return iterator(getLastChild()); +} + +inline iterator_range<DWARFDie::iterator> DWARFDie::children() const { + return make_range(begin(), end()); +} + +} // end namespace llvm + +namespace std { + +template <> +class reverse_iterator<llvm::DWARFDie::iterator> + : public llvm::iterator_facade_base< + reverse_iterator<llvm::DWARFDie::iterator>, + bidirectional_iterator_tag, const llvm::DWARFDie> { + +private: + llvm::DWARFDie Die; + bool AtEnd; + +public: + reverse_iterator(llvm::DWARFDie::iterator It) + : Die(It.Die), AtEnd(!It.Die.getPreviousSibling()) { + if (!AtEnd) + Die = Die.getPreviousSibling(); + } + + llvm::DWARFDie::iterator base() const { + return llvm::DWARFDie::iterator(AtEnd ? Die : Die.getSibling()); + } + + reverse_iterator<llvm::DWARFDie::iterator> &operator++() { + assert(!AtEnd && "Incrementing rend"); + llvm::DWARFDie D = Die.getPreviousSibling(); + if (D) + Die = D; + else + AtEnd = true; + return *this; + } + + reverse_iterator<llvm::DWARFDie::iterator> &operator--() { + if (AtEnd) { + AtEnd = false; + return *this; + } + Die = Die.getSibling(); + assert(!Die.isNULL() && "Decrementing rbegin"); + return *this; + } + + const llvm::DWARFDie &operator*() const { + assert(Die.isValid()); + return Die; + } + + // FIXME: We should be able to specify the equals operator as a friend, but + // that causes the compiler to think the operator overload is ambiguous + // with the friend declaration and the actual definition as candidates. + bool equals(const reverse_iterator<llvm::DWARFDie::iterator> &RHS) const { + return Die == RHS.Die && AtEnd == RHS.AtEnd; + } +}; + +} // namespace std + +namespace llvm { + +inline bool operator==(const std::reverse_iterator<DWARFDie::iterator> &LHS, + const std::reverse_iterator<DWARFDie::iterator> &RHS) { + return LHS.equals(RHS); +} + +inline bool operator!=(const std::reverse_iterator<DWARFDie::iterator> &LHS, + const std::reverse_iterator<DWARFDie::iterator> &RHS) { + return !(LHS == RHS); +} + +inline std::reverse_iterator<DWARFDie::iterator> DWARFDie::rbegin() const { + return llvm::make_reverse_iterator(end()); +} + +inline std::reverse_iterator<DWARFDie::iterator> DWARFDie::rend() const { + return llvm::make_reverse_iterator(begin()); +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDIE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h new file mode 100644 index 000000000..456d9df95 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -0,0 +1,159 @@ +//===--- DWARFExpression.h - DWARF Expression handling ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFEXPRESSION_H +#define LLVM_DEBUGINFO_DWARFEXPRESSION_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/DataExtractor.h" + +namespace llvm { +class DWARFUnit; +class MCRegisterInfo; +class raw_ostream; + +class DWARFExpression { +public: + class iterator; + + /// This class represents an Operation in the Expression. Each operation can + /// have up to 2 oprerands. + /// + /// An Operation can be in Error state (check with isError()). This + /// means that it couldn't be decoded successfully and if it is the + /// case, all others fields contain undefined values. + class Operation { + public: + /// Size and signedness of expression operations' operands. + enum Encoding : uint8_t { + Size1 = 0, + Size2 = 1, + Size4 = 2, + Size8 = 3, + SizeLEB = 4, + SizeAddr = 5, + SizeRefAddr = 6, + SizeBlock = 7, ///< Preceding operand contains block size + BaseTypeRef = 8, + SignBit = 0x80, + SignedSize1 = SignBit | Size1, + SignedSize2 = SignBit | Size2, + SignedSize4 = SignBit | Size4, + SignedSize8 = SignBit | Size8, + SignedSizeLEB = SignBit | SizeLEB, + SizeNA = 0xFF ///< Unused operands get this encoding. + }; + + enum DwarfVersion : uint8_t { + DwarfNA, ///< Serves as a marker for unused entries + Dwarf2 = 2, + Dwarf3, + Dwarf4, + Dwarf5 + }; + + /// Description of the encoding of one expression Op. + struct Description { + DwarfVersion Version; ///< Dwarf version where the Op was introduced. + Encoding Op[2]; ///< Encoding for Op operands, or SizeNA. + + Description(DwarfVersion Version = DwarfNA, Encoding Op1 = SizeNA, + Encoding Op2 = SizeNA) + : Version(Version) { + Op[0] = Op1; + Op[1] = Op2; + } + }; + + private: + friend class DWARFExpression::iterator; + uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>. + Description Desc; + bool Error; + uint64_t EndOffset; + uint64_t Operands[2]; + uint64_t OperandEndOffsets[2]; + + public: + Description &getDescription() { return Desc; } + uint8_t getCode() { return Opcode; } + uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; } + uint64_t getOperandEndOffset(unsigned Idx) { return OperandEndOffsets[Idx]; } + uint64_t getEndOffset() { return EndOffset; } + bool extract(DataExtractor Data, uint16_t Version, uint8_t AddressSize, + uint64_t Offset); + bool isError() { return Error; } + bool print(raw_ostream &OS, const DWARFExpression *Expr, + const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH); + bool verify(DWARFUnit *U); + }; + + /// An iterator to go through the expression operations. + class iterator + : public iterator_facade_base<iterator, std::forward_iterator_tag, + Operation> { + friend class DWARFExpression; + const DWARFExpression *Expr; + uint64_t Offset; + Operation Op; + iterator(const DWARFExpression *Expr, uint64_t Offset) + : Expr(Expr), Offset(Offset) { + Op.Error = + Offset >= Expr->Data.getData().size() || + !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset); + } + + public: + class Operation &operator++() { + Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; + Op.Error = + Offset >= Expr->Data.getData().size() || + !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset); + return Op; + } + + class Operation &operator*() { + return Op; + } + + // Comparison operators are provided out of line. + friend bool operator==(const iterator &, const iterator &); + }; + + DWARFExpression(DataExtractor Data, uint16_t Version, uint8_t AddressSize) + : Data(Data), Version(Version), AddressSize(AddressSize) { + assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2); + } + + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, Data.getData().size()); } + + void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U, + bool IsEH = false) const; + + bool verify(DWARFUnit *U); + +private: + DataExtractor Data; + uint16_t Version; + uint8_t AddressSize; +}; + +inline bool operator==(const DWARFExpression::iterator &LHS, + const DWARFExpression::iterator &RHS) { + return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset; +} + +inline bool operator!=(const DWARFExpression::iterator &LHS, + const DWARFExpression::iterator &RHS) { + return !(LHS == RHS); +} +} +#endif diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h new file mode 100644 index 000000000..6fec6fcb6 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -0,0 +1,321 @@ +//===- DWARFFormValue.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H +#define LLVM_DEBUGINFO_DWARFFORMVALUE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include <cstdint> + +namespace llvm { + +class DWARFContext; +class DWARFUnit; +class raw_ostream; + +class DWARFFormValue { +public: + enum FormClass { + FC_Unknown, + FC_Address, + FC_Block, + FC_Constant, + FC_String, + FC_Flag, + FC_Reference, + FC_Indirect, + FC_SectionOffset, + FC_Exprloc + }; + +private: + struct ValueType { + ValueType() { uval = 0; } + ValueType(int64_t V) : sval(V) {} + ValueType(uint64_t V) : uval(V) {} + ValueType(const char *V) : cstr(V) {} + + union { + uint64_t uval; + int64_t sval; + const char *cstr; + }; + const uint8_t *data = nullptr; + uint64_t SectionIndex; /// Section index for reference forms. + }; + + 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. + + DWARFFormValue(dwarf::Form F, ValueType V) : Form(F), Value(V) {} + +public: + DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} + + static DWARFFormValue createFromSValue(dwarf::Form F, int64_t V); + static DWARFFormValue createFromUValue(dwarf::Form F, uint64_t V); + static DWARFFormValue createFromPValue(dwarf::Form F, const char *V); + static DWARFFormValue createFromBlockValue(dwarf::Form F, + ArrayRef<uint8_t> D); + static DWARFFormValue createFromUnit(dwarf::Form F, const DWARFUnit *Unit, + uint64_t *OffsetPtr); + + dwarf::Form getForm() const { return Form; } + uint64_t getRawUValue() const { return Value.uval; } + + bool isFormClass(FormClass FC) const; + const DWARFUnit *getUnit() const { return U; } + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = DIDumpOptions()) const; + void dumpSectionedAddress(raw_ostream &OS, DIDumpOptions DumpOpts, + object::SectionedAddress SA) const; + static void dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS, + DIDumpOptions DumpOpts, uint64_t SectionIndex); + + /// Extracts a value in \p Data at offset \p *OffsetPtr. The information + /// in \p FormParams is needed to interpret some forms. The optional + /// \p Context and \p Unit allows extracting information if the form refers + /// to other sections (e.g., .debug_str). + bool extractValue(const DWARFDataExtractor &Data, uint64_t *OffsetPtr, + dwarf::FormParams FormParams, + const DWARFContext *Context = nullptr, + const DWARFUnit *Unit = nullptr); + + bool extractValue(const DWARFDataExtractor &Data, uint64_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; + } + + /// getAsFoo functions below return the extracted value as Foo if only + /// DWARFFormValue has form class is suitable for representing Foo. + Optional<uint64_t> getAsReference() const; + struct UnitOffset { + DWARFUnit *Unit; + uint64_t Offset; + }; + Optional<UnitOffset> getAsRelativeReference() const; + Optional<uint64_t> getAsUnsignedConstant() const; + Optional<int64_t> getAsSignedConstant() const; + Optional<const char *> getAsCString() const; + Optional<uint64_t> getAsAddress() const; + Optional<object::SectionedAddress> getAsSectionedAddress() const; + Optional<uint64_t> getAsSectionOffset() const; + Optional<ArrayRef<uint8_t>> getAsBlock() const; + Optional<uint64_t> getAsCStringOffset() const; + Optional<uint64_t> getAsReferenceUVal() const; + + /// Skip a form's value in \p DebugInfoData at the offset specified by + /// \p OffsetPtr. + /// + /// Skips the bytes for the current form and updates the offset. + /// + /// \param DebugInfoData The data where we want to skip the value. + /// \param OffsetPtr A reference to the offset that will be updated. + /// \param Params DWARF parameters to help interpret forms. + /// \returns true on success, false if the form was not skipped. + bool skipValue(DataExtractor DebugInfoData, uint64_t *OffsetPtr, + const dwarf::FormParams Params) const { + return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params); + } + + /// Skip a form's value in \p DebugInfoData at the offset specified by + /// \p OffsetPtr. + /// + /// Skips the bytes for the specified form and updates the offset. + /// + /// \param Form The DW_FORM enumeration that indicates the form to skip. + /// \param DebugInfoData The data where we want to skip the value. + /// \param OffsetPtr A reference to the offset that will be updated. + /// \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, + uint64_t *OffsetPtr, + const dwarf::FormParams FormParams); + +private: + void dumpString(raw_ostream &OS) const; +}; + +namespace dwarf { + +/// Take an optional DWARFFormValue and try to extract a string value from it. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and was a string. +inline Optional<const char *> toString(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsCString(); + return None; +} + +/// Take an optional DWARFFormValue and try to extract a string value from it. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and was a string. +inline StringRef toStringRef(const Optional<DWARFFormValue> &V, + StringRef Default = {}) { + if (V) + if (auto S = V->getAsCString()) + return *S; + return Default; +} + +/// Take an optional DWARFFormValue and extract a string value from it. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the string value or Default if the V doesn't have a value or the +/// form value's encoding wasn't a string. +inline const char *toString(const Optional<DWARFFormValue> &V, + const char *Default) { + return toString(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract an unsigned constant. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a unsigned constant form. +inline Optional<uint64_t> toUnsigned(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsUnsignedConstant(); + return None; +} + +/// Take an optional DWARFFormValue and extract a unsigned constant. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted unsigned value or Default if the V doesn't have a +/// value or the form value's encoding wasn't an unsigned constant form. +inline uint64_t toUnsigned(const Optional<DWARFFormValue> &V, + uint64_t Default) { + return toUnsigned(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract an reference. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a reference form. +inline Optional<uint64_t> toReference(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsReference(); + return None; +} + +/// Take an optional DWARFFormValue and extract a reference. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted reference value or Default if the V doesn't have a +/// value or the form value's encoding wasn't a reference form. +inline uint64_t toReference(const Optional<DWARFFormValue> &V, + uint64_t Default) { + return toReference(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract an signed constant. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a signed constant form. +inline Optional<int64_t> toSigned(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsSignedConstant(); + return None; +} + +/// Take an optional DWARFFormValue and extract a signed integer. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted signed integer value or Default if the V doesn't +/// have a value or the form value's encoding wasn't a signed integer form. +inline int64_t toSigned(const Optional<DWARFFormValue> &V, int64_t Default) { + return toSigned(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract an address. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a address form. +inline Optional<uint64_t> toAddress(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsAddress(); + return None; +} + +inline Optional<object::SectionedAddress> +toSectionedAddress(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsSectionedAddress(); + return None; +} + +/// Take an optional DWARFFormValue and extract a address. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted address value or Default if the V doesn't have a +/// value or the form value's encoding wasn't an address form. +inline uint64_t toAddress(const Optional<DWARFFormValue> &V, uint64_t Default) { + return toAddress(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract an section offset. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a section offset form. +inline Optional<uint64_t> toSectionOffset(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsSectionOffset(); + return None; +} + +/// Take an optional DWARFFormValue and extract a section offset. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted section offset value or Default if the V doesn't +/// have a value or the form value's encoding wasn't a section offset form. +inline uint64_t toSectionOffset(const Optional<DWARFFormValue> &V, + uint64_t Default) { + return toSectionOffset(V).getValueOr(Default); +} + +/// Take an optional DWARFFormValue and try to extract block data. +/// +/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a block form. +inline Optional<ArrayRef<uint8_t>> toBlock(const Optional<DWARFFormValue> &V) { + if (V) + return V->getAsBlock(); + return None; +} + +} // end namespace dwarf + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFFORMVALUE_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h new file mode 100644 index 000000000..38cd42ddb --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFGdbIndex.h @@ -0,0 +1,82 @@ +//===- DWARFGdbIndex.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H +#define LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> +#include <utility> + +namespace llvm { + +class raw_ostream; + +class DWARFGdbIndex { + uint32_t Version; + + uint32_t CuListOffset; + uint32_t TuListOffset; + uint32_t AddressAreaOffset; + uint32_t SymbolTableOffset; + uint32_t ConstantPoolOffset; + + struct CompUnitEntry { + uint64_t Offset; /// Offset of a CU in the .debug_info section. + uint64_t Length; /// Length of that CU. + }; + SmallVector<CompUnitEntry, 0> CuList; + + struct TypeUnitEntry { + uint64_t Offset; + uint64_t TypeOffset; + uint64_t TypeSignature; + }; + SmallVector<TypeUnitEntry, 0> TuList; + + struct AddressEntry { + uint64_t LowAddress; /// The low address. + uint64_t HighAddress; /// The high address. + uint32_t CuIndex; /// The CU index. + }; + SmallVector<AddressEntry, 0> AddressArea; + + struct SymTableEntry { + uint32_t NameOffset; /// Offset of the symbol's name in the constant pool. + uint32_t VecOffset; /// Offset of the CU vector in the constant pool. + }; + SmallVector<SymTableEntry, 0> SymbolTable; + + /// Each value is CU index + attributes. + SmallVector<std::pair<uint32_t, SmallVector<uint32_t, 0>>, 0> + ConstantPoolVectors; + + StringRef ConstantPoolStrings; + uint32_t StringPoolOffset; + + void dumpCUList(raw_ostream &OS) const; + void dumpTUList(raw_ostream &OS) const; + void dumpAddressArea(raw_ostream &OS) const; + void dumpSymbolTable(raw_ostream &OS) const; + void dumpConstantPool(raw_ostream &OS) const; + + bool parseImpl(DataExtractor Data); + +public: + void dump(raw_ostream &OS); + void parse(DataExtractor Data); + + bool HasContent = false; + bool HasError = false; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFGDBINDEX_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h new file mode 100644 index 000000000..496fdb247 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFListTable.h @@ -0,0 +1,290 @@ +//===- DWARFListTable.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/Errc.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. + uint64_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: + const ListEntries &getEntries() const { return Entries; } + bool empty() const { return Entries.empty(); } + void clear() { Entries.clear(); } + Error extract(DWARFDataExtractor Data, uint64_t HeaderOffset, uint64_t End, + uint64_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. + uint64_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<uint64_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. + uint64_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(); + } + uint64_t getHeaderOffset() const { return HeaderOffset; } + uint8_t getAddrSize() const { return HeaderData.AddrSize; } + uint64_t getLength() const { return HeaderData.Length; } + uint16_t getVersion() const { return HeaderData.Version; } + StringRef getSectionName() const { return SectionName; } + StringRef getListTypeString() const { return ListTypeString; } + dwarf::DwarfFormat getFormat() const { return Format; } + + /// Return the size of the table header including the length but not including + /// the offsets. + static uint8_t getHeaderSize(dwarf::DwarfFormat Format) { + switch (Format) { + case dwarf::DwarfFormat::DWARF32: + return 12; + case dwarf::DwarfFormat::DWARF64: + return 20; + } + llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64"); + } + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const; + Optional<uint64_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, uint64_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). + uint64_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<uint64_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, uint64_t *OffsetPtr) { + return Header.extract(Data, OffsetPtr); + } + /// Extract an entire table, including all list entries. + Error extract(DWARFDataExtractor Data, uint64_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, uint64_t Offset); + + uint64_t getHeaderOffset() const { return Header.getHeaderOffset(); } + uint8_t getAddrSize() const { return Header.getAddrSize(); } + dwarf::DwarfFormat getFormat() const { return Header.getFormat(); } + + void dump(raw_ostream &OS, + llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress, + DIDumpOptions DumpOpts = {}) const; + + /// Return the contents of the offset entry designated by a given index. + Optional<uint64_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 { + return DWARFListTableHeader::getHeaderSize(getFormat()); + } + + uint64_t length() { return Header.length(); } +}; + +template <typename DWARFListType> +Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data, + uint64_t *OffsetPtr) { + clear(); + if (Error E = extractHeaderAndOffsets(Data, OffsetPtr)) + return E; + + Data.setAddressSize(Header.getAddrSize()); + uint64_t End = getHeaderOffset() + Header.length(); + while (*OffsetPtr < End) { + DWARFListType CurrentList; + uint64_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, + uint64_t HeaderOffset, uint64_t End, + uint64_t *OffsetPtr, + StringRef SectionName, + StringRef ListTypeString) { + if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End) + return createStringError(errc::invalid_argument, + "invalid %s list offset 0x%" PRIx64, + 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 createStringError(errc::illegal_byte_sequence, + "no end of list marker detected at end of %s table " + "starting at offset 0x%" PRIx64, + SectionName.data(), HeaderOffset); +} + +template <typename DWARFListType> +void DWARFListTableBase<DWARFListType>::dump( + raw_ostream &OS, + llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress, + 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, LookupPooledAddress); +} + +template <typename DWARFListType> +Expected<DWARFListType> +DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data, + uint64_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; + uint64_t End = getHeaderOffset() + Header.length(); + uint64_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/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h new file mode 100644 index 000000000..88fe3f434 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -0,0 +1,85 @@ +//===- DWARFObject.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===-----------------------------------------------------------------------===/ + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFOBJECT_H +#define LLVM_DEBUGINFO_DWARF_DWARFOBJECT_H + +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/Object/ObjectFile.h" + +namespace llvm { +// This is responsible for low level access to the object file. It +// knows how to find the required sections and compute relocated +// values. +// The default implementations of the get<Section> methods return dummy values. +// This is to allow clients that only need some of those to implement just the +// ones they need. We can't use unreachable for as many cases because the parser +// implementation is eager and will call some of these methods even if the +// result is not used. +class DWARFObject { + DWARFSection Dummy; + +public: + virtual ~DWARFObject() = default; + virtual StringRef getFileName() const { llvm_unreachable("unimplemented"); } + virtual const object::ObjectFile *getFile() const { return nullptr; } + virtual ArrayRef<SectionName> getSectionNames() const { return {}; } + virtual bool isLittleEndian() const = 0; + virtual uint8_t getAddressSize() const { llvm_unreachable("unimplemented"); } + virtual void + forEachInfoSections(function_ref<void(const DWARFSection &)> F) const {} + virtual void + forEachTypesSections(function_ref<void(const DWARFSection &)> F) const {} + virtual StringRef getAbbrevSection() const { return ""; } + virtual const DWARFSection &getLocSection() const { return Dummy; } + virtual const DWARFSection &getLoclistsSection() const { return Dummy; } + virtual StringRef getArangesSection() const { return ""; } + virtual const DWARFSection &getFrameSection() const { return Dummy; } + virtual const DWARFSection &getEHFrameSection() const { return Dummy; } + virtual const DWARFSection &getLineSection() const { return Dummy; } + virtual StringRef getLineStrSection() const { return ""; } + virtual StringRef getStrSection() const { return ""; } + virtual const DWARFSection &getRangesSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsSection() const { return Dummy; } + virtual StringRef getMacinfoSection() const { return ""; } + virtual const DWARFSection &getPubnamesSection() const { return Dummy; } + virtual const DWARFSection &getPubtypesSection() const { return Dummy; } + virtual const DWARFSection &getGnuPubnamesSection() const { return Dummy; } + virtual const DWARFSection &getGnuPubtypesSection() const { return Dummy; } + virtual const DWARFSection &getStrOffsetsSection() const { return Dummy; } + virtual void + forEachInfoDWOSections(function_ref<void(const DWARFSection &)> F) const {} + virtual void + forEachTypesDWOSections(function_ref<void(const DWARFSection &)> F) const {} + virtual StringRef getAbbrevDWOSection() const { return ""; } + virtual const DWARFSection &getLineDWOSection() const { return Dummy; } + virtual const DWARFSection &getLocDWOSection() const { return Dummy; } + virtual StringRef getStrDWOSection() const { return ""; } + virtual const DWARFSection &getStrOffsetsDWOSection() const { + return Dummy; + } + virtual const DWARFSection &getRangesDWOSection() 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 &getNamesSection() const { return Dummy; } + virtual const DWARFSection &getAppleObjCSection() const { return Dummy; } + virtual StringRef getCUIndexSection() const { return ""; } + virtual StringRef getGdbIndexSection() const { return ""; } + virtual StringRef getTUIndexSection() const { return ""; } + virtual Optional<RelocAddrEntry> find(const DWARFSection &Sec, + uint64_t Pos) const = 0; +}; + +} // namespace llvm +#endif diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h new file mode 100644 index 000000000..3add71194 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h @@ -0,0 +1,38 @@ +//===- DWARFRelocMap.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H +#define LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/Object/RelocationResolver.h" +#include <cstdint> + +namespace llvm { + +/// RelocAddrEntry contains relocated value and section index. +/// Section index is -1LL if relocation points to absolute symbol. +struct RelocAddrEntry { + uint64_t SectionIndex; + object::RelocationRef Reloc; + uint64_t SymbolValue; + Optional<object::RelocationRef> Reloc2; + uint64_t SymbolValue2; + object::RelocationResolver Resolver; +}; + +/// In place of applying the relocations to the data we've read from disk we use +/// a separate mapping table to the side and checking that at locations in the +/// dwarf where we expect relocated values. This adds a bit of complexity to the +/// dwarf parsing/extraction at the benefit of not allocating memory for the +/// entire size of the debug info sections. +using RelocAddrMap = DenseMap<uint64_t, RelocAddrEntry>; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFRELOCMAP_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h new file mode 100644 index 000000000..054524d36 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFSection.h @@ -0,0 +1,27 @@ +//===- DWARFSection.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFSECTION_H +#define LLVM_DEBUGINFO_DWARF_DWARFSECTION_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +struct DWARFSection { + StringRef Data; +}; + +struct SectionName { + StringRef Name; + bool IsNameUnique; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFSECTION_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h new file mode 100644 index 000000000..c95bdcbd8 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -0,0 +1,46 @@ +//===- DWARFTypeUnit.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H +#define LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> + +namespace llvm { + +class DWARFContext; +class DWARFDebugAbbrev; +struct DWARFSection; +class raw_ostream; + +class DWARFTypeUnit : public DWARFUnit { +public: + DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, const DWARFSection *LocSection, + StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, + const DWARFSection &LS, bool LE, bool IsDWO, + const DWARFUnitVector &UnitVector) + : DWARFUnit(Context, Section, Header, DA, RS, LocSection, SS, SOS, AOS, + LS, LE, IsDWO, UnitVector) {} + + uint64_t getTypeHash() const { return getHeader().getTypeHash(); } + uint64_t getTypeOffset() const { return getHeader().getTypeOffset(); } + + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; + // Enable LLVM-style RTTI. + static bool classof(const DWARFUnit *U) { return U->isTypeUnit(); } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEUNIT_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h new file mode 100644 index 000000000..51de114a3 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -0,0 +1,527 @@ +//===- DWARFUnit.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNIT_H +#define LLVM_DEBUGINFO_DWARF_DWARFUNIT_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#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" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Support/DataExtractor.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <map> +#include <memory> +#include <utility> +#include <vector> + +namespace llvm { + +class DWARFAbbreviationDeclarationSet; +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. + uint64_t Offset = 0; + // Version, address size, and DWARF format. + dwarf::FormParams FormParams; + uint64_t Length = 0; + uint64_t AbbrOffset = 0; + + // For DWO units only. + const DWARFUnitIndex::Entry *IndexEntry = nullptr; + + // For type units only. + uint64_t TypeHash = 0; + uint64_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, + uint64_t *offset_ptr, DWARFSectionKind Kind = DW_SECT_INFO, + const DWARFUnitIndex *Index = nullptr, + const DWARFUnitIndex::Entry *Entry = nullptr); + uint64_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(); + } + uint64_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; } + uint64_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; } + uint8_t getUnitLengthFieldByteSize() const { + return dwarf::getUnitLengthFieldByteSize(FormParams.Format); + } + uint64_t getNextUnitOffset() const { + return Offset + Length + getUnitLengthFieldByteSize(); + } +}; + +const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind); + +/// Describe a collection of units. Intended to hold all units either from +/// .debug_info and .debug_types, or from .debug_info.dwo and .debug_types.dwo. +class DWARFUnitVector final : public SmallVector<std::unique_ptr<DWARFUnit>, 1> { + std::function<std::unique_ptr<DWARFUnit>(uint64_t, DWARFSectionKind, + const DWARFSection *, + const DWARFUnitIndex::Entry *)> + Parser; + int NumInfoUnits = -1; + +public: + using UnitVector = SmallVectorImpl<std::unique_ptr<DWARFUnit>>; + using iterator = typename UnitVector::iterator; + using iterator_range = llvm::iterator_range<typename UnitVector::iterator>; + + DWARFUnit *getUnitForOffset(uint64_t Offset) const; + DWARFUnit *getUnitForIndexEntry(const DWARFUnitIndex::Entry &E); + + /// Read units from a .debug_info or .debug_types section. Calls made + /// before finishedInfoUnits() are assumed to be for .debug_info sections, + /// calls after finishedInfoUnits() are for .debug_types sections. Caller + /// must not mix calls to addUnitsForSection and addUnitsForDWOSection. + void addUnitsForSection(DWARFContext &C, const DWARFSection &Section, + DWARFSectionKind SectionKind); + /// Read units from a .debug_info.dwo or .debug_types.dwo section. Calls + /// made before finishedInfoUnits() are assumed to be for .debug_info.dwo + /// sections, calls after finishedInfoUnits() are for .debug_types.dwo + /// sections. Caller must not mix calls to addUnitsForSection and + /// addUnitsForDWOSection. + void addUnitsForDWOSection(DWARFContext &C, const DWARFSection &DWOSection, + DWARFSectionKind SectionKind, bool Lazy = false); + + /// Add an existing DWARFUnit to this UnitVector. This is used by the DWARF + /// verifier to process unit separately. + DWARFUnit *addUnit(std::unique_ptr<DWARFUnit> Unit); + + /// Returns number of all units held by this instance. + unsigned getNumUnits() const { return size(); } + /// Returns number of units from all .debug_info[.dwo] sections. + unsigned getNumInfoUnits() const { + return NumInfoUnits == -1 ? size() : NumInfoUnits; + } + /// Returns number of units from all .debug_types[.dwo] sections. + unsigned getNumTypesUnits() const { return size() - NumInfoUnits; } + /// Indicate that parsing .debug_info[.dwo] is done, and remaining units + /// will be from .debug_types[.dwo]. + void finishedInfoUnits() { NumInfoUnits = size(); } + +private: + void addUnitsImpl(DWARFContext &Context, const DWARFObject &Obj, + const DWARFSection &Section, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, const DWARFSection *LocSection, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, + bool IsDWO, bool Lazy, DWARFSectionKind SectionKind); +}; + +/// Represents base address of the CU. +/// 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. + dwarf::FormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32}; + + StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size, + uint8_t Version, dwarf::DwarfFormat Format) + : Base(Base), Size(Size), FormParams({Version, 0, Format}) {} + StrOffsetsContributionDescriptor() = default; + + uint8_t getVersion() const { return FormParams.Version; } + dwarf::DwarfFormat getFormat() const { return FormParams.Format; } + uint8_t getDwarfOffsetByteSize() const { + return FormParams.getDwarfOffsetByteSize(); + } + /// Determine whether a contribution to the string offsets table is + /// consistent with the relevant section size and that its length is + /// a multiple of the size of one of its entries. + Expected<StrOffsetsContributionDescriptor> + validateContributionSize(DWARFDataExtractor &DA); +}; + +class DWARFUnit { + DWARFContext &Context; + /// Section containing this DWARFUnit. + const DWARFSection &InfoSection; + + DWARFUnitHeader Header; + const DWARFDebugAbbrev *Abbrev; + const DWARFSection *RangeSection; + uint64_t RangeSectionBase; + /// We either keep track of the location list section or its data, depending + /// on whether we are handling a split DWARF section or not. + union { + const DWARFSection *LocSection; + StringRef LocSectionData; + }; + const DWARFSection &LineSection; + StringRef StringSection; + const DWARFSection &StringOffsetSection; + const DWARFSection *AddrOffsetSection; + uint32_t AddrOffsetSectionBase = 0; + bool isLittleEndian; + bool IsDWO; + const DWARFUnitVector &UnitVector; + + /// Start, length, and DWARF format of the unit's contribution to the string + /// offsets table (DWARF v5). + Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution; + + /// A table of range lists (DWARF v5 and later). + Optional<DWARFDebugRnglistTable> RngListTable; + + mutable const DWARFAbbreviationDeclarationSet *Abbrevs; + llvm::Optional<object::SectionedAddress> BaseAddr; + /// The compile unit debug information entry items. + std::vector<DWARFDebugInfoEntry> DieArray; + + /// 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; + + uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) { + auto First = DieArray.data(); + assert(Die >= First && Die < First + DieArray.size()); + return Die - First; + } + +protected: + const DWARFUnitHeader &getHeader() const { return Header; } + + /// 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 + /// DIE's DW_AT_str_offsets_base attribute. + Expected<Optional<StrOffsetsContributionDescriptor>> + determineStringOffsetsTableContribution(DWARFDataExtractor &DA); + + /// Find the unit's contribution to the string offsets table and determine its + /// length and form. The given offset is expected to be 0 in a dwo file or, + /// in a dwp file, the start of the unit's contribution to the string offsets + /// table section (as determined by the index table). + Expected<Optional<StrOffsetsContributionDescriptor>> + determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA); + +public: + DWARFUnit(DWARFContext &Context, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, const DWARFSection *LocSection, + StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, + const DWARFSection &LS, bool LE, bool IsDWO, + const DWARFUnitVector &UnitVector); + + virtual ~DWARFUnit(); + + bool isDWOUnit() const { return IsDWO; } + DWARFContext& getContext() const { return Context; } + const DWARFSection &getInfoSection() const { return InfoSection; } + const DWARFSection *getLocSection() const { return LocSection; } + StringRef getLocSectionData() const { return LocSectionData; } + uint64_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(); + } + uint64_t getLength() const { return Header.getLength(); } + uint8_t getUnitType() const { return Header.getUnitType(); } + bool isTypeUnit() const { return Header.isTypeUnit(); } + uint64_t getNextUnitOffset() const { return Header.getNextUnitOffset(); } + const DWARFSection &getLineSection() const { return LineSection; } + StringRef getStringSection() const { return StringSection; } + const DWARFSection &getStringOffsetSection() const { + return StringOffsetSection; + } + + void setAddrOffsetSection(const DWARFSection *AOS, uint32_t Base) { + AddrOffsetSection = AOS; + AddrOffsetSectionBase = Base; + } + + /// Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + + void setRangesSection(const DWARFSection *RS, uint64_t Base) { + RangeSection = RS; + RangeSectionBase = Base; + } + + Optional<object::SectionedAddress> + getAddrOffsetSectionItem(uint32_t Index) const; + Optional<uint64_t> getStringOffsetSectionItem(uint32_t Index) const; + + DWARFDataExtractor getDebugInfoExtractor() const; + + DataExtractor getStringExtractor() const { + return DataExtractor(StringSection, false, 0); + } + + /// 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(uint64_t RangeListOffset, + DWARFDebugRangeList &RangeList) const; + void clear(); + + const Optional<StrOffsetsContributionDescriptor> & + getStringOffsetsTableContribution() const { + return StringOffsetsTableContribution; + } + + uint8_t getDwarfStringOffsetsByteSize() const { + assert(StringOffsetsTableContribution); + return StringOffsetsTableContribution->getDwarfOffsetByteSize(); + } + + uint64_t getStringOffsetsBase() const { + assert(StringOffsetsTableContribution); + return StringOffsetsTableContribution->Base; + } + + const DWARFAbbreviationDeclarationSet *getAbbreviations() const; + + static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { + switch (UnitType) { + case dwarf::DW_UT_compile: + return Tag == dwarf::DW_TAG_compile_unit; + case dwarf::DW_UT_type: + return Tag == dwarf::DW_TAG_type_unit; + case dwarf::DW_UT_partial: + return Tag == dwarf::DW_TAG_partial_unit; + case dwarf::DW_UT_skeleton: + return Tag == dwarf::DW_TAG_skeleton_unit; + case dwarf::DW_UT_split_compile: + case dwarf::DW_UT_split_type: + return dwarf::isUnitType(Tag); + } + return false; + } + + /// 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 + /// DWARF5 is defined as one of the following six types. + static uint32_t getDWARF5HeaderSize(uint8_t UnitType) { + switch (UnitType) { + case dwarf::DW_UT_compile: + case dwarf::DW_UT_partial: + return 12; + case dwarf::DW_UT_skeleton: + case dwarf::DW_UT_split_compile: + return 20; + case dwarf::DW_UT_type: + case dwarf::DW_UT_split_type: + return 24; + } + llvm_unreachable("Invalid UnitType."); + } + + llvm::Optional<object::SectionedAddress> getBaseAddress(); + + DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { + extractDIEsIfNeeded(ExtractUnitDIEOnly); + if (DieArray.empty()) + return DWARFDie(); + return DWARFDie(this, &DieArray[0]); + } + + DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true) { + parseDWO(); + if (DWO) + return DWO->getUnitDIE(ExtractUnitDIEOnly); + return getUnitDIE(ExtractUnitDIEOnly); + } + + const char *getCompilationDir(); + 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(uint64_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<uint64_t> getRnglistOffset(uint32_t Index) { + if (RngListTable) + return RngListTable->getOffsetEntry(Index); + return None; + } + + Expected<DWARFAddressRangesVector> collectAddressRanges(); + + /// Returns subprogram DIE with address range encompassing the provided + /// address. The pointer is alive as long as parsed compile unit DIEs are not + /// cleared. + DWARFDie getSubroutineForAddress(uint64_t Address); + + /// getInlinedChainForAddress - fetches inlined chain for a given address. + /// Returns empty chain if there is no subprogram containing address. The + /// chain is valid as long as parsed compile unit DIEs are not cleared. + void getInlinedChainForAddress(uint64_t Address, + SmallVectorImpl<DWARFDie> &InlinedChain); + + /// Return the DWARFUnitVector containing this unit. + const DWARFUnitVector &getUnitVector() const { return UnitVector; } + + /// Returns the number of DIEs in the unit. Parses the unit + /// if necessary. + unsigned getNumDIEs() { + extractDIEsIfNeeded(false); + return DieArray.size(); + } + + /// 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 + /// method on a DIE that isn't accessible by following + /// children/sibling links starting from this unit's getUnitDIE(). + uint32_t getDIEIndex(const DWARFDie &D) { + return getDIEIndex(D.getDebugInfoEntry()); + } + + /// Return the DIE object at the given index. + DWARFDie getDIEAtIndex(unsigned Index) { + assert(Index < DieArray.size()); + return DWARFDie(this, &DieArray[Index]); + } + + 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); + + /// 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. + DWARFDie getDIEForOffset(uint64_t Offset) { + extractDIEsIfNeeded(false); + assert(!DieArray.empty()); + auto It = + llvm::partition_point(DieArray, [=](const DWARFDebugInfoEntry &DIE) { + return DIE.getOffset() < Offset; + }); + if (It != DieArray.end() && It->getOffset() == Offset) + return DWARFDie(this, &*It); + return DWARFDie(); + } + + uint32_t getLineTableOffset() const { + if (auto IndexEntry = Header.getIndexEntry()) + if (const auto *Contrib = IndexEntry->getOffset(DW_SECT_LINE)) + return Contrib->Offset; + return 0; + } + + die_iterator_range dies() { + extractDIEsIfNeeded(false); + return die_iterator_range(DieArray.begin(), DieArray.end()); + } + + virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0; + + Error tryExtractDIEsIfNeeded(bool CUDieOnly); + +private: + /// Size in bytes of the .debug_info data associated with this compile unit. + size_t getDebugInfoSize() const { + return Header.getLength() + Header.getUnitLengthFieldByteSize() - + getHeaderSize(); + } + + /// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it + /// hasn't already been done + void extractDIEsIfNeeded(bool CUDieOnly); + + /// extractDIEsToVector - Appends all parsed DIEs to a vector. + void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs, + std::vector<DWARFDebugInfoEntry> &DIEs) const; + + /// clearDIEs - Clear parsed DIEs to keep memory usage low. + void clearDIEs(bool KeepCUDie); + + /// parseDWO - Parses .dwo file for current compile unit. Returns true if + /// it was actually constructed. + bool parseDWO(); +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFUNIT_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h new file mode 100644 index 000000000..684103aac --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -0,0 +1,105 @@ +//===- DWARFUnitIndex.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H +#define LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataExtractor.h" +#include <cstdint> +#include <memory> + +namespace llvm { + +class raw_ostream; + +enum DWARFSectionKind { + DW_SECT_INFO = 1, + DW_SECT_TYPES, + DW_SECT_ABBREV, + DW_SECT_LINE, + DW_SECT_LOC, + DW_SECT_STR_OFFSETS, + DW_SECT_MACINFO, + DW_SECT_MACRO, +}; + +class DWARFUnitIndex { + struct Header { + uint32_t Version; + uint32_t NumColumns; + uint32_t NumUnits; + uint32_t NumBuckets = 0; + + bool parse(DataExtractor IndexData, uint64_t *OffsetPtr); + void dump(raw_ostream &OS) const; + }; + +public: + class Entry { + public: + struct SectionContribution { + uint32_t Offset; + uint32_t Length; + }; + + private: + const DWARFUnitIndex *Index; + uint64_t Signature; + std::unique_ptr<SectionContribution[]> Contributions; + friend class DWARFUnitIndex; + + public: + const SectionContribution *getOffset(DWARFSectionKind Sec) const; + const SectionContribution *getOffset() const; + + const SectionContribution *getOffsets() const { + return Contributions.get(); + } + + uint64_t getSignature() const { return Signature; } + }; + +private: + struct Header Header; + + DWARFSectionKind InfoColumnKind; + int InfoColumn = -1; + std::unique_ptr<DWARFSectionKind[]> ColumnKinds; + std::unique_ptr<Entry[]> Rows; + mutable std::vector<Entry *> OffsetLookup; + + static StringRef getColumnHeader(DWARFSectionKind DS); + + bool parseImpl(DataExtractor IndexData); + +public: + DWARFUnitIndex(DWARFSectionKind InfoColumnKind) + : InfoColumnKind(InfoColumnKind) {} + + explicit operator bool() const { return Header.NumBuckets; } + + bool parse(DataExtractor IndexData); + void dump(raw_ostream &OS) const; + + const Entry *getFromOffset(uint32_t Offset) const; + const Entry *getFromHash(uint64_t Offset) const; + + ArrayRef<DWARFSectionKind> getColumnKinds() const { + return makeArrayRef(ColumnKinds.get(), Header.NumColumns); + } + + ArrayRef<Entry> getRows() const { + return makeArrayRef(Rows.get(), Header.NumBuckets); + } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFUNITINDEX_H diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h new file mode 100644 index 000000000..a4a3a11d4 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -0,0 +1,336 @@ +//===- DWARFVerifier.h ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H +#define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H + +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" + +#include <cstdint> +#include <map> +#include <set> + +namespace llvm { +class raw_ostream; +struct DWARFAttribute; +class DWARFContext; +class DWARFDie; +class DWARFUnit; +class DWARFCompileUnit; +class DWARFDataExtractor; +class DWARFDebugAbbrev; +class DataExtractor; +struct DWARFSection; + +/// A class that verifies DWARF debug information given a DWARF Context. +class DWARFVerifier { +public: + /// A class that keeps the address range information for a single DIE. + struct DieRangeInfo { + DWARFDie Die; + + /// Sorted DWARFAddressRanges. + std::vector<DWARFAddressRange> Ranges; + + /// Sorted DWARFAddressRangeInfo. + std::set<DieRangeInfo> Children; + + DieRangeInfo() = default; + DieRangeInfo(DWARFDie Die) : Die(Die) {} + + /// Used for unit testing. + DieRangeInfo(std::vector<DWARFAddressRange> Ranges) + : Ranges(std::move(Ranges)) {} + + typedef std::vector<DWARFAddressRange>::const_iterator + address_range_iterator; + typedef std::set<DieRangeInfo>::const_iterator die_range_info_iterator; + + /// Inserts the address range. If the range overlaps with an existing + /// range, the range is *not* added and an iterator to the overlapping + /// range is returned. + /// + /// This is used for finding overlapping ranges within the same DIE. + address_range_iterator insert(const DWARFAddressRange &R); + + /// Finds an address range in the sorted vector of ranges. + address_range_iterator findRange(const DWARFAddressRange &R) const { + auto Begin = Ranges.begin(); + auto End = Ranges.end(); + auto Iter = std::upper_bound(Begin, End, R); + if (Iter != Begin) + --Iter; + return Iter; + } + + /// Inserts the address range info. If any of its ranges overlaps with a + /// range in an existing range info, the range info is *not* added and an + /// iterator to the overlapping range info. + /// + /// This is used for finding overlapping children of the same DIE. + die_range_info_iterator insert(const DieRangeInfo &RI); + + /// Return true if ranges in this object contains all ranges within RHS. + bool contains(const DieRangeInfo &RHS) const; + + /// Return true if any range in this object intersects with any range in + /// RHS. + bool intersects(const DieRangeInfo &RHS) const; + }; + +private: + raw_ostream &OS; + DWARFContext &DCtx; + DIDumpOptions DumpOpts; + /// A map that tracks all references (converted absolute references) so we + /// can verify each reference points to a valid DIE and not an offset that + /// lies between to valid DIEs. + std::map<uint64_t, std::set<uint64_t>> ReferenceToDIEOffsets; + uint32_t NumDebugLineErrors = 0; + // Used to relax some checks that do not currently work portably + bool IsObjectFile; + bool IsMachOObject; + + raw_ostream &error() const; + raw_ostream &warn() const; + raw_ostream ¬e() const; + raw_ostream &dump(const DWARFDie &Die, unsigned indent = 0) const; + + /// Verifies the abbreviations section. + /// + /// This function currently checks that: + /// --No abbreviation declaration has more than one attributes with the same + /// name. + /// + /// \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 occurred during verification. + unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev); + + /// Verifies the header of a unit in a .debug_info or .debug_types section. + /// + /// This function currently checks for: + /// - Unit is in 32-bit DWARF format. The function can be modified to + /// support 64-bit format. + /// - The DWARF version is valid + /// - The unit type is valid (if unit is in version >=5) + /// - The unit doesn't extend beyond the containing section + /// - The address size is valid + /// - The offset in the .debug_abbrev section is valid + /// + /// \param DebugInfoData The section data + /// \param Offset A reference to the offset start of the unit. The offset will + /// be updated to point to the next unit in the section + /// \param UnitIndex The index of the unit to be verified + /// \param UnitType A reference to the type of the unit + /// \param isUnitDWARF64 A reference to a flag that shows whether the unit is + /// in 64-bit format. + /// + /// \returns true if the header is verified successfully, false otherwise. + bool verifyUnitHeader(const DWARFDataExtractor DebugInfoData, + uint64_t *Offset, unsigned UnitIndex, uint8_t &UnitType, + bool &isUnitDWARF64); + + /// Verifies the header of a unit in a .debug_info or .debug_types section. + /// + /// This function currently verifies: + /// - The debug info attributes. + /// - The debug info form=s. + /// - The presence of a root DIE. + /// - That the root DIE is a unit DIE. + /// - If a unit type is provided, that the unit DIE matches the unit type. + /// - The DIE ranges. + /// - That call site entries are only nested within subprograms with a + /// DW_AT_call attribute. + /// + /// \param Unit The DWARF Unit to verify. + /// + /// \returns The number of errors that occurred during verification. + unsigned verifyUnitContents(DWARFUnit &Unit); + + /// Verifies the unit headers and contents in a .debug_info or .debug_types + /// section. + /// + /// \param S The DWARF Section to verify. + /// \param SectionKind The object-file section kind that S comes from. + /// + /// \returns The number of errors that occurred during verification. + unsigned verifyUnitSection(const DWARFSection &S, + DWARFSectionKind SectionKind); + + /// Verifies that a call site entry is nested within a subprogram with a + /// DW_AT_call attribute. + /// + /// \returns Number of errors that occurred during verification. + unsigned verifyDebugInfoCallSite(const DWARFDie &Die); + + /// Verify that all Die ranges are valid. + /// + /// This function currently checks for: + /// - cases in which lowPC >= highPC + /// + /// \returns Number of errors that occurred during verification. + unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI); + + /// Verifies the attribute's DWARF attribute and its value. + /// + /// This function currently checks for: + /// - DW_AT_ranges values is a valid .debug_ranges offset + /// - DW_AT_stmt_list is a valid .debug_line offset + /// + /// \param Die The DWARF DIE that owns the attribute value + /// \param AttrValue The DWARF attribute value to check + /// + /// \returns NumErrors The number of errors occurred during verification of + /// attributes' values in a unit + unsigned verifyDebugInfoAttribute(const DWARFDie &Die, + DWARFAttribute &AttrValue); + + /// Verifies the attribute's DWARF form. + /// + /// This function currently checks for: + /// - All DW_FORM_ref values that are CU relative have valid CU offsets + /// - All DW_FORM_ref_addr values have valid section offsets + /// - All DW_FORM_strp values have valid .debug_str offsets + /// + /// \param Die The DWARF DIE that owns the attribute value + /// \param AttrValue The DWARF attribute value to check + /// + /// \returns NumErrors The number of errors occurred during verification of + /// attributes' forms in a unit + unsigned verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue); + + /// Verifies the all valid references that were found when iterating through + /// all of the DIE attributes. + /// + /// This function will verify that all references point to DIEs whose DIE + /// offset matches. This helps to ensure if a DWARF link phase moved things + /// around, that it doesn't create invalid references by failing to relocate + /// CU relative and absolute references. + /// + /// \returns NumErrors The number of errors occurred during verification of + /// references for the .debug_info and .debug_types sections + unsigned verifyDebugInfoReferences(); + + /// 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(); + + /// Verify that all of the rows in the line table are valid. + /// + /// This function currently checks for: + /// - addresses within a sequence that decrease in value + /// - invalid file indexes + void verifyDebugLineRows(); + + /// Verify that an Apple-style accelerator table is valid. + /// + /// This function currently checks that: + /// - The fixed part of the header fits in the section + /// - The size of the section is as large as what the header describes + /// - There is at least one atom + /// - The form for each atom is valid + /// - The tag for each DIE in the table is valid + /// - The buckets have a valid index, or they are empty + /// - Each hashdata offset is valid + /// - Each DIE is valid + /// + /// \param AccelSection pointer to the section containing the acceleration table + /// \param StrData pointer to the string section + /// \param SectionName the name of the table we're verifying + /// + /// \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, + DIDumpOptions DumpOpts = DIDumpOptions::getForSingleDIE()); + + /// Verify the information in any of the following sections, if available: + /// .debug_abbrev, debug_abbrev.dwo + /// + /// Any errors are reported to the stream that was this object was + /// constructed with. + /// + /// \returns true if .debug_abbrev and .debug_abbrev.dwo verify successfully, + /// false otherwise. + bool handleDebugAbbrev(); + + /// Verify the information in the .debug_info and .debug_types sections. + /// + /// Any errors are reported to the stream that this object was + /// constructed with. + /// + /// \returns true if all sections verify successfully, false otherwise. + bool handleDebugInfo(); + + /// Verify the information in the .debug_line section. + /// + /// Any errors are reported to the stream that was this object was + /// constructed with. + /// + /// \returns true if the .debug_line verifies successfully, false otherwise. + bool handleDebugLine(); + + /// Verify the information in accelerator tables, if they exist. + /// + /// Any errors are reported to the stream that was this object was + /// constructed with. + /// + /// \returns true if the existing Apple-style accelerator tables verify + /// successfully, false otherwise. + bool handleAccelTables(); +}; + +static inline bool operator<(const DWARFVerifier::DieRangeInfo &LHS, + const DWARFVerifier::DieRangeInfo &RHS) { + return std::tie(LHS.Ranges, LHS.Die) < std::tie(RHS.Ranges, RHS.Die); +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |