aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/include/llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h
blob: 0d4de7bfe426d72d7511a7bcac157b25bf1fb19f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

//===--- TPCIndirectionUtils.h - TPC based indirection utils ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
// TargetProcessControl API to interact with the target process.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
#define LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H

#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"

#include <mutex>

namespace llvm {
namespace orc {

class TargetProcessControl;

/// Provides TargetProcessControl based indirect stubs, trampoline pool and
/// lazy call through manager.
class TPCIndirectionUtils {
  friend class TPCIndirectionUtilsAccess;

public:
  /// ABI support base class. Used to write resolver, stub, and trampoline
  /// blocks.
  class ABISupport {
  protected:
    ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
               unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
        : PointerSize(PointerSize), TrampolineSize(TrampolineSize),
          StubSize(StubSize),
          StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
          ResolverCodeSize(ResolverCodeSize) {}

  public:
    virtual ~ABISupport();

    unsigned getPointerSize() const { return PointerSize; }
    unsigned getTrampolineSize() const { return TrampolineSize; }
    unsigned getStubSize() const { return StubSize; }
    unsigned getStubToPointerMaxDisplacement() const {
      return StubToPointerMaxDisplacement;
    }
    unsigned getResolverCodeSize() const { return ResolverCodeSize; }

    virtual void writeResolverCode(char *ResolverWorkingMem,
                                   JITTargetAddress ResolverTargetAddr,
                                   JITTargetAddress ReentryFnAddr,
                                   JITTargetAddress ReentryCtxAddr) const = 0;

    virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
                                  JITTargetAddress TrampolineBlockTragetAddr,
                                  JITTargetAddress ResolverAddr,
                                  unsigned NumTrampolines) const = 0;

    virtual void
    writeIndirectStubsBlock(char *StubsBlockWorkingMem,
                            JITTargetAddress StubsBlockTargetAddress,
                            JITTargetAddress PointersBlockTargetAddress,
                            unsigned NumStubs) const = 0;

  private:
    unsigned PointerSize = 0;
    unsigned TrampolineSize = 0;
    unsigned StubSize = 0;
    unsigned StubToPointerMaxDisplacement = 0;
    unsigned ResolverCodeSize = 0;
  };

  /// Create using the given ABI class.
  template <typename ORCABI>
  static std::unique_ptr<TPCIndirectionUtils>
  CreateWithABI(TargetProcessControl &TPC);

  /// Create based on the TargetProcessControl triple.
  static Expected<std::unique_ptr<TPCIndirectionUtils>>
  Create(TargetProcessControl &TPC);

  /// Return a reference to the TargetProcessControl object.
  TargetProcessControl &getTargetProcessControl() const { return TPC; }

  /// Return a reference to the ABISupport object for this instance.
  ABISupport &getABISupport() const { return *ABI; }

  /// Release memory for resources held by this instance. This *must* be called
  /// prior to destruction of the class.
  Error cleanup();

  /// Write resolver code to the target process and return its address.
  /// This must be called before any call to createTrampolinePool or
  /// createLazyCallThroughManager.
  Expected<JITTargetAddress>
  writeResolverBlock(JITTargetAddress ReentryFnAddr,
                     JITTargetAddress ReentryCtxAddr);

  /// Returns the address of the Resolver block. Returns zero if the
  /// writeResolverBlock method has not previously been called.
  JITTargetAddress getResolverBlockAddress() const { return ResolverBlockAddr; }

  /// Create an IndirectStubsManager for the target process.
  std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();

  /// Create a TrampolinePool for the target process.
  TrampolinePool &getTrampolinePool();

  /// Create a LazyCallThroughManager.
  /// This function should only be called once.
  LazyCallThroughManager &
  createLazyCallThroughManager(ExecutionSession &ES,
                               JITTargetAddress ErrorHandlerAddr);

  /// Create a LazyCallThroughManager for the target process.
  LazyCallThroughManager &getLazyCallThroughManager() {
    assert(LCTM && "createLazyCallThroughManager must be called first");
    return *LCTM;
  }

private:
  using Allocation = jitlink::JITLinkMemoryManager::Allocation;

  struct IndirectStubInfo {
    IndirectStubInfo() = default;
    IndirectStubInfo(JITTargetAddress StubAddress,
                     JITTargetAddress PointerAddress)
        : StubAddress(StubAddress), PointerAddress(PointerAddress) {}
    JITTargetAddress StubAddress = 0;
    JITTargetAddress PointerAddress = 0;
  };

  using IndirectStubInfoVector = std::vector<IndirectStubInfo>;

  /// Create a TPCIndirectionUtils instance.
  TPCIndirectionUtils(TargetProcessControl &TPC,
                      std::unique_ptr<ABISupport> ABI);

  Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);

  std::mutex TPCUIMutex;
  TargetProcessControl &TPC;
  std::unique_ptr<ABISupport> ABI;
  JITTargetAddress ResolverBlockAddr;
  std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> ResolverBlock;
  std::unique_ptr<TrampolinePool> TP;
  std::unique_ptr<LazyCallThroughManager> LCTM;

  std::vector<IndirectStubInfo> AvailableIndirectStubs;
  std::vector<std::unique_ptr<Allocation>> IndirectStubAllocs;
};

/// This will call writeResolver on the given TPCIndirectionUtils instance
/// to set up re-entry via a function that will directly return the trampoline
/// landing address.
///
/// The TPCIndirectionUtils' LazyCallThroughManager must have been previously
/// created via TPCIndirectionUtils::createLazyCallThroughManager.
///
/// The TPCIndirectionUtils' writeResolver method must not have been previously
/// called.
///
/// This function is experimental and likely subject to revision.
Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU);

namespace detail {

template <typename ORCABI>
class ABISupportImpl : public TPCIndirectionUtils::ABISupport {
public:
  ABISupportImpl()
      : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
                   ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
                   ORCABI::ResolverCodeSize) {}

  void writeResolverCode(char *ResolverWorkingMem,
                         JITTargetAddress ResolverTargetAddr,
                         JITTargetAddress ReentryFnAddr,
                         JITTargetAddress ReentryCtxAddr) const override {
    ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
                              ReentryFnAddr, ReentryCtxAddr);
  }

  void writeTrampolines(char *TrampolineBlockWorkingMem,
                        JITTargetAddress TrampolineBlockTargetAddr,
                        JITTargetAddress ResolverAddr,
                        unsigned NumTrampolines) const override {
    ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
                             TrampolineBlockTargetAddr, ResolverAddr,
                             NumTrampolines);
  }

  void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
                               JITTargetAddress StubsBlockTargetAddress,
                               JITTargetAddress PointersBlockTargetAddress,
                               unsigned NumStubs) const override {
    ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
                                    StubsBlockTargetAddress,
                                    PointersBlockTargetAddress, NumStubs);
  }
};

} // end namespace detail

template <typename ORCABI>
std::unique_ptr<TPCIndirectionUtils>
TPCIndirectionUtils::CreateWithABI(TargetProcessControl &TPC) {
  return std::unique_ptr<TPCIndirectionUtils>(new TPCIndirectionUtils(
      TPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
}

} // end namespace orc
} // end namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif