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