brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 2cffca2 Raw
221 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Simple out-of-process executor for llvm-jitlink.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/StringRef.h"14#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX, LLVM_ENABLE_THREADS15#include "llvm/ExecutionEngine/Orc/TargetProcess/DefaultHostBootstrapValues.h"16#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"17#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"18#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"19#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"20#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"21#include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h"22#include "llvm/Support/Compiler.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/DynamicLibrary.h"25#include "llvm/Support/Error.h"26#include "llvm/Support/MathExtras.h"27#include "llvm/Support/raw_ostream.h"28#include <cstring>29#include <sstream>30 31#ifdef LLVM_ON_UNIX32 33#include <netdb.h>34#include <netinet/in.h>35#include <sys/socket.h>36 37#endif38 39using namespace llvm;40using namespace llvm::orc;41 42ExitOnError ExitOnErr;43 44LLVM_ATTRIBUTE_USED void linkComponents() {45  errs() << (void *)&llvm_orc_registerEHFrameSectionAllocAction46         << (void *)&llvm_orc_deregisterEHFrameSectionAllocAction47         << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;48}49 50void printErrorAndExit(Twine ErrMsg) {51#ifndef NDEBUG52  const char *DebugOption = "[debug] ";53#else54  const char *DebugOption = "";55#endif56 57  errs() << "error: " << ErrMsg.str() << "\n\n"58         << "Usage:\n"59         << "  llvm-jitlink-executor " << DebugOption60         << "[test-jitloadergdb] filedescs=<infd>,<outfd> [args...]\n"61         << "  llvm-jitlink-executor " << DebugOption62         << "[test-jitloadergdb] listen=<host>:<port> [args...]\n";63  exit(1);64}65 66int openListener(std::string Host, std::string PortStr) {67#ifndef LLVM_ON_UNIX68  // FIXME: Add TCP support for Windows.69  printErrorAndExit("listen option not supported");70  return 0;71#else72  addrinfo Hints{};73  Hints.ai_family = AF_INET;74  Hints.ai_socktype = SOCK_STREAM;75  Hints.ai_flags = AI_PASSIVE;76 77  addrinfo *AI;78  if (int EC = getaddrinfo(nullptr, PortStr.c_str(), &Hints, &AI)) {79    errs() << "Error setting up bind address: " << gai_strerror(EC) << "\n";80    exit(1);81  }82 83  // Create a socket from first addrinfo structure returned by getaddrinfo.84  int SockFD;85  if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) {86    errs() << "Error creating socket: " << std::strerror(errno) << "\n";87    exit(1);88  }89 90  // Avoid "Address already in use" errors.91  const int Yes = 1;92  if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {93    errs() << "Error calling setsockopt: " << std::strerror(errno) << "\n";94    exit(1);95  }96 97  // Bind the socket to the desired port.98  if (bind(SockFD, AI->ai_addr, AI->ai_addrlen) < 0) {99    errs() << "Error on binding: " << std::strerror(errno) << "\n";100    exit(1);101  }102 103  // Listen for incomming connections.104  static constexpr int ConnectionQueueLen = 1;105  listen(SockFD, ConnectionQueueLen);106 107#if defined(_AIX)108  assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");109  socklen_t AddrLen = Lo_32(AI->ai_addrlen);110  return accept(SockFD, AI->ai_addr, &AddrLen);111#else112  return accept(SockFD, AI->ai_addr, &AI->ai_addrlen);113#endif114 115#endif // LLVM_ON_UNIX116}117 118#if LLVM_ENABLE_THREADS119 120// JITLink debug support plugins put information about JITed code in this GDB121// JIT Interface global from OrcTargetProcess.122extern "C" LLVM_ABI struct jit_descriptor __jit_debug_descriptor;123 124static void *findLastDebugDescriptorEntryPtr() {125  struct jit_code_entry *Last = __jit_debug_descriptor.first_entry;126  while (Last && Last->next_entry)127    Last = Last->next_entry;128  return Last;129}130 131#endif132 133int main(int argc, char *argv[]) {134#if LLVM_ENABLE_THREADS135 136  ExitOnErr.setBanner(std::string(argv[0]) + ": ");137 138  unsigned FirstProgramArg = 1;139  int InFD = 0;140  int OutFD = 0;141 142  if (argc < 2)143    printErrorAndExit("insufficient arguments");144 145  StringRef NextArg = argv[FirstProgramArg++];146#ifndef NDEBUG147  if (NextArg == "debug") {148    DebugFlag = true;149    NextArg = argv[FirstProgramArg++];150  }151#endif152 153  std::vector<StringRef> TestOutputFlags;154  while (NextArg.starts_with("test-")) {155    TestOutputFlags.push_back(NextArg);156    NextArg = argv[FirstProgramArg++];157  }158 159  if (llvm::is_contained(TestOutputFlags, "test-jitloadergdb"))160    fprintf(stderr, "__jit_debug_descriptor.last_entry = 0x%016" PRIx64 "\n",161            pointerToJITTargetAddress(findLastDebugDescriptorEntryPtr()));162 163  StringRef SpecifierType, Specifier;164  std::tie(SpecifierType, Specifier) = NextArg.split('=');165  if (SpecifierType == "filedescs") {166    StringRef FD1Str, FD2Str;167    std::tie(FD1Str, FD2Str) = Specifier.split(',');168    if (FD1Str.getAsInteger(10, InFD))169      printErrorAndExit(FD1Str + " is not a valid file descriptor");170    if (FD2Str.getAsInteger(10, OutFD))171      printErrorAndExit(FD2Str + " is not a valid file descriptor");172  } else if (SpecifierType == "listen") {173    StringRef Host, PortStr;174    std::tie(Host, PortStr) = Specifier.split(':');175 176    int Port = 0;177    if (PortStr.getAsInteger(10, Port))178      printErrorAndExit("port number '" + PortStr + "' is not a valid integer");179 180    InFD = OutFD = openListener(Host.str(), PortStr.str());181  } else182    printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");183 184  auto Server =185      ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(186          [](SimpleRemoteEPCServer::Setup &S) -> Error {187            S.setDispatcher(188                std::make_unique<SimpleRemoteEPCServer::ThreadDispatcher>());189            S.bootstrapSymbols() =190                SimpleRemoteEPCServer::defaultBootstrapSymbols();191            addDefaultBootstrapValuesForHostProcess(S.bootstrapMap(),192                                                    S.bootstrapSymbols());193#ifdef __APPLE__194            if (UnwindInfoManager::TryEnable())195              UnwindInfoManager::addBootstrapSymbols(S.bootstrapSymbols());196#endif // __APPLE__197            S.services().push_back(198                std::make_unique<rt_bootstrap::SimpleExecutorMemoryManager>());199            S.services().push_back(200                std::make_unique<201                    rt_bootstrap::ExecutorSharedMemoryMapperService>());202            return Error::success();203          },204          InFD, OutFD));205 206  ExitOnErr(Server->waitForDisconnect());207 208  if (llvm::is_contained(TestOutputFlags, "test-jitloadergdb"))209    fprintf(stderr, "__jit_debug_descriptor.last_entry = 0x%016" PRIx64 "\n",210            pointerToJITTargetAddress(findLastDebugDescriptorEntryPtr()));211 212  return 0;213 214#else215  errs() << argv[0]216         << " error: this tool requires threads, but LLVM was "217            "built with LLVM_ENABLE_THREADS=Off\n";218  return 1;219#endif220}221