llvm-jitlink-executor.cpp 5.4 KB

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