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
29namespace llvm {
30
31/// A format-neutral container for source line information.
32struct 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
53 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(args: FileName, args: FunctionName, args: StartFileName, args: Line, args: Column,
68 args: StartLine, args: Discriminator) <
69 std::tie(args: RHS.FileName, args: RHS.FunctionName, args: RHS.StartFileName, args: RHS.Line,
70 args: RHS.Column, args: RHS.StartLine, args: RHS.Discriminator);
71 }
72
73 explicit operator bool() const { return *this != DILineInfo(); }
74
75 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
89using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>;
90
91/// A format-neutral container for inlined code description.
92class DIInliningInfo {
93 SmallVector<DILineInfo, 4> Frames;
94
95public:
96 DIInliningInfo() = default;
97
98 /// Returns the frame at `Index`. Frames are stored in bottom-up
99 /// (leaf-to-root) order with increasing index.
100 const DILineInfo &getFrame(unsigned Index) const {
101 assert(Index < Frames.size());
102 return Frames[Index];
103 }
104
105 DILineInfo *getMutableFrame(unsigned Index) {
106 assert(Index < Frames.size());
107 return &Frames[Index];
108 }
109
110 uint32_t getNumberOfFrames() const { return Frames.size(); }
111
112 void addFrame(const DILineInfo &Frame) { Frames.push_back(Elt: Frame); }
113
114 void resize(unsigned i) { Frames.resize(N: i); }
115};
116
117/// Container for description of a global variable.
118struct 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
125 DIGlobal() : Name(DILineInfo::BadString) {}
126};
127
128struct 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.
140enum class DINameKind { None, ShortName, LinkageName };
141
142/// Controls which fields of DILineInfo container should be filled
143/// with data.
144struct 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)
162 : 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.
170enum 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};
178static_assert(DIDT_ID_Count <= 32, "section types overflow storage");
179
180/// Selects which debug sections get dumped.
181enum 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.
193struct 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::function<llvm::StringRef(uint64_t DwarfRegNum, bool IsEH)>
210 GetNameForDWARFReg;
211
212 /// Return default option set for printing a single DIE without children.
213 static DIDumpOptions getForSingleDIE() {
214 DIDumpOptions Opts;
215 Opts.ChildRecurseDepth = 0;
216 Opts.ParentRecurseDepth = 0;
217 return Opts;
218 }
219
220 /// Return the options with RecurseDepth set to 0 unless explicitly required.
221 DIDumpOptions noImplicitRecursion() const {
222 DIDumpOptions Opts = *this;
223 if (ChildRecurseDepth == -1U && !ShowChildren)
224 Opts.ChildRecurseDepth = 0;
225 if (ParentRecurseDepth == -1U && !ShowParents)
226 Opts.ParentRecurseDepth = 0;
227 return Opts;
228 }
229
230 std::function<void(Error)> RecoverableErrorHandler =
231 WithColor::defaultErrorHandler;
232 std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler;
233};
234
235class DIContext {
236public:
237 enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF };
238
239 DIContext(DIContextKind K) : Kind(K) {}
240 virtual ~DIContext() = default;
241
242 DIContextKind getKind() const { return Kind; }
243
244 virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
245
246 virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) {
247 // No verifier? Just say things went well.
248 return true;
249 }
250
251 virtual DILineInfo getLineInfoForAddress(
252 object::SectionedAddress Address,
253 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
254 virtual DILineInfo
255 getLineInfoForDataAddress(object::SectionedAddress Address) = 0;
256 virtual DILineInfoTable getLineInfoForAddressRange(
257 object::SectionedAddress Address, uint64_t Size,
258 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
259 virtual DIInliningInfo getInliningInfoForAddress(
260 object::SectionedAddress Address,
261 DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
262
263 virtual std::vector<DILocal>
264 getLocalsForAddress(object::SectionedAddress Address) = 0;
265
266private:
267 const DIContextKind Kind;
268};
269
270/// An inferface for inquiring the load address of a loaded object file
271/// to be used by the DIContext implementations when applying relocations
272/// on the fly.
273class LoadedObjectInfo {
274protected:
275 LoadedObjectInfo() = default;
276 LoadedObjectInfo(const LoadedObjectInfo &) = default;
277
278public:
279 virtual ~LoadedObjectInfo() = default;
280
281 /// Obtain the Load Address of a section by SectionRef.
282 ///
283 /// Calculate the address of the given section.
284 /// The section need not be present in the local address space. The addresses
285 /// need to be consistent with the addresses used to query the DIContext and
286 /// the output of this function should be deterministic, i.e. repeated calls
287 /// with the same Sec should give the same address.
288 virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const {
289 return 0;
290 }
291
292 /// If conveniently available, return the content of the given Section.
293 ///
294 /// When the section is available in the local address space, in relocated
295 /// (loaded) form, e.g. because it was relocated by a JIT for execution, this
296 /// function should provide the contents of said section in `Data`. If the
297 /// loaded section is not available, or the cost of retrieving it would be
298 /// prohibitive, this function should return false. In that case, relocations
299 /// will be read from the local (unrelocated) object file and applied on the
300 /// fly. Note that this method is used purely for optimzation purposes in the
301 /// common case of JITting in the local address space, so returning false
302 /// should always be correct.
303 virtual bool getLoadedSectionContents(const object::SectionRef &Sec,
304 StringRef &Data) const {
305 return false;
306 }
307
308 // FIXME: This is untested and unused anywhere in the LLVM project, it's
309 // used/needed by Julia (an external project). It should have some coverage
310 // (at least tests, but ideally example functionality).
311 /// Obtain a copy of this LoadedObjectInfo.
312 virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0;
313};
314
315template <typename Derived, typename Base = LoadedObjectInfo>
316struct LoadedObjectInfoHelper : Base {
317protected:
318 LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
319 LoadedObjectInfoHelper() = default;
320
321public:
322 template <typename... Ts>
323 LoadedObjectInfoHelper(Ts &&...Args) : Base(std::forward<Ts>(Args)...) {}
324
325 std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
326 return std::make_unique<Derived>(static_cast<const Derived &>(*this));
327 }
328};
329
330} // end namespace llvm
331
332#endif // LLVM_DEBUGINFO_DICONTEXT_H
333

source code of llvm/include/llvm/DebugInfo/DIContext.h