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