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