remotemono
RMonoAPIFunctionWrap_Def.h
1 /*
2  Copyright 2020 David "Alemarius Nexus" Lerch
3 
4  This file is part of RemoteMono.
5 
6  RemoteMono is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  RemoteMono is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with RemoteMono. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #pragma once
21 
22 #include "../config.h"
23 
24 #include <type_traits>
25 #include <tuple>
26 #include <BlackBone/Process/Process.h>
27 #include <BlackBone/Process/RPC/RemoteFunction.hpp>
28 #include "RMonoAPIBase_Def.h"
29 #include "RMonoAPIFunctionTypeAdapters.h"
30 #include "RMonoAPIFunctionSimple_Def.h"
31 #include "RMonoAPIFunctionCommon_Def.h"
32 #include "abi/RMonoABITypeTraits.h"
33 
34 
35 
36 namespace remotemono
37 {
38 
39 
40 
41 // **************************************************************
42 // * *
43 // * BASE CLASS *
44 // * *
45 // **************************************************************
46 
47 
75 template <class CommonT, typename ABI, typename RetT, typename... ArgsT>
77 {
78 public:
79  typedef RetT WrapRetType;
80  typedef std::tuple<ArgsT...> WrapArgsTuple;
81 
82  typedef RMonoAPIFunctionSimple<RetT, ArgsT...> WrapFunc;
83 
84 public:
87 
88  void linkWrap(blackbone::ptr_t wrapFuncAddr)
89  {
90  this->wrapFunc.rebuild(getRemoteMonoAPI()->getProcess(), wrapFuncAddr, getRemoteMonoAPI()->getWorkerThread());
91  }
92 
93  RetT invokeWrap(ArgsT... args) { return wrapFunc(args...); }
94 
95  blackbone::ptr_t getWrapFuncAddress() const { return wrapFunc.getAddress(); }
96 
97 private:
98  ABI* getABI() { return static_cast<CommonT*>(this)->getABI(); }
99  RMonoAPIBase* getRemoteMonoAPI() { return static_cast<CommonT*>(this)->getRemoteMonoAPI(); }
100 
101 protected:
102  WrapFunc wrapFunc;
103 };
104 
105 
106 
107 
108 
109 
110 
111 // **************************************************************
112 // * *
113 // * ADAPTER CHAIN *
114 // * *
115 // **************************************************************
116 
117 // Can be used to adapt the definition types into the API types, e.g. by adding, changing or removing arguments.
118 
119 template <typename CommonT, typename ABI, typename RetT, typename... ArgsT>
121  CommonT,
122  ABI,
123  typename RMonoAPIReturnTypeAdapter<ABI, RetT>::WrapType,
124  typename RMonoAPIParamTypeAdapter<ABI, ArgsT>::WrapType...
125  > {};
126 
127 
128 template <typename Enable, typename CommonT, typename ABI, typename RetT, typename... ArgsT>
130 
131 // Transform Variant return type to output parameter
132 template <typename CommonT, typename ABI, typename RetT, typename... ArgsT>
134  std::enable_if_t<std::is_base_of_v<RMonoVariant, typename RetT::Type>>,
135  CommonT, ABI, RetT, ArgsT...
136  > : public RMonoAPIFunctionWrapAdapterFinal<CommonT, ABI,
137  tags::ReturnNull<typename RMonoABITypeTraits<ABI>::irmono_voidp>, tags::ParamOut<RMonoVariant>, ArgsT...> {};
138 
139 // Add hidden dataBlockPtr parameter for string return types
140 template <typename CommonT, typename ABI, typename RetT, typename... ArgsT>
142  std::enable_if_t <
143  std::is_base_of_v<std::string, typename RetT::Type>
144  || std::is_base_of_v<std::u16string, typename RetT::Type>
145  || std::is_base_of_v<std::u32string, typename RetT::Type>
146  >,
147  CommonT, ABI, RetT, ArgsT...
148  > : public RMonoAPIFunctionWrapAdapterFinal<CommonT, ABI, RetT, tags::ParamNull<typename RMonoABITypeTraits<ABI>::irmono_voidp>, ArgsT...> {};
149 
150 template <typename CommonT, typename ABI, typename RetT, typename... ArgsT>
152  std::enable_if_t <
153  !std::is_base_of_v<RMonoVariant, typename RetT::Type>
154  && !std::is_base_of_v<std::string, typename RetT::Type>
155  && !std::is_base_of_v<std::u16string, typename RetT::Type>
156  && !std::is_base_of_v<std::u32string, typename RetT::Type>
157  >,
158  CommonT, ABI, RetT, ArgsT...
159  > : public RMonoAPIFunctionWrapAdapterFinal<CommonT, ABI, RetT, ArgsT...> {};
160 
161 
162 template <typename Enable, typename CommonT, typename ABI, typename RetT, typename... ArgsT>
163 class RMonoAPIFunctionWrapAdapter : public RMonoAPIFunctionWrapAdapterRetToOutParam<void, CommonT, ABI, RetT, ArgsT...> {};
164 
165 
166 
167 
168 
169 
170 
171 // **************************************************************
172 // * *
173 // * FRONT CLASS *
174 // * *
175 // **************************************************************
176 
182 template <typename CommonT, typename ABI, typename RetT, typename... ArgsT>
183 class RMonoAPIFunctionWrap : public RMonoAPIFunctionWrapAdapter<void, CommonT, ABI, RetT, ArgsT...>
184 {
185 private:
186  typedef RMonoABITypeTraits<ABI> ABITypeTraits;
187 
188  REMOTEMONO_ABI_TYPETRAITS_TYPEDEFS(ABITypeTraits)
189 
190  typedef RMonoVariant Variant;
192 
193  typedef typename RMonoAPIFunctionCommon<ABI>::variantflags_t variantflags_t;
194 
195  typedef typename RMonoAPIFunctionCommonTraits<CommonT>::DefRetType DefRetType;
196  typedef typename RMonoAPIFunctionCommonTraits<CommonT>::DefArgsTuple DefArgsTuple;
197 
198  struct AsmBuildContext
199  {
200  blackbone::IAsmHelper* a;
201 
202  bool x64;
203 
204  blackbone::ptr_t gchandleGetTargetAddr;
205  blackbone::ptr_t gchandleNewAddr;
206  blackbone::ptr_t objectGetClassAddr;
207  blackbone::ptr_t classIsValuetypeAddr;
208  blackbone::ptr_t objectUnboxAddr;
209 
210  int32_t regSize;
211  int32_t rawArgStackSize;
212 
213  // ZBP-relative offsets
214  int32_t stackOffsArgBase;
215  int32_t stackOffsRetval;
216  };
217 
218 public:
219  template <size_t idx = 0>
220  constexpr static std::enable_if_t<idx < std::tuple_size_v<DefArgsTuple>, bool> needsWrapFuncArg()
221  {
222  typedef std::tuple_element_t<idx, DefArgsTuple> ArgType;
223 
224  // TODO: We don't actually need a wrapper for primitive ParamOut<> arguments. A raw call would be enough, but
225  // we'd need to allocate memory for the output, which is why we'll currently just let the wrapper logic handle
226  // such arguments.
227  if constexpr (
228  std::is_base_of_v<Variant, typename ArgType::Type>
229  || std::is_base_of_v<VariantArray, typename ArgType::Type>
230  || std::is_base_of_v<std::string_view, typename ArgType::Type>
231  || std::is_base_of_v<std::u16string_view, typename ArgType::Type>
232  || std::is_base_of_v<std::u32string_view, typename ArgType::Type>
233  || std::is_base_of_v<RMonoObjectHandleTag, typename ArgType::Type>
234  || tags::has_param_tag_v<ArgType, tags::ParamOutTag>
235  ) {
236  return true;
237  } else {
238  return needsWrapFuncArg<idx+1>();
239  }
240  }
241 
242  template <size_t idx = 0>
243  constexpr static std::enable_if_t<idx == std::tuple_size_v<DefArgsTuple>, bool> needsWrapFuncArg() { return false; }
244 
248  constexpr static bool needsWrapFunc()
249  {
250  if constexpr (
251  std::is_base_of_v<Variant, typename DefRetType::Type>
252  || std::is_base_of_v<VariantArray, typename DefRetType::Type>
253  || std::is_base_of_v<std::string, typename DefRetType::Type>
254  || std::is_base_of_v<std::u16string, typename DefRetType::Type>
255  || std::is_base_of_v<std::u32string, typename DefRetType::Type>
256  || std::is_base_of_v<RMonoObjectHandleTag, typename DefRetType::Type>
257  ) {
258  return true;
259  } else {
260  return needsWrapFuncArg<0>();
261  }
262  }
263 
264 public:
265  asmjit::Label compileWrap(blackbone::IAsmHelper& a);
266 
267 protected:
268  void resetWrap()
269  {
270  wrapFunc.reset();
271  }
272 
273 private:
274  void generateWrapperAsm(AsmBuildContext& ctx);
275 
276 
277  template <size_t wrapArgIdx>
278  void genWrapperSpillArgsToStackX64(AsmBuildContext& ctx);
279 
280 
281  void genWrapperReserveStack(AsmBuildContext& ctx);
282 
283  template <size_t wrapArgIdx, typename ArgT, typename... RestT>
284  void genWrapperReserveArgStack(AsmBuildContext& ctx, PackHelper<ArgT>, PackHelper<RestT>... rest);
285  template <size_t wrapArgIdx>
286  void genWrapperReserveArgStack(AsmBuildContext& ctx) {}
287 
288  template <size_t rawArgIdx>
289  void genWrapperCalculateRawArgStackSize(AsmBuildContext& ctx);
290 
291 
292  void genWrapperBuildRawArgs(AsmBuildContext& ctx);
293 
294  template <size_t wrapArgIdx, size_t rawArgIdx, typename ArgT, typename... RestT>
295  void genWrapperBuildRawArg(AsmBuildContext& ctx, PackHelper<ArgT>, PackHelper<RestT>... rest);
296  template <size_t wrapArgIdx, size_t rawArgIdx>
297  void genWrapperBuildRawArg(AsmBuildContext& ctx) {}
298 
299 
300  template <size_t rawArgIdx>
301  void genWrapperMoveStackArgsToRegsX64(AsmBuildContext& ctx);
302 
303 
304  void genWrapperHandleRetAndOutParams(AsmBuildContext& ctx);
305 
306  template <size_t wrapArgIdx, size_t rawArgIdx, typename ArgT, typename... RestT>
307  void genWrapperHandleOutParams(AsmBuildContext& ctx, PackHelper<ArgT>, PackHelper<RestT>... rest);
308  template <size_t wrapArgIdx, size_t rawArgIdx>
309  void genWrapperHandleOutParams(AsmBuildContext& ctx) {}
310 
311 
312  void genGchandleGetTargetChecked(AsmBuildContext& ctx);
313  void genGchandleNewChecked(AsmBuildContext& ctx);
314  void genIsValueTypeInstance(AsmBuildContext& ctx);
315  void genObjectUnbox(AsmBuildContext& ctx);
316 
317  template <size_t argIdx, typename ArgsTupleT>
318  constexpr size_t calcStackArgOffset()
319  {
320  if constexpr(argIdx == 0) {
321  return 0;
322  } else {
323  return static_align(sizeof(std::tuple_element_t<argIdx-1, ArgsTupleT>), sizeof(irmono_voidp))
324  + calcStackArgOffset<argIdx-1, ArgsTupleT>();
325  }
326  }
327 
328  template <size_t argIdx>
329  asmjit::X86Mem ptrWrapFuncArg(AsmBuildContext& ctx, size_t partIdx = 0, uint32_t size = 0)
330  {
331  return asmjit::host::ptr (
332  (*ctx.a)->zbp,
333  int32_t (
334  ctx.stackOffsArgBase
335  + calcStackArgOffset<argIdx, typename RMonoAPIFunctionWrapTraits<CommonT>::WrapArgsTuple>()
336  + partIdx*sizeof(irmono_voidp)
337  ),
338  size
339  );
340  }
341 
342  template <size_t argIdx>
343  asmjit::X86Mem ptrRawFuncArg(AsmBuildContext& ctx, size_t partIdx = 0, uint32_t size = 0)
344  {
345  return asmjit::host::ptr (
346  (*ctx.a)->zsp,
347  int32_t (
348  calcStackArgOffset<argIdx, typename RMonoAPIFunctionRawTraits<CommonT>::RawArgsTuple>()
349  + partIdx*sizeof(irmono_voidp)
350  ),
351  size
352  );
353  }
354 
355 private:
356  ABI* getABI() { return static_cast<CommonT*>(this)->getABI(); }
357  RMonoAPIBase* getRemoteMonoAPI() { return static_cast<CommonT*>(this)->getRemoteMonoAPI(); }
358 };
359 
360 
361 }
362 
363 
remotemono::RMonoAPIFunctionWrapAdapterRetToOutParam
Definition: RMonoAPIFunctionWrap_Def.h:129
remotemono::RMonoAPIFunctionCommon
Definition: RMonoAPIFunctionCommon_Def.h:32
remotemono::RMonoAPIFunctionCommonTraits
Definition: RMonoAPIFunctionTypeAdapters.h:120
remotemono::RMonoAPIFunctionWrapTraits
Definition: RMonoAPIFunctionTypeAdapters.h:126
remotemono::RMonoAPIBase
Definition: RMonoAPIBase_Def.h:43
remotemono::RMonoAPIFunctionSimple
Definition: RMonoAPIFunctionSimple_Def.h:39
remotemono::RMonoAPIFunctionWrap
Definition: RMonoAPIFunctionWrap_Def.h:184
remotemono::RMonoAPIFunctionWrapAdapterFinal
Definition: RMonoAPIFunctionWrap_Def.h:125
remotemono::RMonoVariantArray
Definition: RMonoVariantArray_Def.h:47
remotemono::PackHelper
Definition: util.h:147
remotemono::RMonoAPIFunctionWrapAdapter
Definition: RMonoAPIFunctionWrap_Def.h:163
remotemono::RMonoAPIFunctionRawTraits
Definition: RMonoAPIFunctionTypeAdapters.h:123
remotemono::RMonoAPIFunctionWrapBase
Definition: RMonoAPIFunctionWrap_Def.h:77
remotemono::RMonoVariant
Definition: RMonoVariant_Def.h:71