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