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