1258f055eSStefan Gränitz //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===// 2258f055eSStefan Gränitz // 3258f055eSStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4258f055eSStefan Gränitz // See https://llvm.org/LICENSE.txt for license information. 5258f055eSStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6258f055eSStefan Gränitz // 7258f055eSStefan Gränitz //===----------------------------------------------------------------------===// 8258f055eSStefan Gränitz 9258f055eSStefan Gränitz #include "RemoteJITUtils.h" 10258f055eSStefan Gränitz 11258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 12662c5544SLang Hames #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" 13662c5544SLang Hames #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" 14ac2daacbSStefan Gränitz #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h" 15258f055eSStefan Gränitz #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 16258f055eSStefan Gränitz #include "llvm/Support/FileSystem.h" 17258f055eSStefan Gränitz #include "llvm/Support/Path.h" 18258f055eSStefan Gränitz 19258f055eSStefan Gränitz #ifdef LLVM_ON_UNIX 20258f055eSStefan Gränitz #include <netdb.h> 21258f055eSStefan Gränitz #include <netinet/in.h> 22258f055eSStefan Gränitz #include <sys/socket.h> 23258f055eSStefan Gränitz #include <unistd.h> 24258f055eSStefan Gränitz #endif // LLVM_ON_UNIX 25258f055eSStefan Gränitz 26258f055eSStefan Gränitz using namespace llvm; 27258f055eSStefan Gränitz using namespace llvm::orc; 28258f055eSStefan Gränitz 29ac2daacbSStefan Gränitz Error addDebugSupport(ObjectLayer &ObjLayer) { 30ac2daacbSStefan Gränitz ExecutionSession &ES = ObjLayer.getExecutionSession(); 31ac2daacbSStefan Gränitz auto Registrar = createJITLoaderGDBRegistrar(ES); 32258f055eSStefan Gränitz if (!Registrar) 33258f055eSStefan Gränitz return Registrar.takeError(); 34258f055eSStefan Gränitz 35ac2daacbSStefan Gränitz auto *ObjLinkingLayer = cast<ObjectLinkingLayer>(&ObjLayer); 36ac2daacbSStefan Gränitz if (!ObjLinkingLayer) 37ac2daacbSStefan Gränitz return createStringError(inconvertibleErrorCode(), 38ac2daacbSStefan Gränitz "No debug support for given object layer type"); 39258f055eSStefan Gränitz 40ac2daacbSStefan Gränitz ObjLinkingLayer->addPlugin( 41ac2daacbSStefan Gränitz std::make_unique<DebugObjectManagerPlugin>(ES, std::move(*Registrar))); 42258f055eSStefan Gränitz return Error::success(); 43258f055eSStefan Gränitz } 44258f055eSStefan Gränitz 45258f055eSStefan Gränitz Expected<std::unique_ptr<DefinitionGenerator>> 46ac2daacbSStefan Gränitz loadDylib(ExecutionSession &ES, StringRef RemotePath) { 47ac2daacbSStefan Gränitz if (auto Handle = ES.getExecutorProcessControl().loadDylib(RemotePath.data())) 48ac2daacbSStefan Gränitz return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle); 49258f055eSStefan Gränitz else 50258f055eSStefan Gränitz return Handle.takeError(); 51258f055eSStefan Gränitz } 52258f055eSStefan Gränitz 53ac2daacbSStefan Gränitz static void findLocalExecutorHelper() {} 54ac2daacbSStefan Gränitz std::string findLocalExecutor(const char *HostArgv0) { 55ac2daacbSStefan Gränitz // This just needs to be some static symbol in the binary; C++ doesn't 56258f055eSStefan Gränitz // allow taking the address of ::main however. 57ac2daacbSStefan Gränitz uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper); 58ac2daacbSStefan Gränitz void *VoidPtr = reinterpret_cast<void *>(UIntPtr); 59ac2daacbSStefan Gränitz SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr)); 60258f055eSStefan Gränitz sys::path::remove_filename(FullName); 61ac2daacbSStefan Gränitz sys::path::append(FullName, "llvm-jitlink-executor"); 62258f055eSStefan Gränitz return FullName.str().str(); 63258f055eSStefan Gränitz } 64258f055eSStefan Gränitz 65258f055eSStefan Gränitz #ifndef LLVM_ON_UNIX 66258f055eSStefan Gränitz 67258f055eSStefan Gränitz // FIXME: Add support for Windows. 68ac2daacbSStefan Gränitz Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>> 69ac2daacbSStefan Gränitz launchLocalExecutor(StringRef ExecutablePath) { 70258f055eSStefan Gränitz return make_error<StringError>( 71258f055eSStefan Gränitz "Remote JITing not yet supported on non-unix platforms", 72258f055eSStefan Gränitz inconvertibleErrorCode()); 73258f055eSStefan Gränitz } 74258f055eSStefan Gränitz 75258f055eSStefan Gränitz // FIXME: Add support for Windows. 76ac2daacbSStefan Gränitz Expected<std::unique_ptr<SimpleRemoteEPC>> 77ac2daacbSStefan Gränitz connectTCPSocket(StringRef NetworkAddress) { 78258f055eSStefan Gränitz return make_error<StringError>( 79258f055eSStefan Gränitz "Remote JITing not yet supported on non-unix platforms", 80258f055eSStefan Gränitz inconvertibleErrorCode()); 81258f055eSStefan Gränitz } 82258f055eSStefan Gränitz 83258f055eSStefan Gränitz #else 84258f055eSStefan Gränitz 85ac2daacbSStefan Gränitz Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>> 86ac2daacbSStefan Gränitz launchLocalExecutor(StringRef ExecutablePath) { 87258f055eSStefan Gränitz constexpr int ReadEnd = 0; 88258f055eSStefan Gränitz constexpr int WriteEnd = 1; 89258f055eSStefan Gränitz 90ac2daacbSStefan Gränitz if (!sys::fs::can_execute(ExecutablePath)) 91ac2daacbSStefan Gränitz return make_error<StringError>( 92ac2daacbSStefan Gränitz formatv("Specified executor invalid: {0}", ExecutablePath), 93ac2daacbSStefan Gränitz inconvertibleErrorCode()); 94ac2daacbSStefan Gränitz 95258f055eSStefan Gränitz // Pipe FDs. 96258f055eSStefan Gränitz int ToExecutor[2]; 97258f055eSStefan Gränitz int FromExecutor[2]; 98258f055eSStefan Gränitz 99258f055eSStefan Gränitz // Create pipes to/from the executor.. 100258f055eSStefan Gränitz if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) 101258f055eSStefan Gränitz return make_error<StringError>("Unable to create pipe for executor", 102258f055eSStefan Gränitz inconvertibleErrorCode()); 103258f055eSStefan Gränitz 104ac2daacbSStefan Gränitz pid_t ProcessID = fork(); 105258f055eSStefan Gränitz if (ProcessID == 0) { 106258f055eSStefan Gränitz // In the child... 107258f055eSStefan Gränitz 108258f055eSStefan Gränitz // Close the parent ends of the pipes 109258f055eSStefan Gränitz close(ToExecutor[WriteEnd]); 110258f055eSStefan Gränitz close(FromExecutor[ReadEnd]); 111258f055eSStefan Gränitz 112258f055eSStefan Gränitz // Execute the child process. 113258f055eSStefan Gränitz std::unique_ptr<char[]> ExecPath, FDSpecifier; 114258f055eSStefan Gränitz { 115258f055eSStefan Gränitz ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1); 116258f055eSStefan Gränitz strcpy(ExecPath.get(), ExecutablePath.data()); 117258f055eSStefan Gränitz 118258f055eSStefan Gränitz std::string FDSpecifierStr("filedescs="); 119258f055eSStefan Gränitz FDSpecifierStr += utostr(ToExecutor[ReadEnd]); 120258f055eSStefan Gränitz FDSpecifierStr += ','; 121258f055eSStefan Gränitz FDSpecifierStr += utostr(FromExecutor[WriteEnd]); 122258f055eSStefan Gränitz FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); 123258f055eSStefan Gränitz strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); 124258f055eSStefan Gränitz } 125258f055eSStefan Gränitz 126258f055eSStefan Gränitz char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr}; 127258f055eSStefan Gränitz int RC = execvp(ExecPath.get(), Args); 128258f055eSStefan Gränitz if (RC != 0) 129258f055eSStefan Gränitz return make_error<StringError>( 130258f055eSStefan Gränitz "Unable to launch out-of-process executor '" + ExecutablePath + "'\n", 131258f055eSStefan Gränitz inconvertibleErrorCode()); 132258f055eSStefan Gränitz 133258f055eSStefan Gränitz llvm_unreachable("Fork won't return in success case"); 134258f055eSStefan Gränitz } 135258f055eSStefan Gränitz // else we're the parent... 136258f055eSStefan Gränitz 137258f055eSStefan Gränitz // Close the child ends of the pipes 138258f055eSStefan Gränitz close(ToExecutor[ReadEnd]); 139258f055eSStefan Gränitz close(FromExecutor[WriteEnd]); 140258f055eSStefan Gränitz 141ac2daacbSStefan Gränitz auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( 142*2e6c92c5SLang Hames std::make_unique<DynamicThreadPoolTaskDispatcher>(), 143ac2daacbSStefan Gränitz FromExecutor[ReadEnd], ToExecutor[WriteEnd]); 144ac2daacbSStefan Gränitz if (!EPC) 145ac2daacbSStefan Gränitz return EPC.takeError(); 146258f055eSStefan Gränitz 147ac2daacbSStefan Gränitz return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID)); 148258f055eSStefan Gränitz } 149258f055eSStefan Gränitz 150258f055eSStefan Gränitz static Expected<int> connectTCPSocketImpl(std::string Host, 151258f055eSStefan Gränitz std::string PortStr) { 152258f055eSStefan Gränitz addrinfo *AI; 153258f055eSStefan Gränitz addrinfo Hints{}; 154258f055eSStefan Gränitz Hints.ai_family = AF_INET; 155258f055eSStefan Gränitz Hints.ai_socktype = SOCK_STREAM; 156258f055eSStefan Gränitz Hints.ai_flags = AI_NUMERICSERV; 157258f055eSStefan Gränitz 158258f055eSStefan Gränitz if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) 159258f055eSStefan Gränitz return make_error<StringError>( 160258f055eSStefan Gränitz formatv("address resolution failed ({0})", gai_strerror(EC)), 161258f055eSStefan Gränitz inconvertibleErrorCode()); 162258f055eSStefan Gränitz 163258f055eSStefan Gränitz // Cycle through the returned addrinfo structures and connect to the first 164258f055eSStefan Gränitz // reachable endpoint. 165258f055eSStefan Gränitz int SockFD; 166258f055eSStefan Gränitz addrinfo *Server; 167258f055eSStefan Gränitz for (Server = AI; Server != nullptr; Server = Server->ai_next) { 168258f055eSStefan Gränitz // If socket fails, maybe it's because the address family is not supported. 169258f055eSStefan Gränitz // Skip to the next addrinfo structure. 170258f055eSStefan Gränitz if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) 171258f055eSStefan Gränitz continue; 172258f055eSStefan Gränitz 173258f055eSStefan Gränitz // If connect works, we exit the loop with a working socket. 174258f055eSStefan Gränitz if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) 175258f055eSStefan Gränitz break; 176258f055eSStefan Gränitz 177258f055eSStefan Gränitz close(SockFD); 178258f055eSStefan Gränitz } 179258f055eSStefan Gränitz freeaddrinfo(AI); 180258f055eSStefan Gränitz 181258f055eSStefan Gränitz // Did we reach the end of the loop without connecting to a valid endpoint? 182258f055eSStefan Gränitz if (Server == nullptr) 183258f055eSStefan Gränitz return make_error<StringError>("invalid hostname", 184258f055eSStefan Gränitz inconvertibleErrorCode()); 185258f055eSStefan Gränitz 186258f055eSStefan Gränitz return SockFD; 187258f055eSStefan Gränitz } 188258f055eSStefan Gränitz 189ac2daacbSStefan Gränitz Expected<std::unique_ptr<SimpleRemoteEPC>> 190ac2daacbSStefan Gränitz connectTCPSocket(StringRef NetworkAddress) { 191258f055eSStefan Gränitz auto CreateErr = [NetworkAddress](StringRef Details) { 192258f055eSStefan Gränitz return make_error<StringError>( 193258f055eSStefan Gränitz formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress, 194258f055eSStefan Gränitz Details), 195258f055eSStefan Gränitz inconvertibleErrorCode()); 196258f055eSStefan Gränitz }; 197258f055eSStefan Gränitz 198258f055eSStefan Gränitz StringRef Host, PortStr; 199258f055eSStefan Gränitz std::tie(Host, PortStr) = NetworkAddress.split(':'); 200258f055eSStefan Gränitz if (Host.empty()) 201258f055eSStefan Gränitz return CreateErr("host name cannot be empty"); 202258f055eSStefan Gränitz if (PortStr.empty()) 203258f055eSStefan Gränitz return CreateErr("port cannot be empty"); 204258f055eSStefan Gränitz int Port = 0; 205258f055eSStefan Gränitz if (PortStr.getAsInteger(10, Port)) 206258f055eSStefan Gränitz return CreateErr("port number is not a valid integer"); 207258f055eSStefan Gränitz 208258f055eSStefan Gränitz Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str()); 209258f055eSStefan Gränitz if (!SockFD) 210258f055eSStefan Gränitz return CreateErr(toString(SockFD.takeError())); 211258f055eSStefan Gränitz 212*2e6c92c5SLang Hames return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( 213*2e6c92c5SLang Hames std::make_unique<DynamicThreadPoolTaskDispatcher>(), *SockFD); 214258f055eSStefan Gränitz } 215258f055eSStefan Gränitz 216258f055eSStefan Gränitz #endif 217