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
9 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
10
11 #include "llvm/ExecutionEngine/Orc/Core.h"
12 #include "llvm/Support/CommandLine.h"
13 #include "llvm/Support/Debug.h"
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/Format.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/raw_ostream.h"
19
20 #define DEBUG_TYPE "orc"
21
22 using namespace llvm;
23
24 namespace {
25
26 #ifndef NDEBUG
27
28 cl::opt<bool> PrintHidden("debug-orc-print-hidden", cl::init(true),
29 cl::desc("debug print hidden symbols defined by "
30 "materialization units"),
31 cl::Hidden);
32
33 cl::opt<bool> PrintCallable("debug-orc-print-callable", cl::init(true),
34 cl::desc("debug print callable symbols defined by "
35 "materialization units"),
36 cl::Hidden);
37
38 cl::opt<bool> PrintData("debug-orc-print-data", cl::init(true),
39 cl::desc("debug print data symbols defined by "
40 "materialization units"),
41 cl::Hidden);
42
43 #endif // NDEBUG
44
45 // SetPrinter predicate that prints every element.
46 template <typename T> struct PrintAll {
operator ()__anon5843eeeb0111::PrintAll47 bool operator()(const T &E) { return true; }
48 };
49
anyPrintSymbolOptionSet()50 bool anyPrintSymbolOptionSet() {
51 #ifndef NDEBUG
52 return PrintHidden || PrintCallable || PrintData;
53 #else
54 return false;
55 #endif // NDEBUG
56 }
57
flagsMatchCLOpts(const JITSymbolFlags & Flags)58 bool 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.
80 template <typename Sequence,
81 typename Pred = PrintAll<typename Sequence::value_type>>
82 class SequencePrinter {
83 public:
SequencePrinter(const Sequence & S,char OpenSeq,char CloseSeq,Pred ShouldPrint=Pred ())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
printTo(llvm::raw_ostream & OS) const89 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
103 private:
104 const Sequence &S;
105 char OpenSeq;
106 char CloseSeq;
107 mutable Pred ShouldPrint;
108 };
109
110 template <typename Sequence, typename Pred>
printSequence(const Sequence & S,char OpenSeq,char CloseSeq,Pred P=Pred ())111 SequencePrinter<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.
117 template <typename Sequence, typename Pred>
operator <<(llvm::raw_ostream & OS,const SequencePrinter<Sequence,Pred> & Printer)118 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
119 const SequencePrinter<Sequence, Pred> &Printer) {
120 Printer.printTo(OS);
121 return OS;
122 }
123
124 struct PrintSymbolFlagsMapElemsMatchingCLOpts {
operator ()__anon5843eeeb0111::PrintSymbolFlagsMapElemsMatchingCLOpts125 bool operator()(const orc::SymbolFlagsMap::value_type &KV) {
126 return flagsMatchCLOpts(KV.second);
127 }
128 };
129
130 struct PrintSymbolMapElemsMatchingCLOpts {
operator ()__anon5843eeeb0111::PrintSymbolMapElemsMatchingCLOpts131 bool operator()(const orc::SymbolMap::value_type &KV) {
132 return flagsMatchCLOpts(KV.second.getFlags());
133 }
134 };
135
136 } // end anonymous namespace
137
138 namespace llvm {
139 namespace orc {
140
operator <<(raw_ostream & OS,const SymbolStringPtr & Sym)141 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym) {
142 return OS << *Sym;
143 }
144
operator <<(raw_ostream & OS,const SymbolNameSet & Symbols)145 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
146 return OS << printSequence(Symbols, '{', '}', PrintAll<SymbolStringPtr>());
147 }
148
operator <<(raw_ostream & OS,const SymbolNameVector & Symbols)149 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols) {
150 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
151 }
152
operator <<(raw_ostream & OS,ArrayRef<SymbolStringPtr> Symbols)153 raw_ostream &operator<<(raw_ostream &OS, ArrayRef<SymbolStringPtr> Symbols) {
154 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
155 }
156
operator <<(raw_ostream & OS,const JITSymbolFlags & Flags)157 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
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
operator <<(raw_ostream & OS,const JITEvaluatedSymbol & Sym)175 raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
176 return OS << format("0x%016" PRIx64, Sym.getAddress()) << " "
177 << Sym.getFlags();
178 }
179
operator <<(raw_ostream & OS,const SymbolFlagsMap::value_type & KV)180 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV) {
181 return OS << "(\"" << KV.first << "\", " << KV.second << ")";
182 }
183
operator <<(raw_ostream & OS,const SymbolMap::value_type & KV)184 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
185 return OS << "(\"" << KV.first << "\": " << KV.second << ")";
186 }
187
operator <<(raw_ostream & OS,const SymbolFlagsMap & SymbolFlags)188 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
189 return OS << printSequence(SymbolFlags, '{', '}',
190 PrintSymbolFlagsMapElemsMatchingCLOpts());
191 }
192
operator <<(raw_ostream & OS,const SymbolMap & Symbols)193 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
194 return OS << printSequence(Symbols, '{', '}',
195 PrintSymbolMapElemsMatchingCLOpts());
196 }
197
operator <<(raw_ostream & OS,const SymbolDependenceMap::value_type & KV)198 raw_ostream &operator<<(raw_ostream &OS,
199 const SymbolDependenceMap::value_type &KV) {
200 return OS << "(" << KV.first->getName() << ", " << KV.second << ")";
201 }
202
operator <<(raw_ostream & OS,const SymbolDependenceMap & Deps)203 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
204 return OS << printSequence(Deps, '{', '}',
205 PrintAll<SymbolDependenceMap::value_type>());
206 }
207
operator <<(raw_ostream & OS,const MaterializationUnit & MU)208 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU) {
209 OS << "MU@" << &MU << " (\"" << MU.getName() << "\"";
210 if (anyPrintSymbolOptionSet())
211 OS << ", " << MU.getSymbols();
212 return OS << ")";
213 }
214
operator <<(raw_ostream & OS,const LookupKind & K)215 raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K) {
216 switch (K) {
217 case LookupKind::Static:
218 return OS << "Static";
219 case LookupKind::DLSym:
220 return OS << "DLSym";
221 }
222 llvm_unreachable("Invalid lookup kind");
223 }
224
operator <<(raw_ostream & OS,const JITDylibLookupFlags & JDLookupFlags)225 raw_ostream &operator<<(raw_ostream &OS,
226 const JITDylibLookupFlags &JDLookupFlags) {
227 switch (JDLookupFlags) {
228 case JITDylibLookupFlags::MatchExportedSymbolsOnly:
229 return OS << "MatchExportedSymbolsOnly";
230 case JITDylibLookupFlags::MatchAllSymbols:
231 return OS << "MatchAllSymbols";
232 }
233 llvm_unreachable("Invalid JITDylib lookup flags");
234 }
235
operator <<(raw_ostream & OS,const SymbolLookupFlags & LookupFlags)236 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LookupFlags) {
237 switch (LookupFlags) {
238 case SymbolLookupFlags::RequiredSymbol:
239 return OS << "RequiredSymbol";
240 case SymbolLookupFlags::WeaklyReferencedSymbol:
241 return OS << "WeaklyReferencedSymbol";
242 }
243 llvm_unreachable("Invalid symbol lookup flags");
244 }
245
operator <<(raw_ostream & OS,const SymbolLookupSet::value_type & KV)246 raw_ostream &operator<<(raw_ostream &OS,
247 const SymbolLookupSet::value_type &KV) {
248 return OS << "(" << KV.first << ", " << KV.second << ")";
249 }
250
operator <<(raw_ostream & OS,const SymbolLookupSet & LookupSet)251 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet) {
252 return OS << printSequence(LookupSet, '{', '}',
253 PrintAll<SymbolLookupSet::value_type>());
254 }
255
operator <<(raw_ostream & OS,const JITDylibSearchOrder & SearchOrder)256 raw_ostream &operator<<(raw_ostream &OS,
257 const JITDylibSearchOrder &SearchOrder) {
258 OS << "[";
259 if (!SearchOrder.empty()) {
260 assert(SearchOrder.front().first &&
261 "JITDylibList entries must not be null");
262 OS << " (\"" << SearchOrder.front().first->getName() << "\", "
263 << SearchOrder.begin()->second << ")";
264 for (auto &KV : llvm::drop_begin(SearchOrder)) {
265 assert(KV.first && "JITDylibList entries must not be null");
266 OS << ", (\"" << KV.first->getName() << "\", " << KV.second << ")";
267 }
268 }
269 OS << " ]";
270 return OS;
271 }
272
operator <<(raw_ostream & OS,const SymbolAliasMap & Aliases)273 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases) {
274 OS << "{";
275 for (auto &KV : Aliases)
276 OS << " " << *KV.first << ": " << KV.second.Aliasee << " "
277 << KV.second.AliasFlags;
278 OS << " }";
279 return OS;
280 }
281
operator <<(raw_ostream & OS,const SymbolState & S)282 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) {
283 switch (S) {
284 case SymbolState::Invalid:
285 return OS << "Invalid";
286 case SymbolState::NeverSearched:
287 return OS << "Never-Searched";
288 case SymbolState::Materializing:
289 return OS << "Materializing";
290 case SymbolState::Resolved:
291 return OS << "Resolved";
292 case SymbolState::Emitted:
293 return OS << "Emitted";
294 case SymbolState::Ready:
295 return OS << "Ready";
296 }
297 llvm_unreachable("Invalid state");
298 }
299
operator <<(raw_ostream & OS,const SymbolStringPool & SSP)300 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPool &SSP) {
301 std::lock_guard<std::mutex> Lock(SSP.PoolMutex);
302 for (auto &KV : SSP.Pool)
303 OS << KV.first() << ": " << KV.second << "\n";
304 return OS;
305 }
306
DumpObjects(std::string DumpDir,std::string IdentifierOverride)307 DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride)
308 : DumpDir(std::move(DumpDir)),
309 IdentifierOverride(std::move(IdentifierOverride)) {
310
311 /// Discard any trailing separators.
312 while (!this->DumpDir.empty() &&
313 sys::path::is_separator(this->DumpDir.back()))
314 this->DumpDir.pop_back();
315 }
316
317 Expected<std::unique_ptr<MemoryBuffer>>
operator ()(std::unique_ptr<MemoryBuffer> Obj)318 DumpObjects::operator()(std::unique_ptr<MemoryBuffer> Obj) {
319 size_t Idx = 1;
320
321 std::string DumpPathStem;
322 raw_string_ostream(DumpPathStem)
323 << DumpDir << (DumpDir.empty() ? "" : "/") << getBufferIdentifier(*Obj);
324
325 std::string DumpPath = DumpPathStem + ".o";
326 while (sys::fs::exists(DumpPath)) {
327 DumpPath.clear();
328 raw_string_ostream(DumpPath) << DumpPathStem << "." << (++Idx) << ".o";
329 }
330
331 LLVM_DEBUG({
332 dbgs() << "Dumping object buffer [ " << (const void *)Obj->getBufferStart()
333 << " -- " << (const void *)(Obj->getBufferEnd() - 1) << " ] to "
334 << DumpPath << "\n";
335 });
336
337 std::error_code EC;
338 raw_fd_ostream DumpStream(DumpPath, EC);
339 if (EC)
340 return errorCodeToError(EC);
341 DumpStream.write(Obj->getBufferStart(), Obj->getBufferSize());
342
343 return std::move(Obj);
344 }
345
getBufferIdentifier(MemoryBuffer & B)346 StringRef DumpObjects::getBufferIdentifier(MemoryBuffer &B) {
347 if (!IdentifierOverride.empty())
348 return IdentifierOverride;
349 StringRef Identifier = B.getBufferIdentifier();
350 Identifier.consume_back(".o");
351 return Identifier;
352 }
353
354 } // End namespace orc.
355 } // End namespace llvm.
356