354 lines · cpp
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-exception6//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 21using namespace llvm;22 23namespace {24 25#ifndef NDEBUG26 27cl::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 32cl::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 37cl::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 // NDEBUG43 44// SetPrinter predicate that prints every element.45template <typename T> struct PrintAll {46 bool operator()(const T &E) { return true; }47};48 49bool anyPrintSymbolOptionSet() {50#ifndef NDEBUG51 return PrintHidden || PrintCallable || PrintData;52#else53 return false;54#endif // NDEBUG55}56 57bool flagsMatchCLOpts(const JITSymbolFlags &Flags) {58#ifndef NDEBUG59 // 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#else74 return false;75#endif // NDEBUG76}77 78// Prints a sequence of items, filtered by an user-supplied predicate.79template <typename Sequence,80 typename Pred = PrintAll<typename Sequence::value_type>>81class SequencePrinter {82public: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 102private:103 const Sequence &S;104 char OpenSeq;105 char CloseSeq;106 mutable Pred ShouldPrint;107};108 109template <typename Sequence, typename Pred>110SequencePrinter<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.116template <typename Sequence, typename Pred>117llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,118 const SequencePrinter<Sequence, Pred> &Printer) {119 Printer.printTo(OS);120 return OS;121}122 123struct PrintSymbolFlagsMapElemsMatchingCLOpts {124 bool operator()(const orc::SymbolFlagsMap::value_type &KV) {125 return flagsMatchCLOpts(KV.second);126 }127};128 129struct PrintSymbolMapElemsMatchingCLOpts {130 bool operator()(const orc::SymbolMap::value_type &KV) {131 return flagsMatchCLOpts(KV.second.getFlags());132 }133};134 135} // end anonymous namespace136 137namespace llvm {138namespace orc {139 140raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {141 return OS << printSequence(Symbols, '{', '}', PrintAll<SymbolStringPtr>());142}143 144raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols) {145 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());146}147 148raw_ostream &operator<<(raw_ostream &OS, ArrayRef<SymbolStringPtr> Symbols) {149 return OS << printSequence(Symbols, '[', ']', PrintAll<SymbolStringPtr>());150}151 152raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {153 if (Flags.hasError())154 OS << "[*ERROR*]";155 if (Flags.isCallable())156 OS << "[Callable]";157 else158 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 170raw_ostream &operator<<(raw_ostream &OS, const ExecutorSymbolDef &Sym) {171 return OS << Sym.getAddress() << " " << Sym.getFlags();172}173 174raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV) {175 return OS << "(\"" << KV.first << "\", " << KV.second << ")";176}177 178raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {179 return OS << "(\"" << KV.first << "\": " << KV.second << ")";180}181 182raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {183 return OS << printSequence(SymbolFlags, '{', '}',184 PrintSymbolFlagsMapElemsMatchingCLOpts());185}186 187raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {188 return OS << printSequence(Symbols, '{', '}',189 PrintSymbolMapElemsMatchingCLOpts());190}191 192raw_ostream &operator<<(raw_ostream &OS,193 const SymbolDependenceMap::value_type &KV) {194 return OS << "(" << KV.first->getName() << ", " << KV.second << ")";195}196 197raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {198 return OS << printSequence(Deps, '{', '}',199 PrintAll<SymbolDependenceMap::value_type>());200}201 202raw_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 209raw_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 219raw_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 230raw_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 240raw_ostream &operator<<(raw_ostream &OS,241 const SymbolLookupSet::value_type &KV) {242 return OS << "(" << KV.first << ", " << KV.second << ")";243}244 245raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet) {246 return OS << printSequence(LookupSet, '{', '}',247 PrintAll<SymbolLookupSet::value_type>());248}249 250raw_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 267raw_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 276raw_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 294raw_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 305DumpObjects::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 315Expected<std::unique_ptr<MemoryBuffer>>316DumpObjects::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 344StringRef 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