• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- TPCIndirectionUtils.h - TPC based indirection utils ----*- C++ -*-===//
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 // Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
10 // TargetProcessControl API to interact with the target process.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
16 
17 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
18 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
19 #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
20 
21 #include <mutex>
22 
23 namespace llvm {
24 namespace orc {
25 
26 class TargetProcessControl;
27 
28 /// Provides TargetProcessControl based indirect stubs, trampoline pool and
29 /// lazy call through manager.
30 class TPCIndirectionUtils {
31   friend class TPCIndirectionUtilsAccess;
32 
33 public:
34   /// ABI support base class. Used to write resolver, stub, and trampoline
35   /// blocks.
36   class ABISupport {
37   protected:
ABISupport(unsigned PointerSize,unsigned TrampolineSize,unsigned StubSize,unsigned StubToPointerMaxDisplacement,unsigned ResolverCodeSize)38     ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
39                unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
40         : PointerSize(PointerSize), TrampolineSize(TrampolineSize),
41           StubSize(StubSize),
42           StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
43           ResolverCodeSize(ResolverCodeSize) {}
44 
45   public:
46     virtual ~ABISupport();
47 
getPointerSize()48     unsigned getPointerSize() const { return PointerSize; }
getTrampolineSize()49     unsigned getTrampolineSize() const { return TrampolineSize; }
getStubSize()50     unsigned getStubSize() const { return StubSize; }
getStubToPointerMaxDisplacement()51     unsigned getStubToPointerMaxDisplacement() const {
52       return StubToPointerMaxDisplacement;
53     }
getResolverCodeSize()54     unsigned getResolverCodeSize() const { return ResolverCodeSize; }
55 
56     virtual void writeResolverCode(char *ResolverWorkingMem,
57                                    JITTargetAddress ResolverTargetAddr,
58                                    JITTargetAddress ReentryFnAddr,
59                                    JITTargetAddress ReentryCtxAddr) const = 0;
60 
61     virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
62                                   JITTargetAddress TrampolineBlockTragetAddr,
63                                   JITTargetAddress ResolverAddr,
64                                   unsigned NumTrampolines) const = 0;
65 
66     virtual void
67     writeIndirectStubsBlock(char *StubsBlockWorkingMem,
68                             JITTargetAddress StubsBlockTargetAddress,
69                             JITTargetAddress PointersBlockTargetAddress,
70                             unsigned NumStubs) const = 0;
71 
72   private:
73     unsigned PointerSize = 0;
74     unsigned TrampolineSize = 0;
75     unsigned StubSize = 0;
76     unsigned StubToPointerMaxDisplacement = 0;
77     unsigned ResolverCodeSize = 0;
78   };
79 
80   /// Create using the given ABI class.
81   template <typename ORCABI>
82   static std::unique_ptr<TPCIndirectionUtils>
83   CreateWithABI(TargetProcessControl &TPC);
84 
85   /// Create based on the TargetProcessControl triple.
86   static Expected<std::unique_ptr<TPCIndirectionUtils>>
87   Create(TargetProcessControl &TPC);
88 
89   /// Return a reference to the TargetProcessControl object.
getTargetProcessControl()90   TargetProcessControl &getTargetProcessControl() const { return TPC; }
91 
92   /// Return a reference to the ABISupport object for this instance.
getABISupport()93   ABISupport &getABISupport() const { return *ABI; }
94 
95   /// Release memory for resources held by this instance. This *must* be called
96   /// prior to destruction of the class.
97   Error cleanup();
98 
99   /// Write resolver code to the target process and return its address.
100   /// This must be called before any call to createTrampolinePool or
101   /// createLazyCallThroughManager.
102   Expected<JITTargetAddress>
103   writeResolverBlock(JITTargetAddress ReentryFnAddr,
104                      JITTargetAddress ReentryCtxAddr);
105 
106   /// Returns the address of the Resolver block. Returns zero if the
107   /// writeResolverBlock method has not previously been called.
getResolverBlockAddress()108   JITTargetAddress getResolverBlockAddress() const { return ResolverBlockAddr; }
109 
110   /// Create an IndirectStubsManager for the target process.
111   std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
112 
113   /// Create a TrampolinePool for the target process.
114   TrampolinePool &getTrampolinePool();
115 
116   /// Create a LazyCallThroughManager.
117   /// This function should only be called once.
118   LazyCallThroughManager &
119   createLazyCallThroughManager(ExecutionSession &ES,
120                                JITTargetAddress ErrorHandlerAddr);
121 
122   /// Create a LazyCallThroughManager for the target process.
getLazyCallThroughManager()123   LazyCallThroughManager &getLazyCallThroughManager() {
124     assert(LCTM && "createLazyCallThroughManager must be called first");
125     return *LCTM;
126   }
127 
128 private:
129   using Allocation = jitlink::JITLinkMemoryManager::Allocation;
130 
131   struct IndirectStubInfo {
132     IndirectStubInfo() = default;
IndirectStubInfoIndirectStubInfo133     IndirectStubInfo(JITTargetAddress StubAddress,
134                      JITTargetAddress PointerAddress)
135         : StubAddress(StubAddress), PointerAddress(PointerAddress) {}
136     JITTargetAddress StubAddress = 0;
137     JITTargetAddress PointerAddress = 0;
138   };
139 
140   using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
141 
142   /// Create a TPCIndirectionUtils instance.
143   TPCIndirectionUtils(TargetProcessControl &TPC,
144                       std::unique_ptr<ABISupport> ABI);
145 
146   Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
147 
148   std::mutex TPCUIMutex;
149   TargetProcessControl &TPC;
150   std::unique_ptr<ABISupport> ABI;
151   JITTargetAddress ResolverBlockAddr;
152   std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> ResolverBlock;
153   std::unique_ptr<TrampolinePool> TP;
154   std::unique_ptr<LazyCallThroughManager> LCTM;
155 
156   std::vector<IndirectStubInfo> AvailableIndirectStubs;
157   std::vector<std::unique_ptr<Allocation>> IndirectStubAllocs;
158 };
159 
160 /// This will call writeResolver on the given TPCIndirectionUtils instance
161 /// to set up re-entry via a function that will directly return the trampoline
162 /// landing address.
163 ///
164 /// The TPCIndirectionUtils' LazyCallThroughManager must have been previously
165 /// created via TPCIndirectionUtils::createLazyCallThroughManager.
166 ///
167 /// The TPCIndirectionUtils' writeResolver method must not have been previously
168 /// called.
169 ///
170 /// This function is experimental and likely subject to revision.
171 Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU);
172 
173 namespace detail {
174 
175 template <typename ORCABI>
176 class ABISupportImpl : public TPCIndirectionUtils::ABISupport {
177 public:
ABISupportImpl()178   ABISupportImpl()
179       : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
180                    ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
181                    ORCABI::ResolverCodeSize) {}
182 
writeResolverCode(char * ResolverWorkingMem,JITTargetAddress ResolverTargetAddr,JITTargetAddress ReentryFnAddr,JITTargetAddress ReentryCtxAddr)183   void writeResolverCode(char *ResolverWorkingMem,
184                          JITTargetAddress ResolverTargetAddr,
185                          JITTargetAddress ReentryFnAddr,
186                          JITTargetAddress ReentryCtxAddr) const override {
187     ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
188                               ReentryFnAddr, ReentryCtxAddr);
189   }
190 
writeTrampolines(char * TrampolineBlockWorkingMem,JITTargetAddress TrampolineBlockTargetAddr,JITTargetAddress ResolverAddr,unsigned NumTrampolines)191   void writeTrampolines(char *TrampolineBlockWorkingMem,
192                         JITTargetAddress TrampolineBlockTargetAddr,
193                         JITTargetAddress ResolverAddr,
194                         unsigned NumTrampolines) const override {
195     ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
196                              TrampolineBlockTargetAddr, ResolverAddr,
197                              NumTrampolines);
198   }
199 
writeIndirectStubsBlock(char * StubsBlockWorkingMem,JITTargetAddress StubsBlockTargetAddress,JITTargetAddress PointersBlockTargetAddress,unsigned NumStubs)200   void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
201                                JITTargetAddress StubsBlockTargetAddress,
202                                JITTargetAddress PointersBlockTargetAddress,
203                                unsigned NumStubs) const override {
204     ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
205                                     StubsBlockTargetAddress,
206                                     PointersBlockTargetAddress, NumStubs);
207   }
208 };
209 
210 } // end namespace detail
211 
212 template <typename ORCABI>
213 std::unique_ptr<TPCIndirectionUtils>
CreateWithABI(TargetProcessControl & TPC)214 TPCIndirectionUtils::CreateWithABI(TargetProcessControl &TPC) {
215   return std::unique_ptr<TPCIndirectionUtils>(new TPCIndirectionUtils(
216       TPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
217 }
218 
219 } // end namespace orc
220 } // end namespace llvm
221 
222 #endif // LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
223