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::LastOpC))
161     return make_error<StringError>("Unexpected opcode",
162                                    inconvertibleErrorCode());
163 
164   switch (OpC) {
165   case SimpleRemoteEPCOpcode::Setup:
166     if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
167       return std::move(Err);
168     break;
169   case SimpleRemoteEPCOpcode::Hangup:
170     // FIXME: Put EPC into 'detached' state.
171     return SimpleRemoteEPCTransportClient::EndSession;
172   case SimpleRemoteEPCOpcode::Result:
173     if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
174       return std::move(Err);
175     break;
176   case SimpleRemoteEPCOpcode::CallWrapper:
177     handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
178     break;
179   }
180   return ContinueSession;
181 }
182 
183 void SimpleRemoteEPC::handleDisconnect(Error Err) {
184   PendingCallWrapperResultsMap TmpPending;
185 
186   {
187     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
188     std::swap(TmpPending, PendingCallWrapperResults);
189   }
190 
191   for (auto &KV : TmpPending)
192     KV.second(
193         shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
194 
195   if (Err) {
196     // FIXME: Move ReportError to EPC.
197     if (ES)
198       ES->reportError(std::move(Err));
199     else
200       logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPC: ");
201   }
202 }
203 
204 void SimpleRemoteEPC::setMemoryManager(
205     std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
206   OwnedMemMgr = std::move(MemMgr);
207   this->MemMgr = OwnedMemMgr.get();
208 }
209 
210 void SimpleRemoteEPC::setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess) {
211   OwnedMemAccess = std::move(MemAccess);
212   this->MemAccess = OwnedMemAccess.get();
213 }
214 
215 Error SimpleRemoteEPC::setupDefaultMemoryManager(
216     const SimpleRemoteEPCExecutorInfo &EI) {
217 
218   EPCGenericJITLinkMemoryManager::FuncAddrs FAs;
219 
220   if (auto Err = EI.getBootstrapSymbols(
221           {{FAs.Reserve, "__llvm_orc_memory_reserve"},
222            {FAs.Finalize, "__llvm_orc_memory_finalize"},
223            {FAs.Deallocate, "__llvm_orc_memory_deallocate"}}))
224     return Err;
225 
226   setMemoryManager(
227       std::make_unique<EPCGenericJITLinkMemoryManager>(*this, FAs));
228   return Error::success();
229 }
230 
231 Error SimpleRemoteEPC::setupDefaultMemoryAccess(
232     const SimpleRemoteEPCExecutorInfo &EI) {
233 
234   return Error::success();
235 }
236 
237 Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
238                                    SimpleRemoteEPCArgBytesVector ArgBytes) {
239   if (SeqNo != 0)
240     return make_error<StringError>("Setup packet SeqNo not zero",
241                                    inconvertibleErrorCode());
242 
243   if (TagAddr)
244     return make_error<StringError>("Setup packet TagAddr not zero",
245                                    inconvertibleErrorCode());
246 
247   std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
248   auto I = PendingCallWrapperResults.find(0);
249   assert(PendingCallWrapperResults.size() == 1 &&
250          I != PendingCallWrapperResults.end() &&
251          "Setup message handler not connectly set up");
252   auto SetupMsgHandler = std::move(I->second);
253   PendingCallWrapperResults.erase(I);
254 
255   auto WFR =
256       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
257   SetupMsgHandler(std::move(WFR));
258   return Error::success();
259 }
260 
261 void SimpleRemoteEPC::prepareToReceiveSetupMessage(
262     std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP) {
263   PendingCallWrapperResults[0] =
264       [&](shared::WrapperFunctionResult SetupMsgBytes) {
265         if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
266           ExecInfoP.set_value(
267               make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
268           return;
269         }
270         using SPSSerialize =
271             shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
272         shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
273         SimpleRemoteEPCExecutorInfo EI;
274         if (SPSSerialize::deserialize(IB, EI))
275           ExecInfoP.set_value(EI);
276         else
277           ExecInfoP.set_value(make_error<StringError>(
278               "Could not deserialize setup message", inconvertibleErrorCode()));
279       };
280 }
281 
282 Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
283                                     SimpleRemoteEPCArgBytesVector ArgBytes) {
284   SendResultFunction SendResult;
285 
286   if (TagAddr)
287     return make_error<StringError>("Unexpected TagAddr in result message",
288                                    inconvertibleErrorCode());
289 
290   {
291     std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
292     auto I = PendingCallWrapperResults.find(SeqNo);
293     if (I == PendingCallWrapperResults.end())
294       return make_error<StringError>("No call for sequence number " +
295                                          Twine(SeqNo),
296                                      inconvertibleErrorCode());
297     SendResult = std::move(I->second);
298     PendingCallWrapperResults.erase(I);
299     releaseSeqNo(SeqNo);
300   }
301 
302   auto WFR =
303       shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
304   SendResult(std::move(WFR));
305   return Error::success();
306 }
307 
308 void SimpleRemoteEPC::handleCallWrapper(
309     uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
310     SimpleRemoteEPCArgBytesVector ArgBytes) {
311   assert(ES && "No ExecutionSession attached");
312   ES->runJITDispatchHandler(
313       [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
314         if (auto Err =
315                 T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
316                                ExecutorAddress(), {WFR.data(), WFR.size()}))
317           getExecutionSession().reportError(std::move(Err));
318       },
319       TagAddr.getValue(), ArgBytes);
320 }
321 
322 } // end namespace orc
323 } // end namespace llvm
324