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(ExecutionSession &ES,
51                                std::unique_ptr<RPCChannel> Channel,
52                                std::unique_ptr<RPCEndpoint> Endpoint);
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 
RemoteExecutorProcessControl(ExecutionSession & ES,std::unique_ptr<RPCChannel> Channel,std::unique_ptr<RPCEndpoint> Endpoint)66 RemoteExecutorProcessControl::RemoteExecutorProcessControl(
67     ExecutionSession &ES, std::unique_ptr<RPCChannel> Channel,
68     std::unique_ptr<RPCEndpoint> Endpoint)
69     : BaseT(ES.getSymbolStringPool(), *Endpoint,
70             [&ES](Error Err) { ES.reportError(std::move(Err)); }),
71       Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
72 
__anonec7c0e3e0202() 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 
initializeMemoryManagement()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 
disconnect()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>>
operator ()(ExecutionSession & ES,const Triple & TT)111 JITLinkExecutor::operator()(ExecutionSession &ES, const Triple &TT) {
112   return std::make_unique<ObjectLinkingLayer>(ES, EPC->getMemMgr());
113 }
114 
addDebugSupport(ObjectLayer & ObjLayer)115 Error JITLinkExecutor::addDebugSupport(ObjectLayer &ObjLayer) {
116   auto Registrar = createJITLoaderGDBRegistrar(*EPC);
117   if (!Registrar)
118     return Registrar.takeError();
119 
120   cast<ObjectLinkingLayer>(&ObjLayer)->addPlugin(
121       std::make_unique<DebugObjectManagerPlugin>(ObjLayer.getExecutionSession(),
122                                                  std::move(*Registrar)));
123 
124   return Error::success();
125 }
126 
127 Expected<std::unique_ptr<DefinitionGenerator>>
loadDylib(StringRef RemotePath)128 JITLinkExecutor::loadDylib(StringRef RemotePath) {
129   if (auto Handle = EPC->loadDylib(RemotePath.data()))
130     return std::make_unique<EPCDynamicLibrarySearchGenerator>(*EPC, *Handle);
131   else
132     return Handle.takeError();
133 }
134 
runAsMain(JITEvaluatedSymbol MainSym,ArrayRef<std::string> Args)135 Expected<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym,
136                                          ArrayRef<std::string> Args) {
137   return EPC->runAsMain(MainSym.getAddress(), Args);
138 }
139 
disconnect()140 Error JITLinkExecutor::disconnect() { return EPC->disconnect(); }
141 
defaultPath(const char * HostArgv0,StringRef ExecutorName)142 static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName) {
143   // This just needs to be some symbol in the binary; C++ doesn't
144   // allow taking the address of ::main however.
145   void *P = (void *)(intptr_t)defaultPath;
146   SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, P));
147   sys::path::remove_filename(FullName);
148   sys::path::append(FullName, ExecutorName);
149   return FullName.str().str();
150 }
151 
152 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>>
FindLocal(const char * HostArgv)153 JITLinkExecutor::FindLocal(const char *HostArgv) {
154   std::string BestGuess = defaultPath(HostArgv, "llvm-jitlink-executor");
155   auto Executor = CreateLocal(BestGuess);
156   if (!Executor) {
157     consumeError(Executor.takeError());
158     return make_error<StringError>(
159         formatv("Unable to find usable executor: {0}", BestGuess),
160         inconvertibleErrorCode());
161   }
162   return Executor;
163 }
164 
165 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>>
CreateLocal(std::string ExecutablePath)166 JITLinkExecutor::CreateLocal(std::string ExecutablePath) {
167   if (!sys::fs::can_execute(ExecutablePath))
168     return make_error<StringError>(
169         formatv("Specified executor invalid: {0}", ExecutablePath),
170         inconvertibleErrorCode());
171   return std::unique_ptr<ChildProcessJITLinkExecutor>(
172       new ChildProcessJITLinkExecutor(std::move(ExecutablePath)));
173 }
174 
TCPSocketJITLinkExecutor(std::unique_ptr<RemoteExecutorProcessControl> EPC)175 TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor(
176     std::unique_ptr<RemoteExecutorProcessControl> EPC) {
177   this->EPC = std::move(EPC);
178 }
179 
180 #ifndef LLVM_ON_UNIX
181 
182 // FIXME: Add support for Windows.
launch(ExecutionSession & ES)183 Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {
184   return make_error<StringError>(
185       "Remote JITing not yet supported on non-unix platforms",
186       inconvertibleErrorCode());
187 }
188 
189 // FIXME: Add support for Windows.
190 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>>
ConnectTCPSocket(StringRef NetworkAddress,ExecutionSession & ES)191 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,
192                                   ExecutionSession &ES) {
193   return make_error<StringError>(
194       "Remote JITing not yet supported on non-unix platforms",
195       inconvertibleErrorCode());
196 }
197 
198 #else
199 
launch(ExecutionSession & ES)200 Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {
201   constexpr int ReadEnd = 0;
202   constexpr int WriteEnd = 1;
203 
204   // Pipe FDs.
205   int ToExecutor[2];
206   int FromExecutor[2];
207 
208   // Create pipes to/from the executor..
209   if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
210     return make_error<StringError>("Unable to create pipe for executor",
211                                    inconvertibleErrorCode());
212 
213   ProcessID = fork();
214   if (ProcessID == 0) {
215     // In the child...
216 
217     // Close the parent ends of the pipes
218     close(ToExecutor[WriteEnd]);
219     close(FromExecutor[ReadEnd]);
220 
221     // Execute the child process.
222     std::unique_ptr<char[]> ExecPath, FDSpecifier;
223     {
224       ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
225       strcpy(ExecPath.get(), ExecutablePath.data());
226 
227       std::string FDSpecifierStr("filedescs=");
228       FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
229       FDSpecifierStr += ',';
230       FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
231       FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
232       strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
233     }
234 
235     char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr};
236     int RC = execvp(ExecPath.get(), Args);
237     if (RC != 0)
238       return make_error<StringError>(
239           "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",
240           inconvertibleErrorCode());
241 
242     llvm_unreachable("Fork won't return in success case");
243   }
244   // else we're the parent...
245 
246   // Close the child ends of the pipes
247   close(ToExecutor[ReadEnd]);
248   close(FromExecutor[WriteEnd]);
249 
250   auto Channel =
251       std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
252   auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>(
253       *Channel, true);
254 
255   EPC = std::make_unique<RemoteExecutorProcessControl>(ES, std::move(Channel),
256                                                        std::move(Endpoint));
257 
258   if (auto Err = EPC->initializeORCRPCEPCBase())
259     return joinErrors(std::move(Err), EPC->disconnect());
260 
261   EPC->initializeMemoryManagement();
262 
263   shared::registerStringError<RPCChannel>();
264   return Error::success();
265 }
266 
connectTCPSocketImpl(std::string Host,std::string PortStr)267 static Expected<int> connectTCPSocketImpl(std::string Host,
268                                           std::string PortStr) {
269   addrinfo *AI;
270   addrinfo Hints{};
271   Hints.ai_family = AF_INET;
272   Hints.ai_socktype = SOCK_STREAM;
273   Hints.ai_flags = AI_NUMERICSERV;
274 
275   if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
276     return make_error<StringError>(
277         formatv("address resolution failed ({0})", gai_strerror(EC)),
278         inconvertibleErrorCode());
279 
280   // Cycle through the returned addrinfo structures and connect to the first
281   // reachable endpoint.
282   int SockFD;
283   addrinfo *Server;
284   for (Server = AI; Server != nullptr; Server = Server->ai_next) {
285     // If socket fails, maybe it's because the address family is not supported.
286     // Skip to the next addrinfo structure.
287     if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
288       continue;
289 
290     // If connect works, we exit the loop with a working socket.
291     if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
292       break;
293 
294     close(SockFD);
295   }
296   freeaddrinfo(AI);
297 
298   // Did we reach the end of the loop without connecting to a valid endpoint?
299   if (Server == nullptr)
300     return make_error<StringError>("invalid hostname",
301                                    inconvertibleErrorCode());
302 
303   return SockFD;
304 }
305 
306 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>>
ConnectTCPSocket(StringRef NetworkAddress,ExecutionSession & ES)307 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,
308                                   ExecutionSession &ES) {
309   auto CreateErr = [NetworkAddress](StringRef Details) {
310     return make_error<StringError>(
311         formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
312                 Details),
313         inconvertibleErrorCode());
314   };
315 
316   StringRef Host, PortStr;
317   std::tie(Host, PortStr) = NetworkAddress.split(':');
318   if (Host.empty())
319     return CreateErr("host name cannot be empty");
320   if (PortStr.empty())
321     return CreateErr("port cannot be empty");
322   int Port = 0;
323   if (PortStr.getAsInteger(10, Port))
324     return CreateErr("port number is not a valid integer");
325 
326   Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
327   if (!SockFD)
328     return CreateErr(toString(SockFD.takeError()));
329 
330   auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD);
331   auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>(
332       *Channel, true);
333 
334   auto EPC = std::make_unique<RemoteExecutorProcessControl>(
335       ES, std::move(Channel), std::move(Endpoint));
336 
337   if (auto Err = EPC->initializeORCRPCEPCBase())
338     return joinErrors(std::move(Err), EPC->disconnect());
339 
340   EPC->initializeMemoryManagement();
341   shared::registerStringError<RPCChannel>();
342 
343   return std::unique_ptr<TCPSocketJITLinkExecutor>(
344       new TCPSocketJITLinkExecutor(std::move(EPC)));
345 }
346 
347 #endif
348