Home | History | Annotate | Line # | Download | only in DebugInfo
      1 //===- DIContext.h ----------------------------------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines DIContext, an abstract data structure that holds
     10 // debug information data.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_DEBUGINFO_DICONTEXT_H
     15 #define LLVM_DEBUGINFO_DICONTEXT_H
     16 
     17 #include "llvm/ADT/SmallVector.h"
     18 #include "llvm/Object/ObjectFile.h"
     19 #include "llvm/Support/WithColor.h"
     20 #include "llvm/Support/raw_ostream.h"
     21 #include <cassert>
     22 #include <cstdint>
     23 #include <memory>
     24 #include <string>
     25 #include <tuple>
     26 #include <utility>
     27 
     28 namespace llvm {
     29 
     30 /// A format-neutral container for source line information.
     31 struct DILineInfo {
     32   // DILineInfo contains "<invalid>" for function/filename it cannot fetch.
     33   static constexpr const char *const BadString = "<invalid>";
     34   // Use "??" instead of "<invalid>" to make our output closer to addr2line.
     35   static constexpr const char *const Addr2LineBadString = "??";
     36   std::string FileName;
     37   std::string FunctionName;
     38   std::string StartFileName;
     39   Optional<StringRef> Source;
     40   uint32_t Line = 0;
     41   uint32_t Column = 0;
     42   uint32_t StartLine = 0;
     43   Optional<uint64_t> StartAddress;
     44 
     45   // DWARF-specific.
     46   uint32_t Discriminator = 0;
     47 
     48   DILineInfo()
     49       : FileName(BadString), FunctionName(BadString), StartFileName(BadString) {
     50   }
     51 
     52   bool operator==(const DILineInfo &RHS) const {
     53     return Line == RHS.Line && Column == RHS.Column &&
     54            FileName == RHS.FileName && FunctionName == RHS.FunctionName &&
     55            StartFileName == RHS.StartFileName && StartLine == RHS.StartLine &&
     56            Discriminator == RHS.Discriminator;
     57   }
     58 
     59   bool operator!=(const DILineInfo &RHS) const {
     60     return !(*this == RHS);
     61   }
     62 
     63   bool operator<(const DILineInfo &RHS) const {
     64     return std::tie(FileName, FunctionName, StartFileName, Line, Column,
     65                     StartLine, Discriminator) <
     66            std::tie(RHS.FileName, RHS.FunctionName, RHS.StartFileName, RHS.Line,
     67                     RHS.Column, RHS.StartLine, RHS.Discriminator);
     68   }
     69 
     70   explicit operator bool() const { return *this != DILineInfo(); }
     71 
     72   void dump(raw_ostream &OS) {
     73     OS << "Line info: ";
     74     if (FileName != BadString)
     75       OS << "file '" << FileName << "', ";
     76     if (FunctionName != BadString)
     77       OS << "function '" << FunctionName << "', ";
     78     OS << "line " << Line << ", ";
     79     OS << "column " << Column << ", ";
     80     if (StartFileName != BadString)
     81       OS << "start file '" << StartFileName << "', ";
     82     OS << "start line " << StartLine << '\n';
     83   }
     84 };
     85 
     86 using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>;
     87 
     88 /// A format-neutral container for inlined code description.
     89 class DIInliningInfo {
     90   SmallVector<DILineInfo, 4> Frames;
     91 
     92 public:
     93   DIInliningInfo() = default;
     94 
     95   const DILineInfo & getFrame(unsigned Index) const {
     96     assert(Index < Frames.size());
     97     return Frames[Index];
     98   }
     99 
    100   DILineInfo *getMutableFrame(unsigned Index) {
    101     assert(Index < Frames.size());
    102     return &Frames[Index];
    103   }
    104 
    105   uint32_t getNumberOfFrames() const {
    106     return Frames.size();
    107   }
    108 
    109   void addFrame(const DILineInfo &Frame) {
    110     Frames.push_back(Frame);
    111   }
    112 
    113   void resize(unsigned i) {
    114     Frames.resize(i);
    115   }
    116 };
    117 
    118 /// Container for description of a global variable.
    119 struct DIGlobal {
    120   std::string Name;
    121   uint64_t Start = 0;
    122   uint64_t Size = 0;
    123 
    124   DIGlobal() : Name(DILineInfo::BadString) {}
    125 };
    126 
    127 struct DILocal {
    128   std::string FunctionName;
    129   std::string Name;
    130   std::string DeclFile;
    131   uint64_t DeclLine = 0;
    132   Optional<int64_t> FrameOffset;
    133   Optional<uint64_t> Size;
    134   Optional<uint64_t> TagOffset;
    135 };
    136 
    137 /// A DINameKind is passed to name search methods to specify a
    138 /// preference regarding the type of name resolution the caller wants.
    139 enum class DINameKind { None, ShortName, LinkageName };
    140 
    141 /// Controls which fields of DILineInfo container should be filled
    142 /// with data.
    143 struct DILineInfoSpecifier {
    144   enum class FileLineInfoKind {
    145     None,
    146     // RawValue is whatever the compiler stored in the filename table.  Could be
    147     // a full path, could be something else.
    148     RawValue,
    149     BaseNameOnly,
    150     // Relative to the compilation directory.
    151     RelativeFilePath,
    152     AbsoluteFilePath
    153   };
    154   using FunctionNameKind = DINameKind;
    155 
    156   FileLineInfoKind FLIKind;
    157   FunctionNameKind FNKind;
    158 
    159   DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::RawValue,
    160                       FunctionNameKind FNKind = FunctionNameKind::None)
    161       : FLIKind(FLIKind), FNKind(FNKind) {}
    162 };
    163 
    164 /// This is just a helper to programmatically construct DIDumpType.
    165 enum DIDumpTypeCounter {
    166 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
    167   DIDT_ID_##ENUM_NAME,
    168 #include "llvm/BinaryFormat/Dwarf.def"
    169 #undef HANDLE_DWARF_SECTION
    170   DIDT_ID_UUID,
    171   DIDT_ID_Count
    172 };
    173 static_assert(DIDT_ID_Count <= 32, "section types overflow storage");
    174 
    175 /// Selects which debug sections get dumped.
    176 enum DIDumpType : unsigned {
    177   DIDT_Null,
    178   DIDT_All             = ~0U,
    179 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
    180   DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME,
    181 #include "llvm/BinaryFormat/Dwarf.def"
    182 #undef HANDLE_DWARF_SECTION
    183   DIDT_UUID = 1 << DIDT_ID_UUID,
    184 };
    185 
    186 /// Container for dump options that control which debug information will be
    187 /// dumped.
    188 struct DIDumpOptions {
    189   unsigned DumpType = DIDT_All;
    190   unsigned ChildRecurseDepth = -1U;
    191   unsigned ParentRecurseDepth = -1U;
    192   uint16_t Version = 0; // DWARF version to assume when extracting.
    193   uint8_t AddrSize = 4; // Address byte size to assume when extracting.
    194   bool ShowAddresses = true;
    195   bool ShowChildren = false;
    196   bool ShowParents = false;
    197   bool ShowForm = false;
    198   bool SummarizeTypes = false;
    199   bool Verbose = false;
    200   bool DisplayRawContents = false;
    201 
    202   /// Return default option set for printing a single DIE without children.
    203   static DIDumpOptions getForSingleDIE() {
    204     DIDumpOptions Opts;
    205     Opts.ChildRecurseDepth = 0;
    206     Opts.ParentRecurseDepth = 0;
    207     return Opts;
    208   }
    209 
    210   /// Return the options with RecurseDepth set to 0 unless explicitly required.
    211   DIDumpOptions noImplicitRecursion() const {
    212     DIDumpOptions Opts = *this;
    213     if (ChildRecurseDepth == -1U && !ShowChildren)
    214       Opts.ChildRecurseDepth = 0;
    215     if (ParentRecurseDepth == -1U && !ShowParents)
    216       Opts.ParentRecurseDepth = 0;
    217     return Opts;
    218   }
    219 
    220   std::function<void(Error)> RecoverableErrorHandler =
    221       WithColor::defaultErrorHandler;
    222   std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler;
    223 };
    224 
    225 class DIContext {
    226 public:
    227   enum DIContextKind {
    228     CK_DWARF,
    229     CK_PDB
    230   };
    231 
    232   DIContext(DIContextKind K) : Kind(K) {}
    233   virtual ~DIContext() = default;
    234 
    235   DIContextKind getKind() const { return Kind; }
    236 
    237   virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
    238 
    239   virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) {
    240     // No verifier? Just say things went well.
    241     return true;
    242   }
    243 
    244   virtual DILineInfo getLineInfoForAddress(
    245       object::SectionedAddress Address,
    246       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
    247   virtual DILineInfoTable getLineInfoForAddressRange(
    248       object::SectionedAddress Address, uint64_t Size,
    249       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
    250   virtual DIInliningInfo getInliningInfoForAddress(
    251       object::SectionedAddress Address,
    252       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
    253 
    254   virtual std::vector<DILocal>
    255   getLocalsForAddress(object::SectionedAddress Address) = 0;
    256 
    257 private:
    258   const DIContextKind Kind;
    259 };
    260 
    261 /// An inferface for inquiring the load address of a loaded object file
    262 /// to be used by the DIContext implementations when applying relocations
    263 /// on the fly.
    264 class LoadedObjectInfo {
    265 protected:
    266   LoadedObjectInfo() = default;
    267   LoadedObjectInfo(const LoadedObjectInfo &) = default;
    268 
    269 public:
    270   virtual ~LoadedObjectInfo() = default;
    271 
    272   /// Obtain the Load Address of a section by SectionRef.
    273   ///
    274   /// Calculate the address of the given section.
    275   /// The section need not be present in the local address space. The addresses
    276   /// need to be consistent with the addresses used to query the DIContext and
    277   /// the output of this function should be deterministic, i.e. repeated calls
    278   /// with the same Sec should give the same address.
    279   virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const {
    280     return 0;
    281   }
    282 
    283   /// If conveniently available, return the content of the given Section.
    284   ///
    285   /// When the section is available in the local address space, in relocated
    286   /// (loaded) form, e.g. because it was relocated by a JIT for execution, this
    287   /// function should provide the contents of said section in `Data`. If the
    288   /// loaded section is not available, or the cost of retrieving it would be
    289   /// prohibitive, this function should return false. In that case, relocations
    290   /// will be read from the local (unrelocated) object file and applied on the
    291   /// fly. Note that this method is used purely for optimzation purposes in the
    292   /// common case of JITting in the local address space, so returning false
    293   /// should always be correct.
    294   virtual bool getLoadedSectionContents(const object::SectionRef &Sec,
    295                                         StringRef &Data) const {
    296     return false;
    297   }
    298 
    299   // FIXME: This is untested and unused anywhere in the LLVM project, it's
    300   // used/needed by Julia (an external project). It should have some coverage
    301   // (at least tests, but ideally example functionality).
    302   /// Obtain a copy of this LoadedObjectInfo.
    303   virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0;
    304 };
    305 
    306 template <typename Derived, typename Base = LoadedObjectInfo>
    307 struct LoadedObjectInfoHelper : Base {
    308 protected:
    309   LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
    310   LoadedObjectInfoHelper() = default;
    311 
    312 public:
    313   template <typename... Ts>
    314   LoadedObjectInfoHelper(Ts &&... Args) : Base(std::forward<Ts>(Args)...) {}
    315 
    316   std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
    317     return std::make_unique<Derived>(static_cast<const Derived &>(*this));
    318   }
    319 };
    320 
    321 } // end namespace llvm
    322 
    323 #endif // LLVM_DEBUGINFO_DICONTEXT_H
    324