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 Expected
<std::unique_ptr
<DefinitionGenerator
>>
31 loadDylib(ExecutionSession
&ES
, StringRef RemotePath
) {
32 if (auto Handle
= ES
.getExecutorProcessControl().getDylibMgr().loadDylib(
34 return std::make_unique
<EPCDynamicLibrarySearchGenerator
>(ES
, *Handle
);
36 return Handle
.takeError();
39 static void findLocalExecutorHelper() {}
40 std::string
findLocalExecutor(const char *HostArgv0
) {
41 // This just needs to be some static symbol in the binary; C++ doesn't
42 // allow taking the address of ::main however.
43 uintptr_t UIntPtr
= reinterpret_cast<uintptr_t>(&findLocalExecutorHelper
);
44 void *VoidPtr
= reinterpret_cast<void *>(UIntPtr
);
45 SmallString
<256> FullName(sys::fs::getMainExecutable(HostArgv0
, VoidPtr
));
46 sys::path::remove_filename(FullName
);
47 sys::path::append(FullName
, "llvm-jitlink-executor");
48 return FullName
.str().str();
53 // FIXME: Add support for Windows.
54 Expected
<std::pair
<std::unique_ptr
<SimpleRemoteEPC
>, uint64_t>>
55 launchLocalExecutor(StringRef ExecutablePath
) {
56 return make_error
<StringError
>(
57 "Remote JITing not yet supported on non-unix platforms",
58 inconvertibleErrorCode());
61 // FIXME: Add support for Windows.
62 Expected
<std::unique_ptr
<SimpleRemoteEPC
>>
63 connectTCPSocket(StringRef NetworkAddress
) {
64 return make_error
<StringError
>(
65 "Remote JITing not yet supported on non-unix platforms",
66 inconvertibleErrorCode());
71 Expected
<std::pair
<std::unique_ptr
<SimpleRemoteEPC
>, uint64_t>>
72 launchLocalExecutor(StringRef ExecutablePath
) {
73 constexpr int ReadEnd
= 0;
74 constexpr int WriteEnd
= 1;
76 if (!sys::fs::can_execute(ExecutablePath
))
77 return make_error
<StringError
>(
78 formatv("Specified executor invalid: {0}", ExecutablePath
),
79 inconvertibleErrorCode());
85 // Create pipes to/from the executor..
86 if (pipe(ToExecutor
) != 0 || pipe(FromExecutor
) != 0)
87 return make_error
<StringError
>("Unable to create pipe for executor",
88 inconvertibleErrorCode());
90 pid_t ProcessID
= fork();
94 // Close the parent ends of the pipes
95 close(ToExecutor
[WriteEnd
]);
96 close(FromExecutor
[ReadEnd
]);
98 // Execute the child process.
99 std::unique_ptr
<char[]> ExecPath
, FDSpecifier
, TestOutputFlag
;
101 ExecPath
= std::make_unique
<char[]>(ExecutablePath
.size() + 1);
102 strcpy(ExecPath
.get(), ExecutablePath
.data());
104 const char *TestOutputFlagStr
= "test-jitloadergdb";
105 TestOutputFlag
= std::make_unique
<char[]>(strlen(TestOutputFlagStr
) + 1);
106 strcpy(TestOutputFlag
.get(), TestOutputFlagStr
);
108 std::string
FDSpecifierStr("filedescs=");
109 FDSpecifierStr
+= utostr(ToExecutor
[ReadEnd
]);
110 FDSpecifierStr
+= ',';
111 FDSpecifierStr
+= utostr(FromExecutor
[WriteEnd
]);
112 FDSpecifier
= std::make_unique
<char[]>(FDSpecifierStr
.size() + 1);
113 strcpy(FDSpecifier
.get(), FDSpecifierStr
.c_str());
116 char *const Args
[] = {ExecPath
.get(), TestOutputFlag
.get(),
117 FDSpecifier
.get(), nullptr};
118 int RC
= execvp(ExecPath
.get(), Args
);
120 return make_error
<StringError
>(
121 "Unable to launch out-of-process executor '" + ExecutablePath
+ "'\n",
122 inconvertibleErrorCode());
124 llvm_unreachable("Fork won't return in success case");
126 // else we're the parent...
128 // Close the child ends of the pipes
129 close(ToExecutor
[ReadEnd
]);
130 close(FromExecutor
[WriteEnd
]);
132 auto EPC
= SimpleRemoteEPC::Create
<FDSimpleRemoteEPCTransport
>(
133 std::make_unique
<DynamicThreadPoolTaskDispatcher
>(std::nullopt
),
134 SimpleRemoteEPC::Setup(),
135 FromExecutor
[ReadEnd
], ToExecutor
[WriteEnd
]);
137 return EPC
.takeError();
139 return std::make_pair(std::move(*EPC
), static_cast<uint64_t>(ProcessID
));
142 static Expected
<int> connectTCPSocketImpl(std::string Host
,
143 std::string PortStr
) {
146 Hints
.ai_family
= AF_INET
;
147 Hints
.ai_socktype
= SOCK_STREAM
;
148 Hints
.ai_flags
= AI_NUMERICSERV
;
150 if (int EC
= getaddrinfo(Host
.c_str(), PortStr
.c_str(), &Hints
, &AI
))
151 return make_error
<StringError
>(
152 formatv("address resolution failed ({0})", gai_strerror(EC
)),
153 inconvertibleErrorCode());
155 // Cycle through the returned addrinfo structures and connect to the first
156 // reachable endpoint.
159 for (Server
= AI
; Server
!= nullptr; Server
= Server
->ai_next
) {
160 // If socket fails, maybe it's because the address family is not supported.
161 // Skip to the next addrinfo structure.
162 if ((SockFD
= socket(AI
->ai_family
, AI
->ai_socktype
, AI
->ai_protocol
)) < 0)
165 // If connect works, we exit the loop with a working socket.
166 if (connect(SockFD
, Server
->ai_addr
, Server
->ai_addrlen
) == 0)
173 // Did we reach the end of the loop without connecting to a valid endpoint?
174 if (Server
== nullptr)
175 return make_error
<StringError
>("invalid hostname",
176 inconvertibleErrorCode());
181 Expected
<std::unique_ptr
<SimpleRemoteEPC
>>
182 connectTCPSocket(StringRef NetworkAddress
) {
183 auto CreateErr
= [NetworkAddress
](StringRef Details
) {
184 return make_error
<StringError
>(
185 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress
,
187 inconvertibleErrorCode());
190 StringRef Host
, PortStr
;
191 std::tie(Host
, PortStr
) = NetworkAddress
.split(':');
193 return CreateErr("host name cannot be empty");
195 return CreateErr("port cannot be empty");
197 if (PortStr
.getAsInteger(10, Port
))
198 return CreateErr("port number is not a valid integer");
200 Expected
<int> SockFD
= connectTCPSocketImpl(Host
.str(), PortStr
.str());
202 return CreateErr(toString(SockFD
.takeError()));
204 return SimpleRemoteEPC::Create
<FDSimpleRemoteEPCTransport
>(
205 std::make_unique
<DynamicThreadPoolTaskDispatcher
>(std::nullopt
),
206 SimpleRemoteEPC::Setup(), *SockFD
);