1 //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===//
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/SimpleExecutorMemoryManager.h"
10 
11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
12 #include "llvm/Support/FormatVariadic.h"
13 
14 #define DEBUG_TYPE "orc"
15 
16 namespace llvm {
17 namespace orc {
18 namespace rt_bootstrap {
19 
20 SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() {
21   assert(Allocations.empty() && "shutdown not called?");
22 }
23 
24 Expected<ExecutorAddr> SimpleExecutorMemoryManager::allocate(uint64_t Size) {
25   std::error_code EC;
26   auto MB = sys::Memory::allocateMappedMemory(
27       Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
28   if (EC)
29     return errorCodeToError(EC);
30   std::lock_guard<std::mutex> Lock(M);
31   assert(!Allocations.count(MB.base()) && "Duplicate allocation addr");
32   Allocations[MB.base()].Size = Size;
33   return ExecutorAddr::fromPtr(MB.base());
34 }
35 
36 Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) {
37   ExecutorAddr Base(~0ULL);
38   std::vector<shared::WrapperFunctionCall> DeallocationActions;
39   size_t SuccessfulFinalizationActions = 0;
40 
41   if (FR.Segments.empty()) {
42     // NOTE: Finalizing nothing is currently a no-op. Should it be an error?
43     if (FR.Actions.empty())
44       return Error::success();
45     else
46       return make_error<StringError>("Finalization actions attached to empty "
47                                      "finalization request",
48                                      inconvertibleErrorCode());
49   }
50 
51   for (auto &Seg : FR.Segments)
52     Base = std::min(Base, Seg.Addr);
53 
54   for (auto &ActPair : FR.Actions)
55     if (ActPair.Dealloc)
56       DeallocationActions.push_back(ActPair.Dealloc);
57 
58   // Get the Allocation for this finalization.
59   size_t AllocSize = 0;
60   {
61     std::lock_guard<std::mutex> Lock(M);
62     auto I = Allocations.find(Base.toPtr<void *>());
63     if (I == Allocations.end())
64       return make_error<StringError>("Attempt to finalize unrecognized "
65                                      "allocation " +
66                                          formatv("{0:x}", Base.getValue()),
67                                      inconvertibleErrorCode());
68     AllocSize = I->second.Size;
69     I->second.DeallocationActions = std::move(DeallocationActions);
70   }
71   ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize);
72 
73   // Bail-out function: this will run deallocation actions corresponding to any
74   // completed finalization actions, then deallocate memory.
75   auto BailOut = [&](Error Err) {
76     std::pair<void *, Allocation> AllocToDestroy;
77 
78     // Get allocation to destory.
79     {
80       std::lock_guard<std::mutex> Lock(M);
81       auto I = Allocations.find(Base.toPtr<void *>());
82 
83       // Check for missing allocation (effective a double free).
84       if (I == Allocations.end())
85         return joinErrors(
86             std::move(Err),
87             make_error<StringError>("No allocation entry found "
88                                     "for " +
89                                         formatv("{0:x}", Base.getValue()),
90                                     inconvertibleErrorCode()));
91       AllocToDestroy = std::move(*I);
92       Allocations.erase(I);
93     }
94 
95     // Run deallocation actions for all completed finalization actions.
96     while (SuccessfulFinalizationActions)
97       Err =
98           joinErrors(std::move(Err), FR.Actions[--SuccessfulFinalizationActions]
99                                          .Dealloc.runWithSPSRetErrorMerged());
100 
101     // Deallocate memory.
102     sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size);
103     if (auto EC = sys::Memory::releaseMappedMemory(MB))
104       Err = joinErrors(std::move(Err), errorCodeToError(EC));
105 
106     return Err;
107   };
108 
109   // Copy content and apply permissions.
110   for (auto &Seg : FR.Segments) {
111 
112     // Check segment ranges.
113     if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size()))
114       return BailOut(make_error<StringError>(
115           formatv("Segment {0:x} content size ({1:x} bytes) "
116                   "exceeds segment size ({2:x} bytes)",
117                   Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
118           inconvertibleErrorCode()));
119     ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size);
120     if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd))
121       return BailOut(make_error<StringError>(
122           formatv("Segment {0:x} -- {1:x} crosses boundary of "
123                   "allocation {2:x} -- {3:x}",
124                   Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(),
125                   AllocEnd.getValue()),
126           inconvertibleErrorCode()));
127 
128     char *Mem = Seg.Addr.toPtr<char *>();
129     memcpy(Mem, Seg.Content.data(), Seg.Content.size());
130     memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
131     assert(Seg.Size <= std::numeric_limits<size_t>::max());
132     if (auto EC = sys::Memory::protectMappedMemory(
133             {Mem, static_cast<size_t>(Seg.Size)},
134             tpctypes::fromWireProtectionFlags(Seg.Prot)))
135       return BailOut(errorCodeToError(EC));
136     if (Seg.Prot & tpctypes::WPF_Exec)
137       sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
138   }
139 
140   // Run finalization actions.
141   for (auto &ActPair : FR.Actions) {
142     if (auto Err = ActPair.Finalize.runWithSPSRetErrorMerged())
143       return BailOut(std::move(Err));
144     ++SuccessfulFinalizationActions;
145   }
146 
147   return Error::success();
148 }
149 
150 Error SimpleExecutorMemoryManager::deallocate(
151     const std::vector<ExecutorAddr> &Bases) {
152   std::vector<std::pair<void *, Allocation>> AllocPairs;
153   AllocPairs.reserve(Bases.size());
154 
155   // Get allocation to destory.
156   Error Err = Error::success();
157   {
158     std::lock_guard<std::mutex> Lock(M);
159     for (auto &Base : Bases) {
160       auto I = Allocations.find(Base.toPtr<void *>());
161 
162       // Check for missing allocation (effective a double free).
163       if (I != Allocations.end()) {
164         AllocPairs.push_back(std::move(*I));
165         Allocations.erase(I);
166       } else
167         Err = joinErrors(
168             std::move(Err),
169             make_error<StringError>("No allocation entry found "
170                                     "for " +
171                                         formatv("{0:x}", Base.getValue()),
172                                     inconvertibleErrorCode()));
173     }
174   }
175 
176   while (!AllocPairs.empty()) {
177     auto &P = AllocPairs.back();
178     Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second));
179     AllocPairs.pop_back();
180   }
181 
182   return Err;
183 }
184 
185 Error SimpleExecutorMemoryManager::shutdown() {
186 
187   AllocationsMap AM;
188   {
189     std::lock_guard<std::mutex> Lock(M);
190     AM = std::move(Allocations);
191   }
192 
193   Error Err = Error::success();
194   for (auto &KV : AM)
195     Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second));
196   return Err;
197 }
198 
199 void SimpleExecutorMemoryManager::addBootstrapSymbols(
200     StringMap<ExecutorAddr> &M) {
201   M[rt::SimpleExecutorMemoryManagerInstanceName] = ExecutorAddr::fromPtr(this);
202   M[rt::SimpleExecutorMemoryManagerReserveWrapperName] =
203       ExecutorAddr::fromPtr(&reserveWrapper);
204   M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] =
205       ExecutorAddr::fromPtr(&finalizeWrapper);
206   M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] =
207       ExecutorAddr::fromPtr(&deallocateWrapper);
208 }
209 
210 Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) {
211   Error Err = Error::success();
212 
213   while (!A.DeallocationActions.empty()) {
214     Err = joinErrors(std::move(Err),
215                      A.DeallocationActions.back().runWithSPSRetErrorMerged());
216     A.DeallocationActions.pop_back();
217   }
218 
219   sys::MemoryBlock MB(Base, A.Size);
220   if (auto EC = sys::Memory::releaseMappedMemory(MB))
221     Err = joinErrors(std::move(Err), errorCodeToError(EC));
222 
223   return Err;
224 }
225 
226 llvm::orc::shared::CWrapperFunctionResult
227 SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
228                                             size_t ArgSize) {
229   return shared::WrapperFunction<
230              rt::SPSSimpleExecutorMemoryManagerReserveSignature>::
231       handle(ArgData, ArgSize,
232              shared::makeMethodWrapperHandler(
233                  &SimpleExecutorMemoryManager::allocate))
234           .release();
235 }
236 
237 llvm::orc::shared::CWrapperFunctionResult
238 SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData,
239                                              size_t ArgSize) {
240   return shared::WrapperFunction<
241              rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>::
242       handle(ArgData, ArgSize,
243              shared::makeMethodWrapperHandler(
244                  &SimpleExecutorMemoryManager::finalize))
245           .release();
246 }
247 
248 llvm::orc::shared::CWrapperFunctionResult
249 SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData,
250                                                size_t ArgSize) {
251   return shared::WrapperFunction<
252              rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>::
253       handle(ArgData, ArgSize,
254              shared::makeMethodWrapperHandler(
255                  &SimpleExecutorMemoryManager::deallocate))
256           .release();
257 }
258 
259 } // namespace rt_bootstrap
260 } // end namespace orc
261 } // end namespace llvm
262