xref: /llvm-project/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp (revision ef2389235c5dec03be93f8c9585cd9416767ef4c)
1 //===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink -===//
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 // Simple out-of-process executor for llvm-jitlink.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
15 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
16 #include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
17 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
18 #include "llvm/Support/DynamicLibrary.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <sstream>
22 
23 #ifdef LLVM_ON_UNIX
24 
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 
28 #endif
29 
30 using namespace llvm;
31 using namespace llvm::orc;
32 
33 ExitOnError ExitOnErr;
34 
35 LLVM_ATTRIBUTE_USED void linkComponents() {
36   errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
37          << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
38          << (void *)&llvm_orc_registerJITLoaderGDBWrapper;
39 }
40 
41 void printErrorAndExit(Twine ErrMsg) {
42   errs() << "error: " << ErrMsg.str() << "\n\n"
43          << "Usage:\n"
44          << "  llvm-jitlink-executor filedescs=<infd>,<outfd> [args...]\n"
45          << "  llvm-jitlink-executor listen=<host>:<port> [args...]\n";
46   exit(1);
47 }
48 
49 int openListener(std::string Host, int Port) {
50 #ifndef LLVM_ON_UNIX
51   // FIXME: Add TCP support for Windows.
52   printErrorAndExit("listen option not supported");
53   return 0;
54 #else
55   int SockFD = socket(PF_INET, SOCK_STREAM, 0);
56   struct sockaddr_in ServerAddr, ClientAddr;
57   socklen_t ClientAddrLen = sizeof(ClientAddr);
58   memset(&ServerAddr, 0, sizeof(ServerAddr));
59   ServerAddr.sin_family = PF_INET;
60   ServerAddr.sin_family = INADDR_ANY;
61   ServerAddr.sin_port = htons(Port);
62 
63   {
64     // lose the "Address already in use" error message
65     int Yes = 1;
66     if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
67       errs() << "Error calling setsockopt.\n";
68       exit(1);
69     }
70   }
71 
72   if (bind(SockFD, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) < 0) {
73     errs() << "Error on binding.\n";
74     exit(1);
75   }
76 
77   listen(SockFD, 1);
78   return accept(SockFD, (struct sockaddr *)&ClientAddr, &ClientAddrLen);
79 #endif
80 }
81 
82 int main(int argc, char *argv[]) {
83 
84   ExitOnErr.setBanner(std::string(argv[0]) + ": ");
85 
86   int InFD = 0;
87   int OutFD = 0;
88 
89   if (argc < 2)
90     printErrorAndExit("insufficient arguments");
91   else {
92     StringRef Arg1 = argv[1];
93     StringRef SpecifierType, Specifier;
94     std::tie(SpecifierType, Specifier) = Arg1.split('=');
95     if (SpecifierType == "filedescs") {
96       StringRef FD1Str, FD2Str;
97       std::tie(FD1Str, FD2Str) = Specifier.split(',');
98       if (FD1Str.getAsInteger(10, InFD))
99         printErrorAndExit(FD1Str + " is not a valid file descriptor");
100       if (FD2Str.getAsInteger(10, OutFD))
101         printErrorAndExit(FD2Str + " is not a valid file descriptor");
102     } else if (SpecifierType == "listen") {
103       StringRef Host, PortStr;
104       std::tie(Host, PortStr) = Specifier.split(':');
105 
106       int Port = 0;
107       if (PortStr.getAsInteger(10, Port))
108         printErrorAndExit("port" + PortStr + " is not a valid integer");
109 
110       InFD = OutFD = openListener(Host.str(), Port);
111     } else
112       printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
113   }
114 
115   ExitOnErr.setBanner(std::string(argv[0]) + ":");
116 
117   using JITLinkExecutorEndpoint =
118       shared::MultiThreadedRPCEndpoint<shared::FDRawByteChannel>;
119 
120   shared::registerStringError<shared::FDRawByteChannel>();
121 
122   shared::FDRawByteChannel C(InFD, OutFD);
123   JITLinkExecutorEndpoint EP(C, true);
124   OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
125   Server.setProgramName(std::string("llvm-jitlink-executor"));
126 
127   ExitOnErr(Server.run());
128 
129   return 0;
130 }
131