brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · 6e2aaf3 Raw
209 lines · cpp
1//===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//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#include "RemoteJITUtils.h"10 11#include "llvm/ADT/StringExtras.h"12#include "llvm/ExecutionEngine/Orc/Debugging/ELFDebugObjectPlugin.h"13#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"14#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"15#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Path.h"18 19#ifdef LLVM_ON_UNIX20#include <netdb.h>21#include <netinet/in.h>22#include <sys/socket.h>23#include <unistd.h>24#endif // LLVM_ON_UNIX25 26using namespace llvm;27using namespace llvm::orc;28 29Expected<std::unique_ptr<DefinitionGenerator>>30loadDylib(ExecutionSession &ES, StringRef RemotePath) {31  if (auto Handle = ES.getExecutorProcessControl().getDylibMgr().loadDylib(32          RemotePath.data()))33    return std::make_unique<EPCDynamicLibrarySearchGenerator>(ES, *Handle);34  else35    return Handle.takeError();36}37 38static void findLocalExecutorHelper() {}39std::string findLocalExecutor(const char *HostArgv0) {40  // This just needs to be some static symbol in the binary; C++ doesn't41  // allow taking the address of ::main however.42  uintptr_t UIntPtr = reinterpret_cast<uintptr_t>(&findLocalExecutorHelper);43  void *VoidPtr = reinterpret_cast<void *>(UIntPtr);44  SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, VoidPtr));45  sys::path::remove_filename(FullName);46  sys::path::append(FullName, "llvm-jitlink-executor");47  return FullName.str().str();48}49 50#ifndef LLVM_ON_UNIX51 52// FIXME: Add support for Windows.53Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>54launchLocalExecutor(StringRef ExecutablePath) {55  return make_error<StringError>(56      "Remote JITing not yet supported on non-unix platforms",57      inconvertibleErrorCode());58}59 60// FIXME: Add support for Windows.61Expected<std::unique_ptr<SimpleRemoteEPC>>62connectTCPSocket(StringRef NetworkAddress) {63  return make_error<StringError>(64      "Remote JITing not yet supported on non-unix platforms",65      inconvertibleErrorCode());66}67 68#else69 70Expected<std::pair<std::unique_ptr<SimpleRemoteEPC>, uint64_t>>71launchLocalExecutor(StringRef ExecutablePath) {72  constexpr int ReadEnd = 0;73  constexpr int WriteEnd = 1;74 75  if (!sys::fs::can_execute(ExecutablePath))76    return make_error<StringError>(77        formatv("Specified executor invalid: {0}", ExecutablePath),78        inconvertibleErrorCode());79 80  // Pipe FDs.81  int ToExecutor[2];82  int FromExecutor[2];83 84  // Create pipes to/from the executor..85  if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)86    return make_error<StringError>("Unable to create pipe for executor",87                                   inconvertibleErrorCode());88 89  pid_t ProcessID = fork();90  if (ProcessID == 0) {91    // In the child...92 93    // Close the parent ends of the pipes94    close(ToExecutor[WriteEnd]);95    close(FromExecutor[ReadEnd]);96 97    // Execute the child process.98    std::unique_ptr<char[]> ExecPath, FDSpecifier, TestOutputFlag;99    {100      ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);101      strcpy(ExecPath.get(), ExecutablePath.data());102 103      const char *TestOutputFlagStr = "test-jitloadergdb";104      TestOutputFlag = std::make_unique<char[]>(strlen(TestOutputFlagStr) + 1);105      strcpy(TestOutputFlag.get(), TestOutputFlagStr);106 107      std::string FDSpecifierStr("filedescs=");108      FDSpecifierStr += utostr(ToExecutor[ReadEnd]);109      FDSpecifierStr += ',';110      FDSpecifierStr += utostr(FromExecutor[WriteEnd]);111      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);112      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());113    }114 115    char *const Args[] = {ExecPath.get(), TestOutputFlag.get(),116                          FDSpecifier.get(), nullptr};117    int RC = execvp(ExecPath.get(), Args);118    if (RC != 0)119      return make_error<StringError>(120          "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",121          inconvertibleErrorCode());122 123    llvm_unreachable("Fork won't return in success case");124  }125  // else we're the parent...126 127  // Close the child ends of the pipes128  close(ToExecutor[ReadEnd]);129  close(FromExecutor[WriteEnd]);130 131  auto EPC = SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(132      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),133      SimpleRemoteEPC::Setup(),134      FromExecutor[ReadEnd], ToExecutor[WriteEnd]);135  if (!EPC)136    return EPC.takeError();137 138  return std::make_pair(std::move(*EPC), static_cast<uint64_t>(ProcessID));139}140 141static Expected<int> connectTCPSocketImpl(std::string Host,142                                          std::string PortStr) {143  addrinfo *AI;144  addrinfo Hints{};145  Hints.ai_family = AF_INET;146  Hints.ai_socktype = SOCK_STREAM;147  Hints.ai_flags = AI_NUMERICSERV;148 149  if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))150    return make_error<StringError>(151        formatv("address resolution failed ({0})", gai_strerror(EC)),152        inconvertibleErrorCode());153 154  // Cycle through the returned addrinfo structures and connect to the first155  // reachable endpoint.156  int SockFD;157  addrinfo *Server;158  for (Server = AI; Server != nullptr; Server = Server->ai_next) {159    // If socket fails, maybe it's because the address family is not supported.160    // Skip to the next addrinfo structure.161    if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)162      continue;163 164    // If connect works, we exit the loop with a working socket.165    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)166      break;167 168    close(SockFD);169  }170  freeaddrinfo(AI);171 172  // Did we reach the end of the loop without connecting to a valid endpoint?173  if (Server == nullptr)174    return make_error<StringError>("invalid hostname",175                                   inconvertibleErrorCode());176 177  return SockFD;178}179 180Expected<std::unique_ptr<SimpleRemoteEPC>>181connectTCPSocket(StringRef NetworkAddress) {182  auto CreateErr = [NetworkAddress](StringRef Details) {183    return make_error<StringError>(184        formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,185                Details),186        inconvertibleErrorCode());187  };188 189  StringRef Host, PortStr;190  std::tie(Host, PortStr) = NetworkAddress.split(':');191  if (Host.empty())192    return CreateErr("host name cannot be empty");193  if (PortStr.empty())194    return CreateErr("port cannot be empty");195  int Port = 0;196  if (PortStr.getAsInteger(10, Port))197    return CreateErr("port number is not a valid integer");198 199  Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());200  if (!SockFD)201    return CreateErr(toString(SockFD.takeError()));202 203  return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(204      std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),205      SimpleRemoteEPC::Setup(), *SockFD);206}207 208#endif209