Home | History | Annotate | Line # | Download | only in Orc
      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:
     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 
     48     unsigned getPointerSize() const { return PointerSize; }
     49     unsigned getTrampolineSize() const { return TrampolineSize; }
     50     unsigned getStubSize() const { return StubSize; }
     51     unsigned getStubToPointerMaxDisplacement() const {
     52       return StubToPointerMaxDisplacement;
     53     }
     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.
     90   TargetProcessControl &getTargetProcessControl() const { return TPC; }
     91 
     92   /// Return a reference to the ABISupport object for this instance.
     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.
    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.
    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;
    133     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:
    178   ABISupportImpl()
    179       : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
    180                    ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
    181                    ORCABI::ResolverCodeSize) {}
    182 
    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 
    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 
    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>
    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