Path: blob/main/contrib/llvm-project/clang/lib/Interpreter/RemoteJITUtils.cpp
213766 views
//===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// FIXME: Unify this code with similar functionality in llvm-jitlink.9//10//===----------------------------------------------------------------------===//1112#include "clang/Interpreter/RemoteJITUtils.h"1314#include "llvm/ADT/StringExtras.h"15#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"16#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"17#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"18#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"19#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"20#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"21#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"22#include "llvm/Support/FileSystem.h"23#include "llvm/Support/Path.h"2425#ifdef LLVM_ON_UNIX26#include <netdb.h>27#include <netinet/in.h>28#include <sys/socket.h>29#include <unistd.h>30#endif // LLVM_ON_UNIX3132using namespace llvm;33using namespace llvm::orc;3435Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {36SizeString = SizeString.trim();3738uint64_t Units = 1024;3940if (SizeString.ends_with_insensitive("kb"))41SizeString = SizeString.drop_back(2).rtrim();42else if (SizeString.ends_with_insensitive("mb")) {43Units = 1024 * 1024;44SizeString = SizeString.drop_back(2).rtrim();45} else if (SizeString.ends_with_insensitive("gb")) {46Units = 1024 * 1024 * 1024;47SizeString = SizeString.drop_back(2).rtrim();48}4950uint64_t SlabSize = 0;51if (SizeString.getAsInteger(10, SlabSize))52return make_error<StringError>("Invalid numeric format for slab size",53inconvertibleErrorCode());5455return SlabSize * Units;56}5758Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>59createSharedMemoryManager(SimpleRemoteEPC &SREPC,60StringRef SlabAllocateSizeString) {61SharedMemoryMapper::SymbolAddrs SAs;62if (auto Err = SREPC.getBootstrapSymbols(63{{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName},64{SAs.Reserve,65rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},66{SAs.Initialize,67rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName},68{SAs.Deinitialize,69rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},70{SAs.Release,71rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))72return std::move(Err);7374#ifdef _WIN3275size_t SlabSize = 1024 * 1024;76#else77size_t SlabSize = 1024 * 1024 * 1024;78#endif7980if (!SlabAllocateSizeString.empty()) {81if (Expected<uint64_t> S = getSlabAllocSize(SlabAllocateSizeString))82SlabSize = *S;83else84return S.takeError();85}8687return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>(88SlabSize, SREPC, SAs);89}9091Expected<std::unique_ptr<SimpleRemoteEPC>>92launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,93llvm::StringRef SlabAllocateSizeString) {94#ifndef LLVM_ON_UNIX95// FIXME: Add support for Windows.96return make_error<StringError>("-" + ExecutablePath +97" not supported on non-unix platforms",98inconvertibleErrorCode());99#elif !LLVM_ENABLE_THREADS100// Out of process mode using SimpleRemoteEPC depends on threads.101return make_error<StringError>(102"-" + ExecutablePath +103" requires threads, but LLVM was built with "104"LLVM_ENABLE_THREADS=Off",105inconvertibleErrorCode());106#else107108if (!sys::fs::can_execute(ExecutablePath))109return make_error<StringError>(110formatv("Specified executor invalid: {0}", ExecutablePath),111inconvertibleErrorCode());112113constexpr int ReadEnd = 0;114constexpr int WriteEnd = 1;115116// Pipe FDs.117int ToExecutor[2];118int FromExecutor[2];119120pid_t ChildPID;121122// Create pipes to/from the executor..123if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)124return make_error<StringError>("Unable to create pipe for executor",125inconvertibleErrorCode());126127ChildPID = fork();128129if (ChildPID == 0) {130// In the child...131132// Close the parent ends of the pipes133close(ToExecutor[WriteEnd]);134close(FromExecutor[ReadEnd]);135136// Execute the child process.137std::unique_ptr<char[]> ExecutorPath, FDSpecifier;138{139ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);140strcpy(ExecutorPath.get(), ExecutablePath.data());141142std::string FDSpecifierStr("filedescs=");143FDSpecifierStr += utostr(ToExecutor[ReadEnd]);144FDSpecifierStr += ',';145FDSpecifierStr += utostr(FromExecutor[WriteEnd]);146FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);147strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());148}149150char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};151int RC = execvp(ExecutorPath.get(), Args);152if (RC != 0) {153errs() << "unable to launch out-of-process executor \""154<< ExecutorPath.get() << "\"\n";155exit(1);156}157}158// else we're the parent...159160// Close the child ends of the pipes161close(ToExecutor[ReadEnd]);162close(FromExecutor[WriteEnd]);163164SimpleRemoteEPC::Setup S = SimpleRemoteEPC::Setup();165if (UseSharedMemory)166S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {167return createSharedMemoryManager(EPC, SlabAllocateSizeString);168};169170return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(171std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),172std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);173#endif174}175176#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS177178static Expected<int> connectTCPSocketImpl(std::string Host,179std::string PortStr) {180addrinfo *AI;181addrinfo Hints{};182Hints.ai_family = AF_INET;183Hints.ai_socktype = SOCK_STREAM;184Hints.ai_flags = AI_NUMERICSERV;185186if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))187return make_error<StringError>(188formatv("address resolution failed ({0})", gai_strerror(EC)),189inconvertibleErrorCode());190// Cycle through the returned addrinfo structures and connect to the first191// reachable endpoint.192int SockFD;193addrinfo *Server;194for (Server = AI; Server != nullptr; Server = Server->ai_next) {195// socket might fail, e.g. if the address family is not supported. Skip to196// the next addrinfo structure in such a case.197if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)198continue;199200// If connect returns null, we exit the loop with a working socket.201if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)202break;203204close(SockFD);205}206freeaddrinfo(AI);207208// If we reached the end of the loop without connecting to a valid endpoint,209// dump the last error that was logged in socket() or connect().210if (Server == nullptr)211return make_error<StringError>("invalid hostname",212inconvertibleErrorCode());213214return SockFD;215}216#endif217218Expected<std::unique_ptr<SimpleRemoteEPC>>219connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,220llvm::StringRef SlabAllocateSizeString) {221#ifndef LLVM_ON_UNIX222// FIXME: Add TCP support for Windows.223return make_error<StringError>("-" + NetworkAddress +224" not supported on non-unix platforms",225inconvertibleErrorCode());226#elif !LLVM_ENABLE_THREADS227// Out of process mode using SimpleRemoteEPC depends on threads.228return make_error<StringError>(229"-" + NetworkAddress +230" requires threads, but LLVM was built with "231"LLVM_ENABLE_THREADS=Off",232inconvertibleErrorCode());233#else234235auto CreateErr = [NetworkAddress](Twine Details) {236return make_error<StringError>(237formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,238Details),239inconvertibleErrorCode());240};241242StringRef Host, PortStr;243std::tie(Host, PortStr) = NetworkAddress.split(':');244if (Host.empty())245return CreateErr("Host name for -" + NetworkAddress + " can not be empty");246if (PortStr.empty())247return CreateErr("Port number in -" + NetworkAddress + " can not be empty");248int Port = 0;249if (PortStr.getAsInteger(10, Port))250return CreateErr("Port number '" + PortStr + "' is not a valid integer");251252Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());253if (!SockFD)254return SockFD.takeError();255256SimpleRemoteEPC::Setup S = SimpleRemoteEPC::Setup();257if (UseSharedMemory)258S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {259return createSharedMemoryManager(EPC, SlabAllocateSizeString);260};261262return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(263std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),264std::move(S), *SockFD, *SockFD);265#endif266}267268269