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
28namespace llvm {
29
30/// A format-neutral container for source line information.
31struct 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
85using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>;
86
87/// A format-neutral container for inlined code description.
88class DIInliningInfo {
89 SmallVector<DILineInfo, 4> Frames;
90
91public:
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.
118struct DIGlobal {
119 std::string Name;
120 uint64_t Start = 0;
121 uint64_t Size = 0;
122
123 DIGlobal() : Name(DILineInfo::BadString) {}
124};
125
126struct 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.
138enum class DINameKind { None, ShortName, LinkageName };
139
140/// Controls which fields of DILineInfo container should be filled
141/// with data.
142struct 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.
164enum 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};
172static_assert(DIDT_ID_Count <= 32, "section types overflow storage");
173
174/// Selects which debug sections get dumped.
175enum 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.
187struct 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
224class DIContext {
225public:
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
256private:
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.
263class LoadedObjectInfo {
264protected:
265 LoadedObjectInfo() = default;
266 LoadedObjectInfo(const LoadedObjectInfo &) = default;
267
268public:
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
305template <typename Derived, typename Base = LoadedObjectInfo>
306struct LoadedObjectInfoHelper : Base {
307protected:
308 LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
309 LoadedObjectInfoHelper() = default;
310
311public:
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