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