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