1349cc55cSDimitry Andric //===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h" 10349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h" 11349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12349cc55cSDimitry Andric #include "llvm/Support/Alignment.h" 13349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h" 14349cc55cSDimitry Andric 15349cc55cSDimitry Andric #define DEBUG_TYPE "orc" 16349cc55cSDimitry Andric 1704eeddc0SDimitry Andric using namespace llvm::orc::shared; 1804eeddc0SDimitry Andric 19349cc55cSDimitry Andric namespace llvm { 20349cc55cSDimitry Andric namespace orc { 21349cc55cSDimitry Andric 22349cc55cSDimitry Andric Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>> 23349cc55cSDimitry Andric EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols( 24349cc55cSDimitry Andric ExecutorProcessControl &EPC) { 25349cc55cSDimitry Andric SymbolAddrs SAs; 26349cc55cSDimitry Andric if (auto Err = EPC.getBootstrapSymbols( 27349cc55cSDimitry Andric {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName}, 28349cc55cSDimitry Andric {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName}, 29349cc55cSDimitry Andric {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName}, 30349cc55cSDimitry Andric {SAs.Deallocate, 31349cc55cSDimitry Andric rt::SimpleExecutorMemoryManagerDeallocateWrapperName}, 3204eeddc0SDimitry Andric {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName}, 3304eeddc0SDimitry Andric {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}})) 34349cc55cSDimitry Andric return std::move(Err); 35349cc55cSDimitry Andric return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs)); 36349cc55cSDimitry Andric } 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager( 39349cc55cSDimitry Andric ExecutorProcessControl &EPC, SymbolAddrs SAs) 40349cc55cSDimitry Andric : EPC(EPC), SAs(std::move(SAs)) { 41349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n"); 42349cc55cSDimitry Andric } 43349cc55cSDimitry Andric 44349cc55cSDimitry Andric EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() { 45349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n"); 46349cc55cSDimitry Andric if (!ErrMsg.empty()) 47349cc55cSDimitry Andric errs() << "Destroying with existing errors:\n" << ErrMsg << "\n"; 48349cc55cSDimitry Andric 49349cc55cSDimitry Andric Error Err = Error::success(); 50349cc55cSDimitry Andric if (auto Err2 = EPC.callSPSWrapper< 51349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>( 52349cc55cSDimitry Andric SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) { 53349cc55cSDimitry Andric // FIXME: Report errors through EPC once that functionality is available. 54349cc55cSDimitry Andric logAllUnhandledErrors(std::move(Err2), errs(), ""); 55349cc55cSDimitry Andric return; 56349cc55cSDimitry Andric } 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric if (Err) 59349cc55cSDimitry Andric logAllUnhandledErrors(std::move(Err), errs(), ""); 60349cc55cSDimitry Andric } 61349cc55cSDimitry Andric 62349cc55cSDimitry Andric uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection( 63349cc55cSDimitry Andric uintptr_t Size, unsigned Alignment, unsigned SectionID, 64349cc55cSDimitry Andric StringRef SectionName) { 65349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 66349cc55cSDimitry Andric LLVM_DEBUG({ 67349cc55cSDimitry Andric dbgs() << "Allocator " << (void *)this << " allocating code section " 68349cc55cSDimitry Andric << SectionName << ": size = " << formatv("{0:x}", Size) 69349cc55cSDimitry Andric << " bytes, alignment = " << Alignment << "\n"; 70349cc55cSDimitry Andric }); 71349cc55cSDimitry Andric auto &Seg = Unmapped.back().CodeAllocs; 72349cc55cSDimitry Andric Seg.emplace_back(Size, Alignment); 73349cc55cSDimitry Andric return reinterpret_cast<uint8_t *>( 74349cc55cSDimitry Andric alignAddr(Seg.back().Contents.get(), Align(Alignment))); 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77349cc55cSDimitry Andric uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection( 78349cc55cSDimitry Andric uintptr_t Size, unsigned Alignment, unsigned SectionID, 79349cc55cSDimitry Andric StringRef SectionName, bool IsReadOnly) { 80349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 81349cc55cSDimitry Andric LLVM_DEBUG({ 82349cc55cSDimitry Andric dbgs() << "Allocator " << (void *)this << " allocating " 83349cc55cSDimitry Andric << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName 84349cc55cSDimitry Andric << ": size = " << formatv("{0:x}", Size) << " bytes, alignment " 85349cc55cSDimitry Andric << Alignment << ")\n"; 86349cc55cSDimitry Andric }); 87349cc55cSDimitry Andric 88349cc55cSDimitry Andric auto &Seg = 89349cc55cSDimitry Andric IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs; 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric Seg.emplace_back(Size, Alignment); 92349cc55cSDimitry Andric return reinterpret_cast<uint8_t *>( 93349cc55cSDimitry Andric alignAddr(Seg.back().Contents.get(), Align(Alignment))); 94349cc55cSDimitry Andric } 95349cc55cSDimitry Andric 96349cc55cSDimitry Andric void EPCGenericRTDyldMemoryManager::reserveAllocationSpace( 97*bdd1243dSDimitry Andric uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize, 98*bdd1243dSDimitry Andric Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) { 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric { 101349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 102349cc55cSDimitry Andric // If there's already an error then bail out. 103349cc55cSDimitry Andric if (!ErrMsg.empty()) 104349cc55cSDimitry Andric return; 105349cc55cSDimitry Andric 106*bdd1243dSDimitry Andric if (CodeAlign > EPC.getPageSize()) { 107349cc55cSDimitry Andric ErrMsg = "Invalid code alignment in reserveAllocationSpace"; 108349cc55cSDimitry Andric return; 109349cc55cSDimitry Andric } 110*bdd1243dSDimitry Andric if (RODataAlign > EPC.getPageSize()) { 111349cc55cSDimitry Andric ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace"; 112349cc55cSDimitry Andric return; 113349cc55cSDimitry Andric } 114*bdd1243dSDimitry Andric if (RWDataAlign > EPC.getPageSize()) { 115349cc55cSDimitry Andric ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace"; 116349cc55cSDimitry Andric return; 117349cc55cSDimitry Andric } 118349cc55cSDimitry Andric } 119349cc55cSDimitry Andric 120349cc55cSDimitry Andric uint64_t TotalSize = 0; 121349cc55cSDimitry Andric TotalSize += alignTo(CodeSize, EPC.getPageSize()); 122349cc55cSDimitry Andric TotalSize += alignTo(RODataSize, EPC.getPageSize()); 123349cc55cSDimitry Andric TotalSize += alignTo(RWDataSize, EPC.getPageSize()); 124349cc55cSDimitry Andric 125349cc55cSDimitry Andric LLVM_DEBUG({ 126349cc55cSDimitry Andric dbgs() << "Allocator " << (void *)this << " reserving " 127349cc55cSDimitry Andric << formatv("{0:x}", TotalSize) << " bytes.\n"; 128349cc55cSDimitry Andric }); 129349cc55cSDimitry Andric 130349cc55cSDimitry Andric Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr())); 131349cc55cSDimitry Andric if (auto Err = EPC.callSPSWrapper< 132349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerReserveSignature>( 133349cc55cSDimitry Andric SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) { 134349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 135349cc55cSDimitry Andric ErrMsg = toString(std::move(Err)); 136349cc55cSDimitry Andric return; 137349cc55cSDimitry Andric } 138349cc55cSDimitry Andric if (!TargetAllocAddr) { 139349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 140349cc55cSDimitry Andric ErrMsg = toString(TargetAllocAddr.takeError()); 141349cc55cSDimitry Andric return; 142349cc55cSDimitry Andric } 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 145*bdd1243dSDimitry Andric Unmapped.push_back(SectionAllocGroup()); 146349cc55cSDimitry Andric Unmapped.back().RemoteCode = { 147349cc55cSDimitry Andric *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))}; 148349cc55cSDimitry Andric Unmapped.back().RemoteROData = { 149349cc55cSDimitry Andric Unmapped.back().RemoteCode.End, 150349cc55cSDimitry Andric ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))}; 151349cc55cSDimitry Andric Unmapped.back().RemoteRWData = { 152349cc55cSDimitry Andric Unmapped.back().RemoteROData.End, 153349cc55cSDimitry Andric ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))}; 154349cc55cSDimitry Andric } 155349cc55cSDimitry Andric 156349cc55cSDimitry Andric bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() { 157349cc55cSDimitry Andric return true; 158349cc55cSDimitry Andric } 159349cc55cSDimitry Andric 160349cc55cSDimitry Andric void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr, 161349cc55cSDimitry Andric uint64_t LoadAddr, 162349cc55cSDimitry Andric size_t Size) { 163349cc55cSDimitry Andric LLVM_DEBUG({ 164349cc55cSDimitry Andric dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame " 165349cc55cSDimitry Andric << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n"; 166349cc55cSDimitry Andric }); 167349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 168349cc55cSDimitry Andric // Bail out early if there's already an error. 169349cc55cSDimitry Andric if (!ErrMsg.empty()) 170349cc55cSDimitry Andric return; 171349cc55cSDimitry Andric 172349cc55cSDimitry Andric ExecutorAddr LA(LoadAddr); 173*bdd1243dSDimitry Andric for (auto &SecAllocGroup : llvm::reverse(Unfinalized)) { 174*bdd1243dSDimitry Andric if (SecAllocGroup.RemoteCode.contains(LA) || 175*bdd1243dSDimitry Andric SecAllocGroup.RemoteROData.contains(LA) || 176*bdd1243dSDimitry Andric SecAllocGroup.RemoteRWData.contains(LA)) { 177*bdd1243dSDimitry Andric SecAllocGroup.UnfinalizedEHFrames.push_back({LA, Size}); 178349cc55cSDimitry Andric return; 179349cc55cSDimitry Andric } 180349cc55cSDimitry Andric } 181349cc55cSDimitry Andric ErrMsg = "eh-frame does not lie inside unfinalized alloc"; 182349cc55cSDimitry Andric } 183349cc55cSDimitry Andric 184349cc55cSDimitry Andric void EPCGenericRTDyldMemoryManager::deregisterEHFrames() { 185349cc55cSDimitry Andric // This is a no-op for us: We've registered a deallocation action for it. 186349cc55cSDimitry Andric } 187349cc55cSDimitry Andric 188349cc55cSDimitry Andric void EPCGenericRTDyldMemoryManager::notifyObjectLoaded( 189349cc55cSDimitry Andric RuntimeDyld &Dyld, const object::ObjectFile &Obj) { 190349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 191349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n"); 192349cc55cSDimitry Andric for (auto &ObjAllocs : Unmapped) { 193349cc55cSDimitry Andric mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs, 194349cc55cSDimitry Andric ObjAllocs.RemoteCode.Start); 195349cc55cSDimitry Andric mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs, 196349cc55cSDimitry Andric ObjAllocs.RemoteROData.Start); 197349cc55cSDimitry Andric mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs, 198349cc55cSDimitry Andric ObjAllocs.RemoteRWData.Start); 199349cc55cSDimitry Andric Unfinalized.push_back(std::move(ObjAllocs)); 200349cc55cSDimitry Andric } 201349cc55cSDimitry Andric Unmapped.clear(); 202349cc55cSDimitry Andric } 203349cc55cSDimitry Andric 204349cc55cSDimitry Andric bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) { 205349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n"); 206349cc55cSDimitry Andric 207349cc55cSDimitry Andric // If there's an error then bail out here. 208*bdd1243dSDimitry Andric std::vector<SectionAllocGroup> SecAllocGroups; 209349cc55cSDimitry Andric { 210349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 211349cc55cSDimitry Andric if (ErrMsg && !this->ErrMsg.empty()) { 212349cc55cSDimitry Andric *ErrMsg = std::move(this->ErrMsg); 213349cc55cSDimitry Andric return true; 214349cc55cSDimitry Andric } 215*bdd1243dSDimitry Andric std::swap(SecAllocGroups, Unfinalized); 216349cc55cSDimitry Andric } 217349cc55cSDimitry Andric 218349cc55cSDimitry Andric // Loop over unfinalized objects to make finalization requests. 219*bdd1243dSDimitry Andric for (auto &SecAllocGroup : SecAllocGroups) { 220349cc55cSDimitry Andric 221*bdd1243dSDimitry Andric MemProt SegMemProts[3] = {MemProt::Read | MemProt::Exec, MemProt::Read, 222*bdd1243dSDimitry Andric MemProt::Read | MemProt::Write}; 223349cc55cSDimitry Andric 224*bdd1243dSDimitry Andric ExecutorAddrRange *RemoteAddrs[3] = {&SecAllocGroup.RemoteCode, 225*bdd1243dSDimitry Andric &SecAllocGroup.RemoteROData, 226*bdd1243dSDimitry Andric &SecAllocGroup.RemoteRWData}; 227349cc55cSDimitry Andric 228*bdd1243dSDimitry Andric std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs, 229*bdd1243dSDimitry Andric &SecAllocGroup.RODataAllocs, 230*bdd1243dSDimitry Andric &SecAllocGroup.RWDataAllocs}; 231349cc55cSDimitry Andric 232349cc55cSDimitry Andric tpctypes::FinalizeRequest FR; 233349cc55cSDimitry Andric std::unique_ptr<char[]> AggregateContents[3]; 234349cc55cSDimitry Andric 235349cc55cSDimitry Andric for (unsigned I = 0; I != 3; ++I) { 236349cc55cSDimitry Andric FR.Segments.push_back({}); 237349cc55cSDimitry Andric auto &Seg = FR.Segments.back(); 238*bdd1243dSDimitry Andric Seg.AG = SegMemProts[I]; 239349cc55cSDimitry Andric Seg.Addr = RemoteAddrs[I]->Start; 240349cc55cSDimitry Andric for (auto &SecAlloc : *SegSections[I]) { 241349cc55cSDimitry Andric Seg.Size = alignTo(Seg.Size, SecAlloc.Align); 242349cc55cSDimitry Andric Seg.Size += SecAlloc.Size; 243349cc55cSDimitry Andric } 244349cc55cSDimitry Andric AggregateContents[I] = std::make_unique<char[]>(Seg.Size); 245349cc55cSDimitry Andric size_t SecOffset = 0; 246349cc55cSDimitry Andric for (auto &SecAlloc : *SegSections[I]) { 247349cc55cSDimitry Andric SecOffset = alignTo(SecOffset, SecAlloc.Align); 248349cc55cSDimitry Andric memcpy(&AggregateContents[I][SecOffset], 249349cc55cSDimitry Andric reinterpret_cast<const char *>( 250349cc55cSDimitry Andric alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))), 251349cc55cSDimitry Andric SecAlloc.Size); 252349cc55cSDimitry Andric SecOffset += SecAlloc.Size; 253349cc55cSDimitry Andric // FIXME: Can we reset SecAlloc.Content here, now that it's copied into 254349cc55cSDimitry Andric // the aggregated content? 255349cc55cSDimitry Andric } 256349cc55cSDimitry Andric Seg.Content = {AggregateContents[I].get(), SecOffset}; 257349cc55cSDimitry Andric } 258349cc55cSDimitry Andric 259*bdd1243dSDimitry Andric for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames) 260349cc55cSDimitry Andric FR.Actions.push_back( 26104eeddc0SDimitry Andric {cantFail( 26204eeddc0SDimitry Andric WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( 26304eeddc0SDimitry Andric SAs.RegisterEHFrame, Frame)), 26404eeddc0SDimitry Andric cantFail( 26504eeddc0SDimitry Andric WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( 26604eeddc0SDimitry Andric SAs.DeregisterEHFrame, Frame))}); 267349cc55cSDimitry Andric 268349cc55cSDimitry Andric // We'll also need to make an extra allocation for the eh-frame wrapper call 269349cc55cSDimitry Andric // arguments. 270349cc55cSDimitry Andric Error FinalizeErr = Error::success(); 271349cc55cSDimitry Andric if (auto Err = EPC.callSPSWrapper< 272349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>( 273349cc55cSDimitry Andric SAs.Finalize, FinalizeErr, SAs.Instance, std::move(FR))) { 274349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 275349cc55cSDimitry Andric this->ErrMsg = toString(std::move(Err)); 276349cc55cSDimitry Andric dbgs() << "Serialization error: " << this->ErrMsg << "\n"; 277349cc55cSDimitry Andric if (ErrMsg) 278349cc55cSDimitry Andric *ErrMsg = this->ErrMsg; 279349cc55cSDimitry Andric return true; 280349cc55cSDimitry Andric } 281349cc55cSDimitry Andric if (FinalizeErr) { 282349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 283349cc55cSDimitry Andric this->ErrMsg = toString(std::move(FinalizeErr)); 284349cc55cSDimitry Andric dbgs() << "Finalization error: " << this->ErrMsg << "\n"; 285349cc55cSDimitry Andric if (ErrMsg) 286349cc55cSDimitry Andric *ErrMsg = this->ErrMsg; 287349cc55cSDimitry Andric return true; 288349cc55cSDimitry Andric } 289349cc55cSDimitry Andric } 290349cc55cSDimitry Andric 291349cc55cSDimitry Andric return false; 292349cc55cSDimitry Andric } 293349cc55cSDimitry Andric 294349cc55cSDimitry Andric void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs( 295*bdd1243dSDimitry Andric RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs, 296*bdd1243dSDimitry Andric ExecutorAddr NextAddr) { 297349cc55cSDimitry Andric for (auto &Alloc : Allocs) { 298349cc55cSDimitry Andric NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align)); 299349cc55cSDimitry Andric LLVM_DEBUG({ 300349cc55cSDimitry Andric dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> " 301349cc55cSDimitry Andric << format("0x%016" PRIx64, NextAddr.getValue()) << "\n"; 302349cc55cSDimitry Andric }); 303349cc55cSDimitry Andric Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr( 304349cc55cSDimitry Andric Alloc.Contents.get(), Align(Alloc.Align))), 305349cc55cSDimitry Andric NextAddr.getValue()); 306349cc55cSDimitry Andric Alloc.RemoteAddr = NextAddr; 307349cc55cSDimitry Andric // Only advance NextAddr if it was non-null to begin with, 308349cc55cSDimitry Andric // otherwise leave it as null. 309349cc55cSDimitry Andric if (NextAddr) 310349cc55cSDimitry Andric NextAddr += ExecutorAddrDiff(Alloc.Size); 311349cc55cSDimitry Andric } 312349cc55cSDimitry Andric } 313349cc55cSDimitry Andric 314349cc55cSDimitry Andric } // end namespace orc 315349cc55cSDimitry Andric } // end namespace llvm 316