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