| File: | build/source/llvm/include/llvm/Support/Error.h |
| Warning: | line 519, column 5 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //===- llvm-jitlink.cpp -- Command line interface/tester for llvm-jitlink -===// | |||
| 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 | // This utility provides a simple command line interface to the llvm jitlink | |||
| 10 | // library, which makes relocatable object files executable in memory. Its | |||
| 11 | // primary function is as a testing utility for the jitlink library. | |||
| 12 | // | |||
| 13 | //===----------------------------------------------------------------------===// | |||
| 14 | ||||
| 15 | #include "llvm-jitlink.h" | |||
| 16 | ||||
| 17 | #include "llvm/BinaryFormat/Magic.h" | |||
| 18 | #include "llvm/ExecutionEngine/Orc/COFFPlatform.h" | |||
| 19 | #include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h" | |||
| 20 | #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" | |||
| 21 | #include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h" | |||
| 22 | #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" | |||
| 23 | #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" | |||
| 24 | #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" | |||
| 25 | #include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" | |||
| 26 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" | |||
| 27 | #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" | |||
| 28 | #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" | |||
| 29 | #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h" | |||
| 30 | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" | |||
| 31 | #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" | |||
| 32 | #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" | |||
| 33 | #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" | |||
| 34 | #include "llvm/MC/MCAsmInfo.h" | |||
| 35 | #include "llvm/MC/MCContext.h" | |||
| 36 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" | |||
| 37 | #include "llvm/MC/MCInstPrinter.h" | |||
| 38 | #include "llvm/MC/MCInstrAnalysis.h" | |||
| 39 | #include "llvm/MC/MCInstrInfo.h" | |||
| 40 | #include "llvm/MC/MCRegisterInfo.h" | |||
| 41 | #include "llvm/MC/MCSubtargetInfo.h" | |||
| 42 | #include "llvm/MC/MCTargetOptions.h" | |||
| 43 | #include "llvm/MC/TargetRegistry.h" | |||
| 44 | #include "llvm/Object/COFF.h" | |||
| 45 | #include "llvm/Object/MachO.h" | |||
| 46 | #include "llvm/Object/ObjectFile.h" | |||
| 47 | #include "llvm/Support/CommandLine.h" | |||
| 48 | #include "llvm/Support/Debug.h" | |||
| 49 | #include "llvm/Support/InitLLVM.h" | |||
| 50 | #include "llvm/Support/MemoryBuffer.h" | |||
| 51 | #include "llvm/Support/Path.h" | |||
| 52 | #include "llvm/Support/Process.h" | |||
| 53 | #include "llvm/Support/TargetSelect.h" | |||
| 54 | #include "llvm/Support/Timer.h" | |||
| 55 | ||||
| 56 | #include <cstring> | |||
| 57 | #include <deque> | |||
| 58 | #include <list> | |||
| 59 | #include <string> | |||
| 60 | ||||
| 61 | #ifdef LLVM_ON_UNIX1 | |||
| 62 | #include <netdb.h> | |||
| 63 | #include <netinet/in.h> | |||
| 64 | #include <sys/socket.h> | |||
| 65 | #include <unistd.h> | |||
| 66 | #endif // LLVM_ON_UNIX | |||
| 67 | ||||
| 68 | #define DEBUG_TYPE"llvm_jitlink" "llvm_jitlink" | |||
| 69 | ||||
| 70 | using namespace llvm; | |||
| 71 | using namespace llvm::jitlink; | |||
| 72 | using namespace llvm::orc; | |||
| 73 | ||||
| 74 | static cl::OptionCategory JITLinkCategory("JITLink Options"); | |||
| 75 | ||||
| 76 | static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore, | |||
| 77 | cl::desc("input files"), | |||
| 78 | cl::cat(JITLinkCategory)); | |||
| 79 | ||||
| 80 | static cl::list<std::string> | |||
| 81 | LibrarySearchPaths("L", | |||
| 82 | cl::desc("Add dir to the list of library search paths"), | |||
| 83 | cl::Prefix, cl::cat(JITLinkCategory)); | |||
| 84 | ||||
| 85 | static cl::list<std::string> | |||
| 86 | Libraries("l", | |||
| 87 | cl::desc("Link against library X in the library search paths"), | |||
| 88 | cl::Prefix, cl::cat(JITLinkCategory)); | |||
| 89 | ||||
| 90 | static cl::list<std::string> | |||
| 91 | LibrariesHidden("hidden-l", | |||
| 92 | cl::desc("Link against library X in the library search " | |||
| 93 | "paths with hidden visibility"), | |||
| 94 | cl::Prefix, cl::cat(JITLinkCategory)); | |||
| 95 | ||||
| 96 | static cl::list<std::string> | |||
| 97 | LoadHidden("load_hidden", | |||
| 98 | cl::desc("Link against library X with hidden visibility"), | |||
| 99 | cl::cat(JITLinkCategory)); | |||
| 100 | ||||
| 101 | static cl::opt<bool> SearchSystemLibrary( | |||
| 102 | "search-sys-lib", | |||
| 103 | cl::desc("Add system library paths to library search paths"), | |||
| 104 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 105 | ||||
| 106 | static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"), | |||
| 107 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 108 | ||||
| 109 | static cl::list<std::string> | |||
| 110 | CheckFiles("check", cl::desc("File containing verifier checks"), | |||
| 111 | cl::cat(JITLinkCategory)); | |||
| 112 | ||||
| 113 | static cl::opt<std::string> | |||
| 114 | CheckName("check-name", cl::desc("Name of checks to match against"), | |||
| 115 | cl::init("jitlink-check"), cl::cat(JITLinkCategory)); | |||
| 116 | ||||
| 117 | static cl::opt<std::string> | |||
| 118 | EntryPointName("entry", cl::desc("Symbol to call as main entry point"), | |||
| 119 | cl::init(""), cl::cat(JITLinkCategory)); | |||
| 120 | ||||
| 121 | static cl::list<std::string> JITDylibs( | |||
| 122 | "jd", | |||
| 123 | cl::desc("Specifies the JITDylib to be used for any subsequent " | |||
| 124 | "input file, -L<seacrh-path>, and -l<library> arguments"), | |||
| 125 | cl::cat(JITLinkCategory)); | |||
| 126 | ||||
| 127 | static cl::list<std::string> | |||
| 128 | Dylibs("preload", | |||
| 129 | cl::desc("Pre-load dynamic libraries (e.g. language runtimes " | |||
| 130 | "required by the ORC runtime)"), | |||
| 131 | cl::cat(JITLinkCategory)); | |||
| 132 | ||||
| 133 | static cl::list<std::string> InputArgv("args", cl::Positional, | |||
| 134 | cl::desc("<program arguments>..."), | |||
| 135 | cl::PositionalEatsArgs, | |||
| 136 | cl::cat(JITLinkCategory)); | |||
| 137 | ||||
| 138 | static cl::opt<bool> | |||
| 139 | DebuggerSupport("debugger-support", | |||
| 140 | cl::desc("Enable debugger suppport (default = !-noexec)"), | |||
| 141 | cl::init(true), cl::Hidden, cl::cat(JITLinkCategory)); | |||
| 142 | ||||
| 143 | static cl::opt<bool> | |||
| 144 | NoProcessSymbols("no-process-syms", | |||
| 145 | cl::desc("Do not resolve to llvm-jitlink process symbols"), | |||
| 146 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 147 | ||||
| 148 | static cl::list<std::string> AbsoluteDefs( | |||
| 149 | "abs", | |||
| 150 | cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"), | |||
| 151 | cl::cat(JITLinkCategory)); | |||
| 152 | ||||
| 153 | static cl::list<std::string> | |||
| 154 | Aliases("alias", cl::desc("Inject symbol aliases (syntax: <name>=<addr>)"), | |||
| 155 | cl::cat(JITLinkCategory)); | |||
| 156 | ||||
| 157 | static cl::list<std::string> TestHarnesses("harness", cl::Positional, | |||
| 158 | cl::desc("Test harness files"), | |||
| 159 | cl::PositionalEatsArgs, | |||
| 160 | cl::cat(JITLinkCategory)); | |||
| 161 | ||||
| 162 | static cl::opt<bool> ShowInitialExecutionSessionState( | |||
| 163 | "show-init-es", | |||
| 164 | cl::desc("Print ExecutionSession state before resolving entry point"), | |||
| 165 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 166 | ||||
| 167 | static cl::opt<bool> ShowEntryExecutionSessionState( | |||
| 168 | "show-entry-es", | |||
| 169 | cl::desc("Print ExecutionSession state after resolving entry point"), | |||
| 170 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 171 | ||||
| 172 | static cl::opt<bool> ShowAddrs( | |||
| 173 | "show-addrs", | |||
| 174 | cl::desc("Print registered symbol, section, got and stub addresses"), | |||
| 175 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 176 | ||||
| 177 | static cl::opt<bool> ShowLinkGraph( | |||
| 178 | "show-graph", | |||
| 179 | cl::desc("Print the link graph after fixups have been applied"), | |||
| 180 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 181 | ||||
| 182 | static cl::opt<bool> ShowSizes( | |||
| 183 | "show-sizes", | |||
| 184 | cl::desc("Show sizes pre- and post-dead stripping, and allocations"), | |||
| 185 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 186 | ||||
| 187 | static cl::opt<bool> ShowTimes("show-times", | |||
| 188 | cl::desc("Show times for llvm-jitlink phases"), | |||
| 189 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 190 | ||||
| 191 | static cl::opt<std::string> SlabAllocateSizeString( | |||
| 192 | "slab-allocate", | |||
| 193 | cl::desc("Allocate from a slab of the given size " | |||
| 194 | "(allowable suffixes: Kb, Mb, Gb. default = " | |||
| 195 | "Kb)"), | |||
| 196 | cl::init(""), cl::cat(JITLinkCategory)); | |||
| 197 | ||||
| 198 | static cl::opt<uint64_t> SlabAddress( | |||
| 199 | "slab-address", | |||
| 200 | cl::desc("Set slab target address (requires -slab-allocate and -noexec)"), | |||
| 201 | cl::init(~0ULL), cl::cat(JITLinkCategory)); | |||
| 202 | ||||
| 203 | static cl::opt<uint64_t> SlabPageSize( | |||
| 204 | "slab-page-size", | |||
| 205 | cl::desc("Set page size for slab (requires -slab-allocate and -noexec)"), | |||
| 206 | cl::init(0), cl::cat(JITLinkCategory)); | |||
| 207 | ||||
| 208 | static cl::opt<bool> ShowRelocatedSectionContents( | |||
| 209 | "show-relocated-section-contents", | |||
| 210 | cl::desc("show section contents after fixups have been applied"), | |||
| 211 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 212 | ||||
| 213 | static cl::opt<bool> PhonyExternals( | |||
| 214 | "phony-externals", | |||
| 215 | cl::desc("resolve all otherwise unresolved externals to null"), | |||
| 216 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 217 | ||||
| 218 | static cl::opt<std::string> OutOfProcessExecutor( | |||
| 219 | "oop-executor", cl::desc("Launch an out-of-process executor to run code"), | |||
| 220 | cl::ValueOptional, cl::cat(JITLinkCategory)); | |||
| 221 | ||||
| 222 | static cl::opt<std::string> OutOfProcessExecutorConnect( | |||
| 223 | "oop-executor-connect", | |||
| 224 | cl::desc("Connect to an out-of-process executor via TCP"), | |||
| 225 | cl::cat(JITLinkCategory)); | |||
| 226 | ||||
| 227 | static cl::opt<std::string> | |||
| 228 | OrcRuntime("orc-runtime", cl::desc("Use ORC runtime from given path"), | |||
| 229 | cl::init(""), cl::cat(JITLinkCategory)); | |||
| 230 | ||||
| 231 | static cl::opt<bool> AddSelfRelocations( | |||
| 232 | "add-self-relocations", | |||
| 233 | cl::desc("Add relocations to function pointers to the current function"), | |||
| 234 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 235 | ||||
| 236 | static cl::opt<bool> | |||
| 237 | ShowErrFailedToMaterialize("show-err-failed-to-materialize", | |||
| 238 | cl::desc("Show FailedToMaterialize errors"), | |||
| 239 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 240 | ||||
| 241 | static cl::opt<bool> UseSharedMemory( | |||
| 242 | "use-shared-memory", | |||
| 243 | cl::desc("Use shared memory to transfer generated code and data"), | |||
| 244 | cl::init(false), cl::cat(JITLinkCategory)); | |||
| 245 | ||||
| 246 | static ExitOnError ExitOnErr; | |||
| 247 | ||||
| 248 | static LLVM_ATTRIBUTE_USED__attribute__((__used__)) void linkComponents() { | |||
| 249 | errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper | |||
| 250 | << (void *)&llvm_orc_deregisterEHFrameSectionWrapper | |||
| 251 | << (void *)&llvm_orc_registerJITLoaderGDBWrapper | |||
| 252 | << (void *)&llvm_orc_registerJITLoaderGDBAllocAction; | |||
| 253 | } | |||
| 254 | ||||
| 255 | static bool UseTestResultOverride = false; | |||
| 256 | static int64_t TestResultOverride = 0; | |||
| 257 | ||||
| 258 | extern "C" LLVM_ATTRIBUTE_USED__attribute__((__used__)) void | |||
| 259 | llvm_jitlink_setTestResultOverride(int64_t Value) { | |||
| 260 | TestResultOverride = Value; | |||
| 261 | UseTestResultOverride = true; | |||
| 262 | } | |||
| 263 | ||||
| 264 | static Error addSelfRelocations(LinkGraph &G); | |||
| 265 | ||||
| 266 | namespace { | |||
| 267 | ||||
| 268 | template <typename ErrT> | |||
| 269 | ||||
| 270 | class ConditionalPrintErr { | |||
| 271 | public: | |||
| 272 | ConditionalPrintErr(bool C) : C(C) {} | |||
| 273 | void operator()(ErrT &EI) { | |||
| 274 | if (C) { | |||
| 275 | errs() << "llvm-jitlink error: "; | |||
| 276 | EI.log(errs()); | |||
| 277 | errs() << "\n"; | |||
| 278 | } | |||
| 279 | } | |||
| 280 | ||||
| 281 | private: | |||
| 282 | bool C; | |||
| 283 | }; | |||
| 284 | ||||
| 285 | Expected<std::unique_ptr<MemoryBuffer>> getFile(const Twine &FileName) { | |||
| 286 | if (auto F = MemoryBuffer::getFile(FileName)) | |||
| 287 | return std::move(*F); | |||
| 288 | else | |||
| 289 | return createFileError(FileName, F.getError()); | |||
| 290 | } | |||
| 291 | ||||
| 292 | void reportLLVMJITLinkError(Error Err) { | |||
| 293 | handleAllErrors( | |||
| 294 | std::move(Err), | |||
| 295 | ConditionalPrintErr<orc::FailedToMaterialize>(ShowErrFailedToMaterialize), | |||
| 296 | ConditionalPrintErr<ErrorInfoBase>(true)); | |||
| 297 | } | |||
| 298 | ||||
| 299 | } // end anonymous namespace | |||
| 300 | ||||
| 301 | namespace llvm { | |||
| 302 | ||||
| 303 | static raw_ostream & | |||
| 304 | operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) { | |||
| 305 | return OS << "target addr = " | |||
| 306 | << format("0x%016" PRIx64"l" "x", MRI.getTargetAddress()) | |||
| 307 | << ", content: " << (const void *)MRI.getContent().data() << " -- " | |||
| 308 | << (const void *)(MRI.getContent().data() + MRI.getContent().size()) | |||
| 309 | << " (" << MRI.getContent().size() << " bytes)"; | |||
| 310 | } | |||
| 311 | ||||
| 312 | static raw_ostream & | |||
| 313 | operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) { | |||
| 314 | OS << "Symbols:\n"; | |||
| 315 | for (auto &SKV : SIM) | |||
| 316 | OS << " \"" << SKV.first() << "\" " << SKV.second << "\n"; | |||
| 317 | return OS; | |||
| 318 | } | |||
| 319 | ||||
| 320 | static raw_ostream & | |||
| 321 | operator<<(raw_ostream &OS, const Session::FileInfo &FI) { | |||
| 322 | for (auto &SIKV : FI.SectionInfos) | |||
| 323 | OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n"; | |||
| 324 | for (auto &GOTKV : FI.GOTEntryInfos) | |||
| 325 | OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n"; | |||
| 326 | for (auto &StubKV : FI.StubInfos) | |||
| 327 | OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n"; | |||
| 328 | return OS; | |||
| 329 | } | |||
| 330 | ||||
| 331 | static raw_ostream & | |||
| 332 | operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) { | |||
| 333 | for (auto &FIKV : FIM) | |||
| 334 | OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second; | |||
| 335 | return OS; | |||
| 336 | } | |||
| 337 | ||||
| 338 | static Error applyHarnessPromotions(Session &S, LinkGraph &G) { | |||
| 339 | ||||
| 340 | // If this graph is part of the test harness there's nothing to do. | |||
| 341 | if (S.HarnessFiles.empty() || S.HarnessFiles.count(G.getName())) | |||
| 342 | return Error::success(); | |||
| 343 | ||||
| 344 | LLVM_DEBUG(dbgs() << "Applying promotions to graph " << G.getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Applying promotions to graph " << G.getName() << "\n"; } } while (false); | |||
| 345 | ||||
| 346 | // If this graph is part of the test then promote any symbols referenced by | |||
| 347 | // the harness to default scope, remove all symbols that clash with harness | |||
| 348 | // definitions. | |||
| 349 | std::vector<Symbol *> DefinitionsToRemove; | |||
| 350 | for (auto *Sym : G.defined_symbols()) { | |||
| 351 | ||||
| 352 | if (!Sym->hasName()) | |||
| 353 | continue; | |||
| 354 | ||||
| 355 | if (Sym->getLinkage() == Linkage::Weak) { | |||
| 356 | if (!S.CanonicalWeakDefs.count(Sym->getName()) || | |||
| 357 | S.CanonicalWeakDefs[Sym->getName()] != G.getName()) { | |||
| 358 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n"; }; } } while (false ) | |||
| 359 | dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n"; }; } } while (false ) | |||
| 360 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n"; }; } } while (false ); | |||
| 361 | DefinitionsToRemove.push_back(Sym); | |||
| 362 | } else { | |||
| 363 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Making weak symbol " << Sym->getName() << " strong\n"; }; } } while (false) | |||
| 364 | dbgs() << " Making weak symbol " << Sym->getName() << " strong\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Making weak symbol " << Sym->getName() << " strong\n"; }; } } while (false) | |||
| 365 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << " Making weak symbol " << Sym->getName() << " strong\n"; }; } } while (false); | |||
| 366 | if (S.HarnessExternals.count(Sym->getName())) | |||
| 367 | Sym->setScope(Scope::Default); | |||
| 368 | else | |||
| 369 | Sym->setScope(Scope::Hidden); | |||
| 370 | Sym->setLinkage(Linkage::Strong); | |||
| 371 | } | |||
| 372 | } else if (S.HarnessExternals.count(Sym->getName())) { | |||
| 373 | LLVM_DEBUG(dbgs() << " Promoting " << Sym->getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " Promoting " << Sym ->getName() << "\n"; } } while (false); | |||
| 374 | Sym->setScope(Scope::Default); | |||
| 375 | Sym->setLive(true); | |||
| 376 | continue; | |||
| 377 | } else if (S.HarnessDefinitions.count(Sym->getName())) { | |||
| 378 | LLVM_DEBUG(dbgs() << " Externalizing " << Sym->getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " Externalizing " << Sym->getName() << "\n"; } } while (false); | |||
| 379 | DefinitionsToRemove.push_back(Sym); | |||
| 380 | } | |||
| 381 | } | |||
| 382 | ||||
| 383 | for (auto *Sym : DefinitionsToRemove) | |||
| 384 | G.makeExternal(*Sym); | |||
| 385 | ||||
| 386 | return Error::success(); | |||
| 387 | } | |||
| 388 | ||||
| 389 | static uint64_t computeTotalBlockSizes(LinkGraph &G) { | |||
| 390 | uint64_t TotalSize = 0; | |||
| 391 | for (auto *B : G.blocks()) | |||
| 392 | TotalSize += B->getSize(); | |||
| 393 | return TotalSize; | |||
| 394 | } | |||
| 395 | ||||
| 396 | static void dumpSectionContents(raw_ostream &OS, LinkGraph &G) { | |||
| 397 | constexpr orc::ExecutorAddrDiff DumpWidth = 16; | |||
| 398 | static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two"); | |||
| 399 | ||||
| 400 | // Put sections in address order. | |||
| 401 | std::vector<Section *> Sections; | |||
| 402 | for (auto &S : G.sections()) | |||
| 403 | Sections.push_back(&S); | |||
| 404 | ||||
| 405 | llvm::sort(Sections, [](const Section *LHS, const Section *RHS) { | |||
| 406 | if (LHS->symbols().empty() && RHS->symbols().empty()) | |||
| 407 | return false; | |||
| 408 | if (LHS->symbols().empty()) | |||
| 409 | return false; | |||
| 410 | if (RHS->symbols().empty()) | |||
| 411 | return true; | |||
| 412 | SectionRange LHSRange(*LHS); | |||
| 413 | SectionRange RHSRange(*RHS); | |||
| 414 | return LHSRange.getStart() < RHSRange.getStart(); | |||
| 415 | }); | |||
| 416 | ||||
| 417 | for (auto *S : Sections) { | |||
| 418 | OS << S->getName() << " content:"; | |||
| 419 | if (S->symbols().empty()) { | |||
| 420 | OS << "\n section empty\n"; | |||
| 421 | continue; | |||
| 422 | } | |||
| 423 | ||||
| 424 | // Sort symbols into order, then render. | |||
| 425 | std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end()); | |||
| 426 | llvm::sort(Syms, [](const Symbol *LHS, const Symbol *RHS) { | |||
| 427 | return LHS->getAddress() < RHS->getAddress(); | |||
| 428 | }); | |||
| 429 | ||||
| 430 | orc::ExecutorAddr NextAddr(Syms.front()->getAddress().getValue() & | |||
| 431 | ~(DumpWidth - 1)); | |||
| 432 | for (auto *Sym : Syms) { | |||
| 433 | bool IsZeroFill = Sym->getBlock().isZeroFill(); | |||
| 434 | auto SymStart = Sym->getAddress(); | |||
| 435 | auto SymSize = Sym->getSize(); | |||
| 436 | auto SymEnd = SymStart + SymSize; | |||
| 437 | const uint8_t *SymData = IsZeroFill ? nullptr | |||
| 438 | : reinterpret_cast<const uint8_t *>( | |||
| 439 | Sym->getSymbolContent().data()); | |||
| 440 | ||||
| 441 | // Pad any space before the symbol starts. | |||
| 442 | while (NextAddr != SymStart) { | |||
| 443 | if (NextAddr % DumpWidth == 0) | |||
| 444 | OS << formatv("\n{0:x16}:", NextAddr); | |||
| 445 | OS << " "; | |||
| 446 | ++NextAddr; | |||
| 447 | } | |||
| 448 | ||||
| 449 | // Render the symbol content. | |||
| 450 | while (NextAddr != SymEnd) { | |||
| 451 | if (NextAddr % DumpWidth == 0) | |||
| 452 | OS << formatv("\n{0:x16}:", NextAddr); | |||
| 453 | if (IsZeroFill) | |||
| 454 | OS << " 00"; | |||
| 455 | else | |||
| 456 | OS << formatv(" {0:x-2}", SymData[NextAddr - SymStart]); | |||
| 457 | ++NextAddr; | |||
| 458 | } | |||
| 459 | } | |||
| 460 | OS << "\n"; | |||
| 461 | } | |||
| 462 | } | |||
| 463 | ||||
| 464 | // A memory mapper with a fake offset applied only used for -noexec testing | |||
| 465 | class InProcessDeltaMapper final : public InProcessMemoryMapper { | |||
| 466 | public: | |||
| 467 | InProcessDeltaMapper(size_t PageSize, uint64_t TargetAddr) | |||
| 468 | : InProcessMemoryMapper(PageSize), TargetMapAddr(TargetAddr), | |||
| 469 | DeltaAddr(0) {} | |||
| 470 | ||||
| 471 | static Expected<std::unique_ptr<InProcessDeltaMapper>> Create() { | |||
| 472 | size_t PageSize = SlabPageSize; | |||
| 473 | if (!PageSize) { | |||
| 474 | if (auto PageSizeOrErr = sys::Process::getPageSize()) | |||
| 475 | PageSize = *PageSizeOrErr; | |||
| 476 | else | |||
| 477 | return PageSizeOrErr.takeError(); | |||
| 478 | } | |||
| 479 | ||||
| 480 | if (PageSize == 0) | |||
| 481 | return make_error<StringError>("Page size is zero", | |||
| 482 | inconvertibleErrorCode()); | |||
| 483 | ||||
| 484 | return std::make_unique<InProcessDeltaMapper>(PageSize, SlabAddress); | |||
| 485 | } | |||
| 486 | ||||
| 487 | void reserve(size_t NumBytes, OnReservedFunction OnReserved) override { | |||
| 488 | InProcessMemoryMapper::reserve( | |||
| 489 | NumBytes, [this, OnReserved = std::move(OnReserved)]( | |||
| 490 | Expected<ExecutorAddrRange> Result) mutable { | |||
| 491 | if (!Result) | |||
| 492 | return OnReserved(Result.takeError()); | |||
| 493 | ||||
| 494 | assert(DeltaAddr == 0 && "Overwriting previous offset")(static_cast <bool> (DeltaAddr == 0 && "Overwriting previous offset" ) ? void (0) : __assert_fail ("DeltaAddr == 0 && \"Overwriting previous offset\"" , "llvm/tools/llvm-jitlink/llvm-jitlink.cpp", 494, __extension__ __PRETTY_FUNCTION__)); | |||
| 495 | if (TargetMapAddr != ~0ULL) | |||
| 496 | DeltaAddr = TargetMapAddr - Result->Start.getValue(); | |||
| 497 | auto OffsetRange = ExecutorAddrRange(Result->Start + DeltaAddr, | |||
| 498 | Result->End + DeltaAddr); | |||
| 499 | ||||
| 500 | OnReserved(OffsetRange); | |||
| 501 | }); | |||
| 502 | } | |||
| 503 | ||||
| 504 | char *prepare(ExecutorAddr Addr, size_t ContentSize) override { | |||
| 505 | return InProcessMemoryMapper::prepare(Addr - DeltaAddr, ContentSize); | |||
| 506 | } | |||
| 507 | ||||
| 508 | void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override { | |||
| 509 | // Slide mapping based on delta and make all segments read-writable. | |||
| 510 | auto FixedAI = AI; | |||
| 511 | FixedAI.MappingBase -= DeltaAddr; | |||
| 512 | for (auto &Seg : FixedAI.Segments) | |||
| 513 | Seg.AG = AllocGroup(MemProt::Read | MemProt::Write, | |||
| 514 | Seg.AG.getMemDeallocPolicy()); | |||
| 515 | InProcessMemoryMapper::initialize( | |||
| 516 | FixedAI, [this, OnInitialized = std::move(OnInitialized)]( | |||
| 517 | Expected<ExecutorAddr> Result) mutable { | |||
| 518 | if (!Result) | |||
| 519 | return OnInitialized(Result.takeError()); | |||
| 520 | ||||
| 521 | OnInitialized(ExecutorAddr(Result->getValue() + DeltaAddr)); | |||
| 522 | }); | |||
| 523 | } | |||
| 524 | ||||
| 525 | void deinitialize(ArrayRef<ExecutorAddr> Allocations, | |||
| 526 | OnDeinitializedFunction OnDeInitialized) override { | |||
| 527 | std::vector<ExecutorAddr> Addrs(Allocations.size()); | |||
| 528 | for (const auto Base : Allocations) { | |||
| 529 | Addrs.push_back(Base - DeltaAddr); | |||
| 530 | } | |||
| 531 | ||||
| 532 | InProcessMemoryMapper::deinitialize(Addrs, std::move(OnDeInitialized)); | |||
| 533 | } | |||
| 534 | ||||
| 535 | void release(ArrayRef<ExecutorAddr> Reservations, | |||
| 536 | OnReleasedFunction OnRelease) override { | |||
| 537 | std::vector<ExecutorAddr> Addrs(Reservations.size()); | |||
| 538 | for (const auto Base : Reservations) { | |||
| 539 | Addrs.push_back(Base - DeltaAddr); | |||
| 540 | } | |||
| 541 | InProcessMemoryMapper::release(Addrs, std::move(OnRelease)); | |||
| 542 | } | |||
| 543 | ||||
| 544 | private: | |||
| 545 | uint64_t TargetMapAddr; | |||
| 546 | uint64_t DeltaAddr; | |||
| 547 | }; | |||
| 548 | ||||
| 549 | Expected<uint64_t> getSlabAllocSize(StringRef SizeString) { | |||
| 550 | SizeString = SizeString.trim(); | |||
| 551 | ||||
| 552 | uint64_t Units = 1024; | |||
| 553 | ||||
| 554 | if (SizeString.endswith_insensitive("kb")) | |||
| 555 | SizeString = SizeString.drop_back(2).rtrim(); | |||
| 556 | else if (SizeString.endswith_insensitive("mb")) { | |||
| 557 | Units = 1024 * 1024; | |||
| 558 | SizeString = SizeString.drop_back(2).rtrim(); | |||
| 559 | } else if (SizeString.endswith_insensitive("gb")) { | |||
| 560 | Units = 1024 * 1024 * 1024; | |||
| 561 | SizeString = SizeString.drop_back(2).rtrim(); | |||
| 562 | } | |||
| 563 | ||||
| 564 | uint64_t SlabSize = 0; | |||
| 565 | if (SizeString.getAsInteger(10, SlabSize)) | |||
| 566 | return make_error<StringError>("Invalid numeric format for slab size", | |||
| 567 | inconvertibleErrorCode()); | |||
| 568 | ||||
| 569 | return SlabSize * Units; | |||
| 570 | } | |||
| 571 | ||||
| 572 | static std::unique_ptr<JITLinkMemoryManager> createInProcessMemoryManager() { | |||
| 573 | uint64_t SlabSize; | |||
| 574 | #ifdef _WIN32 | |||
| 575 | SlabSize = 1024 * 1024; | |||
| 576 | #else | |||
| 577 | SlabSize = 1024 * 1024 * 1024; | |||
| 578 | #endif | |||
| 579 | ||||
| 580 | if (!SlabAllocateSizeString.empty()) | |||
| 581 | SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString)); | |||
| 582 | ||||
| 583 | // If this is a -no-exec case and we're tweaking the slab address or size then | |||
| 584 | // use the delta mapper. | |||
| 585 | if (NoExec && (SlabAddress || SlabPageSize)) | |||
| 586 | return ExitOnErr( | |||
| 587 | MapperJITLinkMemoryManager::CreateWithMapper<InProcessDeltaMapper>( | |||
| 588 | SlabSize)); | |||
| 589 | ||||
| 590 | // Otherwise use the standard in-process mapper. | |||
| 591 | return ExitOnErr( | |||
| 592 | MapperJITLinkMemoryManager::CreateWithMapper<InProcessMemoryMapper>( | |||
| 593 | SlabSize)); | |||
| 594 | } | |||
| 595 | ||||
| 596 | Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>> | |||
| 597 | createSharedMemoryManager(SimpleRemoteEPC &SREPC) { | |||
| 598 | SharedMemoryMapper::SymbolAddrs SAs; | |||
| 599 | if (auto Err = SREPC.getBootstrapSymbols( | |||
| 600 | {{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName}, | |||
| 601 | {SAs.Reserve, | |||
| 602 | rt::ExecutorSharedMemoryMapperServiceReserveWrapperName}, | |||
| 603 | {SAs.Initialize, | |||
| 604 | rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName}, | |||
| 605 | {SAs.Deinitialize, | |||
| 606 | rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName}, | |||
| 607 | {SAs.Release, | |||
| 608 | rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}})) | |||
| 609 | return std::move(Err); | |||
| 610 | ||||
| 611 | #ifdef _WIN32 | |||
| 612 | size_t SlabSize = 1024 * 1024; | |||
| 613 | #else | |||
| 614 | size_t SlabSize = 1024 * 1024 * 1024; | |||
| 615 | #endif | |||
| 616 | ||||
| 617 | if (!SlabAllocateSizeString.empty()) | |||
| 618 | SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString)); | |||
| 619 | ||||
| 620 | return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>( | |||
| 621 | SlabSize, SREPC, SAs); | |||
| 622 | } | |||
| 623 | ||||
| 624 | ||||
| 625 | static Expected<MaterializationUnit::Interface> | |||
| 626 | getTestObjectFileInterface(Session &S, MemoryBufferRef O) { | |||
| 627 | ||||
| 628 | // Get the standard interface for this object, but ignore the symbols field. | |||
| 629 | // We'll handle that manually to include promotion. | |||
| 630 | auto I = getObjectFileInterface(S.ES, O); | |||
| 631 | if (!I) | |||
| 632 | return I.takeError(); | |||
| 633 | I->SymbolFlags.clear(); | |||
| 634 | ||||
| 635 | // If creating an object file was going to fail it would have happened above, | |||
| 636 | // so we can 'cantFail' this. | |||
| 637 | auto Obj = cantFail(object::ObjectFile::createObjectFile(O)); | |||
| 638 | ||||
| 639 | // The init symbol must be included in the SymbolFlags map if present. | |||
| 640 | if (I->InitSymbol) | |||
| 641 | I->SymbolFlags[I->InitSymbol] = | |||
| 642 | JITSymbolFlags::MaterializationSideEffectsOnly; | |||
| 643 | ||||
| 644 | for (auto &Sym : Obj->symbols()) { | |||
| 645 | Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); | |||
| 646 | if (!SymFlagsOrErr) | |||
| 647 | // TODO: Test this error. | |||
| 648 | return SymFlagsOrErr.takeError(); | |||
| 649 | ||||
| 650 | // Skip symbols not defined in this object file. | |||
| 651 | if ((*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)) | |||
| 652 | continue; | |||
| 653 | ||||
| 654 | auto Name = Sym.getName(); | |||
| 655 | if (!Name) | |||
| 656 | return Name.takeError(); | |||
| 657 | ||||
| 658 | // Skip symbols that have type SF_File. | |||
| 659 | if (auto SymType = Sym.getType()) { | |||
| 660 | if (*SymType == object::SymbolRef::ST_File) | |||
| 661 | continue; | |||
| 662 | } else | |||
| 663 | return SymType.takeError(); | |||
| 664 | ||||
| 665 | auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); | |||
| 666 | if (!SymFlags) | |||
| 667 | return SymFlags.takeError(); | |||
| 668 | ||||
| 669 | if (SymFlags->isWeak()) { | |||
| 670 | // If this is a weak symbol that's not defined in the harness then we | |||
| 671 | // need to either mark it as strong (if this is the first definition | |||
| 672 | // that we've seen) or discard it. | |||
| 673 | if (S.HarnessDefinitions.count(*Name) || S.CanonicalWeakDefs.count(*Name)) | |||
| 674 | continue; | |||
| 675 | S.CanonicalWeakDefs[*Name] = O.getBufferIdentifier(); | |||
| 676 | *SymFlags &= ~JITSymbolFlags::Weak; | |||
| 677 | if (!S.HarnessExternals.count(*Name)) | |||
| 678 | *SymFlags &= ~JITSymbolFlags::Exported; | |||
| 679 | } else if (S.HarnessExternals.count(*Name)) { | |||
| 680 | *SymFlags |= JITSymbolFlags::Exported; | |||
| 681 | } else if (S.HarnessDefinitions.count(*Name) || | |||
| 682 | !(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) | |||
| 683 | continue; | |||
| 684 | ||||
| 685 | auto InternedName = S.ES.intern(*Name); | |||
| 686 | I->SymbolFlags[InternedName] = std::move(*SymFlags); | |||
| 687 | } | |||
| 688 | ||||
| 689 | return I; | |||
| 690 | } | |||
| 691 | ||||
| 692 | static Error loadProcessSymbols(Session &S) { | |||
| 693 | auto FilterMainEntryPoint = | |||
| 694 | [EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) { | |||
| 695 | return Name != EPName; | |||
| 696 | }; | |||
| 697 | S.MainJD->addGenerator( | |||
| 698 | ExitOnErr(orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess( | |||
| 699 | S.ES, std::move(FilterMainEntryPoint)))); | |||
| 700 | ||||
| 701 | return Error::success(); | |||
| 702 | } | |||
| 703 | ||||
| 704 | static Error loadDylibs(Session &S) { | |||
| 705 | LLVM_DEBUG(dbgs() << "Loading dylibs...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Loading dylibs...\n"; } } while (false); | |||
| 706 | for (const auto &Dylib : Dylibs) { | |||
| 707 | LLVM_DEBUG(dbgs() << " " << Dylib << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " " << Dylib << "\n"; } } while (false); | |||
| 708 | if (auto Err = S.loadAndLinkDynamicLibrary(*S.MainJD, Dylib)) | |||
| 709 | return Err; | |||
| 710 | } | |||
| 711 | ||||
| 712 | return Error::success(); | |||
| 713 | } | |||
| 714 | ||||
| 715 | static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() { | |||
| 716 | #ifndef LLVM_ON_UNIX1 | |||
| 717 | // FIXME: Add support for Windows. | |||
| 718 | return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr + | |||
| 719 | " not supported on non-unix platforms", | |||
| 720 | inconvertibleErrorCode()); | |||
| 721 | #elif !LLVM_ENABLE_THREADS1 | |||
| 722 | // Out of process mode using SimpleRemoteEPC depends on threads. | |||
| 723 | return make_error<StringError>( | |||
| 724 | "-" + OutOfProcessExecutor.ArgStr + | |||
| 725 | " requires threads, but LLVM was built with " | |||
| 726 | "LLVM_ENABLE_THREADS=Off", | |||
| 727 | inconvertibleErrorCode()); | |||
| 728 | #else | |||
| 729 | ||||
| 730 | constexpr int ReadEnd = 0; | |||
| 731 | constexpr int WriteEnd = 1; | |||
| 732 | ||||
| 733 | // Pipe FDs. | |||
| 734 | int ToExecutor[2]; | |||
| 735 | int FromExecutor[2]; | |||
| 736 | ||||
| 737 | pid_t ChildPID; | |||
| 738 | ||||
| 739 | // Create pipes to/from the executor.. | |||
| 740 | if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) | |||
| 741 | return make_error<StringError>("Unable to create pipe for executor", | |||
| 742 | inconvertibleErrorCode()); | |||
| 743 | ||||
| 744 | ChildPID = fork(); | |||
| 745 | ||||
| 746 | if (ChildPID == 0) { | |||
| 747 | // In the child... | |||
| 748 | ||||
| 749 | // Close the parent ends of the pipes | |||
| 750 | close(ToExecutor[WriteEnd]); | |||
| 751 | close(FromExecutor[ReadEnd]); | |||
| 752 | ||||
| 753 | // Execute the child process. | |||
| 754 | std::unique_ptr<char[]> ExecutorPath, FDSpecifier; | |||
| 755 | { | |||
| 756 | ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1); | |||
| 757 | strcpy(ExecutorPath.get(), OutOfProcessExecutor.data()); | |||
| 758 | ||||
| 759 | std::string FDSpecifierStr("filedescs="); | |||
| 760 | FDSpecifierStr += utostr(ToExecutor[ReadEnd]); | |||
| 761 | FDSpecifierStr += ','; | |||
| 762 | FDSpecifierStr += utostr(FromExecutor[WriteEnd]); | |||
| 763 | FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); | |||
| 764 | strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); | |||
| 765 | } | |||
| 766 | ||||
| 767 | char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr}; | |||
| 768 | int RC = execvp(ExecutorPath.get(), Args); | |||
| 769 | if (RC != 0) { | |||
| 770 | errs() << "unable to launch out-of-process executor \"" | |||
| 771 | << ExecutorPath.get() << "\"\n"; | |||
| 772 | exit(1); | |||
| 773 | } | |||
| 774 | } | |||
| 775 | // else we're the parent... | |||
| 776 | ||||
| 777 | // Close the child ends of the pipes | |||
| 778 | close(ToExecutor[ReadEnd]); | |||
| 779 | close(FromExecutor[WriteEnd]); | |||
| 780 | ||||
| 781 | auto S = SimpleRemoteEPC::Setup(); | |||
| 782 | if (UseSharedMemory) | |||
| 783 | S.CreateMemoryManager = createSharedMemoryManager; | |||
| 784 | ||||
| 785 | return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( | |||
| 786 | std::make_unique<DynamicThreadPoolTaskDispatcher>(), std::move(S), | |||
| 787 | FromExecutor[ReadEnd], ToExecutor[WriteEnd]); | |||
| 788 | #endif | |||
| 789 | } | |||
| 790 | ||||
| 791 | #if LLVM_ON_UNIX1 && LLVM_ENABLE_THREADS1 | |||
| 792 | static Error createTCPSocketError(Twine Details) { | |||
| 793 | return make_error<StringError>( | |||
| 794 | formatv("Failed to connect TCP socket '{0}': {1}", | |||
| 795 | OutOfProcessExecutorConnect, Details), | |||
| 796 | inconvertibleErrorCode()); | |||
| 797 | } | |||
| 798 | ||||
| 799 | static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) { | |||
| 800 | addrinfo *AI; | |||
| 801 | addrinfo Hints{}; | |||
| 802 | Hints.ai_family = AF_INET2; | |||
| 803 | Hints.ai_socktype = SOCK_STREAMSOCK_STREAM; | |||
| 804 | Hints.ai_flags = AI_NUMERICSERV0x0400; | |||
| 805 | ||||
| 806 | if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) | |||
| 807 | return createTCPSocketError("Address resolution failed (" + | |||
| 808 | StringRef(gai_strerror(EC)) + ")"); | |||
| 809 | ||||
| 810 | // Cycle through the returned addrinfo structures and connect to the first | |||
| 811 | // reachable endpoint. | |||
| 812 | int SockFD; | |||
| 813 | addrinfo *Server; | |||
| 814 | for (Server = AI; Server != nullptr; Server = Server->ai_next) { | |||
| 815 | // socket might fail, e.g. if the address family is not supported. Skip to | |||
| 816 | // the next addrinfo structure in such a case. | |||
| 817 | if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) | |||
| 818 | continue; | |||
| 819 | ||||
| 820 | // If connect returns null, we exit the loop with a working socket. | |||
| 821 | if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) | |||
| 822 | break; | |||
| 823 | ||||
| 824 | close(SockFD); | |||
| 825 | } | |||
| 826 | freeaddrinfo(AI); | |||
| 827 | ||||
| 828 | // If we reached the end of the loop without connecting to a valid endpoint, | |||
| 829 | // dump the last error that was logged in socket() or connect(). | |||
| 830 | if (Server == nullptr) | |||
| 831 | return createTCPSocketError(std::strerror(errno(*__errno_location ()))); | |||
| 832 | ||||
| 833 | return SockFD; | |||
| 834 | } | |||
| 835 | #endif | |||
| 836 | ||||
| 837 | static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() { | |||
| 838 | #ifndef LLVM_ON_UNIX1 | |||
| 839 | // FIXME: Add TCP support for Windows. | |||
| 840 | return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr + | |||
| 841 | " not supported on non-unix platforms", | |||
| 842 | inconvertibleErrorCode()); | |||
| 843 | #elif !LLVM_ENABLE_THREADS1 | |||
| 844 | // Out of process mode using SimpleRemoteEPC depends on threads. | |||
| 845 | return make_error<StringError>( | |||
| 846 | "-" + OutOfProcessExecutorConnect.ArgStr + | |||
| 847 | " requires threads, but LLVM was built with " | |||
| 848 | "LLVM_ENABLE_THREADS=Off", | |||
| 849 | inconvertibleErrorCode()); | |||
| 850 | #else | |||
| 851 | ||||
| 852 | StringRef Host, PortStr; | |||
| 853 | std::tie(Host, PortStr) = StringRef(OutOfProcessExecutorConnect).split(':'); | |||
| 854 | if (Host.empty()) | |||
| 855 | return createTCPSocketError("Host name for -" + | |||
| 856 | OutOfProcessExecutorConnect.ArgStr + | |||
| 857 | " can not be empty"); | |||
| 858 | if (PortStr.empty()) | |||
| 859 | return createTCPSocketError("Port number in -" + | |||
| 860 | OutOfProcessExecutorConnect.ArgStr + | |||
| 861 | " can not be empty"); | |||
| 862 | int Port = 0; | |||
| 863 | if (PortStr.getAsInteger(10, Port)) | |||
| 864 | return createTCPSocketError("Port number '" + PortStr + | |||
| 865 | "' is not a valid integer"); | |||
| 866 | ||||
| 867 | Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str()); | |||
| 868 | if (!SockFD) | |||
| 869 | return SockFD.takeError(); | |||
| 870 | ||||
| 871 | auto S = SimpleRemoteEPC::Setup(); | |||
| 872 | if (UseSharedMemory) | |||
| 873 | S.CreateMemoryManager = createSharedMemoryManager; | |||
| 874 | ||||
| 875 | return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( | |||
| 876 | std::make_unique<DynamicThreadPoolTaskDispatcher>(), | |||
| 877 | std::move(S), *SockFD, *SockFD); | |||
| 878 | #endif | |||
| 879 | } | |||
| 880 | ||||
| 881 | class PhonyExternalsGenerator : public DefinitionGenerator { | |||
| 882 | public: | |||
| 883 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, | |||
| 884 | JITDylibLookupFlags JDLookupFlags, | |||
| 885 | const SymbolLookupSet &LookupSet) override { | |||
| 886 | SymbolMap PhonySymbols; | |||
| 887 | for (auto &KV : LookupSet) | |||
| 888 | PhonySymbols[KV.first] = JITEvaluatedSymbol(0, JITSymbolFlags::Exported); | |||
| 889 | return JD.define(absoluteSymbols(std::move(PhonySymbols))); | |||
| 890 | } | |||
| 891 | }; | |||
| 892 | ||||
| 893 | Expected<std::unique_ptr<Session>> Session::Create(Triple TT) { | |||
| 894 | ||||
| 895 | std::unique_ptr<ExecutorProcessControl> EPC; | |||
| 896 | if (OutOfProcessExecutor.getNumOccurrences()) { | |||
| 897 | /// If -oop-executor is passed then launch the executor. | |||
| 898 | if (auto REPC = launchExecutor()) | |||
| 899 | EPC = std::move(*REPC); | |||
| 900 | else | |||
| 901 | return REPC.takeError(); | |||
| 902 | } else if (OutOfProcessExecutorConnect.getNumOccurrences()) { | |||
| 903 | /// If -oop-executor-connect is passed then connect to the executor. | |||
| 904 | if (auto REPC = connectToExecutor()) | |||
| 905 | EPC = std::move(*REPC); | |||
| 906 | else | |||
| 907 | return REPC.takeError(); | |||
| 908 | } else { | |||
| 909 | /// Otherwise use SelfExecutorProcessControl to target the current process. | |||
| 910 | auto PageSize = sys::Process::getPageSize(); | |||
| 911 | if (!PageSize) | |||
| 912 | return PageSize.takeError(); | |||
| 913 | EPC = std::make_unique<SelfExecutorProcessControl>( | |||
| 914 | std::make_shared<SymbolStringPool>(), | |||
| 915 | std::make_unique<InPlaceTaskDispatcher>(), std::move(TT), *PageSize, | |||
| 916 | createInProcessMemoryManager()); | |||
| 917 | } | |||
| 918 | ||||
| 919 | Error Err = Error::success(); | |||
| 920 | std::unique_ptr<Session> S(new Session(std::move(EPC), Err)); | |||
| 921 | if (Err) | |||
| 922 | return std::move(Err); | |||
| 923 | return std::move(S); | |||
| 924 | } | |||
| 925 | ||||
| 926 | Session::~Session() { | |||
| 927 | if (auto Err = ES.endSession()) | |||
| 928 | ES.reportError(std::move(Err)); | |||
| 929 | } | |||
| 930 | ||||
| 931 | Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err) | |||
| 932 | : ES(std::move(EPC)), | |||
| 933 | ObjLayer(ES, ES.getExecutorProcessControl().getMemMgr()) { | |||
| 934 | ||||
| 935 | /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the | |||
| 936 | /// Session. | |||
| 937 | class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin { | |||
| 938 | public: | |||
| 939 | JITLinkSessionPlugin(Session &S) : S(S) {} | |||
| 940 | void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G, | |||
| 941 | PassConfiguration &PassConfig) override { | |||
| 942 | S.modifyPassConfig(G.getTargetTriple(), PassConfig); | |||
| 943 | } | |||
| 944 | ||||
| 945 | Error notifyFailed(MaterializationResponsibility &MR) override { | |||
| 946 | return Error::success(); | |||
| 947 | } | |||
| 948 | Error notifyRemovingResources(ResourceKey K) override { | |||
| 949 | return Error::success(); | |||
| 950 | } | |||
| 951 | void notifyTransferringResources(ResourceKey DstKey, | |||
| 952 | ResourceKey SrcKey) override {} | |||
| 953 | ||||
| 954 | private: | |||
| 955 | Session &S; | |||
| 956 | }; | |||
| 957 | ||||
| 958 | ErrorAsOutParameter _(&Err); | |||
| 959 | ||||
| 960 | ES.setErrorReporter(reportLLVMJITLinkError); | |||
| 961 | ||||
| 962 | if (auto MainJDOrErr = ES.createJITDylib("main")) | |||
| 963 | MainJD = &*MainJDOrErr; | |||
| 964 | else { | |||
| 965 | Err = MainJDOrErr.takeError(); | |||
| 966 | return; | |||
| 967 | } | |||
| 968 | ||||
| 969 | if (!NoProcessSymbols) | |||
| 970 | ExitOnErr(loadProcessSymbols(*this)); | |||
| 971 | else { | |||
| 972 | // This symbol is used in testcases. | |||
| 973 | auto &TestResultJD = ES.createBareJITDylib("<TestResultJD>"); | |||
| 974 | ExitOnErr(TestResultJD.define(absoluteSymbols( | |||
| 975 | {{ES.intern("llvm_jitlink_setTestResultOverride"), | |||
| 976 | {pointerToJITTargetAddress(llvm_jitlink_setTestResultOverride), | |||
| 977 | JITSymbolFlags::Exported}}}))); | |||
| 978 | MainJD->addToLinkOrder(TestResultJD); | |||
| 979 | } | |||
| 980 | ||||
| 981 | ExitOnErr(loadDylibs(*this)); | |||
| 982 | ||||
| 983 | auto &TT = ES.getExecutorProcessControl().getTargetTriple(); | |||
| 984 | ||||
| 985 | if (DebuggerSupport && TT.isOSBinFormatMachO()) | |||
| 986 | ObjLayer.addPlugin(ExitOnErr( | |||
| 987 | GDBJITDebugInfoRegistrationPlugin::Create(this->ES, *MainJD, TT))); | |||
| 988 | ||||
| 989 | // Set up the platform. | |||
| 990 | if (TT.isOSBinFormatMachO() && !OrcRuntime.empty()) { | |||
| 991 | if (auto P = | |||
| 992 | MachOPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str())) | |||
| 993 | ES.setPlatform(std::move(*P)); | |||
| 994 | else { | |||
| 995 | Err = P.takeError(); | |||
| 996 | return; | |||
| 997 | } | |||
| 998 | } else if (TT.isOSBinFormatELF() && !OrcRuntime.empty()) { | |||
| 999 | if (auto P = | |||
| 1000 | ELFNixPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str())) | |||
| 1001 | ES.setPlatform(std::move(*P)); | |||
| 1002 | else { | |||
| 1003 | Err = P.takeError(); | |||
| 1004 | return; | |||
| 1005 | } | |||
| 1006 | } else if (TT.isOSBinFormatCOFF() && !OrcRuntime.empty()) { | |||
| 1007 | auto LoadDynLibrary = [&, this](JITDylib &JD, StringRef DLLName) -> Error { | |||
| 1008 | if (!DLLName.endswith_insensitive(".dll")) | |||
| 1009 | return make_error<StringError>("DLLName not ending with .dll", | |||
| 1010 | inconvertibleErrorCode()); | |||
| 1011 | return loadAndLinkDynamicLibrary(JD, DLLName); | |||
| 1012 | }; | |||
| 1013 | ||||
| 1014 | if (auto P = COFFPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str(), | |||
| 1015 | std::move(LoadDynLibrary))) | |||
| 1016 | ES.setPlatform(std::move(*P)); | |||
| 1017 | else { | |||
| 1018 | Err = P.takeError(); | |||
| 1019 | return; | |||
| 1020 | } | |||
| 1021 | } else if (TT.isOSBinFormatELF()) { | |||
| 1022 | if (!NoExec) | |||
| 1023 | ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>( | |||
| 1024 | ES, ExitOnErr(EPCEHFrameRegistrar::Create(this->ES)))); | |||
| 1025 | if (DebuggerSupport) | |||
| 1026 | ObjLayer.addPlugin(std::make_unique<DebugObjectManagerPlugin>( | |||
| 1027 | ES, ExitOnErr(createJITLoaderGDBRegistrar(this->ES)))); | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this)); | |||
| 1031 | ||||
| 1032 | // Process any harness files. | |||
| 1033 | for (auto &HarnessFile : TestHarnesses) { | |||
| 1034 | HarnessFiles.insert(HarnessFile); | |||
| 1035 | ||||
| 1036 | auto ObjBuffer = ExitOnErr(getFile(HarnessFile)); | |||
| 1037 | ||||
| 1038 | auto ObjInterface = | |||
| 1039 | ExitOnErr(getObjectFileInterface(ES, ObjBuffer->getMemBufferRef())); | |||
| 1040 | ||||
| 1041 | for (auto &KV : ObjInterface.SymbolFlags) | |||
| 1042 | HarnessDefinitions.insert(*KV.first); | |||
| 1043 | ||||
| 1044 | auto Obj = ExitOnErr( | |||
| 1045 | object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); | |||
| 1046 | ||||
| 1047 | for (auto &Sym : Obj->symbols()) { | |||
| 1048 | uint32_t SymFlags = ExitOnErr(Sym.getFlags()); | |||
| 1049 | auto Name = ExitOnErr(Sym.getName()); | |||
| 1050 | ||||
| 1051 | if (Name.empty()) | |||
| 1052 | continue; | |||
| 1053 | ||||
| 1054 | if (SymFlags & object::BasicSymbolRef::SF_Undefined) | |||
| 1055 | HarnessExternals.insert(Name); | |||
| 1056 | } | |||
| 1057 | } | |||
| 1058 | ||||
| 1059 | // If a name is defined by some harness file then it's a definition, not an | |||
| 1060 | // external. | |||
| 1061 | for (auto &DefName : HarnessDefinitions) | |||
| 1062 | HarnessExternals.erase(DefName.getKey()); | |||
| 1063 | } | |||
| 1064 | ||||
| 1065 | void Session::dumpSessionInfo(raw_ostream &OS) { | |||
| 1066 | OS << "Registered addresses:\n" << SymbolInfos << FileInfos; | |||
| 1067 | } | |||
| 1068 | ||||
| 1069 | void Session::modifyPassConfig(const Triple &TT, | |||
| 1070 | PassConfiguration &PassConfig) { | |||
| 1071 | if (!CheckFiles.empty()) | |||
| 1072 | PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) { | |||
| 1073 | auto &EPC = ES.getExecutorProcessControl(); | |||
| 1074 | if (EPC.getTargetTriple().getObjectFormat() == Triple::ELF) | |||
| 1075 | return registerELFGraphInfo(*this, G); | |||
| 1076 | ||||
| 1077 | if (EPC.getTargetTriple().getObjectFormat() == Triple::MachO) | |||
| 1078 | return registerMachOGraphInfo(*this, G); | |||
| 1079 | ||||
| 1080 | if (EPC.getTargetTriple().getObjectFormat() == Triple::COFF) | |||
| 1081 | return registerCOFFGraphInfo(*this, G); | |||
| 1082 | ||||
| 1083 | return make_error<StringError>("Unsupported object format for GOT/stub " | |||
| 1084 | "registration", | |||
| 1085 | inconvertibleErrorCode()); | |||
| 1086 | }); | |||
| 1087 | ||||
| 1088 | if (ShowLinkGraph) | |||
| 1089 | PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error { | |||
| 1090 | outs() << "Link graph \"" << G.getName() << "\" post-fixup:\n"; | |||
| 1091 | G.dump(outs()); | |||
| 1092 | return Error::success(); | |||
| 1093 | }); | |||
| 1094 | ||||
| 1095 | PassConfig.PrePrunePasses.push_back( | |||
| 1096 | [this](LinkGraph &G) { return applyHarnessPromotions(*this, G); }); | |||
| 1097 | ||||
| 1098 | if (ShowSizes) { | |||
| 1099 | PassConfig.PrePrunePasses.push_back([this](LinkGraph &G) -> Error { | |||
| 1100 | SizeBeforePruning += computeTotalBlockSizes(G); | |||
| 1101 | return Error::success(); | |||
| 1102 | }); | |||
| 1103 | PassConfig.PostFixupPasses.push_back([this](LinkGraph &G) -> Error { | |||
| 1104 | SizeAfterFixups += computeTotalBlockSizes(G); | |||
| 1105 | return Error::success(); | |||
| 1106 | }); | |||
| 1107 | } | |||
| 1108 | ||||
| 1109 | if (ShowRelocatedSectionContents) | |||
| 1110 | PassConfig.PostFixupPasses.push_back([](LinkGraph &G) -> Error { | |||
| 1111 | outs() << "Relocated section contents for " << G.getName() << ":\n"; | |||
| 1112 | dumpSectionContents(outs(), G); | |||
| 1113 | return Error::success(); | |||
| 1114 | }); | |||
| 1115 | ||||
| 1116 | if (AddSelfRelocations) | |||
| 1117 | PassConfig.PostPrunePasses.push_back(addSelfRelocations); | |||
| 1118 | } | |||
| 1119 | ||||
| 1120 | Expected<JITDylib *> Session::getOrLoadDynamicLibrary(StringRef LibPath) { | |||
| 1121 | auto It = DynLibJDs.find(LibPath.str()); | |||
| 1122 | if (It != DynLibJDs.end()) { | |||
| 1123 | return It->second; | |||
| 1124 | } | |||
| 1125 | auto G = EPCDynamicLibrarySearchGenerator::Load(ES, LibPath.data()); | |||
| 1126 | if (!G) | |||
| 1127 | return G.takeError(); | |||
| 1128 | auto JD = &ES.createBareJITDylib(LibPath.str()); | |||
| 1129 | ||||
| 1130 | JD->addGenerator(std::move(*G)); | |||
| 1131 | DynLibJDs.emplace(LibPath.str(), JD); | |||
| 1132 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath << "\n"; }; } } while (false) | |||
| 1133 | dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPathdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath << "\n"; }; } } while (false) | |||
| 1134 | << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath << "\n"; }; } } while (false) | |||
| 1135 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath << "\n"; }; } } while (false); | |||
| 1136 | return JD; | |||
| 1137 | } | |||
| 1138 | ||||
| 1139 | Error Session::loadAndLinkDynamicLibrary(JITDylib &JD, StringRef LibPath) { | |||
| 1140 | auto DL = getOrLoadDynamicLibrary(LibPath); | |||
| 1141 | if (!DL) | |||
| 1142 | return DL.takeError(); | |||
| 1143 | JD.addToLinkOrder(**DL); | |||
| 1144 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1145 | dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1146 | << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1147 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName() << "\n"; }; } } while (false); | |||
| 1148 | return Error::success(); | |||
| 1149 | } | |||
| 1150 | ||||
| 1151 | Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) { | |||
| 1152 | auto FileInfoItr = FileInfos.find(FileName); | |||
| 1153 | if (FileInfoItr == FileInfos.end()) | |||
| 1154 | return make_error<StringError>("file \"" + FileName + "\" not recognized", | |||
| 1155 | inconvertibleErrorCode()); | |||
| 1156 | return FileInfoItr->second; | |||
| 1157 | } | |||
| 1158 | ||||
| 1159 | Expected<Session::MemoryRegionInfo &> | |||
| 1160 | Session::findSectionInfo(StringRef FileName, StringRef SectionName) { | |||
| 1161 | auto FI = findFileInfo(FileName); | |||
| 1162 | if (!FI) | |||
| 1163 | return FI.takeError(); | |||
| 1164 | auto SecInfoItr = FI->SectionInfos.find(SectionName); | |||
| 1165 | if (SecInfoItr == FI->SectionInfos.end()) | |||
| 1166 | return make_error<StringError>("no section \"" + SectionName + | |||
| 1167 | "\" registered for file \"" + FileName + | |||
| 1168 | "\"", | |||
| 1169 | inconvertibleErrorCode()); | |||
| 1170 | return SecInfoItr->second; | |||
| 1171 | } | |||
| 1172 | ||||
| 1173 | Expected<Session::MemoryRegionInfo &> | |||
| 1174 | Session::findStubInfo(StringRef FileName, StringRef TargetName) { | |||
| 1175 | auto FI = findFileInfo(FileName); | |||
| 1176 | if (!FI) | |||
| 1177 | return FI.takeError(); | |||
| 1178 | auto StubInfoItr = FI->StubInfos.find(TargetName); | |||
| 1179 | if (StubInfoItr == FI->StubInfos.end()) | |||
| 1180 | return make_error<StringError>("no stub for \"" + TargetName + | |||
| 1181 | "\" registered for file \"" + FileName + | |||
| 1182 | "\"", | |||
| 1183 | inconvertibleErrorCode()); | |||
| 1184 | return StubInfoItr->second; | |||
| 1185 | } | |||
| 1186 | ||||
| 1187 | Expected<Session::MemoryRegionInfo &> | |||
| 1188 | Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) { | |||
| 1189 | auto FI = findFileInfo(FileName); | |||
| 1190 | if (!FI) | |||
| 1191 | return FI.takeError(); | |||
| 1192 | auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName); | |||
| 1193 | if (GOTInfoItr == FI->GOTEntryInfos.end()) | |||
| 1194 | return make_error<StringError>("no GOT entry for \"" + TargetName + | |||
| 1195 | "\" registered for file \"" + FileName + | |||
| 1196 | "\"", | |||
| 1197 | inconvertibleErrorCode()); | |||
| 1198 | return GOTInfoItr->second; | |||
| 1199 | } | |||
| 1200 | ||||
| 1201 | bool Session::isSymbolRegistered(StringRef SymbolName) { | |||
| 1202 | return SymbolInfos.count(SymbolName); | |||
| 1203 | } | |||
| 1204 | ||||
| 1205 | Expected<Session::MemoryRegionInfo &> | |||
| 1206 | Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) { | |||
| 1207 | auto SymInfoItr = SymbolInfos.find(SymbolName); | |||
| 1208 | if (SymInfoItr == SymbolInfos.end()) | |||
| 1209 | return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName + | |||
| 1210 | " not found", | |||
| 1211 | inconvertibleErrorCode()); | |||
| 1212 | return SymInfoItr->second; | |||
| 1213 | } | |||
| 1214 | ||||
| 1215 | } // end namespace llvm | |||
| 1216 | ||||
| 1217 | static Triple getFirstFileTriple() { | |||
| 1218 | static Triple FirstTT = []() { | |||
| 1219 | assert(!InputFiles.empty() && "InputFiles can not be empty")(static_cast <bool> (!InputFiles.empty() && "InputFiles can not be empty" ) ? void (0) : __assert_fail ("!InputFiles.empty() && \"InputFiles can not be empty\"" , "llvm/tools/llvm-jitlink/llvm-jitlink.cpp", 1219, __extension__ __PRETTY_FUNCTION__)); | |||
| 1220 | for (auto InputFile : InputFiles) { | |||
| 1221 | auto ObjBuffer = ExitOnErr(getFile(InputFile)); | |||
| 1222 | file_magic Magic = identify_magic(ObjBuffer->getBuffer()); | |||
| 1223 | switch (Magic) { | |||
| 1224 | case file_magic::coff_object: | |||
| 1225 | case file_magic::elf_relocatable: | |||
| 1226 | case file_magic::macho_object: { | |||
| 1227 | auto Obj = ExitOnErr( | |||
| 1228 | object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); | |||
| 1229 | Triple TT = Obj->makeTriple(); | |||
| 1230 | if (Magic == file_magic::coff_object) { | |||
| 1231 | // TODO: Move this to makeTriple() if possible. | |||
| 1232 | TT.setObjectFormat(Triple::COFF); | |||
| 1233 | TT.setOS(Triple::OSType::Win32); | |||
| 1234 | } | |||
| 1235 | return TT; | |||
| 1236 | } | |||
| 1237 | default: | |||
| 1238 | break; | |||
| 1239 | } | |||
| 1240 | } | |||
| 1241 | return Triple(); | |||
| 1242 | }(); | |||
| 1243 | ||||
| 1244 | return FirstTT; | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | static Error sanitizeArguments(const Triple &TT, const char *ArgV0) { | |||
| 1248 | ||||
| 1249 | // -noexec and --args should not be used together. | |||
| 1250 | if (NoExec && !InputArgv.empty()) | |||
| 1251 | errs() << "Warning: --args passed to -noexec run will be ignored.\n"; | |||
| 1252 | ||||
| 1253 | // Set the entry point name if not specified. | |||
| 1254 | if (EntryPointName.empty()) | |||
| 1255 | EntryPointName = TT.getObjectFormat() == Triple::MachO ? "_main" : "main"; | |||
| 1256 | ||||
| 1257 | // Disable debugger support by default in noexec tests. | |||
| 1258 | if (DebuggerSupport.getNumOccurrences() == 0 && NoExec) | |||
| 1259 | DebuggerSupport = false; | |||
| 1260 | ||||
| 1261 | // If -slab-allocate is passed, check that we're not trying to use it in | |||
| 1262 | // -oop-executor or -oop-executor-connect mode. | |||
| 1263 | // | |||
| 1264 | // FIXME: Remove once we enable remote slab allocation. | |||
| 1265 | if (SlabAllocateSizeString != "") { | |||
| 1266 | if (OutOfProcessExecutor.getNumOccurrences() || | |||
| 1267 | OutOfProcessExecutorConnect.getNumOccurrences()) | |||
| 1268 | return make_error<StringError>( | |||
| 1269 | "-slab-allocate cannot be used with -oop-executor or " | |||
| 1270 | "-oop-executor-connect", | |||
| 1271 | inconvertibleErrorCode()); | |||
| 1272 | } | |||
| 1273 | ||||
| 1274 | // If -slab-address is passed, require -slab-allocate and -noexec | |||
| 1275 | if (SlabAddress != ~0ULL) { | |||
| 1276 | if (SlabAllocateSizeString == "" || !NoExec) | |||
| 1277 | return make_error<StringError>( | |||
| 1278 | "-slab-address requires -slab-allocate and -noexec", | |||
| 1279 | inconvertibleErrorCode()); | |||
| 1280 | ||||
| 1281 | if (SlabPageSize == 0) | |||
| 1282 | errs() << "Warning: -slab-address used without -slab-page-size.\n"; | |||
| 1283 | } | |||
| 1284 | ||||
| 1285 | if (SlabPageSize != 0) { | |||
| 1286 | // -slab-page-size requires slab alloc. | |||
| 1287 | if (SlabAllocateSizeString == "") | |||
| 1288 | return make_error<StringError>("-slab-page-size requires -slab-allocate", | |||
| 1289 | inconvertibleErrorCode()); | |||
| 1290 | ||||
| 1291 | // Check -slab-page-size / -noexec interactions. | |||
| 1292 | if (!NoExec) { | |||
| 1293 | if (auto RealPageSize = sys::Process::getPageSize()) { | |||
| 1294 | if (SlabPageSize % *RealPageSize) | |||
| 1295 | return make_error<StringError>( | |||
| 1296 | "-slab-page-size must be a multiple of real page size for exec " | |||
| 1297 | "tests (did you mean to use -noexec ?)\n", | |||
| 1298 | inconvertibleErrorCode()); | |||
| 1299 | } else { | |||
| 1300 | errs() << "Could not retrieve process page size:\n"; | |||
| 1301 | logAllUnhandledErrors(RealPageSize.takeError(), errs(), ""); | |||
| 1302 | errs() << "Executing with slab page size = " | |||
| 1303 | << formatv("{0:x}", SlabPageSize) << ".\n" | |||
| 1304 | << "Tool may crash if " << formatv("{0:x}", SlabPageSize) | |||
| 1305 | << " is not a multiple of the real process page size.\n" | |||
| 1306 | << "(did you mean to use -noexec ?)"; | |||
| 1307 | } | |||
| 1308 | } | |||
| 1309 | } | |||
| 1310 | ||||
| 1311 | // Only one of -oop-executor and -oop-executor-connect can be used. | |||
| 1312 | if (!!OutOfProcessExecutor.getNumOccurrences() && | |||
| 1313 | !!OutOfProcessExecutorConnect.getNumOccurrences()) | |||
| 1314 | return make_error<StringError>( | |||
| 1315 | "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" + | |||
| 1316 | OutOfProcessExecutorConnect.ArgStr + " can be specified", | |||
| 1317 | inconvertibleErrorCode()); | |||
| 1318 | ||||
| 1319 | // If -oop-executor was used but no value was specified then use a sensible | |||
| 1320 | // default. | |||
| 1321 | if (!!OutOfProcessExecutor.getNumOccurrences() && | |||
| 1322 | OutOfProcessExecutor.empty()) { | |||
| 1323 | SmallString<256> OOPExecutorPath(sys::fs::getMainExecutable( | |||
| 1324 | ArgV0, reinterpret_cast<void *>(&sanitizeArguments))); | |||
| 1325 | sys::path::remove_filename(OOPExecutorPath); | |||
| 1326 | sys::path::append(OOPExecutorPath, "llvm-jitlink-executor"); | |||
| 1327 | OutOfProcessExecutor = OOPExecutorPath.str().str(); | |||
| 1328 | } | |||
| 1329 | ||||
| 1330 | return Error::success(); | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | static void addPhonyExternalsGenerator(Session &S) { | |||
| 1334 | S.MainJD->addGenerator(std::make_unique<PhonyExternalsGenerator>()); | |||
| 1335 | } | |||
| 1336 | ||||
| 1337 | static Error createJITDylibs(Session &S, | |||
| 1338 | std::map<unsigned, JITDylib *> &IdxToJD) { | |||
| 1339 | // First, set up JITDylibs. | |||
| 1340 | LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Creating JITDylibs...\n" ; } } while (false); | |||
| 1341 | { | |||
| 1342 | // Create a "main" JITLinkDylib. | |||
| 1343 | IdxToJD[0] = S.MainJD; | |||
| 1344 | S.JDSearchOrder.push_back({S.MainJD, JITDylibLookupFlags::MatchAllSymbols}); | |||
| 1345 | LLVM_DEBUG(dbgs() << " 0: " << S.MainJD->getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " 0: " << S.MainJD ->getName() << "\n"; } } while (false); | |||
| 1346 | ||||
| 1347 | // Add any extra JITDylibs from the command line. | |||
| 1348 | for (auto JDItr = JITDylibs.begin(), JDEnd = JITDylibs.end(); | |||
| 1349 | JDItr != JDEnd; ++JDItr) { | |||
| 1350 | auto JD = S.ES.createJITDylib(*JDItr); | |||
| 1351 | if (!JD) | |||
| 1352 | return JD.takeError(); | |||
| 1353 | unsigned JDIdx = JITDylibs.getPosition(JDItr - JITDylibs.begin()); | |||
| 1354 | IdxToJD[JDIdx] = &*JD; | |||
| 1355 | S.JDSearchOrder.push_back({&*JD, JITDylibLookupFlags::MatchAllSymbols}); | |||
| 1356 | LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD->getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " " << JDIdx << ": " << JD->getName() << "\n"; } } while (false ); | |||
| 1357 | } | |||
| 1358 | } | |||
| 1359 | ||||
| 1360 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false) | |||
| 1361 | dbgs() << "Dylib search order is [ ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false) | |||
| 1362 | for (auto &KV : S.JDSearchOrder)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false) | |||
| 1363 | dbgs() << KV.first->getName() << " ";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false) | |||
| 1364 | dbgs() << "]\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false) | |||
| 1365 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Dylib search order is [ " ; for (auto &KV : S.JDSearchOrder) dbgs() << KV.first ->getName() << " "; dbgs() << "]\n"; }; } } while (false); | |||
| 1366 | ||||
| 1367 | return Error::success(); | |||
| 1368 | } | |||
| 1369 | ||||
| 1370 | static Error addAbsoluteSymbols(Session &S, | |||
| 1371 | const std::map<unsigned, JITDylib *> &IdxToJD) { | |||
| 1372 | // Define absolute symbols. | |||
| 1373 | LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Defining absolute symbols...\n" ; } } while (false); | |||
| 1374 | for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end(); | |||
| 1375 | AbsDefItr != AbsDefEnd; ++AbsDefItr) { | |||
| 1376 | unsigned AbsDefArgIdx = | |||
| 1377 | AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin()); | |||
| 1378 | auto &JD = *std::prev(IdxToJD.lower_bound(AbsDefArgIdx))->second; | |||
| 1379 | ||||
| 1380 | StringRef AbsDefStmt = *AbsDefItr; | |||
| 1381 | size_t EqIdx = AbsDefStmt.find_first_of('='); | |||
| 1382 | if (EqIdx == StringRef::npos) | |||
| 1383 | return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt + | |||
| 1384 | "\". Syntax: <name>=<addr>", | |||
| 1385 | inconvertibleErrorCode()); | |||
| 1386 | StringRef Name = AbsDefStmt.substr(0, EqIdx).trim(); | |||
| 1387 | StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim(); | |||
| 1388 | ||||
| 1389 | uint64_t Addr; | |||
| 1390 | if (AddrStr.getAsInteger(0, Addr)) | |||
| 1391 | return make_error<StringError>("Invalid address expression \"" + AddrStr + | |||
| 1392 | "\" in absolute symbol definition \"" + | |||
| 1393 | AbsDefStmt + "\"", | |||
| 1394 | inconvertibleErrorCode()); | |||
| 1395 | JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported); | |||
| 1396 | if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}}))) | |||
| 1397 | return Err; | |||
| 1398 | ||||
| 1399 | // Register the absolute symbol with the session symbol infos. | |||
| 1400 | S.SymbolInfos[Name] = {ArrayRef<char>(), Addr}; | |||
| 1401 | } | |||
| 1402 | ||||
| 1403 | return Error::success(); | |||
| 1404 | } | |||
| 1405 | ||||
| 1406 | static Error addAliases(Session &S, | |||
| 1407 | const std::map<unsigned, JITDylib *> &IdxToJD) { | |||
| 1408 | // Define absolute symbols. | |||
| 1409 | LLVM_DEBUG(dbgs() << "Defining aliases...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Defining aliases...\n"; } } while (false); | |||
| 1410 | for (auto AliasItr = Aliases.begin(), AliasEnd = Aliases.end(); | |||
| 1411 | AliasItr != AliasEnd; ++AliasItr) { | |||
| 1412 | unsigned AliasArgIdx = Aliases.getPosition(AliasItr - Aliases.begin()); | |||
| 1413 | auto &JD = *std::prev(IdxToJD.lower_bound(AliasArgIdx))->second; | |||
| 1414 | ||||
| 1415 | StringRef AliasStmt = *AliasItr; | |||
| 1416 | size_t EqIdx = AliasStmt.find_first_of('='); | |||
| 1417 | if (EqIdx == StringRef::npos) | |||
| 1418 | return make_error<StringError>("Invalid alias definition \"" + AliasStmt + | |||
| 1419 | "\". Syntax: <name>=<addr>", | |||
| 1420 | inconvertibleErrorCode()); | |||
| 1421 | StringRef Alias = AliasStmt.substr(0, EqIdx).trim(); | |||
| 1422 | StringRef Aliasee = AliasStmt.substr(EqIdx + 1).trim(); | |||
| 1423 | ||||
| 1424 | SymbolAliasMap SAM; | |||
| 1425 | SAM[S.ES.intern(Alias)] = {S.ES.intern(Aliasee), JITSymbolFlags::Exported}; | |||
| 1426 | if (auto Err = JD.define(symbolAliases(std::move(SAM)))) | |||
| 1427 | return Err; | |||
| 1428 | } | |||
| 1429 | ||||
| 1430 | return Error::success(); | |||
| 1431 | } | |||
| 1432 | ||||
| 1433 | static Error addTestHarnesses(Session &S) { | |||
| 1434 | LLVM_DEBUG(dbgs() << "Adding test harness objects...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Adding test harness objects...\n" ; } } while (false); | |||
| 1435 | for (auto HarnessFile : TestHarnesses) { | |||
| 1436 | LLVM_DEBUG(dbgs() << " " << HarnessFile << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " " << HarnessFile << "\n"; } } while (false); | |||
| 1437 | auto ObjBuffer = getFile(HarnessFile); | |||
| 1438 | if (!ObjBuffer) | |||
| 1439 | return ObjBuffer.takeError(); | |||
| 1440 | if (auto Err = S.ObjLayer.add(*S.MainJD, std::move(*ObjBuffer))) | |||
| 1441 | return Err; | |||
| 1442 | } | |||
| 1443 | return Error::success(); | |||
| 1444 | } | |||
| 1445 | ||||
| 1446 | static Error addObjects(Session &S, | |||
| 1447 | const std::map<unsigned, JITDylib *> &IdxToJD) { | |||
| 1448 | ||||
| 1449 | // Load each object into the corresponding JITDylib.. | |||
| 1450 | LLVM_DEBUG(dbgs() << "Adding objects...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Adding objects...\n"; } } while (false); | |||
| 1451 | for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); | |||
| 1452 | InputFileItr != InputFileEnd; ++InputFileItr) { | |||
| 1453 | unsigned InputFileArgIdx = | |||
| 1454 | InputFiles.getPosition(InputFileItr - InputFiles.begin()); | |||
| 1455 | const std::string &InputFile = *InputFileItr; | |||
| 1456 | if (StringRef(InputFile).endswith(".a") || | |||
| 1457 | StringRef(InputFile).endswith(".lib")) | |||
| 1458 | continue; | |||
| 1459 | auto &JD = *std::prev(IdxToJD.lower_bound(InputFileArgIdx))->second; | |||
| 1460 | LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFiledo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " " << InputFileArgIdx << ": \"" << InputFile << "\" to " << JD.getName() << "\n";; } } while (false) | |||
| 1461 | << "\" to " << JD.getName() << "\n";)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << " " << InputFileArgIdx << ": \"" << InputFile << "\" to " << JD.getName() << "\n";; } } while (false); | |||
| 1462 | auto ObjBuffer = getFile(InputFile); | |||
| 1463 | if (!ObjBuffer) | |||
| 1464 | return ObjBuffer.takeError(); | |||
| 1465 | ||||
| 1466 | if (S.HarnessFiles.empty()) { | |||
| 1467 | if (auto Err = S.ObjLayer.add(JD, std::move(*ObjBuffer))) | |||
| 1468 | return Err; | |||
| 1469 | } else { | |||
| 1470 | // We're in -harness mode. Use a custom interface for this | |||
| 1471 | // test object. | |||
| 1472 | auto ObjInterface = | |||
| 1473 | getTestObjectFileInterface(S, (*ObjBuffer)->getMemBufferRef()); | |||
| 1474 | if (!ObjInterface) | |||
| 1475 | return ObjInterface.takeError(); | |||
| 1476 | if (auto Err = S.ObjLayer.add(JD, std::move(*ObjBuffer), | |||
| 1477 | std::move(*ObjInterface))) | |||
| 1478 | return Err; | |||
| 1479 | } | |||
| 1480 | } | |||
| 1481 | ||||
| 1482 | return Error::success(); | |||
| 1483 | } | |||
| 1484 | ||||
| 1485 | static Expected<MaterializationUnit::Interface> | |||
| 1486 | getObjectFileInterfaceHidden(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { | |||
| 1487 | auto I = getObjectFileInterface(ES, ObjBuffer); | |||
| 1488 | if (I) { | |||
| 1489 | for (auto &KV : I->SymbolFlags) | |||
| 1490 | KV.second &= ~JITSymbolFlags::Exported; | |||
| 1491 | } | |||
| 1492 | return I; | |||
| 1493 | } | |||
| 1494 | ||||
| 1495 | static SmallVector<StringRef, 5> getSearchPathsFromEnvVar(Session &S) { | |||
| 1496 | // FIXME: Handle EPC environment. | |||
| 1497 | SmallVector<StringRef, 5> PathVec; | |||
| 1498 | auto TT = S.ES.getExecutorProcessControl().getTargetTriple(); | |||
| 1499 | if (TT.isOSBinFormatCOFF()) | |||
| 1500 | StringRef(getenv("PATH")).split(PathVec, ";"); | |||
| 1501 | else if (TT.isOSBinFormatELF()) | |||
| 1502 | StringRef(getenv("LD_LIBRARY_PATH")).split(PathVec, ":"); | |||
| 1503 | ||||
| 1504 | return PathVec; | |||
| 1505 | } | |||
| 1506 | ||||
| 1507 | static Error addLibraries(Session &S, | |||
| 1508 | const std::map<unsigned, JITDylib *> &IdxToJD) { | |||
| 1509 | ||||
| 1510 | // 1. Collect search paths for each JITDylib. | |||
| 1511 | DenseMap<const JITDylib *, SmallVector<StringRef, 2>> JDSearchPaths; | |||
| 1512 | ||||
| 1513 | for (auto LSPItr = LibrarySearchPaths.begin(), | |||
| 1514 | LSPEnd = LibrarySearchPaths.end(); | |||
| 1515 | LSPItr != LSPEnd; ++LSPItr) { | |||
| 1516 | unsigned LibrarySearchPathIdx = | |||
| 1517 | LibrarySearchPaths.getPosition(LSPItr - LibrarySearchPaths.begin()); | |||
| 1518 | auto &JD = *std::prev(IdxToJD.lower_bound(LibrarySearchPathIdx))->second; | |||
| 1519 | ||||
| 1520 | StringRef LibrarySearchPath = *LSPItr; | |||
| 1521 | if (sys::fs::get_file_type(LibrarySearchPath) != | |||
| 1522 | sys::fs::file_type::directory_file) | |||
| 1523 | return make_error<StringError>("While linking " + JD.getName() + ", -L" + | |||
| 1524 | LibrarySearchPath + | |||
| 1525 | " does not point to a directory", | |||
| 1526 | inconvertibleErrorCode()); | |||
| 1527 | ||||
| 1528 | JDSearchPaths[&JD].push_back(*LSPItr); | |||
| 1529 | } | |||
| 1530 | ||||
| 1531 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1532 | if (!JDSearchPaths.empty())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1533 | dbgs() << "Search paths:\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1534 | for (auto &KV : JDSearchPaths) {do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1535 | dbgs() << " " << KV.first->getName() << ": [";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1536 | for (auto &LibSearchPath : KV.second)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1537 | dbgs() << " \"" << LibSearchPath << "\"";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1538 | dbgs() << " ]\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1539 | }do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false) | |||
| 1540 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { if (!JDSearchPaths.empty()) dbgs() << "Search paths:\n"; for (auto &KV : JDSearchPaths) { dbgs () << " " << KV.first->getName() << ": [" ; for (auto &LibSearchPath : KV.second) dbgs() << " \"" << LibSearchPath << "\""; dbgs() << " ]\n" ; } }; } } while (false); | |||
| 1541 | ||||
| 1542 | // 2. Collect library loads | |||
| 1543 | struct LibraryLoad { | |||
| 1544 | std::string LibName; | |||
| 1545 | bool IsPath = false; | |||
| 1546 | unsigned Position; | |||
| 1547 | StringRef *CandidateExtensions; | |||
| 1548 | enum { Standard, Hidden } Modifier; | |||
| 1549 | }; | |||
| 1550 | ||||
| 1551 | // Queue to load library as in the order as it appears in the argument list. | |||
| 1552 | std::deque<LibraryLoad> LibraryLoadQueue; | |||
| 1553 | // Add archive files from the inputs to LibraryLoads. | |||
| 1554 | for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); | |||
| 1555 | InputFileItr != InputFileEnd; ++InputFileItr) { | |||
| 1556 | StringRef InputFile = *InputFileItr; | |||
| 1557 | if (!InputFile.endswith(".a") && !InputFile.endswith(".lib")) | |||
| 1558 | continue; | |||
| 1559 | LibraryLoad LL; | |||
| 1560 | LL.LibName = InputFile.str(); | |||
| 1561 | LL.IsPath = true; | |||
| 1562 | LL.Position = InputFiles.getPosition(InputFileItr - InputFiles.begin()); | |||
| 1563 | LL.CandidateExtensions = nullptr; | |||
| 1564 | LL.Modifier = LibraryLoad::Standard; | |||
| 1565 | LibraryLoadQueue.push_back(std::move(LL)); | |||
| 1566 | } | |||
| 1567 | ||||
| 1568 | // Add -load_hidden arguments to LibraryLoads. | |||
| 1569 | for (auto LibItr = LoadHidden.begin(), LibEnd = LoadHidden.end(); | |||
| 1570 | LibItr != LibEnd; ++LibItr) { | |||
| 1571 | LibraryLoad LL; | |||
| 1572 | LL.LibName = *LibItr; | |||
| 1573 | LL.IsPath = true; | |||
| 1574 | LL.Position = LoadHidden.getPosition(LibItr - LoadHidden.begin()); | |||
| 1575 | LL.CandidateExtensions = nullptr; | |||
| 1576 | LL.Modifier = LibraryLoad::Hidden; | |||
| 1577 | LibraryLoadQueue.push_back(std::move(LL)); | |||
| 1578 | } | |||
| 1579 | StringRef StandardExtensions[] = {".so", ".dylib", ".dll", ".a", ".lib"}; | |||
| 1580 | StringRef DynLibExtensionsOnly[] = {".so", ".dylib", ".dll"}; | |||
| 1581 | StringRef ArchiveExtensionsOnly[] = {".a", ".lib"}; | |||
| 1582 | ||||
| 1583 | // Add -lx arguments to LibraryLoads. | |||
| 1584 | for (auto LibItr = Libraries.begin(), LibEnd = Libraries.end(); | |||
| 1585 | LibItr != LibEnd; ++LibItr) { | |||
| 1586 | LibraryLoad LL; | |||
| 1587 | LL.LibName = *LibItr; | |||
| 1588 | LL.Position = Libraries.getPosition(LibItr - Libraries.begin()); | |||
| 1589 | LL.CandidateExtensions = StandardExtensions; | |||
| 1590 | LL.Modifier = LibraryLoad::Standard; | |||
| 1591 | LibraryLoadQueue.push_back(std::move(LL)); | |||
| 1592 | } | |||
| 1593 | ||||
| 1594 | // Add -hidden-lx arguments to LibraryLoads. | |||
| 1595 | for (auto LibHiddenItr = LibrariesHidden.begin(), | |||
| 1596 | LibHiddenEnd = LibrariesHidden.end(); | |||
| 1597 | LibHiddenItr != LibHiddenEnd; ++LibHiddenItr) { | |||
| 1598 | LibraryLoad LL; | |||
| 1599 | LL.LibName = *LibHiddenItr; | |||
| 1600 | LL.Position = | |||
| 1601 | LibrariesHidden.getPosition(LibHiddenItr - LibrariesHidden.begin()); | |||
| 1602 | LL.CandidateExtensions = ArchiveExtensionsOnly; | |||
| 1603 | LL.Modifier = LibraryLoad::Hidden; | |||
| 1604 | LibraryLoadQueue.push_back(std::move(LL)); | |||
| 1605 | } | |||
| 1606 | ||||
| 1607 | // If there are any load-<modified> options then turn on flag overrides | |||
| 1608 | // to avoid flag mismatch errors. | |||
| 1609 | if (!LibrariesHidden.empty() || !LoadHidden.empty()) | |||
| 1610 | S.ObjLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); | |||
| 1611 | ||||
| 1612 | // Sort library loads by position in the argument list. | |||
| 1613 | llvm::sort(LibraryLoadQueue, | |||
| 1614 | [](const LibraryLoad &LHS, const LibraryLoad &RHS) { | |||
| 1615 | return LHS.Position < RHS.Position; | |||
| 1616 | }); | |||
| 1617 | ||||
| 1618 | // 3. Process library loads. | |||
| 1619 | auto AddArchive = [&](const char *Path, const LibraryLoad &LL) | |||
| 1620 | -> Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> { | |||
| 1621 | unique_function<Expected<MaterializationUnit::Interface>( | |||
| 1622 | ExecutionSession & ES, MemoryBufferRef ObjBuffer)> | |||
| 1623 | GetObjFileInterface; | |||
| 1624 | switch (LL.Modifier) { | |||
| 1625 | case LibraryLoad::Standard: | |||
| 1626 | GetObjFileInterface = getObjectFileInterface; | |||
| 1627 | break; | |||
| 1628 | case LibraryLoad::Hidden: | |||
| 1629 | GetObjFileInterface = getObjectFileInterfaceHidden; | |||
| 1630 | break; | |||
| 1631 | } | |||
| 1632 | auto G = StaticLibraryDefinitionGenerator::Load( | |||
| 1633 | S.ObjLayer, Path, S.ES.getExecutorProcessControl().getTargetTriple(), | |||
| 1634 | std::move(GetObjFileInterface)); | |||
| 1635 | if (!G) | |||
| 1636 | return G.takeError(); | |||
| 1637 | ||||
| 1638 | // Push additional dynamic libraries to search. | |||
| 1639 | // Note that this mechanism only happens in COFF. | |||
| 1640 | for (auto FileName : (*G)->getImportedDynamicLibraries()) { | |||
| 1641 | LibraryLoad NewLL; | |||
| 1642 | auto FileNameRef = StringRef(FileName); | |||
| 1643 | if (!FileNameRef.endswith_insensitive(".dll")) | |||
| 1644 | return make_error<StringError>( | |||
| 1645 | "COFF Imported library not ending with dll extension?", | |||
| 1646 | inconvertibleErrorCode()); | |||
| 1647 | NewLL.LibName = FileNameRef.drop_back(strlen(".dll")).str(); | |||
| 1648 | NewLL.Position = LL.Position; | |||
| 1649 | NewLL.CandidateExtensions = DynLibExtensionsOnly; | |||
| 1650 | NewLL.Modifier = LibraryLoad::Standard; | |||
| 1651 | LibraryLoadQueue.push_front(std::move(NewLL)); | |||
| 1652 | } | |||
| 1653 | return G; | |||
| 1654 | }; | |||
| 1655 | ||||
| 1656 | SmallVector<StringRef, 5> SystemSearchPaths; | |||
| 1657 | if (SearchSystemLibrary.getValue()) | |||
| 1658 | SystemSearchPaths = getSearchPathsFromEnvVar(S); | |||
| 1659 | while (!LibraryLoadQueue.empty()) { | |||
| 1660 | bool LibFound = false; | |||
| 1661 | auto LL = LibraryLoadQueue.front(); | |||
| 1662 | LibraryLoadQueue.pop_front(); | |||
| 1663 | auto &JD = *std::prev(IdxToJD.lower_bound(LL.Position))->second; | |||
| 1664 | ||||
| 1665 | // If this is the name of a JITDylib then link against that. | |||
| 1666 | if (auto *LJD = S.ES.getJITDylibByName(LL.LibName)) { | |||
| 1667 | JD.addToLinkOrder(*LJD); | |||
| 1668 | continue; | |||
| 1669 | } | |||
| 1670 | ||||
| 1671 | if (LL.IsPath) { | |||
| 1672 | auto G = AddArchive(LL.LibName.c_str(), LL); | |||
| 1673 | if (!G) | |||
| 1674 | return createFileError(LL.LibName, G.takeError()); | |||
| 1675 | JD.addGenerator(std::move(*G)); | |||
| 1676 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LL.LibName << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1677 | dbgs() << "Adding generator for static library " << LL.LibName << " to "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LL.LibName << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1678 | << JD.getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LL.LibName << " to " << JD.getName() << "\n"; }; } } while (false) | |||
| 1679 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LL.LibName << " to " << JD.getName() << "\n"; }; } } while (false); | |||
| 1680 | continue; | |||
| 1681 | } | |||
| 1682 | ||||
| 1683 | // Otherwise look through the search paths. | |||
| 1684 | auto CurJDSearchPaths = JDSearchPaths[&JD]; | |||
| 1685 | for (StringRef SearchPath : | |||
| 1686 | concat<StringRef>(CurJDSearchPaths, SystemSearchPaths)) { | |||
| 1687 | for (const char *LibExt : {".dylib", ".so", ".dll", ".a", ".lib"}) { | |||
| 1688 | SmallVector<char, 256> LibPath; | |||
| 1689 | LibPath.reserve(SearchPath.size() + strlen("lib") + LL.LibName.size() + | |||
| 1690 | strlen(LibExt) + 2); // +2 for pathsep, null term. | |||
| 1691 | llvm::copy(SearchPath, std::back_inserter(LibPath)); | |||
| 1692 | if (StringRef(LibExt) != ".lib" && StringRef(LibExt) != ".dll") | |||
| 1693 | sys::path::append(LibPath, "lib" + LL.LibName + LibExt); | |||
| 1694 | else | |||
| 1695 | sys::path::append(LibPath, LL.LibName + LibExt); | |||
| 1696 | LibPath.push_back('\0'); | |||
| 1697 | ||||
| 1698 | // Skip missing or non-regular paths. | |||
| 1699 | if (sys::fs::get_file_type(LibPath.data()) != | |||
| 1700 | sys::fs::file_type::regular_file) { | |||
| 1701 | continue; | |||
| 1702 | } | |||
| 1703 | ||||
| 1704 | file_magic Magic; | |||
| 1705 | if (auto EC = identify_magic(LibPath, Magic)) { | |||
| 1706 | // If there was an error loading the file then skip it. | |||
| 1707 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but could not identify file type (" << EC.message() << "). Skipping.\n"; }; } } while (false) | |||
| 1708 | dbgs() << "Library search found \"" << LibPathdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but could not identify file type (" << EC.message() << "). Skipping.\n"; }; } } while (false) | |||
| 1709 | << "\", but could not identify file type (" << EC.message()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but could not identify file type (" << EC.message() << "). Skipping.\n"; }; } } while (false) | |||
| 1710 | << "). Skipping.\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but could not identify file type (" << EC.message() << "). Skipping.\n"; }; } } while (false) | |||
| 1711 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but could not identify file type (" << EC.message() << "). Skipping.\n"; }; } } while (false); | |||
| 1712 | continue; | |||
| 1713 | } | |||
| 1714 | ||||
| 1715 | // We identified the magic. Assume that we can load it -- we'll reset | |||
| 1716 | // in the default case. | |||
| 1717 | LibFound = true; | |||
| 1718 | switch (Magic) { | |||
| 1719 | case file_magic::pecoff_executable: | |||
| 1720 | case file_magic::elf_shared_object: | |||
| 1721 | case file_magic::macho_dynamically_linked_shared_lib: { | |||
| 1722 | if (auto Err = S.loadAndLinkDynamicLibrary(JD, LibPath.data())) | |||
| 1723 | return Err; | |||
| 1724 | break; | |||
| 1725 | } | |||
| 1726 | case file_magic::archive: | |||
| 1727 | case file_magic::macho_universal_binary: { | |||
| 1728 | auto G = AddArchive(LibPath.data(), LL); | |||
| 1729 | if (!G) | |||
| 1730 | return G.takeError(); | |||
| 1731 | JD.addGenerator(std::move(*G)); | |||
| 1732 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LibPath.data() << " to " << JD.getName( ) << "\n"; }; } } while (false) | |||
| 1733 | dbgs() << "Adding generator for static library " << LibPath.data()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LibPath.data() << " to " << JD.getName( ) << "\n"; }; } } while (false) | |||
| 1734 | << " to " << JD.getName() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LibPath.data() << " to " << JD.getName( ) << "\n"; }; } } while (false) | |||
| 1735 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Adding generator for static library " << LibPath.data() << " to " << JD.getName( ) << "\n"; }; } } while (false); | |||
| 1736 | break; | |||
| 1737 | } | |||
| 1738 | default: | |||
| 1739 | // This file isn't a recognized library kind. | |||
| 1740 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but file type is not supported. Skipping.\n" ; }; } } while (false) | |||
| 1741 | dbgs() << "Library search found \"" << LibPathdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but file type is not supported. Skipping.\n" ; }; } } while (false) | |||
| 1742 | << "\", but file type is not supported. Skipping.\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but file type is not supported. Skipping.\n" ; }; } } while (false) | |||
| 1743 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Library search found \"" << LibPath << "\", but file type is not supported. Skipping.\n" ; }; } } while (false); | |||
| 1744 | LibFound = false; | |||
| 1745 | break; | |||
| 1746 | } | |||
| 1747 | if (LibFound) | |||
| 1748 | break; | |||
| 1749 | } | |||
| 1750 | if (LibFound) | |||
| 1751 | break; | |||
| 1752 | } | |||
| 1753 | ||||
| 1754 | if (!LibFound) | |||
| 1755 | return make_error<StringError>("While linking " + JD.getName() + | |||
| 1756 | ", could not find library for -l" + | |||
| 1757 | LL.LibName, | |||
| 1758 | inconvertibleErrorCode()); | |||
| 1759 | } | |||
| 1760 | ||||
| 1761 | return Error::success(); | |||
| 1762 | } | |||
| 1763 | ||||
| 1764 | static Error addSessionInputs(Session &S) { | |||
| 1765 | std::map<unsigned, JITDylib *> IdxToJD; | |||
| 1766 | ||||
| 1767 | if (auto Err = createJITDylibs(S, IdxToJD)) | |||
| 1768 | return Err; | |||
| 1769 | ||||
| 1770 | if (auto Err = addAbsoluteSymbols(S, IdxToJD)) | |||
| 1771 | return Err; | |||
| 1772 | ||||
| 1773 | if (auto Err = addAliases(S, IdxToJD)) | |||
| 1774 | return Err; | |||
| 1775 | ||||
| 1776 | if (!TestHarnesses.empty()) | |||
| 1777 | if (auto Err = addTestHarnesses(S)) | |||
| 1778 | return Err; | |||
| 1779 | ||||
| 1780 | if (auto Err = addObjects(S, IdxToJD)) | |||
| 1781 | return Err; | |||
| 1782 | ||||
| 1783 | if (auto Err = addLibraries(S, IdxToJD)) | |||
| 1784 | return Err; | |||
| 1785 | ||||
| 1786 | return Error::success(); | |||
| 1787 | } | |||
| 1788 | ||||
| 1789 | namespace { | |||
| 1790 | struct TargetInfo { | |||
| 1791 | const Target *TheTarget; | |||
| 1792 | std::unique_ptr<MCSubtargetInfo> STI; | |||
| 1793 | std::unique_ptr<MCRegisterInfo> MRI; | |||
| 1794 | std::unique_ptr<MCAsmInfo> MAI; | |||
| 1795 | std::unique_ptr<MCContext> Ctx; | |||
| 1796 | std::unique_ptr<MCDisassembler> Disassembler; | |||
| 1797 | std::unique_ptr<MCInstrInfo> MII; | |||
| 1798 | std::unique_ptr<MCInstrAnalysis> MIA; | |||
| 1799 | std::unique_ptr<MCInstPrinter> InstPrinter; | |||
| 1800 | }; | |||
| 1801 | } // anonymous namespace | |||
| 1802 | ||||
| 1803 | static TargetInfo getTargetInfo(const Triple &TT) { | |||
| 1804 | auto TripleName = TT.str(); | |||
| 1805 | std::string ErrorStr; | |||
| 1806 | const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr); | |||
| 1807 | if (!TheTarget) | |||
| 1808 | ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName + | |||
| 1809 | "': " + ErrorStr, | |||
| 1810 | inconvertibleErrorCode())); | |||
| 1811 | ||||
| 1812 | std::unique_ptr<MCSubtargetInfo> STI( | |||
| 1813 | TheTarget->createMCSubtargetInfo(TripleName, "", "")); | |||
| 1814 | if (!STI) | |||
| 1815 | ExitOnErr( | |||
| 1816 | make_error<StringError>("Unable to create subtarget for " + TripleName, | |||
| 1817 | inconvertibleErrorCode())); | |||
| 1818 | ||||
| 1819 | std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); | |||
| 1820 | if (!MRI) | |||
| 1821 | ExitOnErr(make_error<StringError>("Unable to create target register info " | |||
| 1822 | "for " + | |||
| 1823 | TripleName, | |||
| 1824 | inconvertibleErrorCode())); | |||
| 1825 | ||||
| 1826 | MCTargetOptions MCOptions; | |||
| 1827 | std::unique_ptr<MCAsmInfo> MAI( | |||
| 1828 | TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); | |||
| 1829 | if (!MAI) | |||
| 1830 | ExitOnErr(make_error<StringError>("Unable to create target asm info " + | |||
| 1831 | TripleName, | |||
| 1832 | inconvertibleErrorCode())); | |||
| 1833 | ||||
| 1834 | auto Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(), | |||
| 1835 | MRI.get(), STI.get()); | |||
| 1836 | ||||
| 1837 | std::unique_ptr<MCDisassembler> Disassembler( | |||
| 1838 | TheTarget->createMCDisassembler(*STI, *Ctx)); | |||
| 1839 | if (!Disassembler) | |||
| 1840 | ExitOnErr(make_error<StringError>("Unable to create disassembler for " + | |||
| 1841 | TripleName, | |||
| 1842 | inconvertibleErrorCode())); | |||
| 1843 | ||||
| 1844 | std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); | |||
| 1845 | if (!MII) | |||
| 1846 | ExitOnErr(make_error<StringError>("Unable to create instruction info for" + | |||
| 1847 | TripleName, | |||
| 1848 | inconvertibleErrorCode())); | |||
| 1849 | ||||
| 1850 | std::unique_ptr<MCInstrAnalysis> MIA( | |||
| 1851 | TheTarget->createMCInstrAnalysis(MII.get())); | |||
| 1852 | if (!MIA) | |||
| 1853 | ExitOnErr(make_error<StringError>( | |||
| 1854 | "Unable to create instruction analysis for" + TripleName, | |||
| 1855 | inconvertibleErrorCode())); | |||
| 1856 | ||||
| 1857 | std::unique_ptr<MCInstPrinter> InstPrinter( | |||
| 1858 | TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI)); | |||
| 1859 | if (!InstPrinter) | |||
| 1860 | ExitOnErr(make_error<StringError>( | |||
| 1861 | "Unable to create instruction printer for" + TripleName, | |||
| 1862 | inconvertibleErrorCode())); | |||
| 1863 | return {TheTarget, std::move(STI), std::move(MRI), | |||
| 1864 | std::move(MAI), std::move(Ctx), std::move(Disassembler), | |||
| 1865 | std::move(MII), std::move(MIA), std::move(InstPrinter)}; | |||
| 1866 | } | |||
| 1867 | ||||
| 1868 | static Error runChecks(Session &S) { | |||
| 1869 | const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); | |||
| 1870 | ||||
| 1871 | if (CheckFiles.empty()) | |||
| 1872 | return Error::success(); | |||
| 1873 | ||||
| 1874 | LLVM_DEBUG(dbgs() << "Running checks...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Running checks...\n"; } } while (false); | |||
| 1875 | ||||
| 1876 | auto TI = getTargetInfo(TT); | |||
| 1877 | ||||
| 1878 | auto IsSymbolValid = [&S](StringRef Symbol) { | |||
| 1879 | return S.isSymbolRegistered(Symbol); | |||
| 1880 | }; | |||
| 1881 | ||||
| 1882 | auto GetSymbolInfo = [&S](StringRef Symbol) { | |||
| 1883 | return S.findSymbolInfo(Symbol, "Can not get symbol info"); | |||
| 1884 | }; | |||
| 1885 | ||||
| 1886 | auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) { | |||
| 1887 | return S.findSectionInfo(FileName, SectionName); | |||
| 1888 | }; | |||
| 1889 | ||||
| 1890 | auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) { | |||
| 1891 | return S.findStubInfo(FileName, SectionName); | |||
| 1892 | }; | |||
| 1893 | ||||
| 1894 | auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) { | |||
| 1895 | return S.findGOTEntryInfo(FileName, SectionName); | |||
| 1896 | }; | |||
| 1897 | ||||
| 1898 | RuntimeDyldChecker Checker( | |||
| 1899 | IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, | |||
| 1900 | TT.isLittleEndian() ? support::little : support::big, | |||
| 1901 | TI.Disassembler.get(), TI.InstPrinter.get(), dbgs()); | |||
| 1902 | ||||
| 1903 | std::string CheckLineStart = "# " + CheckName + ":"; | |||
| 1904 | for (auto &CheckFile : CheckFiles) { | |||
| 1905 | auto CheckerFileBuf = ExitOnErr(getFile(CheckFile)); | |||
| 1906 | if (!Checker.checkAllRulesInBuffer(CheckLineStart, &*CheckerFileBuf)) | |||
| 1907 | ExitOnErr(make_error<StringError>( | |||
| 1908 | "Some checks in " + CheckFile + " failed", inconvertibleErrorCode())); | |||
| 1909 | } | |||
| 1910 | ||||
| 1911 | return Error::success(); | |||
| 1912 | } | |||
| 1913 | ||||
| 1914 | static Error addSelfRelocations(LinkGraph &G) { | |||
| 1915 | auto TI = getTargetInfo(G.getTargetTriple()); | |||
| 1916 | for (auto *Sym : G.defined_symbols()) | |||
| 1917 | if (Sym->isCallable()) | |||
| 1918 | if (auto Err = addFunctionPointerRelocationsToCurrentSymbol( | |||
| 1919 | *Sym, G, *TI.Disassembler, *TI.MIA)) | |||
| 1920 | return Err; | |||
| 1921 | return Error::success(); | |||
| 1922 | } | |||
| 1923 | ||||
| 1924 | static void dumpSessionStats(Session &S) { | |||
| 1925 | if (!ShowSizes) | |||
| 1926 | return; | |||
| 1927 | if (!OrcRuntime.empty()) | |||
| 1928 | outs() << "Note: Session stats include runtime and entry point lookup, but " | |||
| 1929 | "not JITDylib initialization/deinitialization.\n"; | |||
| 1930 | if (ShowSizes) | |||
| 1931 | outs() << " Total size of all blocks before pruning: " | |||
| 1932 | << S.SizeBeforePruning | |||
| 1933 | << "\n Total size of all blocks after fixups: " << S.SizeAfterFixups | |||
| 1934 | << "\n"; | |||
| 1935 | } | |||
| 1936 | ||||
| 1937 | static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) { | |||
| 1938 | return S.ES.lookup(S.JDSearchOrder, S.ES.intern(EntryPointName)); | |||
| 1939 | } | |||
| 1940 | ||||
| 1941 | static Expected<JITEvaluatedSymbol> getOrcRuntimeEntryPoint(Session &S) { | |||
| 1942 | std::string RuntimeEntryPoint = "__orc_rt_run_program_wrapper"; | |||
| 1943 | const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); | |||
| 1944 | if (TT.getObjectFormat() == Triple::MachO) | |||
| 1945 | RuntimeEntryPoint = '_' + RuntimeEntryPoint; | |||
| 1946 | return S.ES.lookup(S.JDSearchOrder, S.ES.intern(RuntimeEntryPoint)); | |||
| 1947 | } | |||
| 1948 | ||||
| 1949 | static Expected<JITEvaluatedSymbol> getEntryPoint(Session &S) { | |||
| 1950 | JITEvaluatedSymbol EntryPoint; | |||
| 1951 | ||||
| 1952 | // Find the entry-point function unconditionally, since we want to force | |||
| 1953 | // it to be materialized to collect stats. | |||
| 1954 | if (auto EP = getMainEntryPoint(S)) | |||
| 1955 | EntryPoint = *EP; | |||
| 1956 | else | |||
| 1957 | return EP.takeError(); | |||
| 1958 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Using entry point \"" << EntryPointName << "\": " << formatv("{0:x16}", EntryPoint .getAddress()) << "\n"; }; } } while (false) | |||
| 1959 | dbgs() << "Using entry point \"" << EntryPointNamedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Using entry point \"" << EntryPointName << "\": " << formatv("{0:x16}", EntryPoint .getAddress()) << "\n"; }; } } while (false) | |||
| 1960 | << "\": " << formatv("{0:x16}", EntryPoint.getAddress()) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Using entry point \"" << EntryPointName << "\": " << formatv("{0:x16}", EntryPoint .getAddress()) << "\n"; }; } } while (false) | |||
| 1961 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "Using entry point \"" << EntryPointName << "\": " << formatv("{0:x16}", EntryPoint .getAddress()) << "\n"; }; } } while (false); | |||
| 1962 | ||||
| 1963 | // If we're running with the ORC runtime then replace the entry-point | |||
| 1964 | // with the __orc_rt_run_program symbol. | |||
| 1965 | if (!OrcRuntime.empty()) { | |||
| 1966 | if (auto EP = getOrcRuntimeEntryPoint(S)) | |||
| 1967 | EntryPoint = *EP; | |||
| 1968 | else | |||
| 1969 | return EP.takeError(); | |||
| 1970 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "(called via __orc_rt_run_program_wrapper at " << formatv("{0:x16}", EntryPoint.getAddress()) << ")\n"; }; } } while (false) | |||
| 1971 | dbgs() << "(called via __orc_rt_run_program_wrapper at "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "(called via __orc_rt_run_program_wrapper at " << formatv("{0:x16}", EntryPoint.getAddress()) << ")\n"; }; } } while (false) | |||
| 1972 | << formatv("{0:x16}", EntryPoint.getAddress()) << ")\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "(called via __orc_rt_run_program_wrapper at " << formatv("{0:x16}", EntryPoint.getAddress()) << ")\n"; }; } } while (false) | |||
| 1973 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { { dbgs() << "(called via __orc_rt_run_program_wrapper at " << formatv("{0:x16}", EntryPoint.getAddress()) << ")\n"; }; } } while (false); | |||
| 1974 | } | |||
| 1975 | ||||
| 1976 | return EntryPoint; | |||
| 1977 | } | |||
| 1978 | ||||
| 1979 | static Expected<int> runWithRuntime(Session &S, ExecutorAddr EntryPointAddr) { | |||
| 1980 | StringRef DemangledEntryPoint = EntryPointName; | |||
| 1981 | const auto &TT = S.ES.getExecutorProcessControl().getTargetTriple(); | |||
| 1982 | if (TT.getObjectFormat() == Triple::MachO && | |||
| 1983 | DemangledEntryPoint.front() == '_') | |||
| 1984 | DemangledEntryPoint = DemangledEntryPoint.drop_front(); | |||
| 1985 | using llvm::orc::shared::SPSString; | |||
| 1986 | using SPSRunProgramSig = | |||
| 1987 | int64_t(SPSString, SPSString, shared::SPSSequence<SPSString>); | |||
| 1988 | int64_t Result; | |||
| 1989 | if (auto Err = S.ES.callSPSWrapper<SPSRunProgramSig>( | |||
| 1990 | EntryPointAddr, Result, S.MainJD->getName(), DemangledEntryPoint, | |||
| 1991 | static_cast<std::vector<std::string> &>(InputArgv))) | |||
| 1992 | return std::move(Err); | |||
| 1993 | return Result; | |||
| 1994 | } | |||
| 1995 | ||||
| 1996 | static Expected<int> runWithoutRuntime(Session &S, | |||
| 1997 | ExecutorAddr EntryPointAddr) { | |||
| 1998 | return S.ES.getExecutorProcessControl().runAsMain(EntryPointAddr, InputArgv); | |||
| 1999 | } | |||
| 2000 | ||||
| 2001 | namespace { | |||
| 2002 | struct JITLinkTimers { | |||
| 2003 | TimerGroup JITLinkTG{"llvm-jitlink timers", "timers for llvm-jitlink phases"}; | |||
| 2004 | Timer LoadObjectsTimer{"load", "time to load/add object files", JITLinkTG}; | |||
| 2005 | Timer LinkTimer{"link", "time to link object files", JITLinkTG}; | |||
| 2006 | Timer RunTimer{"run", "time to execute jitlink'd code", JITLinkTG}; | |||
| 2007 | }; | |||
| 2008 | } // namespace | |||
| 2009 | ||||
| 2010 | int main(int argc, char *argv[]) { | |||
| 2011 | InitLLVM X(argc, argv); | |||
| 2012 | ||||
| 2013 | InitializeAllTargetInfos(); | |||
| 2014 | InitializeAllTargetMCs(); | |||
| 2015 | InitializeAllDisassemblers(); | |||
| 2016 | ||||
| 2017 | cl::HideUnrelatedOptions({&JITLinkCategory, &getColorCategory()}); | |||
| 2018 | cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool"); | |||
| 2019 | ExitOnErr.setBanner(std::string(argv[0]) + ": "); | |||
| 2020 | ||||
| 2021 | /// If timers are enabled, create a JITLinkTimers instance. | |||
| 2022 | std::unique_ptr<JITLinkTimers> Timers = | |||
| 2023 | ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr; | |||
| ||||
| 2024 | ||||
| 2025 | ExitOnErr(sanitizeArguments(getFirstFileTriple(), argv[0])); | |||
| 2026 | ||||
| 2027 | auto S = ExitOnErr(Session::Create(getFirstFileTriple())); | |||
| 2028 | ||||
| 2029 | { | |||
| 2030 | TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr); | |||
| 2031 | ExitOnErr(addSessionInputs(*S)); | |||
| 2032 | } | |||
| 2033 | ||||
| 2034 | if (PhonyExternals) | |||
| 2035 | addPhonyExternalsGenerator(*S); | |||
| 2036 | ||||
| 2037 | if (ShowInitialExecutionSessionState) | |||
| 2038 | S->ES.dump(outs()); | |||
| 2039 | ||||
| 2040 | Expected<JITEvaluatedSymbol> EntryPoint(nullptr); | |||
| 2041 | { | |||
| 2042 | ExpectedAsOutParameter<JITEvaluatedSymbol> _(&EntryPoint); | |||
| 2043 | TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr); | |||
| 2044 | EntryPoint = getEntryPoint(*S); | |||
| 2045 | } | |||
| 2046 | ||||
| 2047 | // Print any reports regardless of whether we succeeded or failed. | |||
| 2048 | if (ShowEntryExecutionSessionState) | |||
| 2049 | S->ES.dump(outs()); | |||
| 2050 | ||||
| 2051 | if (ShowAddrs) | |||
| 2052 | S->dumpSessionInfo(outs()); | |||
| 2053 | ||||
| 2054 | dumpSessionStats(*S); | |||
| 2055 | ||||
| 2056 | if (!EntryPoint) { | |||
| 2057 | if (Timers) | |||
| 2058 | Timers->JITLinkTG.printAll(errs()); | |||
| 2059 | reportLLVMJITLinkError(EntryPoint.takeError()); | |||
| 2060 | exit(1); | |||
| 2061 | } | |||
| 2062 | ||||
| 2063 | ExitOnErr(runChecks(*S)); | |||
| 2064 | ||||
| 2065 | if (NoExec) | |||
| 2066 | return 0; | |||
| 2067 | ||||
| 2068 | int Result = 0; | |||
| 2069 | { | |||
| 2070 | LLVM_DEBUG(dbgs() << "Running \"" << EntryPointName << "\"...\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("llvm_jitlink")) { dbgs() << "Running \"" << EntryPointName << "\"...\n"; } } while (false); | |||
| 2071 | TimeRegion TR(Timers ? &Timers->RunTimer : nullptr); | |||
| 2072 | if (!OrcRuntime.empty()) | |||
| 2073 | Result = | |||
| 2074 | ExitOnErr(runWithRuntime(*S, ExecutorAddr(EntryPoint->getAddress()))); | |||
| 2075 | else | |||
| 2076 | Result = ExitOnErr( | |||
| 2077 | runWithoutRuntime(*S, ExecutorAddr(EntryPoint->getAddress()))); | |||
| 2078 | } | |||
| 2079 | ||||
| 2080 | // Destroy the session. | |||
| 2081 | ExitOnErr(S->ES.endSession()); | |||
| 2082 | S.reset(); | |||
| 2083 | ||||
| 2084 | if (Timers) | |||
| 2085 | Timers->JITLinkTG.printAll(errs()); | |||
| 2086 | ||||
| 2087 | // If the executing code set a test result override then use that. | |||
| 2088 | if (UseTestResultOverride) | |||
| 2089 | Result = TestResultOverride; | |||
| 2090 | ||||
| 2091 | return Result; | |||
| 2092 | } |
| 1 | //===- llvm/Support/Error.h - Recoverable error handling --------*- C++ -*-===// | |||
| 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 | // This file defines an API used to report recoverable errors. | |||
| 10 | // | |||
| 11 | //===----------------------------------------------------------------------===// | |||
| 12 | ||||
| 13 | #ifndef LLVM_SUPPORT_ERROR_H | |||
| 14 | #define LLVM_SUPPORT_ERROR_H | |||
| 15 | ||||
| 16 | #include "llvm-c/Error.h" | |||
| 17 | #include "llvm/ADT/SmallVector.h" | |||
| 18 | #include "llvm/ADT/StringExtras.h" | |||
| 19 | #include "llvm/ADT/Twine.h" | |||
| 20 | #include "llvm/Config/abi-breaking.h" | |||
| 21 | #include "llvm/Support/AlignOf.h" | |||
| 22 | #include "llvm/Support/Compiler.h" | |||
| 23 | #include "llvm/Support/Debug.h" | |||
| 24 | #include "llvm/Support/ErrorHandling.h" | |||
| 25 | #include "llvm/Support/ErrorOr.h" | |||
| 26 | #include "llvm/Support/Format.h" | |||
| 27 | #include "llvm/Support/raw_ostream.h" | |||
| 28 | #include <cassert> | |||
| 29 | #include <cstdint> | |||
| 30 | #include <cstdlib> | |||
| 31 | #include <functional> | |||
| 32 | #include <memory> | |||
| 33 | #include <new> | |||
| 34 | #include <string> | |||
| 35 | #include <system_error> | |||
| 36 | #include <type_traits> | |||
| 37 | #include <utility> | |||
| 38 | #include <vector> | |||
| 39 | ||||
| 40 | namespace llvm { | |||
| 41 | ||||
| 42 | class ErrorSuccess; | |||
| 43 | ||||
| 44 | /// Base class for error info classes. Do not extend this directly: Extend | |||
| 45 | /// the ErrorInfo template subclass instead. | |||
| 46 | class ErrorInfoBase { | |||
| 47 | public: | |||
| 48 | virtual ~ErrorInfoBase() = default; | |||
| 49 | ||||
| 50 | /// Print an error message to an output stream. | |||
| 51 | virtual void log(raw_ostream &OS) const = 0; | |||
| 52 | ||||
| 53 | /// Return the error message as a string. | |||
| 54 | virtual std::string message() const { | |||
| 55 | std::string Msg; | |||
| 56 | raw_string_ostream OS(Msg); | |||
| 57 | log(OS); | |||
| 58 | return OS.str(); | |||
| 59 | } | |||
| 60 | ||||
| 61 | /// Convert this error to a std::error_code. | |||
| 62 | /// | |||
| 63 | /// This is a temporary crutch to enable interaction with code still | |||
| 64 | /// using std::error_code. It will be removed in the future. | |||
| 65 | virtual std::error_code convertToErrorCode() const = 0; | |||
| 66 | ||||
| 67 | // Returns the class ID for this type. | |||
| 68 | static const void *classID() { return &ID; } | |||
| 69 | ||||
| 70 | // Returns the class ID for the dynamic type of this ErrorInfoBase instance. | |||
| 71 | virtual const void *dynamicClassID() const = 0; | |||
| 72 | ||||
| 73 | // Check whether this instance is a subclass of the class identified by | |||
| 74 | // ClassID. | |||
| 75 | virtual bool isA(const void *const ClassID) const { | |||
| 76 | return ClassID == classID(); | |||
| 77 | } | |||
| 78 | ||||
| 79 | // Check whether this instance is a subclass of ErrorInfoT. | |||
| 80 | template <typename ErrorInfoT> bool isA() const { | |||
| 81 | return isA(ErrorInfoT::classID()); | |||
| 82 | } | |||
| 83 | ||||
| 84 | private: | |||
| 85 | virtual void anchor(); | |||
| 86 | ||||
| 87 | static char ID; | |||
| 88 | }; | |||
| 89 | ||||
| 90 | /// Lightweight error class with error context and mandatory checking. | |||
| 91 | /// | |||
| 92 | /// Instances of this class wrap a ErrorInfoBase pointer. Failure states | |||
| 93 | /// are represented by setting the pointer to a ErrorInfoBase subclass | |||
| 94 | /// instance containing information describing the failure. Success is | |||
| 95 | /// represented by a null pointer value. | |||
| 96 | /// | |||
| 97 | /// Instances of Error also contains a 'Checked' flag, which must be set | |||
| 98 | /// before the destructor is called, otherwise the destructor will trigger a | |||
| 99 | /// runtime error. This enforces at runtime the requirement that all Error | |||
| 100 | /// instances be checked or returned to the caller. | |||
| 101 | /// | |||
| 102 | /// There are two ways to set the checked flag, depending on what state the | |||
| 103 | /// Error instance is in. For Error instances indicating success, it | |||
| 104 | /// is sufficient to invoke the boolean conversion operator. E.g.: | |||
| 105 | /// | |||
| 106 | /// @code{.cpp} | |||
| 107 | /// Error foo(<...>); | |||
| 108 | /// | |||
| 109 | /// if (auto E = foo(<...>)) | |||
| 110 | /// return E; // <- Return E if it is in the error state. | |||
| 111 | /// // We have verified that E was in the success state. It can now be safely | |||
| 112 | /// // destroyed. | |||
| 113 | /// @endcode | |||
| 114 | /// | |||
| 115 | /// A success value *can not* be dropped. For example, just calling 'foo(<...>)' | |||
| 116 | /// without testing the return value will raise a runtime error, even if foo | |||
| 117 | /// returns success. | |||
| 118 | /// | |||
| 119 | /// For Error instances representing failure, you must use either the | |||
| 120 | /// handleErrors or handleAllErrors function with a typed handler. E.g.: | |||
| 121 | /// | |||
| 122 | /// @code{.cpp} | |||
| 123 | /// class MyErrorInfo : public ErrorInfo<MyErrorInfo> { | |||
| 124 | /// // Custom error info. | |||
| 125 | /// }; | |||
| 126 | /// | |||
| 127 | /// Error foo(<...>) { return make_error<MyErrorInfo>(...); } | |||
| 128 | /// | |||
| 129 | /// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo. | |||
| 130 | /// auto NewE = | |||
| 131 | /// handleErrors(E, | |||
| 132 | /// [](const MyErrorInfo &M) { | |||
| 133 | /// // Deal with the error. | |||
| 134 | /// }, | |||
| 135 | /// [](std::unique_ptr<OtherError> M) -> Error { | |||
| 136 | /// if (canHandle(*M)) { | |||
| 137 | /// // handle error. | |||
| 138 | /// return Error::success(); | |||
| 139 | /// } | |||
| 140 | /// // Couldn't handle this error instance. Pass it up the stack. | |||
| 141 | /// return Error(std::move(M)); | |||
| 142 | /// ); | |||
| 143 | /// // Note - we must check or return NewE in case any of the handlers | |||
| 144 | /// // returned a new error. | |||
| 145 | /// @endcode | |||
| 146 | /// | |||
| 147 | /// The handleAllErrors function is identical to handleErrors, except | |||
| 148 | /// that it has a void return type, and requires all errors to be handled and | |||
| 149 | /// no new errors be returned. It prevents errors (assuming they can all be | |||
| 150 | /// handled) from having to be bubbled all the way to the top-level. | |||
| 151 | /// | |||
| 152 | /// *All* Error instances must be checked before destruction, even if | |||
| 153 | /// they're moved-assigned or constructed from Success values that have already | |||
| 154 | /// been checked. This enforces checking through all levels of the call stack. | |||
| 155 | class [[nodiscard]] Error { | |||
| 156 | // ErrorList needs to be able to yank ErrorInfoBase pointers out of Errors | |||
| 157 | // to add to the error list. It can't rely on handleErrors for this, since | |||
| 158 | // handleErrors does not support ErrorList handlers. | |||
| 159 | friend class ErrorList; | |||
| 160 | ||||
| 161 | // handleErrors needs to be able to set the Checked flag. | |||
| 162 | template <typename... HandlerTs> | |||
| 163 | friend Error handleErrors(Error E, HandlerTs &&... Handlers); | |||
| 164 | ||||
| 165 | // Expected<T> needs to be able to steal the payload when constructed from an | |||
| 166 | // error. | |||
| 167 | template <typename T> friend class Expected; | |||
| 168 | ||||
| 169 | // wrap needs to be able to steal the payload. | |||
| 170 | friend LLVMErrorRef wrap(Error); | |||
| 171 | ||||
| 172 | protected: | |||
| 173 | /// Create a success value. Prefer using 'Error::success()' for readability | |||
| 174 | Error() { | |||
| 175 | setPtr(nullptr); | |||
| 176 | setChecked(false); | |||
| 177 | } | |||
| 178 | ||||
| 179 | public: | |||
| 180 | /// Create a success value. | |||
| 181 | static ErrorSuccess success(); | |||
| 182 | ||||
| 183 | // Errors are not copy-constructable. | |||
| 184 | Error(const Error &Other) = delete; | |||
| 185 | ||||
| 186 | /// Move-construct an error value. The newly constructed error is considered | |||
| 187 | /// unchecked, even if the source error had been checked. The original error | |||
| 188 | /// becomes a checked Success value, regardless of its original state. | |||
| 189 | Error(Error &&Other) { | |||
| 190 | setChecked(true); | |||
| 191 | *this = std::move(Other); | |||
| 192 | } | |||
| 193 | ||||
| 194 | /// Create an error value. Prefer using the 'make_error' function, but | |||
| 195 | /// this constructor can be useful when "re-throwing" errors from handlers. | |||
| 196 | Error(std::unique_ptr<ErrorInfoBase> Payload) { | |||
| 197 | setPtr(Payload.release()); | |||
| 198 | setChecked(false); | |||
| 199 | } | |||
| 200 | ||||
| 201 | // Errors are not copy-assignable. | |||
| 202 | Error &operator=(const Error &Other) = delete; | |||
| 203 | ||||
| 204 | /// Move-assign an error value. The current error must represent success, you | |||
| 205 | /// you cannot overwrite an unhandled error. The current error is then | |||
| 206 | /// considered unchecked. The source error becomes a checked success value, | |||
| 207 | /// regardless of its original state. | |||
| 208 | Error &operator=(Error &&Other) { | |||
| 209 | // Don't allow overwriting of unchecked values. | |||
| 210 | assertIsChecked(); | |||
| 211 | setPtr(Other.getPtr()); | |||
| 212 | ||||
| 213 | // This Error is unchecked, even if the source error was checked. | |||
| 214 | setChecked(false); | |||
| 215 | ||||
| 216 | // Null out Other's payload and set its checked bit. | |||
| 217 | Other.setPtr(nullptr); | |||
| 218 | Other.setChecked(true); | |||
| 219 | ||||
| 220 | return *this; | |||
| 221 | } | |||
| 222 | ||||
| 223 | /// Destroy a Error. Fails with a call to abort() if the error is | |||
| 224 | /// unchecked. | |||
| 225 | ~Error() { | |||
| 226 | assertIsChecked(); | |||
| 227 | delete getPtr(); | |||
| 228 | } | |||
| 229 | ||||
| 230 | /// Bool conversion. Returns true if this Error is in a failure state, | |||
| 231 | /// and false if it is in an accept state. If the error is in a Success state | |||
| 232 | /// it will be considered checked. | |||
| 233 | explicit operator bool() { | |||
| 234 | setChecked(getPtr() == nullptr); | |||
| 235 | return getPtr() != nullptr; | |||
| 236 | } | |||
| 237 | ||||
| 238 | /// Check whether one error is a subclass of another. | |||
| 239 | template <typename ErrT> bool isA() const { | |||
| 240 | return getPtr() && getPtr()->isA(ErrT::classID()); | |||
| 241 | } | |||
| 242 | ||||
| 243 | /// Returns the dynamic class id of this error, or null if this is a success | |||
| 244 | /// value. | |||
| 245 | const void* dynamicClassID() const { | |||
| 246 | if (!getPtr()) | |||
| 247 | return nullptr; | |||
| 248 | return getPtr()->dynamicClassID(); | |||
| 249 | } | |||
| 250 | ||||
| 251 | private: | |||
| 252 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 253 | // assertIsChecked() happens very frequently, but under normal circumstances | |||
| 254 | // is supposed to be a no-op. So we want it to be inlined, but having a bunch | |||
| 255 | // of debug prints can cause the function to be too large for inlining. So | |||
| 256 | // it's important that we define this function out of line so that it can't be | |||
| 257 | // inlined. | |||
| 258 | [[noreturn]] void fatalUncheckedError() const; | |||
| 259 | #endif | |||
| 260 | ||||
| 261 | void assertIsChecked() { | |||
| 262 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 263 | if (LLVM_UNLIKELY(!getChecked() || getPtr())__builtin_expect((bool)(!getChecked() || getPtr()), false)) | |||
| 264 | fatalUncheckedError(); | |||
| 265 | #endif | |||
| 266 | } | |||
| 267 | ||||
| 268 | ErrorInfoBase *getPtr() const { | |||
| 269 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 270 | return reinterpret_cast<ErrorInfoBase*>( | |||
| 271 | reinterpret_cast<uintptr_t>(Payload) & | |||
| 272 | ~static_cast<uintptr_t>(0x1)); | |||
| 273 | #else | |||
| 274 | return Payload; | |||
| 275 | #endif | |||
| 276 | } | |||
| 277 | ||||
| 278 | void setPtr(ErrorInfoBase *EI) { | |||
| 279 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 280 | Payload = reinterpret_cast<ErrorInfoBase*>( | |||
| 281 | (reinterpret_cast<uintptr_t>(EI) & | |||
| 282 | ~static_cast<uintptr_t>(0x1)) | | |||
| 283 | (reinterpret_cast<uintptr_t>(Payload) & 0x1)); | |||
| 284 | #else | |||
| 285 | Payload = EI; | |||
| 286 | #endif | |||
| 287 | } | |||
| 288 | ||||
| 289 | bool getChecked() const { | |||
| 290 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 291 | return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0; | |||
| 292 | #else | |||
| 293 | return true; | |||
| 294 | #endif | |||
| 295 | } | |||
| 296 | ||||
| 297 | void setChecked(bool V) { | |||
| 298 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 299 | Payload = reinterpret_cast<ErrorInfoBase*>( | |||
| 300 | (reinterpret_cast<uintptr_t>(Payload) & | |||
| 301 | ~static_cast<uintptr_t>(0x1)) | | |||
| 302 | (V ? 0 : 1)); | |||
| 303 | #endif | |||
| 304 | } | |||
| 305 | ||||
| 306 | std::unique_ptr<ErrorInfoBase> takePayload() { | |||
| 307 | std::unique_ptr<ErrorInfoBase> Tmp(getPtr()); | |||
| 308 | setPtr(nullptr); | |||
| 309 | setChecked(true); | |||
| 310 | return Tmp; | |||
| 311 | } | |||
| 312 | ||||
| 313 | friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) { | |||
| 314 | if (auto *P = E.getPtr()) | |||
| 315 | P->log(OS); | |||
| 316 | else | |||
| 317 | OS << "success"; | |||
| 318 | return OS; | |||
| 319 | } | |||
| 320 | ||||
| 321 | ErrorInfoBase *Payload = nullptr; | |||
| 322 | }; | |||
| 323 | ||||
| 324 | /// Subclass of Error for the sole purpose of identifying the success path in | |||
| 325 | /// the type system. This allows to catch invalid conversion to Expected<T> at | |||
| 326 | /// compile time. | |||
| 327 | class ErrorSuccess final : public Error {}; | |||
| 328 | ||||
| 329 | inline ErrorSuccess Error::success() { return ErrorSuccess(); } | |||
| 330 | ||||
| 331 | /// Make a Error instance representing failure using the given error info | |||
| 332 | /// type. | |||
| 333 | template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) { | |||
| 334 | return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...)); | |||
| 335 | } | |||
| 336 | ||||
| 337 | /// Base class for user error types. Users should declare their error types | |||
| 338 | /// like: | |||
| 339 | /// | |||
| 340 | /// class MyError : public ErrorInfo<MyError> { | |||
| 341 | /// .... | |||
| 342 | /// }; | |||
| 343 | /// | |||
| 344 | /// This class provides an implementation of the ErrorInfoBase::kind | |||
| 345 | /// method, which is used by the Error RTTI system. | |||
| 346 | template <typename ThisErrT, typename ParentErrT = ErrorInfoBase> | |||
| 347 | class ErrorInfo : public ParentErrT { | |||
| 348 | public: | |||
| 349 | using ParentErrT::ParentErrT; // inherit constructors | |||
| 350 | ||||
| 351 | static const void *classID() { return &ThisErrT::ID; } | |||
| 352 | ||||
| 353 | const void *dynamicClassID() const override { return &ThisErrT::ID; } | |||
| 354 | ||||
| 355 | bool isA(const void *const ClassID) const override { | |||
| 356 | return ClassID == classID() || ParentErrT::isA(ClassID); | |||
| 357 | } | |||
| 358 | }; | |||
| 359 | ||||
| 360 | /// Special ErrorInfo subclass representing a list of ErrorInfos. | |||
| 361 | /// Instances of this class are constructed by joinError. | |||
| 362 | class ErrorList final : public ErrorInfo<ErrorList> { | |||
| 363 | // handleErrors needs to be able to iterate the payload list of an | |||
| 364 | // ErrorList. | |||
| 365 | template <typename... HandlerTs> | |||
| 366 | friend Error handleErrors(Error E, HandlerTs &&... Handlers); | |||
| 367 | ||||
| 368 | // joinErrors is implemented in terms of join. | |||
| 369 | friend Error joinErrors(Error, Error); | |||
| 370 | ||||
| 371 | public: | |||
| 372 | void log(raw_ostream &OS) const override { | |||
| 373 | OS << "Multiple errors:\n"; | |||
| 374 | for (const auto &ErrPayload : Payloads) { | |||
| 375 | ErrPayload->log(OS); | |||
| 376 | OS << "\n"; | |||
| 377 | } | |||
| 378 | } | |||
| 379 | ||||
| 380 | std::error_code convertToErrorCode() const override; | |||
| 381 | ||||
| 382 | // Used by ErrorInfo::classID. | |||
| 383 | static char ID; | |||
| 384 | ||||
| 385 | private: | |||
| 386 | ErrorList(std::unique_ptr<ErrorInfoBase> Payload1, | |||
| 387 | std::unique_ptr<ErrorInfoBase> Payload2) { | |||
| 388 | assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&(static_cast <bool> (!Payload1->isA<ErrorList> () && !Payload2->isA<ErrorList>() && "ErrorList constructor payloads should be singleton errors") ? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\"" , "llvm/include/llvm/Support/Error.h", 389, __extension__ __PRETTY_FUNCTION__ )) | |||
| 389 | "ErrorList constructor payloads should be singleton errors")(static_cast <bool> (!Payload1->isA<ErrorList> () && !Payload2->isA<ErrorList>() && "ErrorList constructor payloads should be singleton errors") ? void (0) : __assert_fail ("!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() && \"ErrorList constructor payloads should be singleton errors\"" , "llvm/include/llvm/Support/Error.h", 389, __extension__ __PRETTY_FUNCTION__ )); | |||
| 390 | Payloads.push_back(std::move(Payload1)); | |||
| 391 | Payloads.push_back(std::move(Payload2)); | |||
| 392 | } | |||
| 393 | ||||
| 394 | static Error join(Error E1, Error E2) { | |||
| 395 | if (!E1) | |||
| 396 | return E2; | |||
| 397 | if (!E2) | |||
| 398 | return E1; | |||
| 399 | if (E1.isA<ErrorList>()) { | |||
| 400 | auto &E1List = static_cast<ErrorList &>(*E1.getPtr()); | |||
| 401 | if (E2.isA<ErrorList>()) { | |||
| 402 | auto E2Payload = E2.takePayload(); | |||
| 403 | auto &E2List = static_cast<ErrorList &>(*E2Payload); | |||
| 404 | for (auto &Payload : E2List.Payloads) | |||
| 405 | E1List.Payloads.push_back(std::move(Payload)); | |||
| 406 | } else | |||
| 407 | E1List.Payloads.push_back(E2.takePayload()); | |||
| 408 | ||||
| 409 | return E1; | |||
| 410 | } | |||
| 411 | if (E2.isA<ErrorList>()) { | |||
| 412 | auto &E2List = static_cast<ErrorList &>(*E2.getPtr()); | |||
| 413 | E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload()); | |||
| 414 | return E2; | |||
| 415 | } | |||
| 416 | return Error(std::unique_ptr<ErrorList>( | |||
| 417 | new ErrorList(E1.takePayload(), E2.takePayload()))); | |||
| 418 | } | |||
| 419 | ||||
| 420 | std::vector<std::unique_ptr<ErrorInfoBase>> Payloads; | |||
| 421 | }; | |||
| 422 | ||||
| 423 | /// Concatenate errors. The resulting Error is unchecked, and contains the | |||
| 424 | /// ErrorInfo(s), if any, contained in E1, followed by the | |||
| 425 | /// ErrorInfo(s), if any, contained in E2. | |||
| 426 | inline Error joinErrors(Error E1, Error E2) { | |||
| 427 | return ErrorList::join(std::move(E1), std::move(E2)); | |||
| 428 | } | |||
| 429 | ||||
| 430 | /// Tagged union holding either a T or a Error. | |||
| 431 | /// | |||
| 432 | /// This class parallels ErrorOr, but replaces error_code with Error. Since | |||
| 433 | /// Error cannot be copied, this class replaces getError() with | |||
| 434 | /// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the | |||
| 435 | /// error class type. | |||
| 436 | /// | |||
| 437 | /// Example usage of 'Expected<T>' as a function return type: | |||
| 438 | /// | |||
| 439 | /// @code{.cpp} | |||
| 440 | /// Expected<int> myDivide(int A, int B) { | |||
| 441 | /// if (B == 0) { | |||
| 442 | /// // return an Error | |||
| 443 | /// return createStringError(inconvertibleErrorCode(), | |||
| 444 | /// "B must not be zero!"); | |||
| 445 | /// } | |||
| 446 | /// // return an integer | |||
| 447 | /// return A / B; | |||
| 448 | /// } | |||
| 449 | /// @endcode | |||
| 450 | /// | |||
| 451 | /// Checking the results of to a function returning 'Expected<T>': | |||
| 452 | /// @code{.cpp} | |||
| 453 | /// if (auto E = Result.takeError()) { | |||
| 454 | /// // We must consume the error. Typically one of: | |||
| 455 | /// // - return the error to our caller | |||
| 456 | /// // - toString(), when logging | |||
| 457 | /// // - consumeError(), to silently swallow the error | |||
| 458 | /// // - handleErrors(), to distinguish error types | |||
| 459 | /// errs() << "Problem with division " << toString(std::move(E)) << "\n"; | |||
| 460 | /// return; | |||
| 461 | /// } | |||
| 462 | /// // use the result | |||
| 463 | /// outs() << "The answer is " << *Result << "\n"; | |||
| 464 | /// @endcode | |||
| 465 | /// | |||
| 466 | /// For unit-testing a function returning an 'Expected<T>', see the | |||
| 467 | /// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h | |||
| 468 | ||||
| 469 | template <class T> class [[nodiscard]] Expected { | |||
| 470 | template <class T1> friend class ExpectedAsOutParameter; | |||
| 471 | template <class OtherT> friend class Expected; | |||
| 472 | ||||
| 473 | static constexpr bool isRef = std::is_reference<T>::value; | |||
| 474 | ||||
| 475 | using wrap = std::reference_wrapper<std::remove_reference_t<T>>; | |||
| 476 | ||||
| 477 | using error_type = std::unique_ptr<ErrorInfoBase>; | |||
| 478 | ||||
| 479 | public: | |||
| 480 | using storage_type = std::conditional_t<isRef, wrap, T>; | |||
| 481 | using value_type = T; | |||
| 482 | ||||
| 483 | private: | |||
| 484 | using reference = std::remove_reference_t<T> &; | |||
| 485 | using const_reference = const std::remove_reference_t<T> &; | |||
| 486 | using pointer = std::remove_reference_t<T> *; | |||
| 487 | using const_pointer = const std::remove_reference_t<T> *; | |||
| 488 | ||||
| 489 | public: | |||
| 490 | /// Create an Expected<T> error value from the given Error. | |||
| 491 | Expected(Error Err) | |||
| 492 | : HasError(true) | |||
| 493 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 494 | // Expected is unchecked upon construction in Debug builds. | |||
| 495 | , Unchecked(true) | |||
| 496 | #endif | |||
| 497 | { | |||
| 498 | assert(Err && "Cannot create Expected<T> from Error success value.")(static_cast <bool> (Err && "Cannot create Expected<T> from Error success value." ) ? void (0) : __assert_fail ("Err && \"Cannot create Expected<T> from Error success value.\"" , "llvm/include/llvm/Support/Error.h", 498, __extension__ __PRETTY_FUNCTION__ )); | |||
| 499 | new (getErrorStorage()) error_type(Err.takePayload()); | |||
| 500 | } | |||
| 501 | ||||
| 502 | /// Forbid to convert from Error::success() implicitly, this avoids having | |||
| 503 | /// Expected<T> foo() { return Error::success(); } which compiles otherwise | |||
| 504 | /// but triggers the assertion above. | |||
| 505 | Expected(ErrorSuccess) = delete; | |||
| 506 | ||||
| 507 | /// Create an Expected<T> success value from the given OtherT value, which | |||
| 508 | /// must be convertible to T. | |||
| 509 | template <typename OtherT> | |||
| 510 | Expected(OtherT &&Val, | |||
| 511 | std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) | |||
| 512 | : HasError(false) | |||
| 513 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 514 | // Expected is unchecked upon construction in Debug builds. | |||
| 515 | , | |||
| 516 | Unchecked(true) | |||
| 517 | #endif | |||
| 518 | { | |||
| 519 | new (getStorage()) storage_type(std::forward<OtherT>(Val)); | |||
| ||||
| 520 | } | |||
| 521 | ||||
| 522 | /// Move construct an Expected<T> value. | |||
| 523 | Expected(Expected &&Other) { moveConstruct(std::move(Other)); } | |||
| 524 | ||||
| 525 | /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT | |||
| 526 | /// must be convertible to T. | |||
| 527 | template <class OtherT> | |||
| 528 | Expected( | |||
| 529 | Expected<OtherT> &&Other, | |||
| 530 | std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) { | |||
| 531 | moveConstruct(std::move(Other)); | |||
| 532 | } | |||
| 533 | ||||
| 534 | /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT | |||
| 535 | /// isn't convertible to T. | |||
| 536 | template <class OtherT> | |||
| 537 | explicit Expected( | |||
| 538 | Expected<OtherT> &&Other, | |||
| 539 | std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) { | |||
| 540 | moveConstruct(std::move(Other)); | |||
| 541 | } | |||
| 542 | ||||
| 543 | /// Move-assign from another Expected<T>. | |||
| 544 | Expected &operator=(Expected &&Other) { | |||
| 545 | moveAssign(std::move(Other)); | |||
| 546 | return *this; | |||
| 547 | } | |||
| 548 | ||||
| 549 | /// Destroy an Expected<T>. | |||
| 550 | ~Expected() { | |||
| 551 | assertIsChecked(); | |||
| 552 | if (!HasError) | |||
| 553 | getStorage()->~storage_type(); | |||
| 554 | else | |||
| 555 | getErrorStorage()->~error_type(); | |||
| 556 | } | |||
| 557 | ||||
| 558 | /// Return false if there is an error. | |||
| 559 | explicit operator bool() { | |||
| 560 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 561 | Unchecked = HasError; | |||
| 562 | #endif | |||
| 563 | return !HasError; | |||
| 564 | } | |||
| 565 | ||||
| 566 | /// Returns a reference to the stored T value. | |||
| 567 | reference get() { | |||
| 568 | assertIsChecked(); | |||
| 569 | return *getStorage(); | |||
| 570 | } | |||
| 571 | ||||
| 572 | /// Returns a const reference to the stored T value. | |||
| 573 | const_reference get() const { | |||
| 574 | assertIsChecked(); | |||
| 575 | return const_cast<Expected<T> *>(this)->get(); | |||
| 576 | } | |||
| 577 | ||||
| 578 | /// Returns \a takeError() after moving the held T (if any) into \p V. | |||
| 579 | template <class OtherT> | |||
| 580 | Error moveInto(OtherT &Value, | |||
| 581 | std::enable_if_t<std::is_assignable<OtherT &, T &&>::value> * = | |||
| 582 | nullptr) && { | |||
| 583 | if (*this) | |||
| 584 | Value = std::move(get()); | |||
| 585 | return takeError(); | |||
| 586 | } | |||
| 587 | ||||
| 588 | /// Check that this Expected<T> is an error of type ErrT. | |||
| 589 | template <typename ErrT> bool errorIsA() const { | |||
| 590 | return HasError && (*getErrorStorage())->template isA<ErrT>(); | |||
| 591 | } | |||
| 592 | ||||
| 593 | /// Take ownership of the stored error. | |||
| 594 | /// After calling this the Expected<T> is in an indeterminate state that can | |||
| 595 | /// only be safely destructed. No further calls (beside the destructor) should | |||
| 596 | /// be made on the Expected<T> value. | |||
| 597 | Error takeError() { | |||
| 598 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 599 | Unchecked = false; | |||
| 600 | #endif | |||
| 601 | return HasError ? Error(std::move(*getErrorStorage())) : Error::success(); | |||
| 602 | } | |||
| 603 | ||||
| 604 | /// Returns a pointer to the stored T value. | |||
| 605 | pointer operator->() { | |||
| 606 | assertIsChecked(); | |||
| 607 | return toPointer(getStorage()); | |||
| 608 | } | |||
| 609 | ||||
| 610 | /// Returns a const pointer to the stored T value. | |||
| 611 | const_pointer operator->() const { | |||
| 612 | assertIsChecked(); | |||
| 613 | return toPointer(getStorage()); | |||
| 614 | } | |||
| 615 | ||||
| 616 | /// Returns a reference to the stored T value. | |||
| 617 | reference operator*() { | |||
| 618 | assertIsChecked(); | |||
| 619 | return *getStorage(); | |||
| 620 | } | |||
| 621 | ||||
| 622 | /// Returns a const reference to the stored T value. | |||
| 623 | const_reference operator*() const { | |||
| 624 | assertIsChecked(); | |||
| 625 | return *getStorage(); | |||
| 626 | } | |||
| 627 | ||||
| 628 | private: | |||
| 629 | template <class T1> | |||
| 630 | static bool compareThisIfSameType(const T1 &a, const T1 &b) { | |||
| 631 | return &a == &b; | |||
| 632 | } | |||
| 633 | ||||
| 634 | template <class T1, class T2> | |||
| 635 | static bool compareThisIfSameType(const T1 &, const T2 &) { | |||
| 636 | return false; | |||
| 637 | } | |||
| 638 | ||||
| 639 | template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) { | |||
| 640 | HasError = Other.HasError; | |||
| 641 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 642 | Unchecked = true; | |||
| 643 | Other.Unchecked = false; | |||
| 644 | #endif | |||
| 645 | ||||
| 646 | if (!HasError) | |||
| 647 | new (getStorage()) storage_type(std::move(*Other.getStorage())); | |||
| 648 | else | |||
| 649 | new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage())); | |||
| 650 | } | |||
| 651 | ||||
| 652 | template <class OtherT> void moveAssign(Expected<OtherT> &&Other) { | |||
| 653 | assertIsChecked(); | |||
| 654 | ||||
| 655 | if (compareThisIfSameType(*this, Other)) | |||
| 656 | return; | |||
| 657 | ||||
| 658 | this->~Expected(); | |||
| 659 | new (this) Expected(std::move(Other)); | |||
| 660 | } | |||
| 661 | ||||
| 662 | pointer toPointer(pointer Val) { return Val; } | |||
| 663 | ||||
| 664 | const_pointer toPointer(const_pointer Val) const { return Val; } | |||
| 665 | ||||
| 666 | pointer toPointer(wrap *Val) { return &Val->get(); } | |||
| 667 | ||||
| 668 | const_pointer toPointer(const wrap *Val) const { return &Val->get(); } | |||
| 669 | ||||
| 670 | storage_type *getStorage() { | |||
| 671 | assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!" ) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\"" , "llvm/include/llvm/Support/Error.h", 671, __extension__ __PRETTY_FUNCTION__ )); | |||
| 672 | return reinterpret_cast<storage_type *>(&TStorage); | |||
| 673 | } | |||
| 674 | ||||
| 675 | const storage_type *getStorage() const { | |||
| 676 | assert(!HasError && "Cannot get value when an error exists!")(static_cast <bool> (!HasError && "Cannot get value when an error exists!" ) ? void (0) : __assert_fail ("!HasError && \"Cannot get value when an error exists!\"" , "llvm/include/llvm/Support/Error.h", 676, __extension__ __PRETTY_FUNCTION__ )); | |||
| 677 | return reinterpret_cast<const storage_type *>(&TStorage); | |||
| 678 | } | |||
| 679 | ||||
| 680 | error_type *getErrorStorage() { | |||
| 681 | assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!" ) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\"" , "llvm/include/llvm/Support/Error.h", 681, __extension__ __PRETTY_FUNCTION__ )); | |||
| 682 | return reinterpret_cast<error_type *>(&ErrorStorage); | |||
| 683 | } | |||
| 684 | ||||
| 685 | const error_type *getErrorStorage() const { | |||
| 686 | assert(HasError && "Cannot get error when a value exists!")(static_cast <bool> (HasError && "Cannot get error when a value exists!" ) ? void (0) : __assert_fail ("HasError && \"Cannot get error when a value exists!\"" , "llvm/include/llvm/Support/Error.h", 686, __extension__ __PRETTY_FUNCTION__ )); | |||
| 687 | return reinterpret_cast<const error_type *>(&ErrorStorage); | |||
| 688 | } | |||
| 689 | ||||
| 690 | // Used by ExpectedAsOutParameter to reset the checked flag. | |||
| 691 | void setUnchecked() { | |||
| 692 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 693 | Unchecked = true; | |||
| 694 | #endif | |||
| 695 | } | |||
| 696 | ||||
| 697 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 698 | [[noreturn]] LLVM_ATTRIBUTE_NOINLINE__attribute__((noinline)) void fatalUncheckedExpected() const { | |||
| 699 | dbgs() << "Expected<T> must be checked before access or destruction.\n"; | |||
| 700 | if (HasError) { | |||
| 701 | dbgs() << "Unchecked Expected<T> contained error:\n"; | |||
| 702 | (*getErrorStorage())->log(dbgs()); | |||
| 703 | } else | |||
| 704 | dbgs() << "Expected<T> value was in success state. (Note: Expected<T> " | |||
| 705 | "values in success mode must still be checked prior to being " | |||
| 706 | "destroyed).\n"; | |||
| 707 | abort(); | |||
| 708 | } | |||
| 709 | #endif | |||
| 710 | ||||
| 711 | void assertIsChecked() const { | |||
| 712 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 713 | if (LLVM_UNLIKELY(Unchecked)__builtin_expect((bool)(Unchecked), false)) | |||
| 714 | fatalUncheckedExpected(); | |||
| 715 | #endif | |||
| 716 | } | |||
| 717 | ||||
| 718 | union { | |||
| 719 | AlignedCharArrayUnion<storage_type> TStorage; | |||
| 720 | AlignedCharArrayUnion<error_type> ErrorStorage; | |||
| 721 | }; | |||
| 722 | bool HasError : 1; | |||
| 723 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS1 | |||
| 724 | bool Unchecked : 1; | |||
| 725 | #endif | |||
| 726 | }; | |||
| 727 | ||||
| 728 | /// Report a serious error, calling any installed error handler. See | |||
| 729 | /// ErrorHandling.h. | |||
| 730 | [[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true); | |||
| 731 | ||||
| 732 | /// Report a fatal error if Err is a failure value. | |||
| 733 | /// | |||
| 734 | /// This function can be used to wrap calls to fallible functions ONLY when it | |||
| 735 | /// is known that the Error will always be a success value. E.g. | |||
| 736 | /// | |||
| 737 | /// @code{.cpp} | |||
| 738 | /// // foo only attempts the fallible operation if DoFallibleOperation is | |||
| 739 | /// // true. If DoFallibleOperation is false then foo always returns | |||
| 740 | /// // Error::success(). | |||
| 741 | /// Error foo(bool DoFallibleOperation); | |||
| 742 | /// | |||
| 743 | /// cantFail(foo(false)); | |||
| 744 | /// @endcode | |||
| 745 | inline void cantFail(Error Err, const char *Msg = nullptr) { | |||
| 746 | if (Err) { | |||
| 747 | if (!Msg) | |||
| 748 | Msg = "Failure value returned from cantFail wrapped call"; | |||
| 749 | #ifndef NDEBUG | |||
| 750 | std::string Str; | |||
| 751 | raw_string_ostream OS(Str); | |||
| 752 | OS << Msg << "\n" << Err; | |||
| 753 | Msg = OS.str().c_str(); | |||
| 754 | #endif | |||
| 755 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 755); | |||
| 756 | } | |||
| 757 | } | |||
| 758 | ||||
| 759 | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | |||
| 760 | /// returns the contained value. | |||
| 761 | /// | |||
| 762 | /// This function can be used to wrap calls to fallible functions ONLY when it | |||
| 763 | /// is known that the Error will always be a success value. E.g. | |||
| 764 | /// | |||
| 765 | /// @code{.cpp} | |||
| 766 | /// // foo only attempts the fallible operation if DoFallibleOperation is | |||
| 767 | /// // true. If DoFallibleOperation is false then foo always returns an int. | |||
| 768 | /// Expected<int> foo(bool DoFallibleOperation); | |||
| 769 | /// | |||
| 770 | /// int X = cantFail(foo(false)); | |||
| 771 | /// @endcode | |||
| 772 | template <typename T> | |||
| 773 | T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) { | |||
| 774 | if (ValOrErr) | |||
| 775 | return std::move(*ValOrErr); | |||
| 776 | else { | |||
| 777 | if (!Msg) | |||
| 778 | Msg = "Failure value returned from cantFail wrapped call"; | |||
| 779 | #ifndef NDEBUG | |||
| 780 | std::string Str; | |||
| 781 | raw_string_ostream OS(Str); | |||
| 782 | auto E = ValOrErr.takeError(); | |||
| 783 | OS << Msg << "\n" << E; | |||
| 784 | Msg = OS.str().c_str(); | |||
| 785 | #endif | |||
| 786 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 786); | |||
| 787 | } | |||
| 788 | } | |||
| 789 | ||||
| 790 | /// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and | |||
| 791 | /// returns the contained reference. | |||
| 792 | /// | |||
| 793 | /// This function can be used to wrap calls to fallible functions ONLY when it | |||
| 794 | /// is known that the Error will always be a success value. E.g. | |||
| 795 | /// | |||
| 796 | /// @code{.cpp} | |||
| 797 | /// // foo only attempts the fallible operation if DoFallibleOperation is | |||
| 798 | /// // true. If DoFallibleOperation is false then foo always returns a Bar&. | |||
| 799 | /// Expected<Bar&> foo(bool DoFallibleOperation); | |||
| 800 | /// | |||
| 801 | /// Bar &X = cantFail(foo(false)); | |||
| 802 | /// @endcode | |||
| 803 | template <typename T> | |||
| 804 | T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) { | |||
| 805 | if (ValOrErr) | |||
| 806 | return *ValOrErr; | |||
| 807 | else { | |||
| 808 | if (!Msg) | |||
| 809 | Msg = "Failure value returned from cantFail wrapped call"; | |||
| 810 | #ifndef NDEBUG | |||
| 811 | std::string Str; | |||
| 812 | raw_string_ostream OS(Str); | |||
| 813 | auto E = ValOrErr.takeError(); | |||
| 814 | OS << Msg << "\n" << E; | |||
| 815 | Msg = OS.str().c_str(); | |||
| 816 | #endif | |||
| 817 | llvm_unreachable(Msg)::llvm::llvm_unreachable_internal(Msg, "llvm/include/llvm/Support/Error.h" , 817); | |||
| 818 | } | |||
| 819 | } | |||
| 820 | ||||
| 821 | /// Helper for testing applicability of, and applying, handlers for | |||
| 822 | /// ErrorInfo types. | |||
| 823 | template <typename HandlerT> | |||
| 824 | class ErrorHandlerTraits | |||
| 825 | : public ErrorHandlerTraits< | |||
| 826 | decltype(&std::remove_reference_t<HandlerT>::operator())> {}; | |||
| 827 | ||||
| 828 | // Specialization functions of the form 'Error (const ErrT&)'. | |||
| 829 | template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> { | |||
| 830 | public: | |||
| 831 | static bool appliesTo(const ErrorInfoBase &E) { | |||
| 832 | return E.template isA<ErrT>(); | |||
| 833 | } | |||
| 834 | ||||
| 835 | template <typename HandlerT> | |||
| 836 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { | |||
| 837 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 837, __extension__ __PRETTY_FUNCTION__ )); | |||
| 838 | return H(static_cast<ErrT &>(*E)); | |||
| 839 | } | |||
| 840 | }; | |||
| 841 | ||||
| 842 | // Specialization functions of the form 'void (const ErrT&)'. | |||
| 843 | template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> { | |||
| 844 | public: | |||
| 845 | static bool appliesTo(const ErrorInfoBase &E) { | |||
| 846 | return E.template isA<ErrT>(); | |||
| 847 | } | |||
| 848 | ||||
| 849 | template <typename HandlerT> | |||
| 850 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { | |||
| 851 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 851, __extension__ __PRETTY_FUNCTION__ )); | |||
| 852 | H(static_cast<ErrT &>(*E)); | |||
| 853 | return Error::success(); | |||
| 854 | } | |||
| 855 | }; | |||
| 856 | ||||
| 857 | /// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'. | |||
| 858 | template <typename ErrT> | |||
| 859 | class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> { | |||
| 860 | public: | |||
| 861 | static bool appliesTo(const ErrorInfoBase &E) { | |||
| 862 | return E.template isA<ErrT>(); | |||
| 863 | } | |||
| 864 | ||||
| 865 | template <typename HandlerT> | |||
| 866 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { | |||
| 867 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 867, __extension__ __PRETTY_FUNCTION__ )); | |||
| 868 | std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); | |||
| 869 | return H(std::move(SubE)); | |||
| 870 | } | |||
| 871 | }; | |||
| 872 | ||||
| 873 | /// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'. | |||
| 874 | template <typename ErrT> | |||
| 875 | class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> { | |||
| 876 | public: | |||
| 877 | static bool appliesTo(const ErrorInfoBase &E) { | |||
| 878 | return E.template isA<ErrT>(); | |||
| 879 | } | |||
| 880 | ||||
| 881 | template <typename HandlerT> | |||
| 882 | static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) { | |||
| 883 | assert(appliesTo(*E) && "Applying incorrect handler")(static_cast <bool> (appliesTo(*E) && "Applying incorrect handler" ) ? void (0) : __assert_fail ("appliesTo(*E) && \"Applying incorrect handler\"" , "llvm/include/llvm/Support/Error.h", 883, __extension__ __PRETTY_FUNCTION__ )); | |||
| 884 | std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release())); | |||
| 885 | H(std::move(SubE)); | |||
| 886 | return Error::success(); | |||
| 887 | } | |||
| 888 | }; | |||
| 889 | ||||
| 890 | // Specialization for member functions of the form 'RetT (const ErrT&)'. | |||
| 891 | template <typename C, typename RetT, typename ErrT> | |||
| 892 | class ErrorHandlerTraits<RetT (C::*)(ErrT &)> | |||
| 893 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; | |||
| 894 | ||||
| 895 | // Specialization for member functions of the form 'RetT (const ErrT&) const'. | |||
| 896 | template <typename C, typename RetT, typename ErrT> | |||
| 897 | class ErrorHandlerTraits<RetT (C::*)(ErrT &) const> | |||
| 898 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; | |||
| 899 | ||||
| 900 | // Specialization for member functions of the form 'RetT (const ErrT&)'. | |||
| 901 | template <typename C, typename RetT, typename ErrT> | |||
| 902 | class ErrorHandlerTraits<RetT (C::*)(const ErrT &)> | |||
| 903 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; | |||
| 904 | ||||
| 905 | // Specialization for member functions of the form 'RetT (const ErrT&) const'. | |||
| 906 | template <typename C, typename RetT, typename ErrT> | |||
| 907 | class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const> | |||
| 908 | : public ErrorHandlerTraits<RetT (&)(ErrT &)> {}; | |||
| 909 | ||||
| 910 | /// Specialization for member functions of the form | |||
| 911 | /// 'RetT (std::unique_ptr<ErrT>)'. | |||
| 912 | template <typename C, typename RetT, typename ErrT> | |||
| 913 | class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)> | |||
| 914 | : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; | |||
| 915 | ||||
| 916 | /// Specialization for member functions of the form | |||
| 917 | /// 'RetT (std::unique_ptr<ErrT>) const'. | |||
| 918 | template <typename C, typename RetT, typename ErrT> | |||
| 919 | class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const> | |||
| 920 | : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {}; | |||
| 921 | ||||
| 922 | inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) { | |||
| 923 | return Error(std::move(Payload)); | |||
| 924 | } | |||
| 925 | ||||
| 926 | template <typename HandlerT, typename... HandlerTs> | |||
| 927 | Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload, | |||
| 928 | HandlerT &&Handler, HandlerTs &&... Handlers) { | |||
| 929 | if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload)) | |||
| 930 | return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler), | |||
| 931 | std::move(Payload)); | |||
| 932 | return handleErrorImpl(std::move(Payload), | |||
| 933 | std::forward<HandlerTs>(Handlers)...); | |||
| 934 | } | |||
| 935 | ||||
| 936 | /// Pass the ErrorInfo(s) contained in E to their respective handlers. Any | |||
| 937 | /// unhandled errors (or Errors returned by handlers) are re-concatenated and | |||
| 938 | /// returned. | |||
| 939 | /// Because this function returns an error, its result must also be checked | |||
| 940 | /// or returned. If you intend to handle all errors use handleAllErrors | |||
| 941 | /// (which returns void, and will abort() on unhandled errors) instead. | |||
| 942 | template <typename... HandlerTs> | |||
| 943 | Error handleErrors(Error E, HandlerTs &&... Hs) { | |||
| 944 | if (!E) | |||
| 945 | return Error::success(); | |||
| 946 | ||||
| 947 | std::unique_ptr<ErrorInfoBase> Payload = E.takePayload(); | |||
| 948 | ||||
| 949 | if (Payload->isA<ErrorList>()) { | |||
| 950 | ErrorList &List = static_cast<ErrorList &>(*Payload); | |||
| 951 | Error R; | |||
| 952 | for (auto &P : List.Payloads) | |||
| 953 | R = ErrorList::join( | |||
| 954 | std::move(R), | |||
| 955 | handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...)); | |||
| 956 | return R; | |||
| 957 | } | |||
| 958 | ||||
| 959 | return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...); | |||
| 960 | } | |||
| 961 | ||||
| 962 | /// Behaves the same as handleErrors, except that by contract all errors | |||
| 963 | /// *must* be handled by the given handlers (i.e. there must be no remaining | |||
| 964 | /// errors after running the handlers, or llvm_unreachable is called). | |||
| 965 | template <typename... HandlerTs> | |||
| 966 | void handleAllErrors(Error E, HandlerTs &&... Handlers) { | |||
| 967 | cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...)); | |||
| 968 | } | |||
| 969 | ||||
| 970 | /// Check that E is a non-error, then drop it. | |||
| 971 | /// If E is an error, llvm_unreachable will be called. | |||
| 972 | inline void handleAllErrors(Error E) { | |||
| 973 | cantFail(std::move(E)); | |||
| 974 | } | |||
| 975 | ||||
| 976 | /// Handle any errors (if present) in an Expected<T>, then try a recovery path. | |||
| 977 | /// | |||
| 978 | /// If the incoming value is a success value it is returned unmodified. If it | |||
| 979 | /// is a failure value then it the contained error is passed to handleErrors. | |||
| 980 | /// If handleErrors is able to handle the error then the RecoveryPath functor | |||
| 981 | /// is called to supply the final result. If handleErrors is not able to | |||
| 982 | /// handle all errors then the unhandled errors are returned. | |||
| 983 | /// | |||
| 984 | /// This utility enables the follow pattern: | |||
| 985 | /// | |||
| 986 | /// @code{.cpp} | |||
| 987 | /// enum FooStrategy { Aggressive, Conservative }; | |||
| 988 | /// Expected<Foo> foo(FooStrategy S); | |||
| 989 | /// | |||
| 990 | /// auto ResultOrErr = | |||
| 991 | /// handleExpected( | |||
| 992 | /// foo(Aggressive), | |||
| 993 | /// []() { return foo(Conservative); }, | |||
| 994 | /// [](AggressiveStrategyError&) { | |||
| 995 | /// // Implicitly conusme this - we'll recover by using a conservative | |||
| 996 | /// // strategy. | |||
| 997 | /// }); | |||
| 998 | /// | |||
| 999 | /// @endcode | |||
| 1000 | template <typename T, typename RecoveryFtor, typename... HandlerTs> | |||
| 1001 | Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath, | |||
| 1002 | HandlerTs &&... Handlers) { | |||
| 1003 | if (ValOrErr) | |||
| 1004 | return ValOrErr; | |||
| 1005 | ||||
| 1006 | if (auto Err = handleErrors(ValOrErr.takeError(), | |||
| 1007 | std::forward<HandlerTs>(Handlers)...)) | |||
| 1008 | return std::move(Err); | |||
| 1009 | ||||
| 1010 | return RecoveryPath(); | |||
| 1011 | } | |||
| 1012 | ||||
| 1013 | /// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner | |||
| 1014 | /// will be printed before the first one is logged. A newline will be printed | |||
| 1015 | /// after each error. | |||
| 1016 | /// | |||
| 1017 | /// This function is compatible with the helpers from Support/WithColor.h. You | |||
| 1018 | /// can pass any of them as the OS. Please consider using them instead of | |||
| 1019 | /// including 'error: ' in the ErrorBanner. | |||
| 1020 | /// | |||
| 1021 | /// This is useful in the base level of your program to allow clean termination | |||
| 1022 | /// (allowing clean deallocation of resources, etc.), while reporting error | |||
| 1023 | /// information to the user. | |||
| 1024 | void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {}); | |||
| 1025 | ||||
| 1026 | /// Write all error messages (if any) in E to a string. The newline character | |||
| 1027 | /// is used to separate error messages. | |||
| 1028 | inline std::string toString(Error E) { | |||
| 1029 | SmallVector<std::string, 2> Errors; | |||
| 1030 | handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) { | |||
| 1031 | Errors.push_back(EI.message()); | |||
| 1032 | }); | |||
| 1033 | return join(Errors.begin(), Errors.end(), "\n"); | |||
| 1034 | } | |||
| 1035 | ||||
| 1036 | /// Consume a Error without doing anything. This method should be used | |||
| 1037 | /// only where an error can be considered a reasonable and expected return | |||
| 1038 | /// value. | |||
| 1039 | /// | |||
| 1040 | /// Uses of this method are potentially indicative of design problems: If it's | |||
| 1041 | /// legitimate to do nothing while processing an "error", the error-producer | |||
| 1042 | /// might be more clearly refactored to return an Optional<T>. | |||
| 1043 | inline void consumeError(Error Err) { | |||
| 1044 | handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {}); | |||
| 1045 | } | |||
| 1046 | ||||
| 1047 | /// Convert an Expected to an Optional without doing anything. This method | |||
| 1048 | /// should be used only where an error can be considered a reasonable and | |||
| 1049 | /// expected return value. | |||
| 1050 | /// | |||
| 1051 | /// Uses of this method are potentially indicative of problems: perhaps the | |||
| 1052 | /// error should be propagated further, or the error-producer should just | |||
| 1053 | /// return an Optional in the first place. | |||
| 1054 | template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) { | |||
| 1055 | if (E) | |||
| 1056 | return std::move(*E); | |||
| 1057 | consumeError(E.takeError()); | |||
| 1058 | return None; | |||
| 1059 | } | |||
| 1060 | ||||
| 1061 | /// Helper for converting an Error to a bool. | |||
| 1062 | /// | |||
| 1063 | /// This method returns true if Err is in an error state, or false if it is | |||
| 1064 | /// in a success state. Puts Err in a checked state in both cases (unlike | |||
| 1065 | /// Error::operator bool(), which only does this for success states). | |||
| 1066 | inline bool errorToBool(Error Err) { | |||
| 1067 | bool IsError = static_cast<bool>(Err); | |||
| 1068 | if (IsError) | |||
| 1069 | consumeError(std::move(Err)); | |||
| 1070 | return IsError; | |||
| 1071 | } | |||
| 1072 | ||||
| 1073 | /// Helper for Errors used as out-parameters. | |||
| 1074 | /// | |||
| 1075 | /// This helper is for use with the Error-as-out-parameter idiom, where an error | |||
| 1076 | /// is passed to a function or method by reference, rather than being returned. | |||
| 1077 | /// In such cases it is helpful to set the checked bit on entry to the function | |||
| 1078 | /// so that the error can be written to (unchecked Errors abort on assignment) | |||
| 1079 | /// and clear the checked bit on exit so that clients cannot accidentally forget | |||
| 1080 | /// to check the result. This helper performs these actions automatically using | |||
| 1081 | /// RAII: | |||
| 1082 | /// | |||
| 1083 | /// @code{.cpp} | |||
| 1084 | /// Result foo(Error &Err) { | |||
| 1085 | /// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set | |||
| 1086 | /// // <body of foo> | |||
| 1087 | /// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed. | |||
| 1088 | /// } | |||
| 1089 | /// @endcode | |||
| 1090 | /// | |||
| 1091 | /// ErrorAsOutParameter takes an Error* rather than Error& so that it can be | |||
| 1092 | /// used with optional Errors (Error pointers that are allowed to be null). If | |||
| 1093 | /// ErrorAsOutParameter took an Error reference, an instance would have to be | |||
| 1094 | /// created inside every condition that verified that Error was non-null. By | |||
| 1095 | /// taking an Error pointer we can just create one instance at the top of the | |||
| 1096 | /// function. | |||
| 1097 | class ErrorAsOutParameter { | |||
| 1098 | public: | |||
| 1099 | ErrorAsOutParameter(Error *Err) : Err(Err) { | |||
| 1100 | // Raise the checked bit if Err is success. | |||
| 1101 | if (Err) | |||
| 1102 | (void)!!*Err; | |||
| 1103 | } | |||
| 1104 | ||||
| 1105 | ~ErrorAsOutParameter() { | |||
| 1106 | // Clear the checked bit. | |||
| 1107 | if (Err && !*Err) | |||
| 1108 | *Err = Error::success(); | |||
| 1109 | } | |||
| 1110 | ||||
| 1111 | private: | |||
| 1112 | Error *Err; | |||
| 1113 | }; | |||
| 1114 | ||||
| 1115 | /// Helper for Expected<T>s used as out-parameters. | |||
| 1116 | /// | |||
| 1117 | /// See ErrorAsOutParameter. | |||
| 1118 | template <typename T> | |||
| 1119 | class ExpectedAsOutParameter { | |||
| 1120 | public: | |||
| 1121 | ExpectedAsOutParameter(Expected<T> *ValOrErr) | |||
| 1122 | : ValOrErr(ValOrErr) { | |||
| 1123 | if (ValOrErr) | |||
| 1124 | (void)!!*ValOrErr; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | ~ExpectedAsOutParameter() { | |||
| 1128 | if (ValOrErr) | |||
| 1129 | ValOrErr->setUnchecked(); | |||
| 1130 | } | |||
| 1131 | ||||
| 1132 | private: | |||
| 1133 | Expected<T> *ValOrErr; | |||
| 1134 | }; | |||
| 1135 | ||||
| 1136 | /// This class wraps a std::error_code in a Error. | |||
| 1137 | /// | |||
| 1138 | /// This is useful if you're writing an interface that returns a Error | |||
| 1139 | /// (or Expected) and you want to call code that still returns | |||
| 1140 | /// std::error_codes. | |||
| 1141 | class ECError : public ErrorInfo<ECError> { | |||
| 1142 | friend Error errorCodeToError(std::error_code); | |||
| 1143 | ||||
| 1144 | void anchor() override; | |||
| 1145 | ||||
| 1146 | public: | |||
| 1147 | void setErrorCode(std::error_code EC) { this->EC = EC; } | |||
| 1148 | std::error_code convertToErrorCode() const override { return EC; } | |||
| 1149 | void log(raw_ostream &OS) const override { OS << EC.message(); } | |||
| 1150 | ||||
| 1151 | // Used by ErrorInfo::classID. | |||
| 1152 | static char ID; | |||
| 1153 | ||||
| 1154 | protected: | |||
| 1155 | ECError() = default; | |||
| 1156 | ECError(std::error_code EC) : EC(EC) {} | |||
| 1157 | ||||
| 1158 | std::error_code EC; | |||
| 1159 | }; | |||
| 1160 | ||||
| 1161 | /// The value returned by this function can be returned from convertToErrorCode | |||
| 1162 | /// for Error values where no sensible translation to std::error_code exists. | |||
| 1163 | /// It should only be used in this situation, and should never be used where a | |||
| 1164 | /// sensible conversion to std::error_code is available, as attempts to convert | |||
| 1165 | /// to/from this error will result in a fatal error. (i.e. it is a programmatic | |||
| 1166 | /// error to try to convert such a value). | |||
| 1167 | std::error_code inconvertibleErrorCode(); | |||
| 1168 | ||||
| 1169 | /// Helper for converting an std::error_code to a Error. | |||
| 1170 | Error errorCodeToError(std::error_code EC); | |||
| 1171 | ||||
| 1172 | /// Helper for converting an ECError to a std::error_code. | |||
| 1173 | /// | |||
| 1174 | /// This method requires that Err be Error() or an ECError, otherwise it | |||
| 1175 | /// will trigger a call to abort(). | |||
| 1176 | std::error_code errorToErrorCode(Error Err); | |||
| 1177 | ||||
| 1178 | /// Convert an ErrorOr<T> to an Expected<T>. | |||
| 1179 | template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) { | |||
| 1180 | if (auto EC = EO.getError()) | |||
| 1181 | return errorCodeToError(EC); | |||
| 1182 | return std::move(*EO); | |||
| 1183 | } | |||
| 1184 | ||||
| 1185 | /// Convert an Expected<T> to an ErrorOr<T>. | |||
| 1186 | template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) { | |||
| 1187 | if (auto Err = E.takeError()) | |||
| 1188 | return errorToErrorCode(std::move(Err)); | |||
| 1189 | return std::move(*E); | |||
| 1190 | } | |||
| 1191 | ||||
| 1192 | /// This class wraps a string in an Error. | |||
| 1193 | /// | |||
| 1194 | /// StringError is useful in cases where the client is not expected to be able | |||
| 1195 | /// to consume the specific error message programmatically (for example, if the | |||
| 1196 | /// error message is to be presented to the user). | |||
| 1197 | /// | |||
| 1198 | /// StringError can also be used when additional information is to be printed | |||
| 1199 | /// along with a error_code message. Depending on the constructor called, this | |||
| 1200 | /// class can either display: | |||
| 1201 | /// 1. the error_code message (ECError behavior) | |||
| 1202 | /// 2. a string | |||
| 1203 | /// 3. the error_code message and a string | |||
| 1204 | /// | |||
| 1205 | /// These behaviors are useful when subtyping is required; for example, when a | |||
| 1206 | /// specific library needs an explicit error type. In the example below, | |||
| 1207 | /// PDBError is derived from StringError: | |||
| 1208 | /// | |||
| 1209 | /// @code{.cpp} | |||
| 1210 | /// Expected<int> foo() { | |||
| 1211 | /// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading, | |||
| 1212 | /// "Additional information"); | |||
| 1213 | /// } | |||
| 1214 | /// @endcode | |||
| 1215 | /// | |||
| 1216 | class StringError : public ErrorInfo<StringError> { | |||
| 1217 | public: | |||
| 1218 | static char ID; | |||
| 1219 | ||||
| 1220 | // Prints EC + S and converts to EC | |||
| 1221 | StringError(std::error_code EC, const Twine &S = Twine()); | |||
| 1222 | ||||
| 1223 | // Prints S and converts to EC | |||
| 1224 | StringError(const Twine &S, std::error_code EC); | |||
| 1225 | ||||
| 1226 | void log(raw_ostream &OS) const override; | |||
| 1227 | std::error_code convertToErrorCode() const override; | |||
| 1228 | ||||
| 1229 | const std::string &getMessage() const { return Msg; } | |||
| 1230 | ||||
| 1231 | private: | |||
| 1232 | std::string Msg; | |||
| 1233 | std::error_code EC; | |||
| 1234 | const bool PrintMsgOnly = false; | |||
| 1235 | }; | |||
| 1236 | ||||
| 1237 | /// Create formatted StringError object. | |||
| 1238 | template <typename... Ts> | |||
| 1239 | inline Error createStringError(std::error_code EC, char const *Fmt, | |||
| 1240 | const Ts &... Vals) { | |||
| 1241 | std::string Buffer; | |||
| 1242 | raw_string_ostream Stream(Buffer); | |||
| 1243 | Stream << format(Fmt, Vals...); | |||
| 1244 | return make_error<StringError>(Stream.str(), EC); | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | Error createStringError(std::error_code EC, char const *Msg); | |||
| 1248 | ||||
| 1249 | inline Error createStringError(std::error_code EC, const Twine &S) { | |||
| 1250 | return createStringError(EC, S.str().c_str()); | |||
| 1251 | } | |||
| 1252 | ||||
| 1253 | template <typename... Ts> | |||
| 1254 | inline Error createStringError(std::errc EC, char const *Fmt, | |||
| 1255 | const Ts &... Vals) { | |||
| 1256 | return createStringError(std::make_error_code(EC), Fmt, Vals...); | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | /// This class wraps a filename and another Error. | |||
| 1260 | /// | |||
| 1261 | /// In some cases, an error needs to live along a 'source' name, in order to | |||
| 1262 | /// show more detailed information to the user. | |||
| 1263 | class FileError final : public ErrorInfo<FileError> { | |||
| 1264 | ||||
| 1265 | friend Error createFileError(const Twine &, Error); | |||
| 1266 | friend Error createFileError(const Twine &, size_t, Error); | |||
| 1267 | ||||
| 1268 | public: | |||
| 1269 | void log(raw_ostream &OS) const override { | |||
| 1270 | assert(Err && "Trying to log after takeError().")(static_cast <bool> (Err && "Trying to log after takeError()." ) ? void (0) : __assert_fail ("Err && \"Trying to log after takeError().\"" , "llvm/include/llvm/Support/Error.h", 1270, __extension__ __PRETTY_FUNCTION__ )); | |||
| 1271 | OS << "'" << FileName << "': "; | |||
| 1272 | if (Line) | |||
| 1273 | OS << "line " << Line.value() << ": "; | |||
| 1274 | Err->log(OS); | |||
| 1275 | } | |||
| 1276 | ||||
| 1277 | std::string messageWithoutFileInfo() const { | |||
| 1278 | std::string Msg; | |||
| 1279 | raw_string_ostream OS(Msg); | |||
| 1280 | Err->log(OS); | |||
| 1281 | return OS.str(); | |||
| 1282 | } | |||
| 1283 | ||||
| 1284 | StringRef getFileName() const { return FileName; } | |||
| 1285 | ||||
| 1286 | Error takeError() { return Error(std::move(Err)); } | |||
| 1287 | ||||
| 1288 | std::error_code convertToErrorCode() const override; | |||
| 1289 | ||||
| 1290 | // Used by ErrorInfo::classID. | |||
| 1291 | static char ID; | |||
| 1292 | ||||
| 1293 | private: | |||
| 1294 | FileError(const Twine &F, Optional<size_t> LineNum, | |||
| 1295 | std::unique_ptr<ErrorInfoBase> E) { | |||
| 1296 | assert(E && "Cannot create FileError from Error success value.")(static_cast <bool> (E && "Cannot create FileError from Error success value." ) ? void (0) : __assert_fail ("E && \"Cannot create FileError from Error success value.\"" , "llvm/include/llvm/Support/Error.h", 1296, __extension__ __PRETTY_FUNCTION__ )); | |||
| 1297 | FileName = F.str(); | |||
| 1298 | Err = std::move(E); | |||
| 1299 | Line = std::move(LineNum); | |||
| 1300 | } | |||
| 1301 | ||||
| 1302 | static Error build(const Twine &F, Optional<size_t> Line, Error E) { | |||
| 1303 | std::unique_ptr<ErrorInfoBase> Payload; | |||
| 1304 | handleAllErrors(std::move(E), | |||
| 1305 | [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error { | |||
| 1306 | Payload = std::move(EIB); | |||
| 1307 | return Error::success(); | |||
| 1308 | }); | |||
| 1309 | return Error( | |||
| 1310 | std::unique_ptr<FileError>(new FileError(F, Line, std::move(Payload)))); | |||
| 1311 | } | |||
| 1312 | ||||
| 1313 | std::string FileName; | |||
| 1314 | Optional<size_t> Line; | |||
| 1315 | std::unique_ptr<ErrorInfoBase> Err; | |||
| 1316 | }; | |||
| 1317 | ||||
| 1318 | /// Concatenate a source file path and/or name with an Error. The resulting | |||
| 1319 | /// Error is unchecked. | |||
| 1320 | inline Error createFileError(const Twine &F, Error E) { | |||
| 1321 | return FileError::build(F, Optional<size_t>(), std::move(E)); | |||
| 1322 | } | |||
| 1323 | ||||
| 1324 | /// Concatenate a source file path and/or name with line number and an Error. | |||
| 1325 | /// The resulting Error is unchecked. | |||
| 1326 | inline Error createFileError(const Twine &F, size_t Line, Error E) { | |||
| 1327 | return FileError::build(F, Optional<size_t>(Line), std::move(E)); | |||
| 1328 | } | |||
| 1329 | ||||
| 1330 | /// Concatenate a source file path and/or name with a std::error_code | |||
| 1331 | /// to form an Error object. | |||
| 1332 | inline Error createFileError(const Twine &F, std::error_code EC) { | |||
| 1333 | return createFileError(F, errorCodeToError(EC)); | |||
| 1334 | } | |||
| 1335 | ||||
| 1336 | /// Concatenate a source file path and/or name with line number and | |||
| 1337 | /// std::error_code to form an Error object. | |||
| 1338 | inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) { | |||
| 1339 | return createFileError(F, Line, errorCodeToError(EC)); | |||
| 1340 | } | |||
| 1341 | ||||
| 1342 | Error createFileError(const Twine &F, ErrorSuccess) = delete; | |||
| 1343 | ||||
| 1344 | /// Helper for check-and-exit error handling. | |||
| 1345 | /// | |||
| 1346 | /// For tool use only. NOT FOR USE IN LIBRARY CODE. | |||
| 1347 | /// | |||
| 1348 | class ExitOnError { | |||
| 1349 | public: | |||
| 1350 | /// Create an error on exit helper. | |||
| 1351 | ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1) | |||
| 1352 | : Banner(std::move(Banner)), | |||
| 1353 | GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {} | |||
| 1354 | ||||
| 1355 | /// Set the banner string for any errors caught by operator(). | |||
| 1356 | void setBanner(std::string Banner) { this->Banner = std::move(Banner); } | |||
| 1357 | ||||
| 1358 | /// Set the exit-code mapper function. | |||
| 1359 | void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) { | |||
| 1360 | this->GetExitCode = std::move(GetExitCode); | |||
| 1361 | } | |||
| 1362 | ||||
| 1363 | /// Check Err. If it's in a failure state log the error(s) and exit. | |||
| 1364 | void operator()(Error Err) const { checkError(std::move(Err)); } | |||
| 1365 | ||||
| 1366 | /// Check E. If it's in a success state then return the contained value. If | |||
| 1367 | /// it's in a failure state log the error(s) and exit. | |||
| 1368 | template <typename T> T operator()(Expected<T> &&E) const { | |||
| 1369 | checkError(E.takeError()); | |||
| 1370 | return std::move(*E); | |||
| 1371 | } | |||
| 1372 | ||||
| 1373 | /// Check E. If it's in a success state then return the contained reference. If | |||
| 1374 | /// it's in a failure state log the error(s) and exit. | |||
| 1375 | template <typename T> T& operator()(Expected<T&> &&E) const { | |||
| 1376 | checkError(E.takeError()); | |||
| 1377 | return *E; | |||
| 1378 | } | |||
| 1379 | ||||
| 1380 | private: | |||
| 1381 | void checkError(Error Err) const { | |||
| 1382 | if (Err) { | |||
| 1383 | int ExitCode = GetExitCode(Err); | |||
| 1384 | logAllUnhandledErrors(std::move(Err), errs(), Banner); | |||
| 1385 | exit(ExitCode); | |||
| 1386 | } | |||
| 1387 | } | |||
| 1388 | ||||
| 1389 | std::string Banner; | |||
| 1390 | std::function<int(const Error &)> GetExitCode; | |||
| 1391 | }; | |||
| 1392 | ||||
| 1393 | /// Conversion from Error to LLVMErrorRef for C error bindings. | |||
| 1394 | inline LLVMErrorRef wrap(Error Err) { | |||
| 1395 | return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release()); | |||
| 1396 | } | |||
| 1397 | ||||
| 1398 | /// Conversion from LLVMErrorRef to Error for C error bindings. | |||
| 1399 | inline Error unwrap(LLVMErrorRef ErrRef) { | |||
| 1400 | return Error(std::unique_ptr<ErrorInfoBase>( | |||
| 1401 | reinterpret_cast<ErrorInfoBase *>(ErrRef))); | |||
| 1402 | } | |||
| 1403 | ||||
| 1404 | } // end namespace llvm | |||
| 1405 | ||||
| 1406 | #endif // LLVM_SUPPORT_ERROR_H |