llvm-jitlink-executor.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. #include "llvm/ADT/StringRef.h"
  13. #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
  14. #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
  15. #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
  16. #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
  17. #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
  18. #include "llvm/Support/Debug.h"
  19. #include "llvm/Support/DynamicLibrary.h"
  20. #include "llvm/Support/Error.h"
  21. #include "llvm/Support/MathExtras.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. #include <cstring>
  24. #include <sstream>
  25. #ifdef LLVM_ON_UNIX
  26. #include <netdb.h>
  27. #include <netinet/in.h>
  28. #include <sys/socket.h>
  29. #endif
  30. using namespace llvm;
  31. using namespace llvm::orc;
  32. ExitOnError ExitOnErr;
  33. LLVM_ATTRIBUTE_USED void linkComponents() {
  34. errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
  35. << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
  36. << (void *)&llvm_orc_registerJITLoaderGDBWrapper
  37. << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
  38. }
  39. void printErrorAndExit(Twine ErrMsg) {
  40. #ifndef NDEBUG
  41. const char *DebugOption = "[debug] ";
  42. #else
  43. const char *DebugOption = "";
  44. #endif
  45. errs() << "error: " << ErrMsg.str() << "\n\n"
  46. << "Usage:\n"
  47. << " llvm-jitlink-executor " << DebugOption
  48. << "filedescs=<infd>,<outfd> [args...]\n"
  49. << " llvm-jitlink-executor " << DebugOption
  50. << "listen=<host>:<port> [args...]\n";
  51. exit(1);
  52. }
  53. int openListener(std::string Host, std::string PortStr) {
  54. #ifndef LLVM_ON_UNIX
  55. // FIXME: Add TCP support for Windows.
  56. printErrorAndExit("listen option not supported");
  57. return 0;
  58. #else
  59. addrinfo Hints{};
  60. Hints.ai_family = AF_INET;
  61. Hints.ai_socktype = SOCK_STREAM;
  62. Hints.ai_flags = AI_PASSIVE;
  63. addrinfo *AI;
  64. if (int EC = getaddrinfo(nullptr, PortStr.c_str(), &Hints, &AI)) {
  65. errs() << "Error setting up bind address: " << gai_strerror(EC) << "\n";
  66. exit(1);
  67. }
  68. // Create a socket from first addrinfo structure returned by getaddrinfo.
  69. int SockFD;
  70. if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) {
  71. errs() << "Error creating socket: " << std::strerror(errno) << "\n";
  72. exit(1);
  73. }
  74. // Avoid "Address already in use" errors.
  75. const int Yes = 1;
  76. if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
  77. errs() << "Error calling setsockopt: " << std::strerror(errno) << "\n";
  78. exit(1);
  79. }
  80. // Bind the socket to the desired port.
  81. if (bind(SockFD, AI->ai_addr, AI->ai_addrlen) < 0) {
  82. errs() << "Error on binding: " << std::strerror(errno) << "\n";
  83. exit(1);
  84. }
  85. // Listen for incomming connections.
  86. static constexpr int ConnectionQueueLen = 1;
  87. listen(SockFD, ConnectionQueueLen);
  88. #if defined(_AIX)
  89. assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");
  90. socklen_t AddrLen = Lo_32(AI->ai_addrlen);
  91. return accept(SockFD, AI->ai_addr, &AddrLen);
  92. #else
  93. return accept(SockFD, AI->ai_addr, &AI->ai_addrlen);
  94. #endif
  95. #endif // LLVM_ON_UNIX
  96. }
  97. int main(int argc, char *argv[]) {
  98. #if LLVM_ENABLE_THREADS
  99. ExitOnErr.setBanner(std::string(argv[0]) + ": ");
  100. unsigned FirstProgramArg = 1;
  101. int InFD = 0;
  102. int OutFD = 0;
  103. if (argc < 2)
  104. printErrorAndExit("insufficient arguments");
  105. else {
  106. StringRef ConnectArg = argv[FirstProgramArg++];
  107. #ifndef NDEBUG
  108. if (ConnectArg == "debug") {
  109. DebugFlag = true;
  110. ConnectArg = argv[FirstProgramArg++];
  111. }
  112. #endif
  113. StringRef SpecifierType, Specifier;
  114. std::tie(SpecifierType, Specifier) = ConnectArg.split('=');
  115. if (SpecifierType == "filedescs") {
  116. StringRef FD1Str, FD2Str;
  117. std::tie(FD1Str, FD2Str) = Specifier.split(',');
  118. if (FD1Str.getAsInteger(10, InFD))
  119. printErrorAndExit(FD1Str + " is not a valid file descriptor");
  120. if (FD2Str.getAsInteger(10, OutFD))
  121. printErrorAndExit(FD2Str + " is not a valid file descriptor");
  122. } else if (SpecifierType == "listen") {
  123. StringRef Host, PortStr;
  124. std::tie(Host, PortStr) = Specifier.split(':');
  125. int Port = 0;
  126. if (PortStr.getAsInteger(10, Port))
  127. printErrorAndExit("port number '" + PortStr +
  128. "' is not a valid integer");
  129. InFD = OutFD = openListener(Host.str(), PortStr.str());
  130. } else
  131. printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
  132. }
  133. auto Server =
  134. ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(
  135. [](SimpleRemoteEPCServer::Setup &S) -> Error {
  136. S.setDispatcher(
  137. std::make_unique<SimpleRemoteEPCServer::ThreadDispatcher>());
  138. S.bootstrapSymbols() =
  139. SimpleRemoteEPCServer::defaultBootstrapSymbols();
  140. S.services().push_back(
  141. std::make_unique<rt_bootstrap::SimpleExecutorMemoryManager>());
  142. S.services().push_back(
  143. std::make_unique<
  144. rt_bootstrap::ExecutorSharedMemoryMapperService>());
  145. return Error::success();
  146. },
  147. InFD, OutFD));
  148. ExitOnErr(Server->waitForDisconnect());
  149. return 0;
  150. #else
  151. errs() << argv[0]
  152. << " error: this tool requires threads, but LLVM was "
  153. "built with LLVM_ENABLE_THREADS=Off\n";
  154. return 1;
  155. #endif
  156. }