xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp (revision 734e82fe33aa764367791a7d603b383996c6b40b)
1 //===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
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/LazyReexports.h"
10 
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
13 
14 #define DEBUG_TYPE "orc"
15 
16 namespace llvm {
17 namespace orc {
18 
19 LazyCallThroughManager::LazyCallThroughManager(
20     ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
21     : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
22 
23 Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
24     JITDylib &SourceJD, SymbolStringPtr SymbolName,
25     NotifyResolvedFunction NotifyResolved) {
26   assert(TP && "TrampolinePool not set");
27 
28   std::lock_guard<std::mutex> Lock(LCTMMutex);
29   auto Trampoline = TP->getTrampoline();
30 
31   if (!Trampoline)
32     return Trampoline.takeError();
33 
34   Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
35   Notifiers[*Trampoline] = std::move(NotifyResolved);
36   return *Trampoline;
37 }
38 
39 JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
40   ES.reportError(std::move(Err));
41   return ErrorHandlerAddr;
42 }
43 
44 Expected<LazyCallThroughManager::ReexportsEntry>
45 LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
46   std::lock_guard<std::mutex> Lock(LCTMMutex);
47   auto I = Reexports.find(TrampolineAddr);
48   if (I == Reexports.end())
49     return createStringError(inconvertibleErrorCode(),
50                              "Missing reexport for trampoline address %p",
51                              TrampolineAddr);
52   return I->second;
53 }
54 
55 Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
56                                              JITTargetAddress ResolvedAddr) {
57   NotifyResolvedFunction NotifyResolved;
58   {
59     std::lock_guard<std::mutex> Lock(LCTMMutex);
60     auto I = Notifiers.find(TrampolineAddr);
61     if (I != Notifiers.end()) {
62       NotifyResolved = std::move(I->second);
63       Notifiers.erase(I);
64     }
65   }
66 
67   return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
68 }
69 
70 void LazyCallThroughManager::resolveTrampolineLandingAddress(
71     JITTargetAddress TrampolineAddr,
72     NotifyLandingResolvedFunction NotifyLandingResolved) {
73 
74   auto Entry = findReexport(TrampolineAddr);
75   if (!Entry)
76     return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
77 
78   // Declaring SLS and the callback outside of the call to ES.lookup is a
79   // workaround to fix build failures on AIX and on z/OS platforms.
80   SymbolLookupSet SLS({Entry->SymbolName});
81   auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
82                    NotifyLandingResolved = std::move(NotifyLandingResolved)](
83                       Expected<SymbolMap> Result) mutable {
84     if (Result) {
85       assert(Result->size() == 1 && "Unexpected result size");
86       assert(Result->count(SymbolName) && "Unexpected result value");
87       JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
88 
89       if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
90         NotifyLandingResolved(reportCallThroughError(std::move(Err)));
91       else
92         NotifyLandingResolved(LandingAddr);
93     } else {
94       NotifyLandingResolved(reportCallThroughError(Result.takeError()));
95     }
96   };
97 
98   ES.lookup(LookupKind::Static,
99             makeJITDylibSearchOrder(Entry->SourceJD,
100                                     JITDylibLookupFlags::MatchAllSymbols),
101             std::move(SLS), SymbolState::Ready, std::move(Callback),
102             NoDependenciesToRegister);
103 }
104 
105 Expected<std::unique_ptr<LazyCallThroughManager>>
106 createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
107                                   JITTargetAddress ErrorHandlerAddr) {
108   switch (T.getArch()) {
109   default:
110     return make_error<StringError>(
111         std::string("No callback manager available for ") + T.str(),
112         inconvertibleErrorCode());
113 
114   case Triple::aarch64:
115   case Triple::aarch64_32:
116     return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
117                                                            ErrorHandlerAddr);
118 
119   case Triple::x86:
120     return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
121 
122   case Triple::loongarch64:
123     return LocalLazyCallThroughManager::Create<OrcLoongArch64>(
124         ES, ErrorHandlerAddr);
125 
126   case Triple::mips:
127     return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
128                                                             ErrorHandlerAddr);
129 
130   case Triple::mipsel:
131     return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
132                                                             ErrorHandlerAddr);
133 
134   case Triple::mips64:
135   case Triple::mips64el:
136     return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
137 
138   case Triple::riscv64:
139     return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES,
140                                                            ErrorHandlerAddr);
141 
142   case Triple::x86_64:
143     if (T.getOS() == Triple::OSType::Win32)
144       return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
145           ES, ErrorHandlerAddr);
146     else
147       return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
148           ES, ErrorHandlerAddr);
149   }
150 }
151 
152 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
153     LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
154     JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
155     : MaterializationUnit(extractFlags(CallableAliases)),
156       LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
157       CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
158 
159 StringRef LazyReexportsMaterializationUnit::getName() const {
160   return "<Lazy Reexports>";
161 }
162 
163 void LazyReexportsMaterializationUnit::materialize(
164     std::unique_ptr<MaterializationResponsibility> R) {
165   auto RequestedSymbols = R->getRequestedSymbols();
166 
167   SymbolAliasMap RequestedAliases;
168   for (auto &RequestedSymbol : RequestedSymbols) {
169     auto I = CallableAliases.find(RequestedSymbol);
170     assert(I != CallableAliases.end() && "Symbol not found in alias map?");
171     RequestedAliases[I->first] = std::move(I->second);
172     CallableAliases.erase(I);
173   }
174 
175   if (!CallableAliases.empty())
176     if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
177                                             std::move(CallableAliases),
178                                             AliaseeTable))) {
179       R->getExecutionSession().reportError(std::move(Err));
180       R->failMaterialization();
181       return;
182     }
183 
184   IndirectStubsManager::StubInitsMap StubInits;
185   for (auto &Alias : RequestedAliases) {
186 
187     auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
188         SourceJD, Alias.second.Aliasee,
189         [&ISManager = this->ISManager,
190          StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
191           return ISManager.updatePointer(*StubSym, ResolvedAddr);
192         });
193 
194     if (!CallThroughTrampoline) {
195       SourceJD.getExecutionSession().reportError(
196           CallThroughTrampoline.takeError());
197       R->failMaterialization();
198       return;
199     }
200 
201     StubInits[*Alias.first] =
202         std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
203   }
204 
205   if (AliaseeTable != nullptr && !RequestedAliases.empty())
206     AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
207 
208   if (auto Err = ISManager.createStubs(StubInits)) {
209     SourceJD.getExecutionSession().reportError(std::move(Err));
210     R->failMaterialization();
211     return;
212   }
213 
214   SymbolMap Stubs;
215   for (auto &Alias : RequestedAliases)
216     Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
217 
218   // No registered dependencies, so these calls cannot fail.
219   cantFail(R->notifyResolved(Stubs));
220   cantFail(R->notifyEmitted());
221 }
222 
223 void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
224                                                const SymbolStringPtr &Name) {
225   assert(CallableAliases.count(Name) &&
226          "Symbol not covered by this MaterializationUnit");
227   CallableAliases.erase(Name);
228 }
229 
230 MaterializationUnit::Interface
231 LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
232   SymbolFlagsMap SymbolFlags;
233   for (auto &KV : Aliases) {
234     assert(KV.second.AliasFlags.isCallable() &&
235            "Lazy re-exports must be callable symbols");
236     SymbolFlags[KV.first] = KV.second.AliasFlags;
237   }
238   return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);
239 }
240 
241 } // End namespace orc.
242 } // End namespace llvm.
243