316 lines · cpp
1//===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"10#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"11#include "llvm/Support/Alignment.h"12#include "llvm/Support/FormatVariadic.h"13 14#define DEBUG_TYPE "orc"15 16using namespace llvm::orc::shared;17 18namespace llvm {19namespace orc {20 21Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>22EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(23 ExecutorProcessControl &EPC) {24 SymbolAddrs SAs;25 if (auto Err = EPC.getBootstrapSymbols(26 {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},27 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},28 {SAs.Initialize,29 rt::SimpleExecutorMemoryManagerInitializeWrapperName},30 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName},31 {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionAllocActionName},32 {SAs.DeregisterEHFrame,33 rt::DeregisterEHFrameSectionAllocActionName}}))34 return std::move(Err);35 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));36}37 38EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(39 ExecutorProcessControl &EPC, SymbolAddrs SAs)40 : EPC(EPC), SAs(std::move(SAs)) {41 LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");42}43 44EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {45 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");46 if (!ErrMsg.empty())47 errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";48 49 Error Err = Error::success();50 if (auto Err2 = EPC.callSPSWrapper<51 rt::SPSSimpleExecutorMemoryManagerReleaseSignature>(52 SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {53 // FIXME: Report errors through EPC once that functionality is available.54 logAllUnhandledErrors(std::move(Err2), errs(), "");55 return;56 }57 58 if (Err)59 logAllUnhandledErrors(std::move(Err), errs(), "");60}61 62uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(63 uintptr_t Size, unsigned Alignment, unsigned SectionID,64 StringRef SectionName) {65 std::lock_guard<std::mutex> Lock(M);66 LLVM_DEBUG({67 dbgs() << "Allocator " << (void *)this << " allocating code section "68 << SectionName << ": size = " << formatv("{0:x}", Size)69 << " bytes, alignment = " << Alignment << "\n";70 });71 auto &Seg = Unmapped.back().CodeAllocs;72 Seg.emplace_back(Size, Alignment);73 return reinterpret_cast<uint8_t *>(74 alignAddr(Seg.back().Contents.get(), Align(Alignment)));75}76 77uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(78 uintptr_t Size, unsigned Alignment, unsigned SectionID,79 StringRef SectionName, bool IsReadOnly) {80 std::lock_guard<std::mutex> Lock(M);81 LLVM_DEBUG({82 dbgs() << "Allocator " << (void *)this << " allocating "83 << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName84 << ": size = " << formatv("{0:x}", Size) << " bytes, alignment "85 << Alignment << ")\n";86 });87 88 auto &Seg =89 IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;90 91 Seg.emplace_back(Size, Alignment);92 return reinterpret_cast<uint8_t *>(93 alignAddr(Seg.back().Contents.get(), Align(Alignment)));94}95 96void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(97 uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,98 Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {99 100 {101 std::lock_guard<std::mutex> Lock(M);102 // If there's already an error then bail out.103 if (!ErrMsg.empty())104 return;105 106 if (CodeAlign > EPC.getPageSize()) {107 ErrMsg = "Invalid code alignment in reserveAllocationSpace";108 return;109 }110 if (RODataAlign > EPC.getPageSize()) {111 ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace";112 return;113 }114 if (RWDataAlign > EPC.getPageSize()) {115 ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace";116 return;117 }118 }119 120 uint64_t TotalSize = 0;121 TotalSize += alignTo(CodeSize, EPC.getPageSize());122 TotalSize += alignTo(RODataSize, EPC.getPageSize());123 TotalSize += alignTo(RWDataSize, EPC.getPageSize());124 125 LLVM_DEBUG({126 dbgs() << "Allocator " << (void *)this << " reserving "127 << formatv("{0:x}", TotalSize) << " bytes.\n";128 });129 130 Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr()));131 if (auto Err = EPC.callSPSWrapper<132 rt::SPSSimpleExecutorMemoryManagerReserveSignature>(133 SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {134 std::lock_guard<std::mutex> Lock(M);135 ErrMsg = toString(std::move(Err));136 return;137 }138 if (!TargetAllocAddr) {139 std::lock_guard<std::mutex> Lock(M);140 ErrMsg = toString(TargetAllocAddr.takeError());141 return;142 }143 144 std::lock_guard<std::mutex> Lock(M);145 Unmapped.push_back(SectionAllocGroup());146 Unmapped.back().RemoteCode = {147 *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))};148 Unmapped.back().RemoteROData = {149 Unmapped.back().RemoteCode.End,150 ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))};151 Unmapped.back().RemoteRWData = {152 Unmapped.back().RemoteROData.End,153 ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))};154}155 156bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {157 return true;158}159 160void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr,161 uint64_t LoadAddr,162 size_t Size) {163 LLVM_DEBUG({164 dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "165 << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";166 });167 std::lock_guard<std::mutex> Lock(M);168 // Bail out early if there's already an error.169 if (!ErrMsg.empty())170 return;171 172 ExecutorAddr LA(LoadAddr);173 for (auto &SecAllocGroup : llvm::reverse(Unfinalized)) {174 if (SecAllocGroup.RemoteCode.contains(LA) ||175 SecAllocGroup.RemoteROData.contains(LA) ||176 SecAllocGroup.RemoteRWData.contains(LA)) {177 SecAllocGroup.UnfinalizedEHFrames.push_back({LA, Size});178 return;179 }180 }181 ErrMsg = "eh-frame does not lie inside unfinalized alloc";182}183 184void EPCGenericRTDyldMemoryManager::deregisterEHFrames() {185 // This is a no-op for us: We've registered a deallocation action for it.186}187 188void EPCGenericRTDyldMemoryManager::notifyObjectLoaded(189 RuntimeDyld &Dyld, const object::ObjectFile &Obj) {190 std::lock_guard<std::mutex> Lock(M);191 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n");192 for (auto &ObjAllocs : Unmapped) {193 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,194 ObjAllocs.RemoteCode.Start);195 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,196 ObjAllocs.RemoteROData.Start);197 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,198 ObjAllocs.RemoteRWData.Start);199 Unfinalized.push_back(std::move(ObjAllocs));200 }201 Unmapped.clear();202}203 204bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) {205 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");206 207 // If there's an error then bail out here.208 std::vector<SectionAllocGroup> SecAllocGroups;209 {210 std::lock_guard<std::mutex> Lock(M);211 if (ErrMsg && !this->ErrMsg.empty()) {212 *ErrMsg = std::move(this->ErrMsg);213 return true;214 }215 std::swap(SecAllocGroups, Unfinalized);216 }217 218 // Loop over unfinalized objects to make finalization requests.219 for (auto &SecAllocGroup : SecAllocGroups) {220 221 MemProt SegMemProts[3] = {MemProt::Read | MemProt::Exec, MemProt::Read,222 MemProt::Read | MemProt::Write};223 224 ExecutorAddrRange *RemoteAddrs[3] = {&SecAllocGroup.RemoteCode,225 &SecAllocGroup.RemoteROData,226 &SecAllocGroup.RemoteRWData};227 228 std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs,229 &SecAllocGroup.RODataAllocs,230 &SecAllocGroup.RWDataAllocs};231 232 tpctypes::FinalizeRequest FR;233 std::unique_ptr<char[]> AggregateContents[3];234 235 for (unsigned I = 0; I != 3; ++I) {236 FR.Segments.push_back({});237 auto &Seg = FR.Segments.back();238 Seg.RAG = SegMemProts[I];239 Seg.Addr = RemoteAddrs[I]->Start;240 for (auto &SecAlloc : *SegSections[I]) {241 Seg.Size = alignTo(Seg.Size, SecAlloc.Align);242 Seg.Size += SecAlloc.Size;243 }244 AggregateContents[I] = std::make_unique<char[]>(Seg.Size);245 size_t SecOffset = 0;246 for (auto &SecAlloc : *SegSections[I]) {247 SecOffset = alignTo(SecOffset, SecAlloc.Align);248 memcpy(&AggregateContents[I][SecOffset],249 reinterpret_cast<const char *>(250 alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))),251 SecAlloc.Size);252 SecOffset += SecAlloc.Size;253 // FIXME: Can we reset SecAlloc.Content here, now that it's copied into254 // the aggregated content?255 }256 Seg.Content = {AggregateContents[I].get(), SecOffset};257 }258 259 for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames)260 FR.Actions.push_back(261 {cantFail(262 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(263 SAs.RegisterEHFrame, Frame)),264 cantFail(265 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(266 SAs.DeregisterEHFrame, Frame))});267 268 // We'll also need to make an extra allocation for the eh-frame wrapper call269 // arguments.270 Expected<ExecutorAddr> InitializeKey((ExecutorAddr()));271 if (auto Err = EPC.callSPSWrapper<272 rt::SPSSimpleExecutorMemoryManagerInitializeSignature>(273 SAs.Initialize, InitializeKey, SAs.Instance, std::move(FR))) {274 std::lock_guard<std::mutex> Lock(M);275 this->ErrMsg = toString(std::move(Err));276 dbgs() << "Serialization error: " << this->ErrMsg << "\n";277 if (ErrMsg)278 *ErrMsg = this->ErrMsg;279 return true;280 }281 if (!InitializeKey) {282 std::lock_guard<std::mutex> Lock(M);283 this->ErrMsg = toString(InitializeKey.takeError());284 dbgs() << "Finalization error: " << this->ErrMsg << "\n";285 if (ErrMsg)286 *ErrMsg = this->ErrMsg;287 return true;288 }289 }290 291 return false;292}293 294void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(295 RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs,296 ExecutorAddr NextAddr) {297 for (auto &Alloc : Allocs) {298 NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align));299 LLVM_DEBUG({300 dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> "301 << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";302 });303 Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(304 Alloc.Contents.get(), Align(Alloc.Align))),305 NextAddr.getValue());306 Alloc.RemoteAddr = NextAddr;307 // Only advance NextAddr if it was non-null to begin with,308 // otherwise leave it as null.309 if (NextAddr)310 NextAddr += ExecutorAddrDiff(Alloc.Size);311 }312}313 314} // end namespace orc315} // end namespace llvm316