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