Home | History | Annotate | Line # | Download | only in LLJITWithRemoteDebugging
      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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include "RemoteJITUtils.h"
     10 
     11 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
     12 #include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h"
     13 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
     14 #include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
     15 #include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
     16 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
     17 #include "llvm/Support/FileSystem.h"
     18 #include "llvm/Support/Path.h"
     19 #include "llvm/Support/ToolOutputFile.h"
     20 
     21 #ifdef LLVM_ON_UNIX
     22 #include <netdb.h>
     23 #include <netinet/in.h>
     24 #include <sys/socket.h>
     25 #include <unistd.h>
     26 #endif // LLVM_ON_UNIX
     27 
     28 using namespace llvm;
     29 using namespace llvm::orc;
     30 
     31 namespace llvm {
     32 namespace orc {
     33 
     34 class RemoteTargetProcessControl
     35     : public OrcRPCTargetProcessControlBase<
     36           shared::MultiThreadedRPCEndpoint<JITLinkExecutor::RPCChannel>> {
     37 public:
     38   using RPCChannel = JITLinkExecutor::RPCChannel;
     39   using RPCEndpoint = shared::MultiThreadedRPCEndpoint<RPCChannel>;
     40 
     41 private:
     42   using ThisT = RemoteTargetProcessControl;
     43   using BaseT = OrcRPCTargetProcessControlBase<RPCEndpoint>;
     44   using MemoryAccess = OrcRPCTPCMemoryAccess<ThisT>;
     45   using MemoryManager = OrcRPCTPCJITLinkMemoryManager<ThisT>;
     46 
     47 public:
     48   using BaseT::initializeORCRPCTPCBase;
     49 
     50   RemoteTargetProcessControl(ExecutionSession &ES,
     51                              std::unique_ptr<RPCChannel> Channel,
     52                              std::unique_ptr<RPCEndpoint> Endpoint);
     53 
     54   void initializeMemoryManagement();
     55   Error disconnect() override;
     56 
     57 private:
     58   std::unique_ptr<RPCChannel> Channel;
     59   std::unique_ptr<RPCEndpoint> Endpoint;
     60   std::unique_ptr<MemoryAccess> OwnedMemAccess;
     61   std::unique_ptr<MemoryManager> OwnedMemMgr;
     62   std::atomic<bool> Finished{false};
     63   std::thread ListenerThread;
     64 };
     65 
     66 RemoteTargetProcessControl::RemoteTargetProcessControl(
     67     ExecutionSession &ES, std::unique_ptr<RPCChannel> Channel,
     68     std::unique_ptr<RPCEndpoint> Endpoint)
     69     : BaseT(ES.getSymbolStringPool(), *Endpoint,
     70             [&ES](Error Err) { ES.reportError(std::move(Err)); }),
     71       Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
     72 
     73   ListenerThread = std::thread([&]() {
     74     while (!Finished) {
     75       if (auto Err = this->Endpoint->handleOne()) {
     76         reportError(std::move(Err));
     77         return;
     78       }
     79     }
     80   });
     81 }
     82 
     83 void RemoteTargetProcessControl::initializeMemoryManagement() {
     84   OwnedMemAccess = std::make_unique<MemoryAccess>(*this);
     85   OwnedMemMgr = std::make_unique<MemoryManager>(*this);
     86 
     87   // Base class needs non-owning access.
     88   MemAccess = OwnedMemAccess.get();
     89   MemMgr = OwnedMemMgr.get();
     90 }
     91 
     92 Error RemoteTargetProcessControl::disconnect() {
     93   std::promise<MSVCPError> P;
     94   auto F = P.get_future();
     95   auto Err = closeConnection([&](Error Err) -> Error {
     96     P.set_value(std::move(Err));
     97     Finished = true;
     98     return Error::success();
     99   });
    100   ListenerThread.join();
    101   return joinErrors(std::move(Err), F.get());
    102 }
    103 
    104 } // namespace orc
    105 } // namespace llvm
    106 
    107 JITLinkExecutor::JITLinkExecutor() = default;
    108 JITLinkExecutor::~JITLinkExecutor() = default;
    109 
    110 Expected<std::unique_ptr<ObjectLayer>>
    111 JITLinkExecutor::operator()(ExecutionSession &ES, const Triple &TT) {
    112   return std::make_unique<ObjectLinkingLayer>(ES, TPC->getMemMgr());
    113 }
    114 
    115 Error JITLinkExecutor::addDebugSupport(ObjectLayer &ObjLayer) {
    116   auto Registrar = createJITLoaderGDBRegistrar(*TPC);
    117   if (!Registrar)
    118     return Registrar.takeError();
    119 
    120   cast<ObjectLinkingLayer>(&ObjLayer)->addPlugin(
    121       std::make_unique<DebugObjectManagerPlugin>(ObjLayer.getExecutionSession(),
    122                                                  std::move(*Registrar)));
    123 
    124   return Error::success();
    125 }
    126 
    127 Expected<std::unique_ptr<DefinitionGenerator>>
    128 JITLinkExecutor::loadDylib(StringRef RemotePath) {
    129   if (auto Handle = TPC->loadDylib(RemotePath.data()))
    130     return std::make_unique<TPCDynamicLibrarySearchGenerator>(*TPC, *Handle);
    131   else
    132     return Handle.takeError();
    133 }
    134 
    135 Expected<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym,
    136                                          ArrayRef<std::string> Args) {
    137   return TPC->runAsMain(MainSym.getAddress(), Args);
    138 }
    139 
    140 Error JITLinkExecutor::disconnect() { return TPC->disconnect(); }
    141 
    142 static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName) {
    143   // This just needs to be some symbol in the binary; C++ doesn't
    144   // allow taking the address of ::main however.
    145   void *P = (void *)(intptr_t)defaultPath;
    146   SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, P));
    147   sys::path::remove_filename(FullName);
    148   sys::path::append(FullName, ExecutorName);
    149   return FullName.str().str();
    150 }
    151 
    152 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>>
    153 JITLinkExecutor::FindLocal(const char *HostArgv) {
    154   std::string BestGuess = defaultPath(HostArgv, "llvm-jitlink-executor");
    155   auto Executor = CreateLocal(BestGuess);
    156   if (!Executor) {
    157     consumeError(Executor.takeError());
    158     return make_error<StringError>(
    159         formatv("Unable to find usable executor: {0}", BestGuess),
    160         inconvertibleErrorCode());
    161   }
    162   return Executor;
    163 }
    164 
    165 Expected<std::unique_ptr<ChildProcessJITLinkExecutor>>
    166 JITLinkExecutor::CreateLocal(std::string ExecutablePath) {
    167   if (!sys::fs::can_execute(ExecutablePath))
    168     return make_error<StringError>(
    169         formatv("Specified executor invalid: {0}", ExecutablePath),
    170         inconvertibleErrorCode());
    171   return std::unique_ptr<ChildProcessJITLinkExecutor>(
    172       new ChildProcessJITLinkExecutor(std::move(ExecutablePath)));
    173 }
    174 
    175 TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor(
    176     std::unique_ptr<RemoteTargetProcessControl> TPC) {
    177   this->TPC = std::move(TPC);
    178 }
    179 
    180 #ifndef LLVM_ON_UNIX
    181 
    182 // FIXME: Add support for Windows.
    183 Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {
    184   return make_error<StringError>(
    185       "Remote JITing not yet supported on non-unix platforms",
    186       inconvertibleErrorCode());
    187 }
    188 
    189 // FIXME: Add support for Windows.
    190 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>>
    191 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,
    192                                   ExecutionSession &ES) {
    193   return make_error<StringError>(
    194       "Remote JITing not yet supported on non-unix platforms",
    195       inconvertibleErrorCode());
    196 }
    197 
    198 #else
    199 
    200 Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {
    201   constexpr int ReadEnd = 0;
    202   constexpr int WriteEnd = 1;
    203 
    204   // Pipe FDs.
    205   int ToExecutor[2];
    206   int FromExecutor[2];
    207 
    208   // Create pipes to/from the executor..
    209   if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
    210     return make_error<StringError>("Unable to create pipe for executor",
    211                                    inconvertibleErrorCode());
    212 
    213   ProcessID = fork();
    214   if (ProcessID == 0) {
    215     // In the child...
    216 
    217     // Close the parent ends of the pipes
    218     close(ToExecutor[WriteEnd]);
    219     close(FromExecutor[ReadEnd]);
    220 
    221     // Execute the child process.
    222     std::unique_ptr<char[]> ExecPath, FDSpecifier;
    223     {
    224       ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
    225       strcpy(ExecPath.get(), ExecutablePath.data());
    226 
    227       std::string FDSpecifierStr("filedescs=");
    228       FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
    229       FDSpecifierStr += ',';
    230       FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
    231       FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
    232       strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
    233     }
    234 
    235     char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr};
    236     int RC = execvp(ExecPath.get(), Args);
    237     if (RC != 0)
    238       return make_error<StringError>(
    239           "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",
    240           inconvertibleErrorCode());
    241 
    242     llvm_unreachable("Fork won't return in success case");
    243   }
    244   // else we're the parent...
    245 
    246   // Close the child ends of the pipes
    247   close(ToExecutor[ReadEnd]);
    248   close(FromExecutor[WriteEnd]);
    249 
    250   auto Channel =
    251       std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
    252   auto Endpoint =
    253       std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true);
    254 
    255   TPC = std::make_unique<RemoteTargetProcessControl>(ES, std::move(Channel),
    256                                                      std::move(Endpoint));
    257 
    258   if (auto Err = TPC->initializeORCRPCTPCBase())
    259     return joinErrors(std::move(Err), TPC->disconnect());
    260 
    261   TPC->initializeMemoryManagement();
    262 
    263   shared::registerStringError<RPCChannel>();
    264   return Error::success();
    265 }
    266 
    267 static Expected<int> connectTCPSocketImpl(std::string Host,
    268                                           std::string PortStr) {
    269   addrinfo *AI;
    270   addrinfo Hints{};
    271   Hints.ai_family = AF_INET;
    272   Hints.ai_socktype = SOCK_STREAM;
    273   Hints.ai_flags = AI_NUMERICSERV;
    274 
    275   if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
    276     return make_error<StringError>(
    277         formatv("address resolution failed ({0})", gai_strerror(EC)),
    278         inconvertibleErrorCode());
    279 
    280   // Cycle through the returned addrinfo structures and connect to the first
    281   // reachable endpoint.
    282   int SockFD;
    283   addrinfo *Server;
    284   for (Server = AI; Server != nullptr; Server = Server->ai_next) {
    285     // If socket fails, maybe it's because the address family is not supported.
    286     // Skip to the next addrinfo structure.
    287     if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
    288       continue;
    289 
    290     // If connect works, we exit the loop with a working socket.
    291     if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
    292       break;
    293 
    294     close(SockFD);
    295   }
    296   freeaddrinfo(AI);
    297 
    298   // Did we reach the end of the loop without connecting to a valid endpoint?
    299   if (Server == nullptr)
    300     return make_error<StringError>("invalid hostname",
    301                                    inconvertibleErrorCode());
    302 
    303   return SockFD;
    304 }
    305 
    306 Expected<std::unique_ptr<TCPSocketJITLinkExecutor>>
    307 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,
    308                                   ExecutionSession &ES) {
    309   auto CreateErr = [NetworkAddress](StringRef Details) {
    310     return make_error<StringError>(
    311         formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
    312                 Details),
    313         inconvertibleErrorCode());
    314   };
    315 
    316   StringRef Host, PortStr;
    317   std::tie(Host, PortStr) = NetworkAddress.split(':');
    318   if (Host.empty())
    319     return CreateErr("host name cannot be empty");
    320   if (PortStr.empty())
    321     return CreateErr("port cannot be empty");
    322   int Port = 0;
    323   if (PortStr.getAsInteger(10, Port))
    324     return CreateErr("port number is not a valid integer");
    325 
    326   Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
    327   if (!SockFD)
    328     return CreateErr(toString(SockFD.takeError()));
    329 
    330   auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD);
    331   auto Endpoint =
    332       std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true);
    333 
    334   auto TPC = std::make_unique<RemoteTargetProcessControl>(
    335       ES, std::move(Channel), std::move(Endpoint));
    336 
    337   if (auto Err = TPC->initializeORCRPCTPCBase())
    338     return joinErrors(std::move(Err), TPC->disconnect());
    339 
    340   TPC->initializeMemoryManagement();
    341   shared::registerStringError<RPCChannel>();
    342 
    343   return std::unique_ptr<TCPSocketJITLinkExecutor>(
    344       new TCPSocketJITLinkExecutor(std::move(TPC)));
    345 }
    346 
    347 #endif
    348