1 //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- 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 #include "RemoteJITUtils.h" 10 11 #include "llvm/ADT/StringExtras.h" 12 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 13 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" 14 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" 15 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h" 16 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 17 #include "llvm/Support/FileSystem.h" 18 #include "llvm/Support/Path.h" 19 20 #ifdef LLVM_ON_UNIX 21 #include <netdb.h> 22 #include <netinet/in.h> 23 #include <sys/socket.h> 24 #include <unistd.h> 25 #endif // LLVM_ON_UNIX 26 27 using namespace llvm; 28 using namespace llvm::orc; 29 30 Expected<std::unique_ptr<DefinitionGenerator>> 31 loadDylib(ExecutionSession &ES, StringRef RemotePath) { 32 if (auto Handle = ES.getExecutorProcessControl().getDylibMgr().loadDylib( 33 RemotePath.data())) 34 return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle); 35 else 36 return Handle.takeError(); 37 } 38 39 static void findLocalExecutorHelper() {} 40 std::string findLocalExecutor(const char *HostArgv0) { 41 // This just needs to be some static symbol in the binary; C++ doesn't 42 // allow taking the address of ::main however. 43 uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper); 44 void *VoidPtr = reinterpret_cast<void *>(UIntPtr); 45 SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr)); 46 sys::path::remove_filename(FullName); 47 sys::path::append(FullName, "llvm-jitlink-executor"); 48 return FullName.str().str(); 49 } 50 51 #ifndef LLVM_ON_UNIX 52 53 // FIXME: Add support for Windows. 54 Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>> 55 launchLocalExecutor(StringRef ExecutablePath) { 56 return make_error<StringError>( 57 "Remote JITing not yet supported on non-unix platforms", 58 inconvertibleErrorCode()); 59 } 60 61 // FIXME: Add support for Windows. 62 Expected<std::unique_ptr<SimpleRemoteEPC>> 63 connectTCPSocket(StringRef NetworkAddress) { 64 return make_error<StringError>( 65 "Remote JITing not yet supported on non-unix platforms", 66 inconvertibleErrorCode()); 67 } 68 69 #else 70 71 Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>> 72 launchLocalExecutor(StringRef ExecutablePath) { 73 constexpr int ReadEnd = 0; 74 constexpr int WriteEnd = 1; 75 76 if (!sys::fs::can_execute(ExecutablePath)) 77 return make_error<StringError>( 78 formatv("Specified executor invalid: {0}", ExecutablePath), 79 inconvertibleErrorCode()); 80 81 // Pipe FDs. 82 int ToExecutor[2]; 83 int FromExecutor[2]; 84 85 // Create pipes to/from the executor.. 86 if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) 87 return make_error<StringError>("Unable to create pipe for executor", 88 inconvertibleErrorCode()); 89 90 pid_t ProcessID = fork(); 91 if (ProcessID == 0) { 92 // In the child... 93 94 // Close the parent ends of the pipes 95 close(ToExecutor[WriteEnd]); 96 close(FromExecutor[ReadEnd]); 97 98 // Execute the child process. 99 std::unique_ptr<char[]> ExecPath, FDSpecifier, TestOutputFlag; 100 { 101 ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1); 102 strcpy(ExecPath.get(), ExecutablePath.data()); 103 104 const char *TestOutputFlagStr = "test-jitloadergdb"; 105 TestOutputFlag = std::make_unique<char[]>(strlen(TestOutputFlagStr) + 1); 106 strcpy(TestOutputFlag.get(), TestOutputFlagStr); 107 108 std::string FDSpecifierStr("filedescs="); 109 FDSpecifierStr += utostr(ToExecutor[ReadEnd]); 110 FDSpecifierStr += ','; 111 FDSpecifierStr += utostr(FromExecutor[WriteEnd]); 112 FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); 113 strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); 114 } 115 116 char *const Args[] = {ExecPath.get(), TestOutputFlag.get(), 117 FDSpecifier.get(), nullptr}; 118 int RC = execvp(ExecPath.get(), Args); 119 if (RC != 0) 120 return make_error<StringError>( 121 "Unable to launch out-of-process executor '" + ExecutablePath + "'\n", 122 inconvertibleErrorCode()); 123 124 llvm_unreachable("Fork won't return in success case"); 125 } 126 // else we're the parent... 127 128 // Close the child ends of the pipes 129 close(ToExecutor[ReadEnd]); 130 close(FromExecutor[WriteEnd]); 131 132 auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( 133 std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt), 134 SimpleRemoteEPC::Setup(), 135 FromExecutor[ReadEnd], ToExecutor[WriteEnd]); 136 if (!EPC) 137 return EPC.takeError(); 138 139 return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID)); 140 } 141 142 static Expected<int> connectTCPSocketImpl(std::string Host, 143 std::string PortStr) { 144 addrinfo *AI; 145 addrinfo Hints{}; 146 Hints.ai_family = AF_INET; 147 Hints.ai_socktype = SOCK_STREAM; 148 Hints.ai_flags = AI_NUMERICSERV; 149 150 if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) 151 return make_error<StringError>( 152 formatv("address resolution failed ({0})", gai_strerror(EC)), 153 inconvertibleErrorCode()); 154 155 // Cycle through the returned addrinfo structures and connect to the first 156 // reachable endpoint. 157 int SockFD; 158 addrinfo *Server; 159 for (Server = AI; Server != nullptr; Server = Server->ai_next) { 160 // If socket fails, maybe it's because the address family is not supported. 161 // Skip to the next addrinfo structure. 162 if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) 163 continue; 164 165 // If connect works, we exit the loop with a working socket. 166 if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) 167 break; 168 169 close(SockFD); 170 } 171 freeaddrinfo(AI); 172 173 // Did we reach the end of the loop without connecting to a valid endpoint? 174 if (Server == nullptr) 175 return make_error<StringError>("invalid hostname", 176 inconvertibleErrorCode()); 177 178 return SockFD; 179 } 180 181 Expected<std::unique_ptr<SimpleRemoteEPC>> 182 connectTCPSocket(StringRef NetworkAddress) { 183 auto CreateErr = [NetworkAddress](StringRef Details) { 184 return make_error<StringError>( 185 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress, 186 Details), 187 inconvertibleErrorCode()); 188 }; 189 190 StringRef Host, PortStr; 191 std::tie(Host, PortStr) = NetworkAddress.split(':'); 192 if (Host.empty()) 193 return CreateErr("host name cannot be empty"); 194 if (PortStr.empty()) 195 return CreateErr("port cannot be empty"); 196 int Port = 0; 197 if (PortStr.getAsInteger(10, Port)) 198 return CreateErr("port number is not a valid integer"); 199 200 Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str()); 201 if (!SockFD) 202 return CreateErr(toString(SockFD.takeError())); 203 204 return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( 205 std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt), 206 SimpleRemoteEPC::Setup(), *SockFD); 207 } 208 209 #endif 210