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/MemoryBuffer.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/raw_ostream.h"
19 #define DEBUG_TYPE "orc"
27 cl::opt
<bool> PrintHidden("debug-orc-print-hidden", cl::init(true),
28 cl::desc("debug print hidden symbols defined by "
29 "materialization units"),
32 cl::opt
<bool> PrintCallable("debug-orc-print-callable", cl::init(true),
33 cl::desc("debug print callable symbols defined by "
34 "materialization units"),
37 cl::opt
<bool> PrintData("debug-orc-print-data", cl::init(true),
38 cl::desc("debug print data symbols defined by "
39 "materialization units"),
44 // SetPrinter predicate that prints every element.
45 template <typename T
> struct PrintAll
{
46 bool operator()(const T
&E
) { return true; }
49 bool anyPrintSymbolOptionSet() {
51 return PrintHidden
|| PrintCallable
|| PrintData
;
57 bool flagsMatchCLOpts(const JITSymbolFlags
&Flags
) {
59 // Bail out early if this is a hidden symbol and we're not printing hiddens.
60 if (!PrintHidden
&& !Flags
.isExported())
63 // Return true if this is callable and we're printing callables.
64 if (PrintCallable
&& Flags
.isCallable())
67 // Return true if this is data and we're printing data.
68 if (PrintData
&& !Flags
.isCallable())
71 // otherwise return false.
78 // Prints a sequence of items, filtered by an user-supplied predicate.
79 template <typename Sequence
,
80 typename Pred
= PrintAll
<typename
Sequence::value_type
>>
81 class SequencePrinter
{
83 SequencePrinter(const Sequence
&S
, char OpenSeq
, char CloseSeq
,
84 Pred ShouldPrint
= Pred())
85 : S(S
), OpenSeq(OpenSeq
), CloseSeq(CloseSeq
),
86 ShouldPrint(std::move(ShouldPrint
)) {}
88 void printTo(llvm::raw_ostream
&OS
) const {
89 bool PrintComma
= false;
99 OS
<< ' ' << CloseSeq
;
106 mutable Pred ShouldPrint
;
109 template <typename Sequence
, typename Pred
>
110 SequencePrinter
<Sequence
, Pred
> printSequence(const Sequence
&S
, char OpenSeq
,
111 char CloseSeq
, Pred P
= Pred()) {
112 return SequencePrinter
<Sequence
, Pred
>(S
, OpenSeq
, CloseSeq
, std::move(P
));
115 // Render a SequencePrinter by delegating to its printTo method.
116 template <typename Sequence
, typename Pred
>
117 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
,
118 const SequencePrinter
<Sequence
, Pred
> &Printer
) {
123 struct PrintSymbolFlagsMapElemsMatchingCLOpts
{
124 bool operator()(const orc::SymbolFlagsMap::value_type
&KV
) {
125 return flagsMatchCLOpts(KV
.second
);
129 struct PrintSymbolMapElemsMatchingCLOpts
{
130 bool operator()(const orc::SymbolMap::value_type
&KV
) {
131 return flagsMatchCLOpts(KV
.second
.getFlags());
135 } // end anonymous namespace
140 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolNameSet
&Symbols
) {
141 return OS
<< printSequence(Symbols
, '{', '}', PrintAll
<SymbolStringPtr
>());
144 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolNameVector
&Symbols
) {
145 return OS
<< printSequence(Symbols
, '[', ']', PrintAll
<SymbolStringPtr
>());
148 raw_ostream
&operator<<(raw_ostream
&OS
, ArrayRef
<SymbolStringPtr
> Symbols
) {
149 return OS
<< printSequence(Symbols
, '[', ']', PrintAll
<SymbolStringPtr
>());
152 raw_ostream
&operator<<(raw_ostream
&OS
, const JITSymbolFlags
&Flags
) {
153 if (Flags
.hasError())
155 if (Flags
.isCallable())
161 else if (Flags
.isCommon())
164 if (!Flags
.isExported())
170 raw_ostream
&operator<<(raw_ostream
&OS
, const ExecutorSymbolDef
&Sym
) {
171 return OS
<< Sym
.getAddress() << " " << Sym
.getFlags();
174 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap::value_type
&KV
) {
175 return OS
<< "(\"" << KV
.first
<< "\", " << KV
.second
<< ")";
178 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap::value_type
&KV
) {
179 return OS
<< "(\"" << KV
.first
<< "\": " << KV
.second
<< ")";
182 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap
&SymbolFlags
) {
183 return OS
<< printSequence(SymbolFlags
, '{', '}',
184 PrintSymbolFlagsMapElemsMatchingCLOpts());
187 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap
&Symbols
) {
188 return OS
<< printSequence(Symbols
, '{', '}',
189 PrintSymbolMapElemsMatchingCLOpts());
192 raw_ostream
&operator<<(raw_ostream
&OS
,
193 const SymbolDependenceMap::value_type
&KV
) {
194 return OS
<< "(" << KV
.first
->getName() << ", " << KV
.second
<< ")";
197 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolDependenceMap
&Deps
) {
198 return OS
<< printSequence(Deps
, '{', '}',
199 PrintAll
<SymbolDependenceMap::value_type
>());
202 raw_ostream
&operator<<(raw_ostream
&OS
, const MaterializationUnit
&MU
) {
203 OS
<< "MU@" << &MU
<< " (\"" << MU
.getName() << "\"";
204 if (anyPrintSymbolOptionSet())
205 OS
<< ", " << MU
.getSymbols();
209 raw_ostream
&operator<<(raw_ostream
&OS
, const LookupKind
&K
) {
211 case LookupKind::Static
:
212 return OS
<< "Static";
213 case LookupKind::DLSym
:
214 return OS
<< "DLSym";
216 llvm_unreachable("Invalid lookup kind");
219 raw_ostream
&operator<<(raw_ostream
&OS
,
220 const JITDylibLookupFlags
&JDLookupFlags
) {
221 switch (JDLookupFlags
) {
222 case JITDylibLookupFlags::MatchExportedSymbolsOnly
:
223 return OS
<< "MatchExportedSymbolsOnly";
224 case JITDylibLookupFlags::MatchAllSymbols
:
225 return OS
<< "MatchAllSymbols";
227 llvm_unreachable("Invalid JITDylib lookup flags");
230 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolLookupFlags
&LookupFlags
) {
231 switch (LookupFlags
) {
232 case SymbolLookupFlags::RequiredSymbol
:
233 return OS
<< "RequiredSymbol";
234 case SymbolLookupFlags::WeaklyReferencedSymbol
:
235 return OS
<< "WeaklyReferencedSymbol";
237 llvm_unreachable("Invalid symbol lookup flags");
240 raw_ostream
&operator<<(raw_ostream
&OS
,
241 const SymbolLookupSet::value_type
&KV
) {
242 return OS
<< "(" << KV
.first
<< ", " << KV
.second
<< ")";
245 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolLookupSet
&LookupSet
) {
246 return OS
<< printSequence(LookupSet
, '{', '}',
247 PrintAll
<SymbolLookupSet::value_type
>());
250 raw_ostream
&operator<<(raw_ostream
&OS
,
251 const JITDylibSearchOrder
&SearchOrder
) {
253 if (!SearchOrder
.empty()) {
254 assert(SearchOrder
.front().first
&&
255 "JITDylibList entries must not be null");
256 OS
<< " (\"" << SearchOrder
.front().first
->getName() << "\", "
257 << SearchOrder
.begin()->second
<< ")";
258 for (auto &KV
: llvm::drop_begin(SearchOrder
)) {
259 assert(KV
.first
&& "JITDylibList entries must not be null");
260 OS
<< ", (\"" << KV
.first
->getName() << "\", " << KV
.second
<< ")";
267 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolAliasMap
&Aliases
) {
269 for (auto &KV
: Aliases
)
270 OS
<< " " << *KV
.first
<< ": " << KV
.second
.Aliasee
<< " "
271 << KV
.second
.AliasFlags
;
276 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolState
&S
) {
278 case SymbolState::Invalid
:
279 return OS
<< "Invalid";
280 case SymbolState::NeverSearched
:
281 return OS
<< "Never-Searched";
282 case SymbolState::Materializing
:
283 return OS
<< "Materializing";
284 case SymbolState::Resolved
:
285 return OS
<< "Resolved";
286 case SymbolState::Emitted
:
287 return OS
<< "Emitted";
288 case SymbolState::Ready
:
289 return OS
<< "Ready";
291 llvm_unreachable("Invalid state");
294 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolStringPool
&SSP
) {
295 std::lock_guard
<std::mutex
> Lock(SSP
.PoolMutex
);
296 SmallVector
<std::pair
<StringRef
, int>, 0> Vec
;
297 for (auto &KV
: SSP
.Pool
)
298 Vec
.emplace_back(KV
.first(), KV
.second
);
299 llvm::sort(Vec
, less_first());
300 for (auto &[K
, V
] : Vec
)
301 OS
<< K
<< ": " << V
<< "\n";
305 DumpObjects::DumpObjects(std::string DumpDir
, std::string IdentifierOverride
)
306 : DumpDir(std::move(DumpDir
)),
307 IdentifierOverride(std::move(IdentifierOverride
)) {
309 /// Discard any trailing separators.
310 while (!this->DumpDir
.empty() &&
311 sys::path::is_separator(this->DumpDir
.back()))
312 this->DumpDir
.pop_back();
315 Expected
<std::unique_ptr
<MemoryBuffer
>>
316 DumpObjects::operator()(std::unique_ptr
<MemoryBuffer
> Obj
) {
319 std::string DumpPathStem
;
320 raw_string_ostream(DumpPathStem
)
321 << DumpDir
<< (DumpDir
.empty() ? "" : "/") << getBufferIdentifier(*Obj
);
323 std::string DumpPath
= DumpPathStem
+ ".o";
324 while (sys::fs::exists(DumpPath
)) {
326 raw_string_ostream(DumpPath
) << DumpPathStem
<< "." << (++Idx
) << ".o";
330 dbgs() << "Dumping object buffer [ " << (const void *)Obj
->getBufferStart()
331 << " -- " << (const void *)(Obj
->getBufferEnd() - 1) << " ] to "
336 raw_fd_ostream
DumpStream(DumpPath
, EC
);
338 return errorCodeToError(EC
);
339 DumpStream
.write(Obj
->getBufferStart(), Obj
->getBufferSize());
341 return std::move(Obj
);
344 StringRef
DumpObjects::getBufferIdentifier(MemoryBuffer
&B
) {
345 if (!IdentifierOverride
.empty())
346 return IdentifierOverride
;
347 StringRef Identifier
= B
.getBufferIdentifier();
348 Identifier
.consume_back(".o");
352 } // End namespace orc.
353 } // End namespace llvm.