123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- //===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink -===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Simple out-of-process executor for llvm-jitlink.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/DynamicLibrary.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/MathExtras.h"
- #include "llvm/Support/raw_ostream.h"
- #include <cstring>
- #include <sstream>
- #ifdef LLVM_ON_UNIX
- #include <netdb.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #endif
- using namespace llvm;
- using namespace llvm::orc;
- ExitOnError ExitOnErr;
- LLVM_ATTRIBUTE_USED void linkComponents() {
- errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
- << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
- << (void *)&llvm_orc_registerJITLoaderGDBWrapper
- << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
- }
- void printErrorAndExit(Twine ErrMsg) {
- #ifndef NDEBUG
- const char *DebugOption = "[debug] ";
- #else
- const char *DebugOption = "";
- #endif
- errs() << "error: " << ErrMsg.str() << "\n\n"
- << "Usage:\n"
- << " llvm-jitlink-executor " << DebugOption
- << "filedescs=<infd>,<outfd> [args...]\n"
- << " llvm-jitlink-executor " << DebugOption
- << "listen=<host>:<port> [args...]\n";
- exit(1);
- }
- int openListener(std::string Host, std::string PortStr) {
- #ifndef LLVM_ON_UNIX
- // FIXME: Add TCP support for Windows.
- printErrorAndExit("listen option not supported");
- return 0;
- #else
- addrinfo Hints{};
- Hints.ai_family = AF_INET;
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_flags = AI_PASSIVE;
- addrinfo *AI;
- if (int EC = getaddrinfo(nullptr, PortStr.c_str(), &Hints, &AI)) {
- errs() << "Error setting up bind address: " << gai_strerror(EC) << "\n";
- exit(1);
- }
- // Create a socket from first addrinfo structure returned by getaddrinfo.
- int SockFD;
- if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) {
- errs() << "Error creating socket: " << std::strerror(errno) << "\n";
- exit(1);
- }
- // Avoid "Address already in use" errors.
- const int Yes = 1;
- if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
- errs() << "Error calling setsockopt: " << std::strerror(errno) << "\n";
- exit(1);
- }
- // Bind the socket to the desired port.
- if (bind(SockFD, AI->ai_addr, AI->ai_addrlen) < 0) {
- errs() << "Error on binding: " << std::strerror(errno) << "\n";
- exit(1);
- }
- // Listen for incomming connections.
- static constexpr int ConnectionQueueLen = 1;
- listen(SockFD, ConnectionQueueLen);
- #if defined(_AIX)
- assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");
- socklen_t AddrLen = Lo_32(AI->ai_addrlen);
- return accept(SockFD, AI->ai_addr, &AddrLen);
- #else
- return accept(SockFD, AI->ai_addr, &AI->ai_addrlen);
- #endif
- #endif // LLVM_ON_UNIX
- }
- int main(int argc, char *argv[]) {
- #if LLVM_ENABLE_THREADS
- ExitOnErr.setBanner(std::string(argv[0]) + ": ");
- unsigned FirstProgramArg = 1;
- int InFD = 0;
- int OutFD = 0;
- if (argc < 2)
- printErrorAndExit("insufficient arguments");
- else {
- StringRef ConnectArg = argv[FirstProgramArg++];
- #ifndef NDEBUG
- if (ConnectArg == "debug") {
- DebugFlag = true;
- ConnectArg = argv[FirstProgramArg++];
- }
- #endif
- StringRef SpecifierType, Specifier;
- std::tie(SpecifierType, Specifier) = ConnectArg.split('=');
- if (SpecifierType == "filedescs") {
- StringRef FD1Str, FD2Str;
- std::tie(FD1Str, FD2Str) = Specifier.split(',');
- if (FD1Str.getAsInteger(10, InFD))
- printErrorAndExit(FD1Str + " is not a valid file descriptor");
- if (FD2Str.getAsInteger(10, OutFD))
- printErrorAndExit(FD2Str + " is not a valid file descriptor");
- } else if (SpecifierType == "listen") {
- StringRef Host, PortStr;
- std::tie(Host, PortStr) = Specifier.split(':');
- int Port = 0;
- if (PortStr.getAsInteger(10, Port))
- printErrorAndExit("port number '" + PortStr +
- "' is not a valid integer");
- InFD = OutFD = openListener(Host.str(), PortStr.str());
- } else
- printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
- }
- auto Server =
- ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(
- [](SimpleRemoteEPCServer::Setup &S) -> Error {
- S.setDispatcher(
- std::make_unique<SimpleRemoteEPCServer::ThreadDispatcher>());
- S.bootstrapSymbols() =
- SimpleRemoteEPCServer::defaultBootstrapSymbols();
- S.services().push_back(
- std::make_unique<rt_bootstrap::SimpleExecutorMemoryManager>());
- S.services().push_back(
- std::make_unique<
- rt_bootstrap::ExecutorSharedMemoryMapperService>());
- return Error::success();
- },
- InFD, OutFD));
- ExitOnErr(Server->waitForDisconnect());
- return 0;
- #else
- errs() << argv[0]
- << " error: this tool requires threads, but LLVM was "
- "built with LLVM_ENABLE_THREADS=Off\n";
- return 1;
- #endif
- }
|