1 //===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
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/SimpleRemoteEPC.h"
10 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
11 #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
12 #include "llvm/Support/FormatVariadic.h"
13 
14 #define DEBUG_TYPE "orc"
15 
16 namespace llvm {
17 namespace orc {
18 namespace shared {
19 
20 template <>
21 class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
22                              SymbolLookupSet::value_type> {
23 public:
24   static size_t size(const SymbolLookupSet::value_type &V) {
25     return SPSArgList<SPSString, bool>::size(
26         *V.first, V.second == SymbolLookupFlags::RequiredSymbol);
27   }
28 
29   static bool serialize(SPSOutputBuffer &OB,
30                         const SymbolLookupSet::value_type &V) {
31     return SPSArgList<SPSString, bool>::serialize(
32         OB, *V.first, V.second == SymbolLookupFlags::RequiredSymbol);
33   }
34 };
35 
36 template <>
37 class TrivialSPSSequenceSerialization<SPSRemoteSymbolLookupSetElement,
38                                       SymbolLookupSet> {
39 public:
40   static constexpr bool available = true;
41 };
42 
43 template <>
44 class SPSSerializationTraits<SPSRemoteSymbolLookup,
45                              ExecutorProcessControl::LookupRequest> {
46   using MemberSerialization =
47       SPSArgList<SPSExecutorAddress, SPSRemoteSymbolLookupSet>;
48 
49 public:
50   static size_t size(const ExecutorProcessControl::LookupRequest &LR) {
51     return MemberSerialization::size(ExecutorAddress(LR.Handle), LR.Symbols);
52   }
53 
54   static bool serialize(SPSOutputBuffer &OB,
55                         const ExecutorProcessControl::LookupRequest &LR) {
56     return MemberSerialization::serialize(OB, ExecutorAddress(LR.Handle),
57                                           LR.Symbols);
58   }
59 };
60 
61 } // end namespace shared
62 
63 SimpleRemoteEPC::~SimpleRemoteEPC() {
64   assert(Disconnected && "Destroyed without disconnection");
65 }
66 
67 Error SimpleRemoteEPC::setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
68                              const SimpleRemoteEPCExecutorInfo &EI) {
69   using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
70   LLVM_DEBUG({
71     dbgs() << "SimpleRemoteEPC received setup message:\n"
72            << "  Triple: " << EI.TargetTriple << "\n"
73            << "  Page size: " << EI.PageSize << "\n"
74            << "  Bootstrap symbols:\n";
75     for (const auto &KV : EI.BootstrapSymbols)
76       dbgs() << "    " << KV.first() << ": "
77              << formatv("{0:x16}", KV.second.getValue()) << "\n";
78   });
79   this->T = std::move(T);
80   TargetTriple = Triple(EI.TargetTriple);
81   PageSize = EI.PageSize;
82 
83   if (auto Err = EI.getBootstrapSymbols(
84           {{JDI.JITDispatchContextAddress, ExecutorSessionObjectName},
85            {JDI.JITDispatchFunctionAddress, DispatchFnName},
86            {LoadDylibAddr, "__llvm_orc_load_dylib"},
87            {LookupSymbolsAddr, "__llvm_orc_lookup_symbols"},
88            {RunAsMainAddr, "__llvm_orc_run_as_main"}}))
89     return Err;
90 
91   if (!MemMgr)
92     if (auto Err = setupDefaultMemoryManager(EI))
93       return Err;
94   if (!MemAccess)
95     if (auto Err = setupDefaultMemoryAccess(EI))
96       return Err;
97 
98   return Error::success();
99 }
100 
101 Expected<tpctypes::DylibHandle>
102 SimpleRemoteEPC::loadDylib(const char *DylibPath) {
103   Expected<tpctypes::DylibHandle> H((tpctypes::DylibHandle()));
104   if (auto Err = callSPSWrapper<shared::SPSLoadDylibSignature>(
105           LoadDylibAddr.getValue(), H, JDI.JITDispatchContextAddress,
106           StringRef(DylibPath), (uint64_t)0))
107     return std::move(Err);
108   return H;
109 }
110 
111 Expected<std::vector<tpctypes::LookupResult>>
112 SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
113   Expected<std::vector<tpctypes::LookupResult>> R(
114       (std::vector<tpctypes::LookupResult>()));
115 
116   if (auto Err = callSPSWrapper<shared::SPSLookupSymbolsSignature>(
117           LookupSymbolsAddr.getValue(), R, JDI.JITDispatchContextAddress,
118           Request))
119     return std::move(Err);
120   return R;
121 }
122 
123 Expected<int32_t> SimpleRemoteEPC::runAsMain(JITTargetAddress MainFnAddr,
124                                              ArrayRef<std::string> Args) {
125   int64_t Result = 0;
126   if (auto Err = callSPSWrapper<shared::SPSRunAsMainSignature>(
127           RunAsMainAddr.getValue(), Result, ExecutorAddress(MainFnAddr), Args))
128     return std::move(Err);
129   return Result;
130 }
131 
132 void SimpleRemoteEPC::callWrapperAsync(SendResultFunction OnComplete,
133                                        JITTargetAddress WrapperFnAddr,
134                                        ArrayRef<char> ArgBuffer) {
135   uint64_t SeqNo;
136   {
137     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
138     SeqNo = getNextSeqNo();
139     assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
140     PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
141   }
142 
143   if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
144                                 ExecutorAddress(WrapperFnAddr), ArgBuffer)) {
145     getExecutionSession().reportError(std::move(Err));
146   }
147 }
148 
149 Error SimpleRemoteEPC::disconnect() {
150   Disconnected = true;
151   T->disconnect();
152   return Error::success();
153 }
154 
155 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
156 SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
157                                ExecutorAddress TagAddr,
158                                SimpleRemoteEPCArgBytesVector ArgBytes) {
159   using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
160   if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) ||
161       static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
162     return make_error<StringError>("Unexpected opcode",
163                                    inconvertibleErrorCode());
164 
165   switch (OpC) {
166   case SimpleRemoteEPCOpcode::Setup:
167     if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
168       return std::move(Err);
169     break;
170   case SimpleRemoteEPCOpcode::Hangup:
171     // FIXME: Put EPC into 'detached' state.
172     return SimpleRemoteEPCTransportClient::EndSession;
173   case SimpleRemoteEPCOpcode::Result:
174     if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
175       return std::move(Err);
176     break;
177   case SimpleRemoteEPCOpcode::CallWrapper:
178     handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
179     break;
180   }
181   return ContinueSession;
182 }
183 
184 void SimpleRemoteEPC::handleDisconnect(Error Err) {
185   PendingCallWrapperResultsMap TmpPending;
186 
187   {
188     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
189     std::swap(TmpPending, PendingCallWrapperResults);
190   }
191 
192   for (auto &KV : TmpPending)
193     KV.second(
194         shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
195 
196   if (Err) {
197     // FIXME: Move ReportError to EPC.
198     if (ES)
199       ES->reportError(std::move(Err));
200     else
201       logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPC: ");
202   }
203 }
204 
205 void SimpleRemoteEPC::setMemoryManager(
206     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
207   OwnedMemMgr = std::move(MemMgr);
208   this->MemMgr = OwnedMemMgr.get();
209 }
210 
211 void SimpleRemoteEPC::setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess) {
212   OwnedMemAccess = std::move(MemAccess);
213   this->MemAccess = OwnedMemAccess.get();
214 }
215 
216 Error SimpleRemoteEPC::setupDefaultMemoryManager(
217     const SimpleRemoteEPCExecutorInfo &EI) {
218 
219   EPCGenericJITLinkMemoryManager::FuncAddrs FAs;
220 
221   if (auto Err = EI.getBootstrapSymbols(
222           {{FAs.Reserve, "__llvm_orc_memory_reserve"},
223            {FAs.Finalize, "__llvm_orc_memory_finalize"},
224            {FAs.Deallocate, "__llvm_orc_memory_deallocate"}}))
225     return Err;
226 
227   setMemoryManager(
228       std::make_unique<EPCGenericJITLinkMemoryManager>(*this, FAs));
229   return Error::success();
230 }
231 
232 Error SimpleRemoteEPC::setupDefaultMemoryAccess(
233     const SimpleRemoteEPCExecutorInfo &EI) {
234 
235   return Error::success();
236 }
237 
238 Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
239                                    SimpleRemoteEPCArgBytesVector ArgBytes) {
240   if (SeqNo != 0)
241     return make_error<StringError>("Setup packet SeqNo not zero",
242                                    inconvertibleErrorCode());
243 
244   if (TagAddr)
245     return make_error<StringError>("Setup packet TagAddr not zero",
246                                    inconvertibleErrorCode());
247 
248   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
249   auto I = PendingCallWrapperResults.find(0);
250   assert(PendingCallWrapperResults.size() == 1 &&
251          I != PendingCallWrapperResults.end() &&
252          "Setup message handler not connectly set up");
253   auto SetupMsgHandler = std::move(I->second);
254   PendingCallWrapperResults.erase(I);
255 
256   auto WFR =
257       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
258   SetupMsgHandler(std::move(WFR));
259   return Error::success();
260 }
261 
262 void SimpleRemoteEPC::prepareToReceiveSetupMessage(
263     std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP) {
264   PendingCallWrapperResults[0] =
265       [&](shared::WrapperFunctionResult SetupMsgBytes) {
266         if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
267           ExecInfoP.set_value(
268               make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
269           return;
270         }
271         using SPSSerialize =
272             shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
273         shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
274         SimpleRemoteEPCExecutorInfo EI;
275         if (SPSSerialize::deserialize(IB, EI))
276           ExecInfoP.set_value(EI);
277         else
278           ExecInfoP.set_value(make_error<StringError>(
279               "Could not deserialize setup message", inconvertibleErrorCode()));
280       };
281 }
282 
283 Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
284                                     SimpleRemoteEPCArgBytesVector ArgBytes) {
285   SendResultFunction SendResult;
286 
287   if (TagAddr)
288     return make_error<StringError>("Unexpected TagAddr in result message",
289                                    inconvertibleErrorCode());
290 
291   {
292     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
293     auto I = PendingCallWrapperResults.find(SeqNo);
294     if (I == PendingCallWrapperResults.end())
295       return make_error<StringError>("No call for sequence number " +
296                                          Twine(SeqNo),
297                                      inconvertibleErrorCode());
298     SendResult = std::move(I->second);
299     PendingCallWrapperResults.erase(I);
300     releaseSeqNo(SeqNo);
301   }
302 
303   auto WFR =
304       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
305   SendResult(std::move(WFR));
306   return Error::success();
307 }
308 
309 void SimpleRemoteEPC::handleCallWrapper(
310     uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
311     SimpleRemoteEPCArgBytesVector ArgBytes) {
312   assert(ES && "No ExecutionSession attached");
313   ES->runJITDispatchHandler(
314       [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
315         if (auto Err =
316                 T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
317                                ExecutorAddress(), {WFR.data(), WFR.size()}))
318           getExecutionSession().reportError(std::move(Err));
319       },
320       TagAddr.getValue(), ArgBytes);
321 }
322 
323 } // end namespace orc
324 } // end namespace llvm
325