xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp (revision 56b17de1e8360fe131d425de20b5e75ff3ea897c)
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 {
47   bool operator()(const T &E) { return true; }
48 };
49 
50 bool anyPrintSymbolOptionSet() {
51 #ifndef NDEBUG
52   return PrintHidden || PrintCallable || PrintData;
53 #else
54   return false;
55 #endif // NDEBUG
56 }
57 
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:
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 
103 private:
104   const Sequence &S;
105   char OpenSeq;
106   char CloseSeq;
107   mutable Pred ShouldPrint;
108 };
109 
110 template <typename Sequence, typename 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>
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 {
125   bool operator()(const orc::SymbolFlagsMap::value_type &KV) {
126     return flagsMatchCLOpts(KV.second);
127   }
128 };
129 
130 struct PrintSymbolMapElemsMatchingCLOpts {
131   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 
141 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym) {
142   return OS << *Sym;
143 }
144 
145 raw_ostream &operator<<(raw_ostream &OS, NonOwningSymbolStringPtr Sym) {
146   return OS << *Sym;
147 }
148 
149 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
150   return OS << printSequence(Symbols, '{', '}', PrintAll<SymbolStringPtr>());
151 }
152 
153 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols) {
154   return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
155 }
156 
157 raw_ostream &operator<<(raw_ostream &OS, ArrayRef<SymbolStringPtr> Symbols) {
158   return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());
159 }
160 
161 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
162   if (Flags.hasError())
163     OS << "[*ERROR*]";
164   if (Flags.isCallable())
165     OS << "[Callable]";
166   else
167     OS << "[Data]";
168   if (Flags.isWeak())
169     OS << "[Weak]";
170   else if (Flags.isCommon())
171     OS << "[Common]";
172 
173   if (!Flags.isExported())
174     OS << "[Hidden]";
175 
176   return OS;
177 }
178 
179 raw_ostream &operator<<(raw_ostream &OS, const ExecutorSymbolDef &Sym) {
180   return OS << Sym.getAddress() << " " << Sym.getFlags();
181 }
182 
183 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV) {
184   return OS << "(\"" << KV.first << "\", " << KV.second << ")";
185 }
186 
187 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
188   return OS << "(\"" << KV.first << "\": " << KV.second << ")";
189 }
190 
191 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
192   return OS << printSequence(SymbolFlags, '{', '}',
193                              PrintSymbolFlagsMapElemsMatchingCLOpts());
194 }
195 
196 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
197   return OS << printSequence(Symbols, '{', '}',
198                              PrintSymbolMapElemsMatchingCLOpts());
199 }
200 
201 raw_ostream &operator<<(raw_ostream &OS,
202                         const SymbolDependenceMap::value_type &KV) {
203   return OS << "(" << KV.first->getName() << ", " << KV.second << ")";
204 }
205 
206 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
207   return OS << printSequence(Deps, '{', '}',
208                              PrintAll<SymbolDependenceMap::value_type>());
209 }
210 
211 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU) {
212   OS << "MU@" << &MU << " (\"" << MU.getName() << "\"";
213   if (anyPrintSymbolOptionSet())
214     OS << ", " << MU.getSymbols();
215   return OS << ")";
216 }
217 
218 raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K) {
219   switch (K) {
220   case LookupKind::Static:
221     return OS << "Static";
222   case LookupKind::DLSym:
223     return OS << "DLSym";
224   }
225   llvm_unreachable("Invalid lookup kind");
226 }
227 
228 raw_ostream &operator<<(raw_ostream &OS,
229                         const JITDylibLookupFlags &JDLookupFlags) {
230   switch (JDLookupFlags) {
231   case JITDylibLookupFlags::MatchExportedSymbolsOnly:
232     return OS << "MatchExportedSymbolsOnly";
233   case JITDylibLookupFlags::MatchAllSymbols:
234     return OS << "MatchAllSymbols";
235   }
236   llvm_unreachable("Invalid JITDylib lookup flags");
237 }
238 
239 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LookupFlags) {
240   switch (LookupFlags) {
241   case SymbolLookupFlags::RequiredSymbol:
242     return OS << "RequiredSymbol";
243   case SymbolLookupFlags::WeaklyReferencedSymbol:
244     return OS << "WeaklyReferencedSymbol";
245   }
246   llvm_unreachable("Invalid symbol lookup flags");
247 }
248 
249 raw_ostream &operator<<(raw_ostream &OS,
250                         const SymbolLookupSet::value_type &KV) {
251   return OS << "(" << KV.first << ", " << KV.second << ")";
252 }
253 
254 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet) {
255   return OS << printSequence(LookupSet, '{', '}',
256                              PrintAll<SymbolLookupSet::value_type>());
257 }
258 
259 raw_ostream &operator<<(raw_ostream &OS,
260                         const JITDylibSearchOrder &SearchOrder) {
261   OS << "[";
262   if (!SearchOrder.empty()) {
263     assert(SearchOrder.front().first &&
264            "JITDylibList entries must not be null");
265     OS << " (\"" << SearchOrder.front().first->getName() << "\", "
266        << SearchOrder.begin()->second << ")";
267     for (auto &KV : llvm::drop_begin(SearchOrder)) {
268       assert(KV.first && "JITDylibList entries must not be null");
269       OS << ", (\"" << KV.first->getName() << "\", " << KV.second << ")";
270     }
271   }
272   OS << " ]";
273   return OS;
274 }
275 
276 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases) {
277   OS << "{";
278   for (auto &KV : Aliases)
279     OS << " " << *KV.first << ": " << KV.second.Aliasee << " "
280        << KV.second.AliasFlags;
281   OS << " }";
282   return OS;
283 }
284 
285 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) {
286   switch (S) {
287   case SymbolState::Invalid:
288     return OS << "Invalid";
289   case SymbolState::NeverSearched:
290     return OS << "Never-Searched";
291   case SymbolState::Materializing:
292     return OS << "Materializing";
293   case SymbolState::Resolved:
294     return OS << "Resolved";
295   case SymbolState::Emitted:
296     return OS << "Emitted";
297   case SymbolState::Ready:
298     return OS << "Ready";
299   }
300   llvm_unreachable("Invalid state");
301 }
302 
303 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPool &SSP) {
304   std::lock_guard<std::mutex> Lock(SSP.PoolMutex);
305   SmallVector<std::pair<StringRef, int>, 0> Vec;
306   for (auto &KV : SSP.Pool)
307     Vec.emplace_back(KV.first(), KV.second);
308   llvm::sort(Vec, less_first());
309   for (auto &[K, V] : Vec)
310     OS << K << ": " << V << "\n";
311   return OS;
312 }
313 
314 DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride)
315     : DumpDir(std::move(DumpDir)),
316       IdentifierOverride(std::move(IdentifierOverride)) {
317 
318   /// Discard any trailing separators.
319   while (!this->DumpDir.empty() &&
320          sys::path::is_separator(this->DumpDir.back()))
321     this->DumpDir.pop_back();
322 }
323 
324 Expected<std::unique_ptr<MemoryBuffer>>
325 DumpObjects::operator()(std::unique_ptr<MemoryBuffer> Obj) {
326   size_t Idx = 1;
327 
328   std::string DumpPathStem;
329   raw_string_ostream(DumpPathStem)
330       << DumpDir << (DumpDir.empty() ? "" : "/") << getBufferIdentifier(*Obj);
331 
332   std::string DumpPath = DumpPathStem + ".o";
333   while (sys::fs::exists(DumpPath)) {
334     DumpPath.clear();
335     raw_string_ostream(DumpPath) << DumpPathStem << "." << (++Idx) << ".o";
336   }
337 
338   LLVM_DEBUG({
339     dbgs() << "Dumping object buffer [ " << (const void *)Obj->getBufferStart()
340            << " -- " << (const void *)(Obj->getBufferEnd() - 1) << " ] to "
341            << DumpPath << "\n";
342   });
343 
344   std::error_code EC;
345   raw_fd_ostream DumpStream(DumpPath, EC);
346   if (EC)
347     return errorCodeToError(EC);
348   DumpStream.write(Obj->getBufferStart(), Obj->getBufferSize());
349 
350   return std::move(Obj);
351 }
352 
353 StringRef DumpObjects::getBufferIdentifier(MemoryBuffer &B) {
354   if (!IdentifierOverride.empty())
355     return IdentifierOverride;
356   StringRef Identifier = B.getBufferIdentifier();
357   Identifier.consume_back(".o");
358   return Identifier;
359 }
360 
361 } // End namespace orc.
362 } // End namespace llvm.
363