diff options
author | Alon Zakai <azakai@google.com> | 2019-12-19 09:04:08 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-19 09:04:08 -0800 |
commit | 4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6 (patch) | |
tree | 91bffc2d47b1fe4bba01e7ada77006ef340bd138 /third_party/llvm-project/include/llvm/DebugInfo | |
parent | 0048f5b004ddf50e750aa335d0be314a73852058 (diff) | |
download | binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.gz binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.bz2 binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.zip |
DWARF parsing and writing support using LLVM (#2520)
This imports LLVM code for DWARF handling. That code has the
Apache 2 license like us. It's also the same code used to
emit DWARF in the common toolchain, so it seems like a safe choice.
This adds two passes: --dwarfdump which runs the same code LLVM
runs for llvm-dwarfdump. This shows we can parse it ok, and will
be useful for debugging. And --dwarfupdate writes out the DWARF
sections (unchanged from what we read, so it just roundtrips - for
updating we need #2515).
This puts LLVM in thirdparty which is added here.
All the LLVM code is behind USE_LLVM_DWARF, which is on
by default, but off in JS for now, as it increases code size by 20%.
This current approach imports the LLVM files directly. This is not
how they are intended to be used, so it required a bunch of
local changes - more than I expected actually, for the platform-specific
stuff. For now this seems to work, so it may be good enough, but
in the long term we may want to switch to linking against libllvm.
A downside to doing that is that binaryen users would need to
have an LLVM build, and even in the waterfall builds we'd have a
problem - while we ship LLVM there anyhow, we constantly update
it, which means that binaryen would need to be on latest llvm all
the time too (which otherwise, given DWARF is quite stable, we
might not need to constantly update).
An even larger issue is that as I did this work I learned about how
DWARF works in LLVM, and while the reading code is easy to
reuse, the writing code is trickier. The main code path is heavily
integrated with the MC layer, which we don't have - we might want
to create a "fake MC layer" for that, but it sounds hard. Instead,
there is the YAML path which is used mostly for testing, and which
can convert DWARF to and from YAML and from binary. Using
the non-YAML parts there, we can convert binary DWARF to
the YAML layer's nice Info data, then convert that to binary. This
works, however, this is not the path LLVM uses normally, and it
supports only some basic DWARF sections - I had to add ranges
support, in fact. So if we need more complex things, we may end
up needing to use the MC layer approach, or consider some other
DWARF library. However, hopefully that should not affect the core
binaryen code which just calls a library for DWARF stuff.
Helps #2400
Diffstat (limited to 'third_party/llvm-project/include/llvm/DebugInfo')
32 files changed, 5677 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h b/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h new file mode 100644 index 000000000..fbebfe634 --- /dev/null +++ b/third_party/llvm-project/include/llvm/DebugInfo/DIContext.h @@ -0,0 +1,302 @@ +//===- DIContext.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 +// +//===----------------------------------------------------------------------===// +// +// This file defines DIContext, an abstract data structure that holds +// debug information data. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_DICONTEXT_H +#define LLVM_DEBUGINFO_DICONTEXT_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <string> +#include <tuple> +#include <utility> + +namespace llvm { + +/// A format-neutral container for source line information. +struct DILineInfo { + // DILineInfo contains "<invalid>" for function/filename it cannot fetch. + static constexpr const char *const BadString = "<invalid>"; + // Use "??" instead of "<invalid>" to make our output closer to addr2line. + static constexpr const char *const Addr2LineBadString = "??"; + std::string FileName; + std::string FunctionName; + Optional<StringRef> Source; + uint32_t Line = 0; + uint32_t Column = 0; + uint32_t StartLine = 0; + + // DWARF-specific. + uint32_t Discriminator = 0; + + DILineInfo() : FileName(BadString), FunctionName(BadString) {} + + bool operator==(const DILineInfo &RHS) const { + return Line == RHS.Line && Column == RHS.Column && + FileName == RHS.FileName && FunctionName == RHS.FunctionName && + StartLine == RHS.StartLine && Discriminator == RHS.Discriminator; + } + + bool operator!=(const DILineInfo &RHS) const { + return !(*this == RHS); + } + + bool operator<(const DILineInfo &RHS) const { + return std::tie(FileName, FunctionName, Line, Column, StartLine, + Discriminator) < + std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column, + RHS.StartLine, RHS.Discriminator); + } + + explicit operator bool() const { return *this != DILineInfo(); } + + void dump(raw_ostream &OS) { + OS << "Line info: "; + if (FileName != BadString) + OS << "file '" << FileName << "', "; + if (FunctionName != BadString) + OS << "function '" << FunctionName << "', "; + OS << "line " << Line << ", "; + OS << "column " << Column << ", "; + OS << "start line " << StartLine << '\n'; + } +}; + +using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>; + +/// A format-neutral container for inlined code description. +class DIInliningInfo { + SmallVector<DILineInfo, 4> Frames; + +public: + DIInliningInfo() = default; + + const DILineInfo & getFrame(unsigned Index) const { + assert(Index < Frames.size()); + return Frames[Index]; + } + + DILineInfo *getMutableFrame(unsigned Index) { + assert(Index < Frames.size()); + return &Frames[Index]; + } + + uint32_t getNumberOfFrames() const { + return Frames.size(); + } + + void addFrame(const DILineInfo &Frame) { + Frames.push_back(Frame); + } + + void resize(unsigned i) { + Frames.resize(i); + } +}; + +/// Container for description of a global variable. +struct DIGlobal { + std::string Name; + uint64_t Start = 0; + uint64_t Size = 0; + + DIGlobal() : Name(DILineInfo::BadString) {} +}; + +struct DILocal { + std::string FunctionName; + std::string Name; + std::string DeclFile; + uint64_t DeclLine = 0; + Optional<int64_t> FrameOffset; + Optional<uint64_t> Size; + Optional<uint64_t> TagOffset; +}; + +/// A DINameKind is passed to name search methods to specify a +/// preference regarding the type of name resolution the caller wants. +enum class DINameKind { None, ShortName, LinkageName }; + +/// Controls which fields of DILineInfo container should be filled +/// with data. +struct DILineInfoSpecifier { + enum class FileLineInfoKind { None, Default, AbsoluteFilePath }; + using FunctionNameKind = DINameKind; + + FileLineInfoKind FLIKind; + FunctionNameKind FNKind; + + DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::Default, + FunctionNameKind FNKind = FunctionNameKind::None) + : FLIKind(FLIKind), FNKind(FNKind) {} +}; + +/// This is just a helper to programmatically construct DIDumpType. +enum DIDumpTypeCounter { +#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ + DIDT_ID_##ENUM_NAME, +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DWARF_SECTION + DIDT_ID_UUID, + DIDT_ID_Count +}; +static_assert(DIDT_ID_Count <= 32, "section types overflow storage"); + +/// Selects which debug sections get dumped. +enum DIDumpType : unsigned { + DIDT_Null, + DIDT_All = ~0U, +#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ + DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME, +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DWARF_SECTION + DIDT_UUID = 1 << DIDT_ID_UUID, +}; + +/// Container for dump options that control which debug information will be +/// dumped. +struct DIDumpOptions { + unsigned DumpType = DIDT_All; + unsigned ChildRecurseDepth = -1U; + unsigned ParentRecurseDepth = -1U; + uint16_t Version = 0; // DWARF version to assume when extracting. + uint8_t AddrSize = 4; // Address byte size to assume when extracting. + bool ShowAddresses = true; + bool ShowChildren = false; + bool ShowParents = false; + bool ShowForm = false; + bool SummarizeTypes = false; + bool Verbose = false; + bool DisplayRawContents = false; + + /// Return default option set for printing a single DIE without children. + static DIDumpOptions getForSingleDIE() { + DIDumpOptions Opts; + Opts.ChildRecurseDepth = 0; + Opts.ParentRecurseDepth = 0; + return Opts; + } + + /// Return the options with RecurseDepth set to 0 unless explicitly required. + DIDumpOptions noImplicitRecursion() const { + DIDumpOptions Opts = *this; + if (ChildRecurseDepth == -1U && !ShowChildren) + Opts.ChildRecurseDepth = 0; + if (ParentRecurseDepth == -1U && !ShowParents) + Opts.ParentRecurseDepth = 0; + return Opts; + } +}; + +class DIContext { +public: + enum DIContextKind { + CK_DWARF, + CK_PDB + }; + + DIContext(DIContextKind K) : Kind(K) {} + virtual ~DIContext() = default; + + DIContextKind getKind() const { return Kind; } + + virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0; + + virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) { + // No verifier? Just say things went well. + return true; + } + + virtual DILineInfo getLineInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; + virtual DILineInfoTable getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; + virtual DIInliningInfo getInliningInfoForAddress( + object::SectionedAddress Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; + + virtual std::vector<DILocal> + getLocalsForAddress(object::SectionedAddress Address) = 0; + +private: + const DIContextKind Kind; +}; + +/// An inferface for inquiring the load address of a loaded object file +/// to be used by the DIContext implementations when applying relocations +/// on the fly. +class LoadedObjectInfo { +protected: + LoadedObjectInfo() = default; + LoadedObjectInfo(const LoadedObjectInfo &) = default; + +public: + virtual ~LoadedObjectInfo() = default; + + /// Obtain the Load Address of a section by SectionRef. + /// + /// Calculate the address of the given section. + /// The section need not be present in the local address space. The addresses + /// need to be consistent with the addresses used to query the DIContext and + /// the output of this function should be deterministic, i.e. repeated calls + /// with the same Sec should give the same address. + virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const { + return 0; + } + + /// If conveniently available, return the content of the given Section. + /// + /// When the section is available in the local address space, in relocated + /// (loaded) form, e.g. because it was relocated by a JIT for execution, this + /// function should provide the contents of said section in `Data`. If the + /// loaded section is not available, or the cost of retrieving it would be + /// prohibitive, this function should return false. In that case, relocations + /// will be read from the local (unrelocated) object file and applied on the + /// fly. Note that this method is used purely for optimzation purposes in the + /// common case of JITting in the local address space, so returning false + /// should always be correct. + virtual bool getLoadedSectionContents(const object::SectionRef &Sec, + StringRef &Data) const { + return false; + } + + // FIXME: This is untested and unused anywhere in the LLVM project, it's + // used/needed by Julia (an external project). It should have some coverage + // (at least tests, but ideally example functionality). + /// Obtain a copy of this LoadedObjectInfo. + virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0; +}; + +template <typename Derived, typename Base = LoadedObjectInfo> +struct LoadedObjectInfoHelper : Base { +protected: + LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default; + LoadedObjectInfoHelper() = default; + +public: + template <typename... Ts> + LoadedObjectInfoHelper(Ts &&... Args) : Base(std::forward<Ts>(Args)...) {} + + std::unique_ptr<llvm::LoadedObjectInfo> clone() const override { + return std::make_unique<Derived>(static_cast<const Derived &>(*this)); + } +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DICONTEXT_H 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 |