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