LLVM: lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

13

14#define DEBUG_TYPE "orc"

15

17

18namespace llvm {

19namespace orc {

20

21Expected<std::unique_ptr>

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(EPC, std::move(SAs));

36}

37

40 : EPC(EPC), SAs(std::move(SAs)) {

41 LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");

42}

43

45 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");

46 if (!ErrMsg.empty())

47 errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";

48

50 if (auto Err2 = EPC.callSPSWrapper<

52 SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {

53

55 return;

56 }

57

58 if (Err)

60}

61

63 uintptr_t Size, unsigned Alignment, unsigned SectionID,

65 std::lock_guardstd::mutex Lock(M);

67 dbgs() << "Allocator " << (void *)this << " allocating code section "

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

78 uintptr_t Size, unsigned Alignment, unsigned SectionID,

80 std::lock_guardstd::mutex Lock(M);

82 dbgs() << "Allocator " << (void *)this << " allocating "

83 << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName

84 << ": 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

97 uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,

98 Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {

99

100 {

101 std::lock_guardstd::mutex Lock(M);

102

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

122 TotalSize += alignTo(RODataSize, EPC.getPageSize());

123 TotalSize += alignTo(RWDataSize, EPC.getPageSize());

124

126 dbgs() << "Allocator " << (void *)this << " reserving "

127 << formatv("{0:x}", TotalSize) << " bytes.\n";

128 });

129

131 if (auto Err = EPC.callSPSWrapper<

133 SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {

134 std::lock_guardstd::mutex Lock(M);

135 ErrMsg = toString(std::move(Err));

136 return;

137 }

138 if (!TargetAllocAddr) {

139 std::lock_guardstd::mutex Lock(M);

140 ErrMsg = toString(TargetAllocAddr.takeError());

141 return;

142 }

143

144 std::lock_guardstd::mutex Lock(M);

145 Unmapped.push_back(SectionAllocGroup());

146 Unmapped.back().RemoteCode = {

148 Unmapped.back().RemoteROData = {

149 Unmapped.back().RemoteCode.End,

151 Unmapped.back().RemoteRWData = {

152 Unmapped.back().RemoteROData.End,

154}

155

159

162 size_t Size) {

164 dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "

165 << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";

166 });

167 std::lock_guardstd::mutex Lock(M);

168

169 if (!ErrMsg.empty())

170 return;

171

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

187

190 std::lock_guardstd::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

205 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");

206

207

208 std::vector SecAllocGroups;

209 {

210 std::lock_guardstd::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

219 for (auto &SecAllocGroup : SecAllocGroups) {

220

223

225 &SecAllocGroup.RemoteROData,

226 &SecAllocGroup.RemoteRWData};

227

228 std::vector *SegSections[3] = {&SecAllocGroup.CodeAllocs,

229 &SecAllocGroup.RODataAllocs,

230 &SecAllocGroup.RWDataAllocs};

231

233 std::unique_ptr<char[]> AggregateContents[3];

234

235 for (unsigned I = 0; I != 3; ++I) {

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

254

255 }

256 Seg.Content = {AggregateContents[I].get(), SecOffset};

257 }

258

259 for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames)

263 SAs.RegisterEHFrame, Frame)),

266 SAs.DeregisterEHFrame, Frame))});

267

268

269

271 if (auto Err = EPC.callSPSWrapper<

273 SAs.Initialize, InitializeKey, SAs.Instance, std::move(FR))) {

274 std::lock_guardstd::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_guardstd::mutex Lock(M);

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 &Allocs,

297 for (auto &Alloc : Allocs) {

300 dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> "

301 << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";

302 });

306 Alloc.RemoteAddr = NextAddr;

307

308

309 if (NextAddr)

311 }

312}

313

314}

315}

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

Error takeError()

Take ownership of the stored error.

LLVM_ABI void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress)

Map a section to its target address space value.

StringRef - Represent a constant reference to a string, i.e.

This class is the base class for all object file types.

uint8_t * allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) override

Allocate a memory block of (at least) the given size suitable for data.

Definition EPCGenericRTDyldMemoryManager.cpp:77

bool finalizeMemory(std::string *ErrMsg=nullptr) override

This method is called when object loading is complete and section page permissions can be applied.

Definition EPCGenericRTDyldMemoryManager.cpp:204

bool needsToReserveAllocationSpace() override

Override to return true to enable the reserveAllocationSpace callback.

Definition EPCGenericRTDyldMemoryManager.cpp:156

static Expected< std::unique_ptr< EPCGenericRTDyldMemoryManager > > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)

Create an EPCGenericRTDyldMemoryManager using the given EPC, looking up the default symbol names in t...

Definition EPCGenericRTDyldMemoryManager.cpp:22

EPCGenericRTDyldMemoryManager(ExecutorProcessControl &EPC, SymbolAddrs SAs)

Create an EPCGenericRTDyldMemoryManager using the given EPC and symbol addrs.

Definition EPCGenericRTDyldMemoryManager.cpp:38

void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize, Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) override

Inform the memory manager about the total amount of memory required to allocate all sections to be lo...

Definition EPCGenericRTDyldMemoryManager.cpp:96

void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override

Register the EH frames with the runtime so that c++ exceptions work.

Definition EPCGenericRTDyldMemoryManager.cpp:160

~EPCGenericRTDyldMemoryManager() override

Definition EPCGenericRTDyldMemoryManager.cpp:44

void notifyObjectLoaded(RuntimeDyld &Dyld, const object::ObjectFile &Obj) override

This method is called after an object has been loaded into memory but before relocations are applied ...

Definition EPCGenericRTDyldMemoryManager.cpp:188

void deregisterEHFrames() override

Definition EPCGenericRTDyldMemoryManager.cpp:184

uint8_t * allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) override

Allocate a memory block of (at least) the given size suitable for executable code.

Definition EPCGenericRTDyldMemoryManager.cpp:62

Represents an address in the executor process.

uint64_t getValue() const

void setValue(uint64_t Addr)

ExecutorProcessControl supports interaction with a JIT target process.

shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature

shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerInitializeSignature

shared::SPSError( shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerReleaseSignature

MemProt

Describes Read/Write/Exec permissions for memory.

uint64_t ExecutorAddrDiff

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})

Log all errors (if any) in E to OS.

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

auto reverse(ContainerTy &&C)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

format_object< Ts... > format(const char *Fmt, const Ts &... Vals)

These are helper functions used to produce formatted output.

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

void cantFail(Error Err, const char *Msg=nullptr)

Report a fatal error if Err is a failure value.

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

uintptr_t alignAddr(const void *Addr, Align Alignment)

Aligns Addr to Alignment bytes, rounding up.

Implement std::hash so that hash_code can be used in STL containers.

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.

This struct is a compact representation of a valid (non-zero power of two) alignment.

Symbol addresses for memory access.

Represents an address range in the exceutor process.

std::vector< SegFinalizeRequest > Segments

shared::AllocActions Actions