1 //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "RemoteJITUtils.h"
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"
22 #include <netinet/in.h>
23 #include <sys/socket.h>
25 #endif // LLVM_ON_UNIX
28 using namespace llvm::orc
;
30 Error
addDebugSupport(ObjectLayer
&ObjLayer
) {
31 ExecutionSession
&ES
= ObjLayer
.getExecutionSession();
32 auto Registrar
= createJITLoaderGDBRegistrar(ES
);
34 return Registrar
.takeError();
36 auto *ObjLinkingLayer
= cast
<ObjectLinkingLayer
>(&ObjLayer
);
38 return createStringError(inconvertibleErrorCode(),
39 "No debug support for given object layer type");
41 ObjLinkingLayer
->addPlugin(std::make_unique
<DebugObjectManagerPlugin
>(
42 ES
, std::move(*Registrar
), true, true));
43 return Error::success();
46 Expected
<std::unique_ptr
<DefinitionGenerator
>>
47 loadDylib(ExecutionSession
&ES
, StringRef RemotePath
) {
48 if (auto Handle
= ES
.getExecutorProcessControl().loadDylib(RemotePath
.data()))
49 return std::make_unique
<EPCDynamicLibrarySearchGenerator
>(ES
, *Handle
);
51 return Handle
.takeError();
54 static void findLocalExecutorHelper() {}
55 std::string
findLocalExecutor(const char *HostArgv0
) {
56 // This just needs to be some static symbol in the binary; C++ doesn't
57 // allow taking the address of ::main however.
58 uintptr_t UIntPtr
= reinterpret_cast<uintptr_t>(&findLocalExecutorHelper
);
59 void *VoidPtr
= reinterpret_cast<void *>(UIntPtr
);
60 SmallString
<256> FullName(sys::fs::getMainExecutable(HostArgv0
, VoidPtr
));
61 sys::path::remove_filename(FullName
);
62 sys::path::append(FullName
, "llvm-jitlink-executor");
63 return FullName
.str().str();
68 // FIXME: Add support for Windows.
69 Expected
<std::pair
<std::unique_ptr
<SimpleRemoteEPC
>, uint64_t>>
70 launchLocalExecutor(StringRef ExecutablePath
) {
71 return make_error
<StringError
>(
72 "Remote JITing not yet supported on non-unix platforms",
73 inconvertibleErrorCode());
76 // FIXME: Add support for Windows.
77 Expected
<std::unique_ptr
<SimpleRemoteEPC
>>
78 connectTCPSocket(StringRef NetworkAddress
) {
79 return make_error
<StringError
>(
80 "Remote JITing not yet supported on non-unix platforms",
81 inconvertibleErrorCode());
86 Expected
<std::pair
<std::unique_ptr
<SimpleRemoteEPC
>, uint64_t>>
87 launchLocalExecutor(StringRef ExecutablePath
) {
88 constexpr int ReadEnd
= 0;
89 constexpr int WriteEnd
= 1;
91 if (!sys::fs::can_execute(ExecutablePath
))
92 return make_error
<StringError
>(
93 formatv("Specified executor invalid: {0}", ExecutablePath
),
94 inconvertibleErrorCode());
100 // Create pipes to/from the executor..
101 if (pipe(ToExecutor
) != 0 || pipe(FromExecutor
) != 0)
102 return make_error
<StringError
>("Unable to create pipe for executor",
103 inconvertibleErrorCode());
105 pid_t ProcessID
= fork();
106 if (ProcessID
== 0) {
109 // Close the parent ends of the pipes
110 close(ToExecutor
[WriteEnd
]);
111 close(FromExecutor
[ReadEnd
]);
113 // Execute the child process.
114 std::unique_ptr
<char[]> ExecPath
, FDSpecifier
;
116 ExecPath
= std::make_unique
<char[]>(ExecutablePath
.size() + 1);
117 strcpy(ExecPath
.get(), ExecutablePath
.data());
119 std::string
FDSpecifierStr("filedescs=");
120 FDSpecifierStr
+= utostr(ToExecutor
[ReadEnd
]);
121 FDSpecifierStr
+= ',';
122 FDSpecifierStr
+= utostr(FromExecutor
[WriteEnd
]);
123 FDSpecifier
= std::make_unique
<char[]>(FDSpecifierStr
.size() + 1);
124 strcpy(FDSpecifier
.get(), FDSpecifierStr
.c_str());
127 char *const Args
[] = {ExecPath
.get(), FDSpecifier
.get(), nullptr};
128 int RC
= execvp(ExecPath
.get(), Args
);
130 return make_error
<StringError
>(
131 "Unable to launch out-of-process executor '" + ExecutablePath
+ "'\n",
132 inconvertibleErrorCode());
134 llvm_unreachable("Fork won't return in success case");
136 // else we're the parent...
138 // Close the child ends of the pipes
139 close(ToExecutor
[ReadEnd
]);
140 close(FromExecutor
[WriteEnd
]);
142 auto EPC
= SimpleRemoteEPC::Create
<FDSimpleRemoteEPCTransport
>(
143 std::make_unique
<DynamicThreadPoolTaskDispatcher
>(),
144 SimpleRemoteEPC::Setup(),
145 FromExecutor
[ReadEnd
], ToExecutor
[WriteEnd
]);
147 return EPC
.takeError();
149 return std::make_pair(std::move(*EPC
), static_cast<uint64_t>(ProcessID
));
152 static Expected
<int> connectTCPSocketImpl(std::string Host
,
153 std::string PortStr
) {
156 Hints
.ai_family
= AF_INET
;
157 Hints
.ai_socktype
= SOCK_STREAM
;
158 Hints
.ai_flags
= AI_NUMERICSERV
;
160 if (int EC
= getaddrinfo(Host
.c_str(), PortStr
.c_str(), &Hints
, &AI
))
161 return make_error
<StringError
>(
162 formatv("address resolution failed ({0})", gai_strerror(EC
)),
163 inconvertibleErrorCode());
165 // Cycle through the returned addrinfo structures and connect to the first
166 // reachable endpoint.
169 for (Server
= AI
; Server
!= nullptr; Server
= Server
->ai_next
) {
170 // If socket fails, maybe it's because the address family is not supported.
171 // Skip to the next addrinfo structure.
172 if ((SockFD
= socket(AI
->ai_family
, AI
->ai_socktype
, AI
->ai_protocol
)) < 0)
175 // If connect works, we exit the loop with a working socket.
176 if (connect(SockFD
, Server
->ai_addr
, Server
->ai_addrlen
) == 0)
183 // Did we reach the end of the loop without connecting to a valid endpoint?
184 if (Server
== nullptr)
185 return make_error
<StringError
>("invalid hostname",
186 inconvertibleErrorCode());
191 Expected
<std::unique_ptr
<SimpleRemoteEPC
>>
192 connectTCPSocket(StringRef NetworkAddress
) {
193 auto CreateErr
= [NetworkAddress
](StringRef Details
) {
194 return make_error
<StringError
>(
195 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress
,
197 inconvertibleErrorCode());
200 StringRef Host
, PortStr
;
201 std::tie(Host
, PortStr
) = NetworkAddress
.split(':');
203 return CreateErr("host name cannot be empty");
205 return CreateErr("port cannot be empty");
207 if (PortStr
.getAsInteger(10, Port
))
208 return CreateErr("port number is not a valid integer");
210 Expected
<int> SockFD
= connectTCPSocketImpl(Host
.str(), PortStr
.str());
212 return CreateErr(toString(SockFD
.takeError()));
214 return SimpleRemoteEPC::Create
<FDSimpleRemoteEPCTransport
>(
215 std::make_unique
<DynamicThreadPoolTaskDispatcher
>(),
216 SimpleRemoteEPC::Setup(), *SockFD
);