[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / lib / ExecutionEngine / Orc / EPCIndirectionUtils.cpp
blobb901a2d2da236f93c62647b7715595d024deac01
1 //===------- EPCIndirectionUtils.cpp -- EPC based indirection APIs --------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
11 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
12 #include "llvm/Support/MathExtras.h"
14 #include <future>
16 using namespace llvm;
17 using namespace llvm::orc;
19 namespace llvm {
20 namespace orc {
22 class EPCIndirectionUtilsAccess {
23 public:
24 using IndirectStubInfo = EPCIndirectionUtils::IndirectStubInfo;
25 using IndirectStubInfoVector = EPCIndirectionUtils::IndirectStubInfoVector;
27 static Expected<IndirectStubInfoVector>
28 getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs) {
29 return EPCIU.getIndirectStubs(NumStubs);
33 } // end namespace orc
34 } // end namespace llvm
36 namespace {
38 class EPCTrampolinePool : public TrampolinePool {
39 public:
40 EPCTrampolinePool(EPCIndirectionUtils &EPCIU);
41 Error deallocatePool();
43 protected:
44 Error grow() override;
46 using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
48 EPCIndirectionUtils &EPCIU;
49 unsigned TrampolineSize = 0;
50 unsigned TrampolinesPerPage = 0;
51 std::vector<FinalizedAlloc> TrampolineBlocks;
54 class EPCIndirectStubsManager : public IndirectStubsManager,
55 private EPCIndirectionUtilsAccess {
56 public:
57 EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
59 Error deallocateStubs();
61 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
62 JITSymbolFlags StubFlags) override;
64 Error createStubs(const StubInitsMap &StubInits) override;
66 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
68 JITEvaluatedSymbol findPointer(StringRef Name) override;
70 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
72 private:
73 using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
75 std::mutex ISMMutex;
76 EPCIndirectionUtils &EPCIU;
77 StringMap<StubInfo> StubInfos;
80 EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU)
81 : EPCIU(EPCIU) {
82 auto &EPC = EPCIU.getExecutorProcessControl();
83 auto &ABI = EPCIU.getABISupport();
85 TrampolineSize = ABI.getTrampolineSize();
86 TrampolinesPerPage =
87 (EPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
90 Error EPCTrampolinePool::deallocatePool() {
91 Error Err = Error::success();
92 std::promise<MSVCPError> DeallocResultP;
93 auto DeallocResultF = DeallocResultP.get_future();
95 EPCIU.getExecutorProcessControl().getMemMgr().deallocate(
96 std::move(TrampolineBlocks),
97 [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
99 return DeallocResultF.get();
102 Error EPCTrampolinePool::grow() {
103 using namespace jitlink;
105 assert(AvailableTrampolines.empty() &&
106 "Grow called with trampolines still available");
108 auto ResolverAddress = EPCIU.getResolverBlockAddress();
109 assert(ResolverAddress && "Resolver address can not be null");
111 auto &EPC = EPCIU.getExecutorProcessControl();
112 auto PageSize = EPC.getPageSize();
113 auto Alloc = SimpleSegmentAlloc::Create(
114 EPC.getMemMgr(), nullptr,
115 {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
116 if (!Alloc)
117 return Alloc.takeError();
119 unsigned NumTrampolines = TrampolinesPerPage;
121 auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
122 EPCIU.getABISupport().writeTrampolines(SegInfo.WorkingMem.data(),
123 SegInfo.Addr.getValue(),
124 ResolverAddress, NumTrampolines);
125 for (unsigned I = 0; I < NumTrampolines; ++I)
126 AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
127 (I * TrampolineSize));
129 auto FA = Alloc->finalize();
130 if (!FA)
131 return FA.takeError();
133 TrampolineBlocks.push_back(std::move(*FA));
135 return Error::success();
138 Error EPCIndirectStubsManager::createStub(StringRef StubName,
139 JITTargetAddress StubAddr,
140 JITSymbolFlags StubFlags) {
141 StubInitsMap SIM;
142 SIM[StubName] = std::make_pair(StubAddr, StubFlags);
143 return createStubs(SIM);
146 Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
147 auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
148 if (!AvailableStubInfos)
149 return AvailableStubInfos.takeError();
152 std::lock_guard<std::mutex> Lock(ISMMutex);
153 unsigned ASIdx = 0;
154 for (auto &SI : StubInits) {
155 auto &A = (*AvailableStubInfos)[ASIdx++];
156 StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
160 auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
161 switch (EPCIU.getABISupport().getPointerSize()) {
162 case 4: {
163 unsigned ASIdx = 0;
164 std::vector<tpctypes::UInt32Write> PtrUpdates;
165 for (auto &SI : StubInits)
166 PtrUpdates.push_back(
167 {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
168 static_cast<uint32_t>(SI.second.first)});
169 return MemAccess.writeUInt32s(PtrUpdates);
171 case 8: {
172 unsigned ASIdx = 0;
173 std::vector<tpctypes::UInt64Write> PtrUpdates;
174 for (auto &SI : StubInits)
175 PtrUpdates.push_back(
176 {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
177 static_cast<uint64_t>(SI.second.first)});
178 return MemAccess.writeUInt64s(PtrUpdates);
180 default:
181 return make_error<StringError>("Unsupported pointer size",
182 inconvertibleErrorCode());
186 JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name,
187 bool ExportedStubsOnly) {
188 std::lock_guard<std::mutex> Lock(ISMMutex);
189 auto I = StubInfos.find(Name);
190 if (I == StubInfos.end())
191 return nullptr;
192 return {I->second.first.StubAddress, I->second.second};
195 JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) {
196 std::lock_guard<std::mutex> Lock(ISMMutex);
197 auto I = StubInfos.find(Name);
198 if (I == StubInfos.end())
199 return nullptr;
200 return {I->second.first.PointerAddress, I->second.second};
203 Error EPCIndirectStubsManager::updatePointer(StringRef Name,
204 JITTargetAddress NewAddr) {
206 JITTargetAddress PtrAddr = 0;
208 std::lock_guard<std::mutex> Lock(ISMMutex);
209 auto I = StubInfos.find(Name);
210 if (I == StubInfos.end())
211 return make_error<StringError>("Unknown stub name",
212 inconvertibleErrorCode());
213 PtrAddr = I->second.first.PointerAddress;
216 auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
217 switch (EPCIU.getABISupport().getPointerSize()) {
218 case 4: {
219 tpctypes::UInt32Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
220 return MemAccess.writeUInt32s(PUpdate);
222 case 8: {
223 tpctypes::UInt64Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
224 return MemAccess.writeUInt64s(PUpdate);
226 default:
227 return make_error<StringError>("Unsupported pointer size",
228 inconvertibleErrorCode());
232 } // end anonymous namespace.
234 namespace llvm {
235 namespace orc {
237 EPCIndirectionUtils::ABISupport::~ABISupport() {}
239 Expected<std::unique_ptr<EPCIndirectionUtils>>
240 EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
241 const auto &TT = EPC.getTargetTriple();
242 switch (TT.getArch()) {
243 default:
244 return make_error<StringError>(
245 std::string("No EPCIndirectionUtils available for ") + TT.str(),
246 inconvertibleErrorCode());
247 case Triple::aarch64:
248 case Triple::aarch64_32:
249 return CreateWithABI<OrcAArch64>(EPC);
251 case Triple::x86:
252 return CreateWithABI<OrcI386>(EPC);
254 case Triple::mips:
255 return CreateWithABI<OrcMips32Be>(EPC);
257 case Triple::mipsel:
258 return CreateWithABI<OrcMips32Le>(EPC);
260 case Triple::mips64:
261 case Triple::mips64el:
262 return CreateWithABI<OrcMips64>(EPC);
264 case Triple::x86_64:
265 if (TT.getOS() == Triple::OSType::Win32)
266 return CreateWithABI<OrcX86_64_Win32>(EPC);
267 else
268 return CreateWithABI<OrcX86_64_SysV>(EPC);
272 Error EPCIndirectionUtils::cleanup() {
274 auto &MemMgr = EPC.getMemMgr();
275 auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
277 if (TP)
278 Err = joinErrors(std::move(Err),
279 static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
281 if (ResolverBlock)
282 Err =
283 joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
285 return Err;
288 Expected<JITTargetAddress>
289 EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
290 JITTargetAddress ReentryCtxAddr) {
291 using namespace jitlink;
293 assert(ABI && "ABI can not be null");
294 auto ResolverSize = ABI->getResolverCodeSize();
296 auto Alloc =
297 SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr,
298 {{MemProt::Read | MemProt::Exec,
299 {ResolverSize, Align(EPC.getPageSize())}}});
301 if (!Alloc)
302 return Alloc.takeError();
304 auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
305 ABI->writeResolverCode(SegInfo.WorkingMem.data(), SegInfo.Addr.getValue(),
306 ReentryFnAddr, ReentryCtxAddr);
308 auto FA = Alloc->finalize();
309 if (!FA)
310 return FA.takeError();
312 ResolverBlock = std::move(*FA);
313 return SegInfo.Addr.getValue();
316 std::unique_ptr<IndirectStubsManager>
317 EPCIndirectionUtils::createIndirectStubsManager() {
318 return std::make_unique<EPCIndirectStubsManager>(*this);
321 TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
322 if (!TP)
323 TP = std::make_unique<EPCTrampolinePool>(*this);
324 return *TP;
327 LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
328 ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
329 assert(!LCTM &&
330 "createLazyCallThroughManager can not have been called before");
331 LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
332 &getTrampolinePool());
333 return *LCTM;
336 EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
337 std::unique_ptr<ABISupport> ABI)
338 : EPC(EPC), ABI(std::move(ABI)) {
339 assert(this->ABI && "ABI can not be null");
341 assert(EPC.getPageSize() > getABISupport().getStubSize() &&
342 "Stubs larger than one page are not supported");
345 Expected<EPCIndirectionUtils::IndirectStubInfoVector>
346 EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
347 using namespace jitlink;
349 std::lock_guard<std::mutex> Lock(EPCUIMutex);
351 // If there aren't enough stubs available then allocate some more.
352 if (NumStubs > AvailableIndirectStubs.size()) {
353 auto NumStubsToAllocate = NumStubs;
354 auto PageSize = EPC.getPageSize();
355 auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
356 NumStubsToAllocate = StubBytes / ABI->getStubSize();
357 auto PtrBytes =
358 alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
360 auto StubProt = MemProt::Read | MemProt::Exec;
361 auto PtrProt = MemProt::Read | MemProt::Write;
363 auto Alloc = SimpleSegmentAlloc::Create(
364 EPC.getMemMgr(), nullptr,
365 {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
366 {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
368 if (!Alloc)
369 return Alloc.takeError();
371 auto StubSeg = Alloc->getSegInfo(StubProt);
372 auto PtrSeg = Alloc->getSegInfo(PtrProt);
374 ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
375 StubSeg.Addr.getValue(),
376 PtrSeg.Addr.getValue(), NumStubsToAllocate);
378 auto FA = Alloc->finalize();
379 if (!FA)
380 return FA.takeError();
382 IndirectStubAllocs.push_back(std::move(*FA));
384 auto StubExecutorAddr = StubSeg.Addr;
385 auto PtrExecutorAddr = PtrSeg.Addr;
386 for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
387 AvailableIndirectStubs.push_back(IndirectStubInfo(
388 StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
389 StubExecutorAddr += ABI->getStubSize();
390 PtrExecutorAddr += ABI->getPointerSize();
394 assert(NumStubs <= AvailableIndirectStubs.size() &&
395 "Sufficient stubs should have been allocated above");
397 IndirectStubInfoVector Result;
398 while (NumStubs--) {
399 Result.push_back(AvailableIndirectStubs.back());
400 AvailableIndirectStubs.pop_back();
403 return std::move(Result);
406 static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
407 JITTargetAddress TrampolineAddr) {
408 auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
409 std::promise<JITTargetAddress> LandingAddrP;
410 auto LandingAddrF = LandingAddrP.get_future();
411 LCTM.resolveTrampolineLandingAddress(
412 TrampolineAddr,
413 [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
414 return LandingAddrF.get();
417 Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
418 auto &LCTM = EPCIU.getLazyCallThroughManager();
419 return EPCIU
420 .writeResolverBlock(pointerToJITTargetAddress(&reentry),
421 pointerToJITTargetAddress(&LCTM))
422 .takeError();
425 } // end namespace orc
426 } // end namespace llvm