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