LLVM 18.0.0git
DebugUtils.cpp
Go to the documentation of this file.
1//===---------- DebugUtils.cpp - Utilities for debugging ORC JITs ---------===//
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
10
13#include "llvm/Support/Debug.h"
15#include "llvm/Support/Format.h"
17#include "llvm/Support/Path.h"
19
20#define DEBUG_TYPE "orc"
21
22using namespace llvm;
23
24namespace {
25
26#ifndef NDEBUG
27
28cl::opt<bool> PrintHidden("debug-orc-print-hidden", cl::init(true),
29 cl::desc("debug print hidden symbols defined by "
30 "materialization units"),
32
33cl::opt<bool> PrintCallable("debug-orc-print-callable", cl::init(true),
34 cl::desc("debug print callable symbols defined by "
35 "materialization units"),
37
38cl::opt<bool> PrintData("debug-orc-print-data", cl::init(true),
39 cl::desc("debug print data symbols defined by "
40 "materialization units"),
42
43#endif // NDEBUG
44
45// SetPrinter predicate that prints every element.
46template <typename T> struct PrintAll {
47 bool operator()(const T &E) { return true; }
48};
49
50bool anyPrintSymbolOptionSet() {
51#ifndef NDEBUG
52 return PrintHidden || PrintCallable || PrintData;
53#else
54 return false;
55#endif // NDEBUG
56}
57
58bool flagsMatchCLOpts(const JITSymbolFlags &Flags) {
59#ifndef NDEBUG
60 // Bail out early if this is a hidden symbol and we're not printing hiddens.
61 if (!PrintHidden && !Flags.isExported())
62 return false;
63
64 // Return true if this is callable and we're printing callables.
65 if (PrintCallable && Flags.isCallable())
66 return true;
67
68 // Return true if this is data and we're printing data.
69 if (PrintData && !Flags.isCallable())
70 return true;
71
72 // otherwise return false.
73 return false;
74#else
75 return false;
76#endif // NDEBUG
77}
78
79// Prints a sequence of items, filtered by an user-supplied predicate.
80template <typename Sequence,
81 typename Pred = PrintAll<typename Sequence::value_type>>
82class SequencePrinter {
83public:
84 SequencePrinter(const Sequence &S, char OpenSeq, char CloseSeq,
85 Pred ShouldPrint = Pred())
86 : S(S), OpenSeq(OpenSeq), CloseSeq(CloseSeq),
87 ShouldPrint(std::move(ShouldPrint)) {}
88
89 void printTo(llvm::raw_ostream &OS) const {
90 bool PrintComma = false;
91 OS << OpenSeq;
92 for (auto &E : S) {
93 if (ShouldPrint(E)) {
94 if (PrintComma)
95 OS << ',';
96 OS << ' ' << E;
97 PrintComma = true;
98 }
99 }
100 OS << ' ' << CloseSeq;
101 }
102
103private:
104 const Sequence &S;
105 char OpenSeq;
106 char CloseSeq;
107 mutable Pred ShouldPrint;
108};
109
110template <typename Sequence, typename Pred>
111SequencePrinter<Sequence, Pred> printSequence(const Sequence &S, char OpenSeq,
112 char CloseSeq, Pred P = Pred()) {
113 return SequencePrinter<Sequence, Pred>(S, OpenSeq, CloseSeq, std::move(P));
114}
115
116// Render a SequencePrinter by delegating to its printTo method.
117template <typename Sequence, typename Pred>
119 const SequencePrinter<Sequence, Pred> &Printer) {
120 Printer.printTo(OS);
121 return OS;
122}
123
124struct PrintSymbolFlagsMapElemsMatchingCLOpts {
125 bool operator()(const orc::SymbolFlagsMap::value_type &KV) {
126 return flagsMatchCLOpts(KV.second);
127 }
128};
129
130struct PrintSymbolMapElemsMatchingCLOpts {
131 bool operator()(const orc::SymbolMap::value_type &KV) {
132 return flagsMatchCLOpts(KV.second.getFlags());
133 }
134};
135
136} // end anonymous namespace
137
138namespace llvm {
139namespace orc {
140
142 return OS << *Sym;
143}
144
146 return OS << printSequence(Symbols, '{', '}', PrintAll<SymbolStringPtr>());
147}
148
150 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
151}
152
154 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
155}
156
158 if (Flags.hasError())
159 OS << "[*ERROR*]";
160 if (Flags.isCallable())
161 OS << "[Callable]";
162 else
163 OS << "[Data]";
164 if (Flags.isWeak())
165 OS << "[Weak]";
166 else if (Flags.isCommon())
167 OS << "[Common]";
168
169 if (!Flags.isExported())
170 OS << "[Hidden]";
171
172 return OS;
173}
174
176 return OS << Sym.getAddress() << " " << Sym.getFlags();
177}
178
180 return OS << "(\"" << KV.first << "\", " << KV.second << ")";
181}
182
184 return OS << "(\"" << KV.first << "\": " << KV.second << ")";
185}
186
188 return OS << printSequence(SymbolFlags, '{', '}',
189 PrintSymbolFlagsMapElemsMatchingCLOpts());
190}
191
192raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
193 return OS << printSequence(Symbols, '{', '}',
194 PrintSymbolMapElemsMatchingCLOpts());
195}
196
199 return OS << "(" << KV.first->getName() << ", " << KV.second << ")";
200}
201
203 return OS << printSequence(Deps, '{', '}',
204 PrintAll<SymbolDependenceMap::value_type>());
205}
206
208 OS << "MU@" << &MU << " (\"" << MU.getName() << "\"";
209 if (anyPrintSymbolOptionSet())
210 OS << ", " << MU.getSymbols();
211 return OS << ")";
212}
213
215 switch (K) {
217 return OS << "Static";
219 return OS << "DLSym";
220 }
221 llvm_unreachable("Invalid lookup kind");
222}
223
225 const JITDylibLookupFlags &JDLookupFlags) {
226 switch (JDLookupFlags) {
228 return OS << "MatchExportedSymbolsOnly";
230 return OS << "MatchAllSymbols";
231 }
232 llvm_unreachable("Invalid JITDylib lookup flags");
233}
234
236 switch (LookupFlags) {
238 return OS << "RequiredSymbol";
240 return OS << "WeaklyReferencedSymbol";
241 }
242 llvm_unreachable("Invalid symbol lookup flags");
243}
244
246 const SymbolLookupSet::value_type &KV) {
247 return OS << "(" << KV.first << ", " << KV.second << ")";
248}
249
251 return OS << printSequence(LookupSet, '{', '}',
252 PrintAll<SymbolLookupSet::value_type>());
253}
254
256 const JITDylibSearchOrder &SearchOrder) {
257 OS << "[";
258 if (!SearchOrder.empty()) {
259 assert(SearchOrder.front().first &&
260 "JITDylibList entries must not be null");
261 OS << " (\"" << SearchOrder.front().first->getName() << "\", "
262 << SearchOrder.begin()->second << ")";
263 for (auto &KV : llvm::drop_begin(SearchOrder)) {
264 assert(KV.first && "JITDylibList entries must not be null");
265 OS << ", (\"" << KV.first->getName() << "\", " << KV.second << ")";
266 }
267 }
268 OS << " ]";
269 return OS;
270}
271
273 OS << "{";
274 for (auto &KV : Aliases)
275 OS << " " << *KV.first << ": " << KV.second.Aliasee << " "
276 << KV.second.AliasFlags;
277 OS << " }";
278 return OS;
279}
280
282 switch (S) {
284 return OS << "Invalid";
286 return OS << "Never-Searched";
288 return OS << "Materializing";
290 return OS << "Resolved";
292 return OS << "Emitted";
294 return OS << "Ready";
295 }
296 llvm_unreachable("Invalid state");
297}
298
300 std::lock_guard<std::mutex> Lock(SSP.PoolMutex);
302 for (auto &KV : SSP.Pool)
303 Vec.emplace_back(KV.first(), KV.second);
304 llvm::sort(Vec, less_first());
305 for (auto &[K, V] : Vec)
306 OS << K << ": " << V << "\n";
307 return OS;
308}
309
310DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride)
311 : DumpDir(std::move(DumpDir)),
312 IdentifierOverride(std::move(IdentifierOverride)) {
313
314 /// Discard any trailing separators.
315 while (!this->DumpDir.empty() &&
316 sys::path::is_separator(this->DumpDir.back()))
317 this->DumpDir.pop_back();
318}
319
321DumpObjects::operator()(std::unique_ptr<MemoryBuffer> Obj) {
322 size_t Idx = 1;
323
324 std::string DumpPathStem;
325 raw_string_ostream(DumpPathStem)
326 << DumpDir << (DumpDir.empty() ? "" : "/") << getBufferIdentifier(*Obj);
327
328 std::string DumpPath = DumpPathStem + ".o";
329 while (sys::fs::exists(DumpPath)) {
330 DumpPath.clear();
331 raw_string_ostream(DumpPath) << DumpPathStem << "." << (++Idx) << ".o";
332 }
333
334 LLVM_DEBUG({
335 dbgs() << "Dumping object buffer [ " << (const void *)Obj->getBufferStart()
336 << " -- " << (const void *)(Obj->getBufferEnd() - 1) << " ] to "
337 << DumpPath << "\n";
338 });
339
340 std::error_code EC;
341 raw_fd_ostream DumpStream(DumpPath, EC);
342 if (EC)
343 return errorCodeToError(EC);
344 DumpStream.write(Obj->getBufferStart(), Obj->getBufferSize());
345
346 return std::move(Obj);
347}
348
349StringRef DumpObjects::getBufferIdentifier(MemoryBuffer &B) {
350 if (!IdentifierOverride.empty())
351 return IdentifierOverride;
352 StringRef Identifier = B.getBufferIdentifier();
353 Identifier.consume_back(".o");
354 return Identifier;
355}
356
357} // End namespace orc.
358} // End namespace llvm.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
dxil pretty DXIL Metadata Pretty Printer
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
Symbol * Sym
Definition: ELF_riscv.cpp:468
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
BucketT value_type
Definition: DenseMap.h:69
Tagged union holding either a T or a Error.
Definition: Error.h:474
Flags for symbols in the JIT.
Definition: JITSymbol.h:74
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:51
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Expected< std::unique_ptr< MemoryBuffer > > operator()(std::unique_ptr< MemoryBuffer > Obj)
Dumps the given buffer to disk.
Definition: DebugUtils.cpp:321
DumpObjects(std::string DumpDir="", std::string IdentifierOverride="")
Construct a DumpObjects transform that will dump objects to disk.
Definition: DebugUtils.cpp:310
Represents a defining location for a JIT symbol.
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
Definition: Core.h:662
virtual StringRef getName() const =0
Return the name of this materialization unit.
const SymbolFlagsMap & getSymbols() const
Return the set of symbols that this source provides.
Definition: Core.h:692
A set of symbols to look up, each associated with a SymbolLookupFlags value.
Definition: Core.h:183
std::pair< SymbolStringPtr, SymbolLookupFlags > value_type
Definition: Core.h:185
String pool for symbol names used by the JIT.
Pointer to a pooled string representing a symbol name.
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:454
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
raw_ostream & write(unsigned char C)
const char * getBufferStart() const
Return the beginning of the current stream buffer, or 0 if the stream is unbuffered.
Definition: raw_ostream.h:387
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
std::vector< std::pair< JITDylib *, JITDylibLookupFlags > > JITDylibSearchOrder
A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search order during symbol lookup.
Definition: Core.h:162
SymbolLookupFlags
Lookup flags that apply to each symbol in a lookup.
Definition: Core.h:145
JITDylibLookupFlags
Lookup flags that apply to each dylib in the search order for a lookup.
Definition: Core.h:135
DenseMap< SymbolStringPtr, ExecutorSymbolDef > SymbolMap
A map from symbol names (as SymbolStringPtrs) to JITSymbols (address/flags pairs).
Definition: Core.h:121
LookupKind
Describes the kind of lookup being performed.
Definition: Core.h:157
std::vector< SymbolStringPtr > SymbolNameVector
A vector of symbol names.
Definition: Core.h:117
SymbolState
Represents the state that a symbol has reached during materialization.
Definition: Core.h:828
@ Materializing
Added to the symbol table, never queried.
@ NeverSearched
No symbol should be in this state.
@ Ready
Emitted to memory, but waiting on transitive dependencies.
@ Emitted
Assigned address, still materializing.
@ Resolved
Queried, materialization begun.
DenseMap< JITDylib *, SymbolNameSet > SymbolDependenceMap
A map from JITDylibs to sets of symbols.
Definition: Core.h:127
raw_ostream & operator<<(raw_ostream &OS, const SymbolStringPtr &Sym)
Render a SymbolStringPtr.
Definition: DebugUtils.cpp:141
bool exists(const basic_file_status &status)
Does file exist?
Definition: Path.cpp:1079
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition: Path.cpp:603
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:330
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1652
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:292
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1854
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:103
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
Function object to check whether the first component of a container supported by std::get (like std::...
Definition: STLExtras.h:1455