EPCGenericRTDyldMemoryManager.cpp 12 KB

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