1 //===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===// 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 "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h" 10 11 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" 12 #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" 13 #include "llvm/Support/FormatVariadic.h" 14 #include "llvm/Support/Host.h" 15 #include "llvm/Support/Process.h" 16 17 #define DEBUG_TYPE "orc" 18 19 using namespace llvm::orc::shared; 20 21 namespace llvm { 22 namespace orc { 23 24 static llvm::orc::shared::detail::CWrapperFunctionResult 25 reserveWrapper(const char *ArgData, size_t ArgSize) { 26 return WrapperFunction<SPSOrcTargetProcessAllocate>::handle( 27 ArgData, ArgSize, 28 [](uint64_t Size) -> Expected<ExecutorAddress> { 29 std::error_code EC; 30 auto MB = sys::Memory::allocateMappedMemory( 31 Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 32 if (EC) 33 return errorCodeToError(EC); 34 return ExecutorAddress::fromPtr(MB.base()); 35 }) 36 .release(); 37 } 38 39 static llvm::orc::shared::detail::CWrapperFunctionResult 40 finalizeWrapper(const char *ArgData, size_t ArgSize) { 41 return WrapperFunction<SPSOrcTargetProcessFinalize>::handle( 42 ArgData, ArgSize, 43 [](const tpctypes::FinalizeRequest &FR) -> Error { 44 for (auto &Seg : FR) { 45 char *Mem = Seg.Addr.toPtr<char *>(); 46 memcpy(Mem, Seg.Content.data(), Seg.Content.size()); 47 memset(Mem + Seg.Content.size(), 0, 48 Seg.Size - Seg.Content.size()); 49 assert(Seg.Size <= std::numeric_limits<size_t>::max()); 50 if (auto EC = sys::Memory::protectMappedMemory( 51 {Mem, static_cast<size_t>(Seg.Size)}, 52 tpctypes::fromWireProtectionFlags(Seg.Prot))) 53 return errorCodeToError(EC); 54 if (Seg.Prot & tpctypes::WPF_Exec) 55 sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); 56 } 57 return Error::success(); 58 }) 59 .release(); 60 } 61 62 static llvm::orc::shared::detail::CWrapperFunctionResult 63 deallocateWrapper(const char *ArgData, size_t ArgSize) { 64 return WrapperFunction<SPSOrcTargetProcessDeallocate>::handle( 65 ArgData, ArgSize, 66 [](ExecutorAddress Base, uint64_t Size) -> Error { 67 sys::MemoryBlock MB(Base.toPtr<void *>(), Size); 68 if (auto EC = sys::Memory::releaseMappedMemory(MB)) 69 return errorCodeToError(EC); 70 return Error::success(); 71 }) 72 .release(); 73 } 74 75 template <typename WriteT, typename SPSWriteT> 76 static llvm::orc::shared::detail::CWrapperFunctionResult 77 writeUIntsWrapper(const char *ArgData, size_t ArgSize) { 78 return WrapperFunction<void(SPSSequence<SPSWriteT>)>::handle( 79 ArgData, ArgSize, 80 [](std::vector<WriteT> Ws) { 81 for (auto &W : Ws) 82 *jitTargetAddressToPointer<decltype(W.Value) *>(W.Address) = 83 W.Value; 84 }) 85 .release(); 86 } 87 88 static llvm::orc::shared::detail::CWrapperFunctionResult 89 writeBuffersWrapper(const char *ArgData, size_t ArgSize) { 90 return WrapperFunction<void(SPSSequence<SPSMemoryAccessBufferWrite>)>::handle( 91 ArgData, ArgSize, 92 [](std::vector<tpctypes::BufferWrite> Ws) { 93 for (auto &W : Ws) 94 memcpy(jitTargetAddressToPointer<char *>(W.Address), 95 W.Buffer.data(), W.Buffer.size()); 96 }) 97 .release(); 98 } 99 100 static llvm::orc::shared::detail::CWrapperFunctionResult 101 runAsMainWrapper(const char *ArgData, size_t ArgSize) { 102 return WrapperFunction<SPSRunAsMainSignature>::handle( 103 ArgData, ArgSize, 104 [](ExecutorAddress MainAddr, 105 std::vector<std::string> Args) -> int64_t { 106 return runAsMain(MainAddr.toPtr<int (*)(int, char *[])>(), Args); 107 }) 108 .release(); 109 } 110 111 SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {} 112 113 #if LLVM_ENABLE_THREADS 114 void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( 115 unique_function<void()> Work) { 116 { 117 std::lock_guard<std::mutex> Lock(DispatchMutex); 118 if (!Running) 119 return; 120 ++Outstanding; 121 } 122 123 std::thread([this, Work = std::move(Work)]() mutable { 124 Work(); 125 std::lock_guard<std::mutex> Lock(DispatchMutex); 126 --Outstanding; 127 OutstandingCV.notify_all(); 128 }).detach(); 129 } 130 131 void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() { 132 std::unique_lock<std::mutex> Lock(DispatchMutex); 133 Running = false; 134 OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); 135 } 136 #endif 137 138 StringMap<ExecutorAddress> SimpleRemoteEPCServer::defaultBootstrapSymbols() { 139 StringMap<ExecutorAddress> DBS; 140 141 DBS["__llvm_orc_memory_reserve"] = ExecutorAddress::fromPtr(&reserveWrapper); 142 DBS["__llvm_orc_memory_finalize"] = 143 ExecutorAddress::fromPtr(&finalizeWrapper); 144 DBS["__llvm_orc_memory_deallocate"] = 145 ExecutorAddress::fromPtr(&deallocateWrapper); 146 DBS["__llvm_orc_memory_write_uint8s"] = ExecutorAddress::fromPtr( 147 &writeUIntsWrapper<tpctypes::UInt8Write, 148 shared::SPSMemoryAccessUInt8Write>); 149 DBS["__llvm_orc_memory_write_uint16s"] = ExecutorAddress::fromPtr( 150 &writeUIntsWrapper<tpctypes::UInt16Write, 151 shared::SPSMemoryAccessUInt16Write>); 152 DBS["__llvm_orc_memory_write_uint32s"] = ExecutorAddress::fromPtr( 153 &writeUIntsWrapper<tpctypes::UInt32Write, 154 shared::SPSMemoryAccessUInt32Write>); 155 DBS["__llvm_orc_memory_write_uint64s"] = ExecutorAddress::fromPtr( 156 &writeUIntsWrapper<tpctypes::UInt64Write, 157 shared::SPSMemoryAccessUInt64Write>); 158 DBS["__llvm_orc_memory_write_buffers"] = 159 ExecutorAddress::fromPtr(&writeBuffersWrapper); 160 DBS["__llvm_orc_run_as_main"] = ExecutorAddress::fromPtr(&runAsMainWrapper); 161 DBS["__llvm_orc_load_dylib"] = ExecutorAddress::fromPtr(&loadDylibWrapper); 162 DBS["__llvm_orc_lookup_symbols"] = 163 ExecutorAddress::fromPtr(&lookupSymbolsWrapper); 164 return DBS; 165 } 166 167 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction> 168 SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, 169 ExecutorAddress TagAddr, 170 SimpleRemoteEPCArgBytesVector ArgBytes) { 171 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>; 172 if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) || 173 static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC)) 174 return make_error<StringError>("Unexpected opcode", 175 inconvertibleErrorCode()); 176 177 // TODO: Clean detach message? 178 switch (OpC) { 179 case SimpleRemoteEPCOpcode::Setup: 180 return make_error<StringError>("Unexpected Setup opcode", 181 inconvertibleErrorCode()); 182 case SimpleRemoteEPCOpcode::Hangup: 183 return SimpleRemoteEPCTransportClient::EndSession; 184 case SimpleRemoteEPCOpcode::Result: 185 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes))) 186 return std::move(Err); 187 break; 188 case SimpleRemoteEPCOpcode::CallWrapper: 189 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes)); 190 break; 191 } 192 return ContinueSession; 193 } 194 195 Error SimpleRemoteEPCServer::waitForDisconnect() { 196 std::unique_lock<std::mutex> Lock(ServerStateMutex); 197 ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; }); 198 return std::move(ShutdownErr); 199 } 200 201 void SimpleRemoteEPCServer::handleDisconnect(Error Err) { 202 PendingJITDispatchResultsMap TmpPending; 203 204 { 205 std::lock_guard<std::mutex> Lock(ServerStateMutex); 206 std::swap(TmpPending, PendingJITDispatchResults); 207 RunState = ServerShuttingDown; 208 } 209 210 // Send out-of-band errors to any waiting threads. 211 for (auto &KV : TmpPending) 212 KV.second->set_value( 213 shared::WrapperFunctionResult::createOutOfBandError("disconnecting")); 214 215 // TODO: Free attached resources. 216 // 1. Close libraries in DylibHandles. 217 218 // Wait for dispatcher to clear. 219 D->shutdown(); 220 221 std::lock_guard<std::mutex> Lock(ServerStateMutex); 222 ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err)); 223 RunState = ServerShutDown; 224 ShutdownCV.notify_all(); 225 } 226 227 Error SimpleRemoteEPCServer::sendSetupMessage( 228 StringMap<ExecutorAddress> BootstrapSymbols) { 229 230 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames; 231 232 std::vector<char> SetupPacket; 233 SimpleRemoteEPCExecutorInfo EI; 234 EI.TargetTriple = sys::getProcessTriple(); 235 if (auto PageSize = sys::Process::getPageSize()) 236 EI.PageSize = *PageSize; 237 else 238 return PageSize.takeError(); 239 EI.BootstrapSymbols = std::move(BootstrapSymbols); 240 241 assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) && 242 "Dispatch context name should not be set"); 243 assert(!EI.BootstrapSymbols.count(DispatchFnName) && 244 "Dispatch function name should not be set"); 245 EI.BootstrapSymbols[ExecutorSessionObjectName] = 246 ExecutorAddress::fromPtr(this); 247 EI.BootstrapSymbols[DispatchFnName] = 248 ExecutorAddress::fromPtr(jitDispatchEntry); 249 250 using SPSSerialize = 251 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>; 252 auto SetupPacketBytes = 253 shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI)); 254 shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size()); 255 if (!SPSSerialize::serialize(OB, EI)) 256 return make_error<StringError>("Could not send setup packet", 257 inconvertibleErrorCode()); 258 259 return T->sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddress(), 260 {SetupPacketBytes.data(), SetupPacketBytes.size()}); 261 } 262 263 Error SimpleRemoteEPCServer::handleResult( 264 uint64_t SeqNo, ExecutorAddress TagAddr, 265 SimpleRemoteEPCArgBytesVector ArgBytes) { 266 std::promise<shared::WrapperFunctionResult> *P = nullptr; 267 { 268 std::lock_guard<std::mutex> Lock(ServerStateMutex); 269 auto I = PendingJITDispatchResults.find(SeqNo); 270 if (I == PendingJITDispatchResults.end()) 271 return make_error<StringError>("No call for sequence number " + 272 Twine(SeqNo), 273 inconvertibleErrorCode()); 274 P = I->second; 275 PendingJITDispatchResults.erase(I); 276 releaseSeqNo(SeqNo); 277 } 278 auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size()); 279 memcpy(R.data(), ArgBytes.data(), ArgBytes.size()); 280 P->set_value(std::move(R)); 281 return Error::success(); 282 } 283 284 void SimpleRemoteEPCServer::handleCallWrapper( 285 uint64_t RemoteSeqNo, ExecutorAddress TagAddr, 286 SimpleRemoteEPCArgBytesVector ArgBytes) { 287 D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() { 288 using WrapperFnTy = 289 shared::detail::CWrapperFunctionResult (*)(const char *, size_t); 290 auto *Fn = TagAddr.toPtr<WrapperFnTy>(); 291 shared::WrapperFunctionResult ResultBytes( 292 Fn(ArgBytes.data(), ArgBytes.size())); 293 if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo, 294 ExecutorAddress(), 295 {ResultBytes.data(), ResultBytes.size()})) 296 ReportError(std::move(Err)); 297 }); 298 } 299 300 shared::detail::CWrapperFunctionResult 301 SimpleRemoteEPCServer::loadDylibWrapper(const char *ArgData, size_t ArgSize) { 302 return shared::WrapperFunction<shared::SPSLoadDylibSignature>::handle( 303 ArgData, ArgSize, 304 [](ExecutorAddress ExecutorSessionObj, std::string Path, 305 uint64_t Flags) -> Expected<uint64_t> { 306 return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>() 307 ->loadDylib(Path, Flags); 308 }) 309 .release(); 310 } 311 312 shared::detail::CWrapperFunctionResult 313 SimpleRemoteEPCServer::lookupSymbolsWrapper(const char *ArgData, 314 size_t ArgSize) { 315 return shared::WrapperFunction<shared::SPSLookupSymbolsSignature>::handle( 316 ArgData, ArgSize, 317 [](ExecutorAddress ExecutorSessionObj, 318 std::vector<RemoteSymbolLookup> Lookup) { 319 return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>() 320 ->lookupSymbols(Lookup); 321 }) 322 .release(); 323 } 324 325 Expected<tpctypes::DylibHandle> 326 SimpleRemoteEPCServer::loadDylib(const std::string &Path, uint64_t Mode) { 327 std::string ErrMsg; 328 const char *P = Path.empty() ? nullptr : Path.c_str(); 329 auto DL = sys::DynamicLibrary::getPermanentLibrary(P, &ErrMsg); 330 if (!DL.isValid()) 331 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 332 std::lock_guard<std::mutex> Lock(ServerStateMutex); 333 uint64_t Id = Dylibs.size(); 334 Dylibs.push_back(std::move(DL)); 335 return Id; 336 } 337 338 Expected<std::vector<std::vector<ExecutorAddress>>> 339 SimpleRemoteEPCServer::lookupSymbols(const std::vector<RemoteSymbolLookup> &L) { 340 std::vector<std::vector<ExecutorAddress>> Result; 341 342 for (const auto &E : L) { 343 if (E.H >= Dylibs.size()) 344 return make_error<StringError>("Unrecognized handle", 345 inconvertibleErrorCode()); 346 auto &DL = Dylibs[E.H]; 347 Result.push_back({}); 348 349 for (const auto &Sym : E.Symbols) { 350 351 const char *DemangledSymName = Sym.Name.c_str(); 352 #ifdef __APPLE__ 353 if (*DemangledSymName == '_') 354 ++DemangledSymName; 355 #endif 356 357 void *Addr = DL.getAddressOfSymbol(DemangledSymName); 358 if (!Addr && Sym.Required) 359 return make_error<StringError>(Twine("Missing definition for ") + 360 DemangledSymName, 361 inconvertibleErrorCode()); 362 363 Result.back().push_back(ExecutorAddress::fromPtr(Addr)); 364 } 365 } 366 367 return std::move(Result); 368 } 369 370 shared::WrapperFunctionResult 371 SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData, 372 size_t ArgSize) { 373 uint64_t SeqNo; 374 std::promise<shared::WrapperFunctionResult> ResultP; 375 auto ResultF = ResultP.get_future(); 376 { 377 std::lock_guard<std::mutex> Lock(ServerStateMutex); 378 if (RunState != ServerRunning) 379 return shared::WrapperFunctionResult::createOutOfBandError( 380 "jit_dispatch not available (EPC server shut down)"); 381 382 SeqNo = getNextSeqNo(); 383 assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use"); 384 PendingJITDispatchResults[SeqNo] = &ResultP; 385 } 386 387 if (auto Err = 388 T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo, 389 ExecutorAddress::fromPtr(FnTag), {ArgData, ArgSize})) 390 ReportError(std::move(Err)); 391 392 return ResultF.get(); 393 } 394 395 shared::detail::CWrapperFunctionResult 396 SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag, 397 const char *ArgData, size_t ArgSize) { 398 return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx) 399 ->doJITDispatch(FnTag, ArgData, ArgSize) 400 .release(); 401 } 402 403 } // end namespace orc 404 } // end namespace llvm 405