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/MemoryBuffer.h" 16 #include "llvm/Support/Path.h" 17 #include "llvm/Support/raw_ostream.h" 18 19 #define DEBUG_TYPE "orc" 20 21 using namespace llvm; 22 23 namespace { 24 25 #ifndef NDEBUG 26 27 cl::opt<bool> PrintHidden("debug-orc-print-hidden", cl::init(true), 28 cl::desc("debug print hidden symbols defined by " 29 "materialization units"), 30 cl::Hidden); 31 32 cl::opt<bool> PrintCallable("debug-orc-print-callable", cl::init(true), 33 cl::desc("debug print callable symbols defined by " 34 "materialization units"), 35 cl::Hidden); 36 37 cl::opt<bool> PrintData("debug-orc-print-data", cl::init(true), 38 cl::desc("debug print data symbols defined by " 39 "materialization units"), 40 cl::Hidden); 41 42 #endif // NDEBUG 43 44 // SetPrinter predicate that prints every element. 45 template <typename T> struct PrintAll { 46 bool operator()(const T &E) { return true; } 47 }; 48 49 bool anyPrintSymbolOptionSet() { 50 #ifndef NDEBUG 51 return PrintHidden || PrintCallable || PrintData; 52 #else 53 return false; 54 #endif // NDEBUG 55 } 56 57 bool flagsMatchCLOpts(const JITSymbolFlags &Flags) { 58 #ifndef NDEBUG 59 // Bail out early if this is a hidden symbol and we're not printing hiddens. 60 if (!PrintHidden && !Flags.isExported()) 61 return false; 62 63 // Return true if this is callable and we're printing callables. 64 if (PrintCallable && Flags.isCallable()) 65 return true; 66 67 // Return true if this is data and we're printing data. 68 if (PrintData && !Flags.isCallable()) 69 return true; 70 71 // otherwise return false. 72 return false; 73 #else 74 return false; 75 #endif // NDEBUG 76 } 77 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 { 82 public: 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)) {} 87 88 void printTo(llvm::raw_ostream &OS) const { 89 bool PrintComma = false; 90 OS << OpenSeq; 91 for (auto &E : S) { 92 if (ShouldPrint(E)) { 93 if (PrintComma) 94 OS << ','; 95 OS << ' ' << E; 96 PrintComma = true; 97 } 98 } 99 OS << ' ' << CloseSeq; 100 } 101 102 private: 103 const Sequence &S; 104 char OpenSeq; 105 char CloseSeq; 106 mutable Pred ShouldPrint; 107 }; 108 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)); 113 } 114 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) { 119 Printer.printTo(OS); 120 return OS; 121 } 122 123 struct PrintSymbolFlagsMapElemsMatchingCLOpts { 124 bool operator()(const orc::SymbolFlagsMap::value_type &KV) { 125 return flagsMatchCLOpts(KV.second); 126 } 127 }; 128 129 struct PrintSymbolMapElemsMatchingCLOpts { 130 bool operator()(const orc::SymbolMap::value_type &KV) { 131 return flagsMatchCLOpts(KV.second.getFlags()); 132 } 133 }; 134 135 } // end anonymous namespace 136 137 namespace llvm { 138 namespace orc { 139 140 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) { 141 return OS << printSequence(Symbols, '{', '}', PrintAll<SymbolStringPtr>()); 142 } 143 144 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols) { 145 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>()); 146 } 147 148 raw_ostream &operator<<(raw_ostream &OS, ArrayRef<SymbolStringPtr> Symbols) { 149 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>()); 150 } 151 152 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) { 153 if (Flags.hasError()) 154 OS << "[*ERROR*]"; 155 if (Flags.isCallable()) 156 OS << "[Callable]"; 157 else 158 OS << "[Data]"; 159 if (Flags.isWeak()) 160 OS << "[Weak]"; 161 else if (Flags.isCommon()) 162 OS << "[Common]"; 163 164 if (!Flags.isExported()) 165 OS << "[Hidden]"; 166 167 return OS; 168 } 169 170 raw_ostream &operator<<(raw_ostream &OS, const ExecutorSymbolDef &Sym) { 171 return OS << Sym.getAddress() << " " << Sym.getFlags(); 172 } 173 174 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV) { 175 return OS << "(\"" << KV.first << "\", " << KV.second << ")"; 176 } 177 178 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) { 179 return OS << "(\"" << KV.first << "\": " << KV.second << ")"; 180 } 181 182 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) { 183 return OS << printSequence(SymbolFlags, '{', '}', 184 PrintSymbolFlagsMapElemsMatchingCLOpts()); 185 } 186 187 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) { 188 return OS << printSequence(Symbols, '{', '}', 189 PrintSymbolMapElemsMatchingCLOpts()); 190 } 191 192 raw_ostream &operator<<(raw_ostream &OS, 193 const SymbolDependenceMap::value_type &KV) { 194 return OS << "(" << KV.first->getName() << ", " << KV.second << ")"; 195 } 196 197 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) { 198 return OS << printSequence(Deps, '{', '}', 199 PrintAll<SymbolDependenceMap::value_type>()); 200 } 201 202 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU) { 203 OS << "MU@" << &MU << " (\"" << MU.getName() << "\""; 204 if (anyPrintSymbolOptionSet()) 205 OS << ", " << MU.getSymbols(); 206 return OS << ")"; 207 } 208 209 raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K) { 210 switch (K) { 211 case LookupKind::Static: 212 return OS << "Static"; 213 case LookupKind::DLSym: 214 return OS << "DLSym"; 215 } 216 llvm_unreachable("Invalid lookup kind"); 217 } 218 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"; 226 } 227 llvm_unreachable("Invalid JITDylib lookup flags"); 228 } 229 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"; 236 } 237 llvm_unreachable("Invalid symbol lookup flags"); 238 } 239 240 raw_ostream &operator<<(raw_ostream &OS, 241 const SymbolLookupSet::value_type &KV) { 242 return OS << "(" << KV.first << ", " << KV.second << ")"; 243 } 244 245 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet) { 246 return OS << printSequence(LookupSet, '{', '}', 247 PrintAll<SymbolLookupSet::value_type>()); 248 } 249 250 raw_ostream &operator<<(raw_ostream &OS, 251 const JITDylibSearchOrder &SearchOrder) { 252 OS << "["; 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 << ")"; 261 } 262 } 263 OS << " ]"; 264 return OS; 265 } 266 267 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases) { 268 OS << "{"; 269 for (auto &KV : Aliases) 270 OS << " " << *KV.first << ": " << KV.second.Aliasee << " " 271 << KV.second.AliasFlags; 272 OS << " }"; 273 return OS; 274 } 275 276 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) { 277 switch (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"; 290 } 291 llvm_unreachable("Invalid state"); 292 } 293 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"; 302 return OS; 303 } 304 305 DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride) 306 : DumpDir(std::move(DumpDir)), 307 IdentifierOverride(std::move(IdentifierOverride)) { 308 309 /// Discard any trailing separators. 310 while (!this->DumpDir.empty() && 311 sys::path::is_separator(this->DumpDir.back())) 312 this->DumpDir.pop_back(); 313 } 314 315 Expected<std::unique_ptr<MemoryBuffer>> 316 DumpObjects::operator()(std::unique_ptr<MemoryBuffer> Obj) { 317 size_t Idx = 1; 318 319 std::string DumpPathStem; 320 raw_string_ostream(DumpPathStem) 321 << DumpDir << (DumpDir.empty() ? "" : "/") << getBufferIdentifier(*Obj); 322 323 std::string DumpPath = DumpPathStem + ".o"; 324 while (sys::fs::exists(DumpPath)) { 325 DumpPath.clear(); 326 raw_string_ostream(DumpPath) << DumpPathStem << "." << (++Idx) << ".o"; 327 } 328 329 LLVM_DEBUG({ 330 dbgs() << "Dumping object buffer [ " << (const void *)Obj->getBufferStart() 331 << " -- " << (const void *)(Obj->getBufferEnd() - 1) << " ] to " 332 << DumpPath << "\n"; 333 }); 334 335 std::error_code EC; 336 raw_fd_ostream DumpStream(DumpPath, EC); 337 if (EC) 338 return errorCodeToError(EC); 339 DumpStream.write(Obj->getBufferStart(), Obj->getBufferSize()); 340 341 return std::move(Obj); 342 } 343 344 StringRef DumpObjects::getBufferIdentifier(MemoryBuffer &B) { 345 if (!IdentifierOverride.empty()) 346 return IdentifierOverride; 347 StringRef Identifier = B.getBufferIdentifier(); 348 Identifier.consume_back(".o"); 349 return Identifier; 350 } 351 352 } // End namespace orc. 353 } // End namespace llvm. 354