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/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 12 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" 13 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" 14 #include "llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h" 15 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h" 16 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 17 #include "llvm/Support/FileSystem.h" 18 #include "llvm/Support/Path.h" 19 #include "llvm/Support/ToolOutputFile.h" 20 21 #ifdef LLVM_ON_UNIX 22 #include <netdb.h> 23 #include <netinet/in.h> 24 #include <sys/socket.h> 25 #include <unistd.h> 26 #endif // LLVM_ON_UNIX 27 28 using namespace llvm; 29 using namespace llvm::orc; 30 31 namespace llvm { 32 namespace orc { 33 34 class RemoteExecutorProcessControl 35 : public OrcRPCExecutorProcessControlBase< 36 shared::MultiThreadedRPCEndpoint<JITLinkExecutor::RPCChannel>> { 37 public: 38 using RPCChannel = JITLinkExecutor::RPCChannel; 39 using RPCEndpoint = shared::MultiThreadedRPCEndpoint<RPCChannel>; 40 41 private: 42 using ThisT = RemoteExecutorProcessControl; 43 using BaseT = OrcRPCExecutorProcessControlBase<RPCEndpoint>; 44 using MemoryAccess = OrcRPCEPCMemoryAccess<ThisT>; 45 using MemoryManager = OrcRPCEPCJITLinkMemoryManager<ThisT>; 46 47 public: 48 using BaseT::initializeORCRPCEPCBase; 49 50 RemoteExecutorProcessControl(std::unique_ptr<RPCChannel> Channel, 51 std::unique_ptr<RPCEndpoint> Endpoint, 52 BaseT::ErrorReporter ReportError); 53 54 void initializeMemoryManagement(); 55 Error disconnect() override; 56 57 private: 58 std::unique_ptr<RPCChannel> Channel; 59 std::unique_ptr<RPCEndpoint> Endpoint; 60 std::unique_ptr<MemoryAccess> OwnedMemAccess; 61 std::unique_ptr<MemoryManager> OwnedMemMgr; 62 std::atomic<bool> Finished{false}; 63 std::thread ListenerThread; 64 }; 65 66 RemoteExecutorProcessControl::RemoteExecutorProcessControl( 67 std::unique_ptr<RPCChannel> Channel, std::unique_ptr<RPCEndpoint> Endpoint, 68 BaseT::ErrorReporter ReportError) 69 : BaseT(std::make_shared<SymbolStringPool>(), *Endpoint, 70 std::move(ReportError)), 71 Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) { 72 73 ListenerThread = std::thread([&]() { 74 while (!Finished) { 75 if (auto Err = this->Endpoint->handleOne()) { 76 reportError(std::move(Err)); 77 return; 78 } 79 } 80 }); 81 } 82 83 void RemoteExecutorProcessControl::initializeMemoryManagement() { 84 OwnedMemAccess = std::make_unique<MemoryAccess>(*this); 85 OwnedMemMgr = std::make_unique<MemoryManager>(*this); 86 87 // Base class needs non-owning access. 88 MemAccess = OwnedMemAccess.get(); 89 MemMgr = OwnedMemMgr.get(); 90 } 91 92 Error RemoteExecutorProcessControl::disconnect() { 93 std::promise<MSVCPError> P; 94 auto F = P.get_future(); 95 auto Err = closeConnection([&](Error Err) -> Error { 96 P.set_value(std::move(Err)); 97 Finished = true; 98 return Error::success(); 99 }); 100 ListenerThread.join(); 101 return joinErrors(std::move(Err), F.get()); 102 } 103 104 } // namespace orc 105 } // namespace llvm 106 107 JITLinkExecutor::JITLinkExecutor() = default; 108 JITLinkExecutor::~JITLinkExecutor() = default; 109 110 Expected<std::unique_ptr<ObjectLayer>> 111 JITLinkExecutor::operator()(ExecutionSession &ES, const Triple &TT) { 112 assert(EPC && "RemoteExecutorProcessControl must be initialized"); 113 return std::make_unique<ObjectLinkingLayer>(ES, EPC->getMemMgr()); 114 } 115 116 std::unique_ptr<ExecutionSession> JITLinkExecutor::startSession() { 117 assert(OwnedEPC && "RemoteExecutorProcessControl must be initialized"); 118 return std::make_unique<ExecutionSession>(std::move(OwnedEPC)); 119 } 120 121 Error JITLinkExecutor::addDebugSupport(ObjectLayer &ObjLayer) { 122 auto Registrar = createJITLoaderGDBRegistrar(EPC->getExecutionSession()); 123 if (!Registrar) 124 return Registrar.takeError(); 125 126 cast<ObjectLinkingLayer>(&ObjLayer)->addPlugin( 127 std::make_unique<DebugObjectManagerPlugin>(ObjLayer.getExecutionSession(), 128 std::move(*Registrar))); 129 130 return Error::success(); 131 } 132 133 Expected<std::unique_ptr<DefinitionGenerator>> 134 JITLinkExecutor::loadDylib(StringRef RemotePath) { 135 if (auto Handle = EPC->loadDylib(RemotePath.data())) 136 return std::make_unique<EPCDynamicLibrarySearchGenerator>( 137 EPC->getExecutionSession(), *Handle); 138 else 139 return Handle.takeError(); 140 } 141 142 Expected<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym, 143 ArrayRef<std::string> Args) { 144 return EPC->runAsMain(MainSym.getAddress(), Args); 145 } 146 147 Error JITLinkExecutor::disconnect() { return EPC->disconnect(); } 148 149 static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName) { 150 // This just needs to be some symbol in the binary; C++ doesn't 151 // allow taking the address of ::main however. 152 void *P = (void *)(intptr_t)defaultPath; 153 SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, P)); 154 sys::path::remove_filename(FullName); 155 sys::path::append(FullName, ExecutorName); 156 return FullName.str().str(); 157 } 158 159 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>> 160 JITLinkExecutor::FindLocal(const char *HostArgv) { 161 std::string BestGuess = defaultPath(HostArgv, "llvm-jitlink-executor"); 162 auto Executor = CreateLocal(BestGuess); 163 if (!Executor) { 164 consumeError(Executor.takeError()); 165 return make_error<StringError>( 166 formatv("Unable to find usable executor: {0}", BestGuess), 167 inconvertibleErrorCode()); 168 } 169 return Executor; 170 } 171 172 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>> 173 JITLinkExecutor::CreateLocal(std::string ExecutablePath) { 174 if (!sys::fs::can_execute(ExecutablePath)) 175 return make_error<StringError>( 176 formatv("Specified executor invalid: {0}", ExecutablePath), 177 inconvertibleErrorCode()); 178 return std::unique_ptr<ChildProcessJITLinkExecutor>( 179 new ChildProcessJITLinkExecutor(std::move(ExecutablePath))); 180 } 181 182 TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor( 183 std::unique_ptr<RemoteExecutorProcessControl> EPC) { 184 this->OwnedEPC = std::move(EPC); 185 this->EPC = this->OwnedEPC.get(); 186 } 187 188 #ifndef LLVM_ON_UNIX 189 190 // FIXME: Add support for Windows. 191 Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) { 192 return make_error<StringError>( 193 "Remote JITing not yet supported on non-unix platforms", 194 inconvertibleErrorCode()); 195 } 196 197 // FIXME: Add support for Windows. 198 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>> 199 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress, 200 ExecutionSession &ES) { 201 return make_error<StringError>( 202 "Remote JITing not yet supported on non-unix platforms", 203 inconvertibleErrorCode()); 204 } 205 206 #else 207 208 Error ChildProcessJITLinkExecutor::launch( 209 unique_function<void(Error)> ErrorReporter) { 210 constexpr int ReadEnd = 0; 211 constexpr int WriteEnd = 1; 212 213 // Pipe FDs. 214 int ToExecutor[2]; 215 int FromExecutor[2]; 216 217 // Create pipes to/from the executor.. 218 if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) 219 return make_error<StringError>("Unable to create pipe for executor", 220 inconvertibleErrorCode()); 221 222 ProcessID = fork(); 223 if (ProcessID == 0) { 224 // In the child... 225 226 // Close the parent ends of the pipes 227 close(ToExecutor[WriteEnd]); 228 close(FromExecutor[ReadEnd]); 229 230 // Execute the child process. 231 std::unique_ptr<char[]> ExecPath, FDSpecifier; 232 { 233 ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1); 234 strcpy(ExecPath.get(), ExecutablePath.data()); 235 236 std::string FDSpecifierStr("filedescs="); 237 FDSpecifierStr += utostr(ToExecutor[ReadEnd]); 238 FDSpecifierStr += ','; 239 FDSpecifierStr += utostr(FromExecutor[WriteEnd]); 240 FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); 241 strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); 242 } 243 244 char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr}; 245 int RC = execvp(ExecPath.get(), Args); 246 if (RC != 0) 247 return make_error<StringError>( 248 "Unable to launch out-of-process executor '" + ExecutablePath + "'\n", 249 inconvertibleErrorCode()); 250 251 llvm_unreachable("Fork won't return in success case"); 252 } 253 // else we're the parent... 254 255 // Close the child ends of the pipes 256 close(ToExecutor[ReadEnd]); 257 close(FromExecutor[WriteEnd]); 258 259 auto Channel = 260 std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]); 261 auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>( 262 *Channel, true); 263 264 OwnedEPC = std::make_unique<RemoteExecutorProcessControl>( 265 std::move(Channel), std::move(Endpoint), std::move(ErrorReporter)); 266 267 if (auto Err = OwnedEPC->initializeORCRPCEPCBase()) 268 return joinErrors(std::move(Err), OwnedEPC->disconnect()); 269 270 OwnedEPC->initializeMemoryManagement(); 271 EPC = OwnedEPC.get(); 272 273 shared::registerStringError<RPCChannel>(); 274 return Error::success(); 275 } 276 277 static Expected<int> connectTCPSocketImpl(std::string Host, 278 std::string PortStr) { 279 addrinfo *AI; 280 addrinfo Hints{}; 281 Hints.ai_family = AF_INET; 282 Hints.ai_socktype = SOCK_STREAM; 283 Hints.ai_flags = AI_NUMERICSERV; 284 285 if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) 286 return make_error<StringError>( 287 formatv("address resolution failed ({0})", gai_strerror(EC)), 288 inconvertibleErrorCode()); 289 290 // Cycle through the returned addrinfo structures and connect to the first 291 // reachable endpoint. 292 int SockFD; 293 addrinfo *Server; 294 for (Server = AI; Server != nullptr; Server = Server->ai_next) { 295 // If socket fails, maybe it's because the address family is not supported. 296 // Skip to the next addrinfo structure. 297 if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) 298 continue; 299 300 // If connect works, we exit the loop with a working socket. 301 if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) 302 break; 303 304 close(SockFD); 305 } 306 freeaddrinfo(AI); 307 308 // Did we reach the end of the loop without connecting to a valid endpoint? 309 if (Server == nullptr) 310 return make_error<StringError>("invalid hostname", 311 inconvertibleErrorCode()); 312 313 return SockFD; 314 } 315 316 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>> 317 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress, 318 unique_function<void(Error)> ErrorReporter) { 319 auto CreateErr = [NetworkAddress](StringRef Details) { 320 return make_error<StringError>( 321 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress, 322 Details), 323 inconvertibleErrorCode()); 324 }; 325 326 StringRef Host, PortStr; 327 std::tie(Host, PortStr) = NetworkAddress.split(':'); 328 if (Host.empty()) 329 return CreateErr("host name cannot be empty"); 330 if (PortStr.empty()) 331 return CreateErr("port cannot be empty"); 332 int Port = 0; 333 if (PortStr.getAsInteger(10, Port)) 334 return CreateErr("port number is not a valid integer"); 335 336 Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str()); 337 if (!SockFD) 338 return CreateErr(toString(SockFD.takeError())); 339 340 auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD); 341 auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>( 342 *Channel, true); 343 344 auto EPC = std::make_unique<RemoteExecutorProcessControl>( 345 std::move(Channel), std::move(Endpoint), std::move(ErrorReporter)); 346 347 if (auto Err = EPC->initializeORCRPCEPCBase()) 348 return joinErrors(std::move(Err), EPC->disconnect()); 349 350 EPC->initializeMemoryManagement(); 351 shared::registerStringError<RPCChannel>(); 352 353 return std::unique_ptr<TCPSocketJITLinkExecutor>( 354 new TCPSocketJITLinkExecutor(std::move(EPC))); 355 } 356 357 #endif 358