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