gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
guest_abi.hh
Go to the documentation of this file.
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Authors: Gabe Black
28  */
29 
30 #ifndef __SIM_GUEST_ABI_HH__
31 #define __SIM_GUEST_ABI_HH__
32 
33 #include <functional>
34 #include <memory>
35 #include <sstream>
36 #include <type_traits>
37 
38 class ThreadContext;
39 
40 namespace GuestABI
41 {
42 
43 /*
44  * To implement an ABI, a subclass needs to implement a system of
45  * specializations of these two templates Result and Argument, and define a
46  * "Position" type.
47  *
48  * The Position type carries information about, for instance, how many
49  * integer registers have been consumed gathering earlier arguments. It
50  * may contain multiple elements if there are multiple dimensions to track,
51  * for instance the number of integer and floating point registers used so far.
52  *
53  * Result and Argument are class templates instead of function templates so
54  * that they can be partially specialized if necessary. C++ doesn't let you
55  * partially specialize function templates because that conflicts with
56  * template resolution using the function's arguments. Since we already know
57  * what type we want and we don't need argument based resolution, we can just
58  * wrap the desired functionality in classes and sidestep the problem.
59  *
60  * Also note that these templates have an "Enabled" parameter to support
61  * std::enable_if style conditional specializations.
62  */
63 
64 /*
65  * Position may need to be initialized based on the ThreadContext, for instance
66  * to find out where the stack pointer is initially.
67  */
68 template <typename ABI, typename Enabled=void>
70 {
71  static typename ABI::Position
72  init(const ThreadContext *tc)
73  {
74  return typename ABI::Position();
75  }
76 };
77 
78 template <typename ABI>
79 struct PositionInitializer<ABI, typename std::enable_if<
80  std::is_constructible<typename ABI::Position, const ThreadContext *>::value
81  >::type>
82 {
83  static typename ABI::Position
84  init(const ThreadContext *tc)
85  {
86  return typename ABI::Position(tc);
87  }
88 };
89 
90 template <typename ABI, typename Ret, typename Enabled=void>
91 struct Result
92 {
93  private:
94  /*
95  * Store result "ret" into the state accessible through tc.
96  *
97  * Note that the declaration below is only to document the expected
98  * signature and is private so it won't be used by accident.
99  * Specializations of this Result class should define their own version
100  * of this method which actually does something and is public.
101  */
102  static void store(ThreadContext *tc, const Ret &ret);
103 
104  /*
105  * Adjust the position of arguments based on the return type, if necessary.
106  *
107  * This method can be excluded if no adjustment is necessary.
108  */
109  static void allocate(ThreadContext *tc, typename ABI::Position &position);
110 };
111 
112 /*
113  * This partial specialization prevents having to special case 'void' when
114  * working with return types.
115  */
116 template <typename ABI>
117 struct Result<ABI, void>
118 {};
119 
120 template <typename ABI, typename Arg, typename Enabled=void>
121 struct Argument
122 {
123  /*
124  * Retrieve an argument of type Arg from the state accessible through tc,
125  * assuming the state represented by "position" has already been used.
126  * Also update position to account for this argument as well.
127  *
128  * Like Result::store above, the declaration below is only to document
129  * the expected method signature.
130  */
131  static Arg get(ThreadContext *tc, typename ABI::Position &position);
132 };
133 
134 
135 /*
136  * This struct template provides a default allocate() method in case the
137  * Result template doesn't provide one. This is the default in cases where the
138  * return type doesn't affect how arguments are laid out.
139  */
140 template <typename ABI, typename Ret, typename Enabled=void>
142 {
143  static void
144  allocate(ThreadContext *tc, typename ABI::Position &position)
145  {}
146 };
147 
148 /*
149  * If the return type *does* affect how the arguments are laid out, the ABI
150  * can implement an allocate() method for the various return types, and this
151  * specialization will call into it.
152  */
153 template <typename ABI, typename Ret>
154 struct ResultAllocator<ABI, Ret, decltype((void)&Result<ABI, Ret>::allocate)>
155 {
156  static void
157  allocate(ThreadContext *tc, typename ABI::Position &position)
158  {
159  Result<ABI, Ret>::allocate(tc, position);
160  }
161 };
162 
163 
164 /*
165  * These templates implement a variadic argument mechanism for guest ABI
166  * functions. A function might be written like this:
167  *
168  * void
169  * func(ThreadContext *tc, VarArgs<Addr, int> varargs)
170  * {
171  * warn("Address = %#x, int = %d.",
172  * varargs.get<Addr>(), varargs.get<int>());
173  * }
174  *
175  * where an object of type VarArgs<...> is its last argument. The types given
176  * to the template specify what types the function might need to retrieve from
177  * varargs. The varargs object will then have get<> methods for each of those
178  * types.
179  *
180  * Note that each get<> will happen live. If you modify values through the
181  * ThreadContext *tc and then run get<>(), you may alter one of your arguments.
182  * If you're going to use tc to modify state, it would be a good idea to use
183  * get<>() as soon as possible to avoid corrupting the functions arguments.
184  */
185 
186 // A recursive template which defines virtual functions to retrieve each of the
187 // requested types. This provides the ABI agnostic interface the function uses.
188 template <typename ...Types>
190 
191 template <typename First, typename ...Types>
192 class VarArgsBase<First, Types...> : public VarArgsBase<Types...>
193 {
194  public:
195  // The virtual function takes a reference parameter so that the different
196  // _getImpl methods can co-exist through overloading.
197  virtual void _getImpl(First &) = 0;
198 
199  // Make sure base class _getImpl-es aren't hidden by this one.
200  using VarArgsBase<Types...>::_getImpl;
201 };
202 
203 // The base case of the recursion.
204 template <>
205 class VarArgsBase<>
206 {
207  protected:
208  // This just gives the "using" statement in the non base case something to
209  // refer to.
210  void _getImpl();
211 };
212 
213 
214 // A recursive template which defines the ABI specific implementation of the
215 // interface defined above.
216 //
217 // The types in Types are consumed one by one, and by
218 // the time we get down to the base case we'd have lost track of the complete
219 // set we need to know what interface to inherit. The Base parameter keeps
220 // track of that through the recursion.
221 template <typename ABI, typename Base, typename ...Types>
223 
224 template <typename ABI, typename Base, typename First, typename ...Types>
225 class VarArgsImpl<ABI, Base, First, Types...> :
226  public VarArgsImpl<ABI, Base, Types...>
227 {
228  protected:
229  // Bring forward the base class constructor.
230  using VarArgsImpl<ABI, Base, Types...>::VarArgsImpl;
231  // Make sure base class _getImpl-es don't get hidden by ours.
232  using VarArgsImpl<ABI, Base, Types...>::_getImpl;
233 
234  // Implement a version of _getImple, using the ABI specialized version of
235  // the Argument class.
236  void
237  _getImpl(First &first) override
238  {
239  first = Argument<ABI, First>::get(this->tc, this->position);
240  }
241 };
242 
243 // The base case of the recursion, which inherits from the interface class.
244 template <typename ABI, typename Base>
245 class VarArgsImpl<ABI, Base> : public Base
246 {
247  protected:
248  // Declare state to pass to the Argument<>::get methods.
250  typename ABI::Position position;
251 
252  // Give the "using" statement in our subclass something to refer to.
253  void _getImpl();
254 
255  public:
256  VarArgsImpl(ThreadContext *_tc, const typename ABI::Position &_pos) :
257  tc(_tc), position(_pos)
258  {}
259 };
260 
261 // A wrapper which provides a nice interface to the virtual functions, and a
262 // hook for the Argument template mechanism.
263 template <typename ...Types>
264 class VarArgs
265 {
266  private:
267  // This points to the implementation which knows how to read arguments
268  // based on the ABI being used.
269  std::shared_ptr<VarArgsBase<Types...>> _ptr;
270 
271  public:
272  VarArgs(VarArgsBase<Types...> *ptr) : _ptr(ptr) {}
273 
274  // This template is a friendlier wrapper around the virtual functions the
275  // raw interface provides. This version lets you pick a type which it then
276  // returns, instead of having to pre-declare a variable to pass in.
277  template <typename Arg>
278  Arg
279  get()
280  {
281  Arg arg;
282  _ptr->_getImpl(arg);
283  return arg;
284  }
285 };
286 
287 template <typename T>
288 struct IsVarArgs : public std::false_type {};
289 
290 template <typename ...Types>
291 struct IsVarArgs<VarArgs<Types...>> : public std::true_type {};
292 
293 template <typename ...Types>
294 std::ostream &
295 operator << (std::ostream &os, const VarArgs<Types...> &va)
296 {
297  os << "...";
298  return os;
299 }
300 
301 // The ABI independent hook which tells the GuestABI mechanism what to do with
302 // a VarArgs argument. It constructs the underlying implementation which knows
303 // about the ABI, and installs it in the VarArgs wrapper to give to the
304 // function.
305 template <typename ABI, typename ...Types>
306 struct Argument<ABI, VarArgs<Types...>>
307 {
308  static VarArgs<Types...>
309  get(ThreadContext *tc, typename ABI::Position &position)
310  {
311  using Base = VarArgsBase<Types...>;
312  using Impl = VarArgsImpl<ABI, Base, Types...>;
313  return VarArgs<Types...>(new Impl(tc, position));
314  }
315 };
316 
317 
318 /*
319  * These functions will likely be common among all ABIs and implement the
320  * mechanism of gathering arguments, calling the target function, and then
321  * storing the result. They might need to be overridden if, for instance,
322  * the location of arguments need to be determined in a different order.
323  * For example, there might be an ABI which gathers arguments starting
324  * from the last in the list instead of the first. This is unlikely but
325  * still possible to support by redefining these functions..
326  */
327 
328 // With no arguments to gather, call the target function and store the
329 // result.
330 template <typename ABI, typename Ret>
331 static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
332 callFrom(ThreadContext *tc, typename ABI::Position &position,
333  std::function<Ret(ThreadContext *)> target)
334 {
335  Ret ret = target(tc);
336  Result<ABI, Ret>::store(tc, ret);
337  return ret;
338 }
339 
340 // With no arguments to gather and nothing to return, call the target function.
341 template <typename ABI>
342 static void
343 callFrom(ThreadContext *tc, typename ABI::Position &position,
344  std::function<void(ThreadContext *)> target)
345 {
346  target(tc);
347 }
348 
349 // Recursively gather arguments for target from tc until we get to the base
350 // case above.
351 template <typename ABI, typename Ret, typename NextArg, typename ...Args>
352 static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
353 callFrom(ThreadContext *tc, typename ABI::Position &position,
354  std::function<Ret(ThreadContext *, NextArg, Args...)> target)
355 {
356  // Extract the next argument from the thread context.
357  NextArg next = Argument<ABI, NextArg>::get(tc, position);
358 
359  // Build a partial function which adds the next argument to the call.
360  std::function<Ret(ThreadContext *, Args...)> partial =
361  [target,next](ThreadContext *_tc, Args... args) {
362  return target(_tc, next, args...);
363  };
364 
365  // Recursively handle any remaining arguments.
366  return callFrom<ABI, Ret, Args...>(tc, position, partial);
367 }
368 
369 // Recursively gather arguments for target from tc until we get to the base
370 // case above. This version is for functions that don't return anything.
371 template <typename ABI, typename NextArg, typename ...Args>
372 static void
373 callFrom(ThreadContext *tc, typename ABI::Position &position,
374  std::function<void(ThreadContext *, NextArg, Args...)> target)
375 {
376  // Extract the next argument from the thread context.
377  NextArg next = Argument<ABI, NextArg>::get(tc, position);
378 
379  // Build a partial function which adds the next argument to the call.
380  std::function<void(ThreadContext *, Args...)> partial =
381  [target,next](ThreadContext *_tc, Args... args) {
382  target(_tc, next, args...);
383  };
384 
385  // Recursively handle any remaining arguments.
386  callFrom<ABI, Args...>(tc, position, partial);
387 }
388 
389 
390 
391 /*
392  * These functions are like the ones above, except they print the arguments
393  * a target function would be called with instead of actually calling it.
394  */
395 
396 // With no arguments to print, add the closing parenthesis and return.
397 template <typename ABI, typename Ret>
398 static void
399 dumpArgsFrom(int count, std::ostream &os, ThreadContext *tc,
400  typename ABI::Position &position)
401 {
402  os << ")";
403 }
404 
405 // Recursively gather arguments for target from tc until we get to the base
406 // case above, and append those arguments to the string stream being
407 // constructed.
408 template <typename ABI, typename Ret, typename NextArg, typename ...Args>
409 static void
410 dumpArgsFrom(int count, std::ostream &os, ThreadContext *tc,
411  typename ABI::Position &position)
412 {
413  // Either open the parenthesis or add a comma, depending on where we are
414  // in the argument list.
415  os << (count ? ", " : "(");
416 
417  // Extract the next argument from the thread context.
418  NextArg next = Argument<ABI, NextArg>::get(tc, position);
419 
420  // Add this argument to the list.
421  os << next;
422 
423  // Recursively handle any remaining arguments.
424  dumpArgsFrom<ABI, Ret, Args...>(count + 1, os, tc, position);
425 }
426 
427 } // namespace GuestABI
428 
429 
430 // These functions wrap a simulator level function with the given signature.
431 // The wrapper takes one argument, a thread context to extract arguments from
432 // and write a result (if any) back to. For convenience, the wrapper also
433 // returns the result of the wrapped function.
434 
435 template <typename ABI, typename Ret, typename ...Args>
436 Ret
438  std::function<Ret(ThreadContext *, Args...)> target)
439 {
440  // Default construct a Position to track consumed resources. Built in
441  // types will be zero initialized.
442  auto position = GuestABI::PositionInitializer<ABI>::init(tc);
444  return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target);
445 }
446 
447 template <typename ABI, typename Ret, typename ...Args>
448 Ret
449 invokeSimcall(ThreadContext *tc, Ret (*target)(ThreadContext *, Args...))
450 {
451  return invokeSimcall<ABI>(
452  tc, std::function<Ret(ThreadContext *, Args...)>(target));
453 }
454 
455 template <typename ABI, typename ...Args>
456 void
458  std::function<void(ThreadContext *, Args...)> target)
459 {
460  // Default construct a Position to track consumed resources. Built in
461  // types will be zero initialized.
462  auto position = GuestABI::PositionInitializer<ABI>::init(tc);
463  GuestABI::callFrom<ABI, Args...>(tc, position, target);
464 }
465 
466 template <typename ABI, typename ...Args>
467 void
468 invokeSimcall(ThreadContext *tc, void (*target)(ThreadContext *, Args...))
469 {
470  invokeSimcall<ABI>(
471  tc, std::function<void(ThreadContext *, Args...)>(target));
472 }
473 
474 
475 // These functions also wrap a simulator level function. Instead of running the
476 // function, they return a string which shows what arguments the function would
477 // be invoked with if it were called from the given context.
478 
479 template <typename ABI, typename Ret, typename ...Args>
480 std::string
481 dumpSimcall(std::string name, ThreadContext *tc,
482  std::function<Ret(ThreadContext *, Args...)> target=
483  std::function<Ret(ThreadContext *, Args...)>())
484 {
485  auto position = GuestABI::PositionInitializer<ABI>::init(tc);
486  std::ostringstream ss;
487 
489  ss << name;
490  GuestABI::dumpArgsFrom<ABI, Ret, Args...>(0, ss, tc, position);
491  return ss.str();
492 }
493 
494 template <typename ABI, typename Ret, typename ...Args>
495 std::string
496 dumpSimcall(std::string name, ThreadContext *tc,
497  Ret (*target)(ThreadContext *, Args...))
498 {
499  return dumpSimcall<ABI>(
500  name, tc, std::function<Ret(ThreadContext *, Args...)>(target));
501 }
502 
503 #endif // __SIM_GUEST_ABI_HH__
count
Definition: misc.hh:705
static Arg get(ThreadContext *tc, typename ABI::Position &position)
std::string dumpSimcall(std::string name, ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target=std::function< Ret(ThreadContext *, Args...)>())
Definition: guest_abi.hh:481
static void dumpArgsFrom(int count, std::ostream &os, ThreadContext *tc, typename ABI::Position &position)
Definition: guest_abi.hh:399
const std::string & name()
Definition: trace.cc:54
VarArgsImpl(ThreadContext *_tc, const typename ABI::Position &_pos)
Definition: guest_abi.hh:256
static void allocate(ThreadContext *tc, typename ABI::Position &position)
Definition: guest_abi.hh:144
static void store(ThreadContext *tc, const Ret &ret)
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:586
static std::enable_if<!std::is_void< Ret >::value, Ret >::type callFrom(ThreadContext *tc, typename ABI::Position &position, std::function< Ret(ThreadContext *)> target)
Definition: guest_abi.hh:332
ThreadContext is the external interface to all thread state for anything outside of the CPU...
Bitfield< 17 > os
Definition: misc.hh:805
uint8_t type
Definition: inet.hh:333
Bitfield< 21 > ss
VarArgs(VarArgsBase< Types... > *ptr)
Definition: guest_abi.hh:272
Bitfield< 8 > va
static void allocate(ThreadContext *tc, typename ABI::Position &position)
Definition: guest_abi.hh:157
std::shared_ptr< VarArgsBase< Types... > > _ptr
Definition: guest_abi.hh:269
static ABI::Position init(const ThreadContext *tc)
Definition: guest_abi.hh:72
static void allocate(ThreadContext *tc, typename ABI::Position &position)
Ret invokeSimcall(ThreadContext *tc, std::function< Ret(ThreadContext *, Args...)> target)
Definition: guest_abi.hh:437
std::ostream & operator<<(std::ostream &os, const VarArgs< Types... > &va)
Definition: guest_abi.hh:295

Generated on Fri Feb 28 2020 16:27:02 for gem5 by doxygen 1.8.13