1 //===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink -===//
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 // Simple out-of-process executor for llvm-jitlink.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
15 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
16 #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
17 #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/DynamicLibrary.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/MathExtras.h"
22 #include "llvm/Support/raw_ostream.h"
29 #include <netinet/in.h>
30 #include <sys/socket.h>
35 using namespace llvm::orc
;
37 ExitOnError ExitOnErr
;
39 LLVM_ATTRIBUTE_USED
void linkComponents() {
40 errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
41 << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
42 << (void *)&llvm_orc_registerJITLoaderGDBWrapper
;
45 void printErrorAndExit(Twine ErrMsg
) {
47 const char *DebugOption
= "[debug] ";
49 const char *DebugOption
= "";
52 errs() << "error: " << ErrMsg
.str() << "\n\n"
54 << " llvm-jitlink-executor " << DebugOption
55 << "filedescs=<infd>,<outfd> [args...]\n"
56 << " llvm-jitlink-executor " << DebugOption
57 << "listen=<host>:<port> [args...]\n";
61 int openListener(std::string Host
, std::string PortStr
) {
63 // FIXME: Add TCP support for Windows.
64 printErrorAndExit("listen option not supported");
68 Hints
.ai_family
= AF_INET
;
69 Hints
.ai_socktype
= SOCK_STREAM
;
70 Hints
.ai_flags
= AI_PASSIVE
;
73 if (int EC
= getaddrinfo(nullptr, PortStr
.c_str(), &Hints
, &AI
)) {
74 errs() << "Error setting up bind address: " << gai_strerror(EC
) << "\n";
78 // Create a socket from first addrinfo structure returned by getaddrinfo.
80 if ((SockFD
= socket(AI
->ai_family
, AI
->ai_socktype
, AI
->ai_protocol
)) < 0) {
81 errs() << "Error creating socket: " << std::strerror(errno
) << "\n";
85 // Avoid "Address already in use" errors.
87 if (setsockopt(SockFD
, SOL_SOCKET
, SO_REUSEADDR
, &Yes
, sizeof(int)) == -1) {
88 errs() << "Error calling setsockopt: " << std::strerror(errno
) << "\n";
92 // Bind the socket to the desired port.
93 if (bind(SockFD
, AI
->ai_addr
, AI
->ai_addrlen
) < 0) {
94 errs() << "Error on binding: " << std::strerror(errno
) << "\n";
98 // Listen for incomming connections.
99 static constexpr int ConnectionQueueLen
= 1;
100 listen(SockFD
, ConnectionQueueLen
);
103 assert(Hi_32(AI
->ai_addrlen
) == 0 && "Field is a size_t on 64-bit AIX");
104 socklen_t AddrLen
= Lo_32(AI
->ai_addrlen
);
105 return accept(SockFD
, AI
->ai_addr
, &AddrLen
);
107 return accept(SockFD
, AI
->ai_addr
, &AI
->ai_addrlen
);
110 #endif // LLVM_ON_UNIX
113 int main(int argc
, char *argv
[]) {
114 #if LLVM_ENABLE_THREADS
116 ExitOnErr
.setBanner(std::string(argv
[0]) + ": ");
118 unsigned FirstProgramArg
= 1;
123 printErrorAndExit("insufficient arguments");
126 StringRef ConnectArg
= argv
[FirstProgramArg
++];
128 if (ConnectArg
== "debug") {
130 ConnectArg
= argv
[FirstProgramArg
++];
134 StringRef SpecifierType
, Specifier
;
135 std::tie(SpecifierType
, Specifier
) = ConnectArg
.split('=');
136 if (SpecifierType
== "filedescs") {
137 StringRef FD1Str
, FD2Str
;
138 std::tie(FD1Str
, FD2Str
) = Specifier
.split(',');
139 if (FD1Str
.getAsInteger(10, InFD
))
140 printErrorAndExit(FD1Str
+ " is not a valid file descriptor");
141 if (FD2Str
.getAsInteger(10, OutFD
))
142 printErrorAndExit(FD2Str
+ " is not a valid file descriptor");
143 } else if (SpecifierType
== "listen") {
144 StringRef Host
, PortStr
;
145 std::tie(Host
, PortStr
) = Specifier
.split(':');
148 if (PortStr
.getAsInteger(10, Port
))
149 printErrorAndExit("port number '" + PortStr
+
150 "' is not a valid integer");
152 InFD
= OutFD
= openListener(Host
.str(), PortStr
.str());
154 printErrorAndExit("invalid specifier type \"" + SpecifierType
+ "\"");
158 ExitOnErr(SimpleRemoteEPCServer::Create
<FDSimpleRemoteEPCTransport
>(
159 [](SimpleRemoteEPCServer::Setup
&S
) -> Error
{
161 std::make_unique
<SimpleRemoteEPCServer::ThreadDispatcher
>());
162 S
.bootstrapSymbols() =
163 SimpleRemoteEPCServer::defaultBootstrapSymbols();
164 S
.services().push_back(
165 std::make_unique
<rt_bootstrap::SimpleExecutorMemoryManager
>());
166 return Error::success();
170 ExitOnErr(Server
->waitForDisconnect());
175 << " error: this tool requires threads, but LLVM was "
176 "built with LLVM_ENABLE_THREADS=Off\n";