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 ExecutorSymbolDef
&Sym
) {
176 return OS
<< Sym
.getAddress() << " " << Sym
.getFlags();
179 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap::value_type
&KV
) {
180 return OS
<< "(\"" << KV
.first
<< "\", " << KV
.second
<< ")";
183 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap::value_type
&KV
) {
184 return OS
<< "(\"" << KV
.first
<< "\": " << KV
.second
<< ")";
187 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolFlagsMap
&SymbolFlags
) {
188 return OS
<< printSequence(SymbolFlags
, '{', '}',
189 PrintSymbolFlagsMapElemsMatchingCLOpts());
192 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolMap
&Symbols
) {
193 return OS
<< printSequence(Symbols
, '{', '}',
194 PrintSymbolMapElemsMatchingCLOpts());
197 raw_ostream
&operator<<(raw_ostream
&OS
,
198 const SymbolDependenceMap::value_type
&KV
) {
199 return OS
<< "(" << KV
.first
->getName() << ", " << KV
.second
<< ")";
202 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolDependenceMap
&Deps
) {
203 return OS
<< printSequence(Deps
, '{', '}',
204 PrintAll
<SymbolDependenceMap::value_type
>());
207 raw_ostream
&operator<<(raw_ostream
&OS
, const MaterializationUnit
&MU
) {
208 OS
<< "MU@" << &MU
<< " (\"" << MU
.getName() << "\"";
209 if (anyPrintSymbolOptionSet())
210 OS
<< ", " << MU
.getSymbols();
214 raw_ostream
&operator<<(raw_ostream
&OS
, const LookupKind
&K
) {
216 case LookupKind::Static
:
217 return OS
<< "Static";
218 case LookupKind::DLSym
:
219 return OS
<< "DLSym";
221 llvm_unreachable("Invalid lookup kind");
224 raw_ostream
&operator<<(raw_ostream
&OS
,
225 const JITDylibLookupFlags
&JDLookupFlags
) {
226 switch (JDLookupFlags
) {
227 case JITDylibLookupFlags::MatchExportedSymbolsOnly
:
228 return OS
<< "MatchExportedSymbolsOnly";
229 case JITDylibLookupFlags::MatchAllSymbols
:
230 return OS
<< "MatchAllSymbols";
232 llvm_unreachable("Invalid JITDylib lookup flags");
235 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolLookupFlags
&LookupFlags
) {
236 switch (LookupFlags
) {
237 case SymbolLookupFlags::RequiredSymbol
:
238 return OS
<< "RequiredSymbol";
239 case SymbolLookupFlags::WeaklyReferencedSymbol
:
240 return OS
<< "WeaklyReferencedSymbol";
242 llvm_unreachable("Invalid symbol lookup flags");
245 raw_ostream
&operator<<(raw_ostream
&OS
,
246 const SymbolLookupSet::value_type
&KV
) {
247 return OS
<< "(" << KV
.first
<< ", " << KV
.second
<< ")";
250 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolLookupSet
&LookupSet
) {
251 return OS
<< printSequence(LookupSet
, '{', '}',
252 PrintAll
<SymbolLookupSet::value_type
>());
255 raw_ostream
&operator<<(raw_ostream
&OS
,
256 const JITDylibSearchOrder
&SearchOrder
) {
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
<< ")";
272 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolAliasMap
&Aliases
) {
274 for (auto &KV
: Aliases
)
275 OS
<< " " << *KV
.first
<< ": " << KV
.second
.Aliasee
<< " "
276 << KV
.second
.AliasFlags
;
281 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolState
&S
) {
283 case SymbolState::Invalid
:
284 return OS
<< "Invalid";
285 case SymbolState::NeverSearched
:
286 return OS
<< "Never-Searched";
287 case SymbolState::Materializing
:
288 return OS
<< "Materializing";
289 case SymbolState::Resolved
:
290 return OS
<< "Resolved";
291 case SymbolState::Emitted
:
292 return OS
<< "Emitted";
293 case SymbolState::Ready
:
294 return OS
<< "Ready";
296 llvm_unreachable("Invalid state");
299 raw_ostream
&operator<<(raw_ostream
&OS
, const SymbolStringPool
&SSP
) {
300 std::lock_guard
<std::mutex
> Lock(SSP
.PoolMutex
);
301 SmallVector
<std::pair
<StringRef
, int>, 0> Vec
;
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";
310 DumpObjects::DumpObjects(std::string DumpDir
, std::string IdentifierOverride
)
311 : DumpDir(std::move(DumpDir
)),
312 IdentifierOverride(std::move(IdentifierOverride
)) {
314 /// Discard any trailing separators.
315 while (!this->DumpDir
.empty() &&
316 sys::path::is_separator(this->DumpDir
.back()))
317 this->DumpDir
.pop_back();
320 Expected
<std::unique_ptr
<MemoryBuffer
>>
321 DumpObjects::operator()(std::unique_ptr
<MemoryBuffer
> Obj
) {
324 std::string DumpPathStem
;
325 raw_string_ostream(DumpPathStem
)
326 << DumpDir
<< (DumpDir
.empty() ? "" : "/") << getBufferIdentifier(*Obj
);
328 std::string DumpPath
= DumpPathStem
+ ".o";
329 while (sys::fs::exists(DumpPath
)) {
331 raw_string_ostream(DumpPath
) << DumpPathStem
<< "." << (++Idx
) << ".o";
335 dbgs() << "Dumping object buffer [ " << (const void *)Obj
->getBufferStart()
336 << " -- " << (const void *)(Obj
->getBufferEnd() - 1) << " ] to "
341 raw_fd_ostream
DumpStream(DumpPath
, EC
);
343 return errorCodeToError(EC
);
344 DumpStream
.write(Obj
->getBufferStart(), Obj
->getBufferSize());
346 return std::move(Obj
);
349 StringRef
DumpObjects::getBufferIdentifier(MemoryBuffer
&B
) {
350 if (!IdentifierOverride
.empty())
351 return IdentifierOverride
;
352 StringRef Identifier
= B
.getBufferIdentifier();
353 Identifier
.consume_back(".o");
357 } // End namespace orc.
358 } // End namespace llvm.