1 //===---------- DebugUtils.cpp - Utilities for debugging ORC JITs ---------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
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"
20 #define DEBUG_TYPE "orc"
28 cl::opt
<bool> PrintHidden("debug-orc-print-hidden", cl::init(true),
29 cl::desc("debug print hidden symbols defined by "
30 "materialization units"),
33 cl::opt
<bool> PrintCallable("debug-orc-print-callable", cl::init(true),
34 cl::desc("debug print callable symbols defined by "
35 "materialization units"),
38 cl::opt
<bool> PrintData("debug-orc-print-data", cl::init(true),
39 cl::desc("debug print data symbols defined by "
40 "materialization units"),
45 // SetPrinter predicate that prints every element.
46 template <typename T
> struct PrintAll
{
47 bool operator()(const T
&E
) { return true; }
50 bool anyPrintSymbolOptionSet() {
52 return PrintHidden
|| PrintCallable
|| PrintData
;
58 bool flagsMatchCLOpts(const JITSymbolFlags
&Flags
) {
60 // Bail out early if this is a hidden symbol and we're not printing hiddens.
61 if (!PrintHidden
&& !Flags
.isExported())
64 // Return true if this is callable and we're printing callables.
65 if (PrintCallable
&& Flags
.isCallable())
68 // Return true if this is data and we're printing data.
69 if (PrintData
&& !Flags
.isCallable())
72 // otherwise return false.
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
{
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
)) {}
89 void printTo(llvm::raw_ostream
&OS
) const {
90 bool PrintComma
= false;
100 OS
<< ' ' << CloseSeq
;
107 mutable Pred ShouldPrint
;
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
));
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
) {
124 struct PrintSymbolFlagsMapElemsMatchingCLOpts
{
125 bool operator()(const orc::SymbolFlagsMap::value_type
&KV
) {
126 return flagsMatchCLOpts(KV
.second
);
130 struct PrintSymbolMapElemsMatchingCLOpts
{
131 bool operator()(const orc::SymbolMap::value_type
&KV
) {
132 return flagsMatchCLOpts(KV
.second
.getFlags());
136 } // end anonymous namespace
141 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolStringPtr
&Sym
) {
145 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolNameSet
&Symbols
) {
146 return OS
<< printSequence(Symbols
, '{', '}', PrintAll
<SymbolStringPtr
>());
149 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolNameVector
&Symbols
) {
150 return OS
<< printSequence(Symbols
, '[', ']', PrintAll
<SymbolStringPtr
>());
153 raw_ostream
&operator<<(raw_ostream
&OS
, ArrayRef
<SymbolStringPtr
> Symbols
) {
154 return OS
<< printSequence(Symbols
, '[', ']', PrintAll
<SymbolStringPtr
>());
157 raw_ostream
&operator<<(raw_ostream
&OS
, const JITSymbolFlags
&Flags
) {
158 if (Flags
.hasError())
160 if (Flags
.isCallable())
166 else if (Flags
.isCommon())
169 if (!Flags
.isExported())
175 raw_ostream
&operator<<(raw_ostream
&OS
, const JITEvaluatedSymbol
&Sym
) {
176 return OS
<< format("0x%016" PRIx64
, Sym
.getAddress()) << " "
180 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap::value_type
&KV
) {
181 return OS
<< "(\"" << KV
.first
<< "\", " << KV
.second
<< ")";
184 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap::value_type
&KV
) {
185 return OS
<< "(\"" << KV
.first
<< "\": " << KV
.second
<< ")";
188 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap
&SymbolFlags
) {
189 return OS
<< printSequence(SymbolFlags
, '{', '}',
190 PrintSymbolFlagsMapElemsMatchingCLOpts());
193 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap
&Symbols
) {
194 return OS
<< printSequence(Symbols
, '{', '}',
195 PrintSymbolMapElemsMatchingCLOpts());
198 raw_ostream
&operator<<(raw_ostream
&OS
,
199 const SymbolDependenceMap::value_type
&KV
) {
200 return OS
<< "(" << KV
.first
->getName() << ", " << KV
.second
<< ")";
203 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolDependenceMap
&Deps
) {
204 return OS
<< printSequence(Deps
, '{', '}',
205 PrintAll
<SymbolDependenceMap::value_type
>());
208 raw_ostream
&operator<<(raw_ostream
&OS
, const MaterializationUnit
&MU
) {
209 OS
<< "MU@" << &MU
<< " (\"" << MU
.getName() << "\"";
210 if (anyPrintSymbolOptionSet())
211 OS
<< ", " << MU
.getSymbols();
215 raw_ostream
&operator<<(raw_ostream
&OS
, const LookupKind
&K
) {
217 case LookupKind::Static
:
218 return OS
<< "Static";
219 case LookupKind::DLSym
:
220 return OS
<< "DLSym";
222 llvm_unreachable("Invalid lookup kind");
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";
233 llvm_unreachable("Invalid JITDylib lookup flags");
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";
243 llvm_unreachable("Invalid symbol lookup flags");
246 raw_ostream
&operator<<(raw_ostream
&OS
,
247 const SymbolLookupSet::value_type
&KV
) {
248 return OS
<< "(" << KV
.first
<< ", " << KV
.second
<< ")";
251 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolLookupSet
&LookupSet
) {
252 return OS
<< printSequence(LookupSet
, '{', '}',
253 PrintAll
<SymbolLookupSet::value_type
>());
256 raw_ostream
&operator<<(raw_ostream
&OS
,
257 const JITDylibSearchOrder
&SearchOrder
) {
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
<< ")";
273 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolAliasMap
&Aliases
) {
275 for (auto &KV
: Aliases
)
276 OS
<< " " << *KV
.first
<< ": " << KV
.second
.Aliasee
<< " "
277 << KV
.second
.AliasFlags
;
282 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolState
&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";
297 llvm_unreachable("Invalid state");
300 DumpObjects::DumpObjects(std::string DumpDir
, std::string IdentifierOverride
)
301 : DumpDir(std::move(DumpDir
)),
302 IdentifierOverride(std::move(IdentifierOverride
)) {
304 /// Discard any trailing separators.
305 while (!this->DumpDir
.empty() &&
306 sys::path::is_separator(this->DumpDir
.back()))
307 this->DumpDir
.pop_back();
310 Expected
<std::unique_ptr
<MemoryBuffer
>>
311 DumpObjects::operator()(std::unique_ptr
<MemoryBuffer
> Obj
) {
314 std::string DumpPathStem
;
315 raw_string_ostream(DumpPathStem
)
316 << DumpDir
<< (DumpDir
.empty() ? "" : "/") << getBufferIdentifier(*Obj
);
318 std::string DumpPath
= DumpPathStem
+ ".o";
319 while (sys::fs::exists(DumpPath
)) {
321 raw_string_ostream(DumpPath
) << DumpPathStem
<< "." << (++Idx
) << ".o";
325 dbgs() << "Dumping object buffer [ " << (const void *)Obj
->getBufferStart()
326 << " -- " << (const void *)(Obj
->getBufferEnd() - 1) << " ] to "
331 raw_fd_ostream
DumpStream(DumpPath
, EC
);
333 return errorCodeToError(EC
);
334 DumpStream
.write(Obj
->getBufferStart(), Obj
->getBufferSize());
336 return std::move(Obj
);
339 StringRef
DumpObjects::getBufferIdentifier(MemoryBuffer
&B
) {
340 if (!IdentifierOverride
.empty())
341 return IdentifierOverride
;
342 StringRef Identifier
= B
.getBufferIdentifier();
343 Identifier
.consume_back(".o");
347 } // End namespace orc.
348 } // End namespace llvm.