| /* |
| * Copyright 2019 Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Gabe Black |
| */ |
| |
| #ifndef __SIM_GUEST_ABI_HH__ |
| #define __SIM_GUEST_ABI_HH__ |
| |
| #include <functional> |
| #include <memory> |
| #include <sstream> |
| #include <type_traits> |
| |
| class ThreadContext; |
| |
| namespace GuestABI |
| { |
| |
| /* |
| * To implement an ABI, a subclass needs to implement a system of |
| * specializations of these two templates Result and Argument, and define a |
| * "Position" type. |
| * |
| * The Position type carries information about, for instance, how many |
| * integer registers have been consumed gathering earlier arguments. It |
| * may contain multiple elements if there are multiple dimensions to track, |
| * for instance the number of integer and floating point registers used so far. |
| * |
| * Result and Argument are class templates instead of function templates so |
| * that they can be partially specialized if necessary. C++ doesn't let you |
| * partially specialize function templates because that conflicts with |
| * template resolution using the function's arguments. Since we already know |
| * what type we want and we don't need argument based resolution, we can just |
| * wrap the desired functionality in classes and sidestep the problem. |
| * |
| * Also note that these templates have an "Enabled" parameter to support |
| * std::enable_if style conditional specializations. |
| */ |
| |
| /* |
| * Position may need to be initialized based on the ThreadContext, for instance |
| * to find out where the stack pointer is initially. |
| */ |
| template <typename ABI, typename Enabled=void> |
| struct PositionInitializer |
| { |
| static typename ABI::Position |
| init(const ThreadContext *tc) |
| { |
| return typename ABI::Position(); |
| } |
| }; |
| |
| template <typename ABI> |
| struct PositionInitializer<ABI, typename std::enable_if< |
| std::is_constructible<typename ABI::Position, const ThreadContext *>::value |
| >::type> |
| { |
| static typename ABI::Position |
| init(const ThreadContext *tc) |
| { |
| return typename ABI::Position(tc); |
| } |
| }; |
| |
| template <typename ABI, typename Ret, typename Enabled=void> |
| struct Result |
| { |
| private: |
| /* |
| * Store result "ret" into the state accessible through tc. |
| * |
| * Note that the declaration below is only to document the expected |
| * signature and is private so it won't be used by accident. |
| * Specializations of this Result class should define their own version |
| * of this method which actually does something and is public. |
| */ |
| static void store(ThreadContext *tc, const Ret &ret); |
| |
| /* |
| * Adjust the position of arguments based on the return type, if necessary. |
| * |
| * This method can be excluded if no adjustment is necessary. |
| */ |
| static void allocate(ThreadContext *tc, typename ABI::Position &position); |
| }; |
| |
| /* |
| * This partial specialization prevents having to special case 'void' when |
| * working with return types. |
| */ |
| template <typename ABI> |
| struct Result<ABI, void> |
| {}; |
| |
| template <typename ABI, typename Arg, typename Enabled=void> |
| struct Argument |
| { |
| /* |
| * Retrieve an argument of type Arg from the state accessible through tc, |
| * assuming the state represented by "position" has already been used. |
| * Also update position to account for this argument as well. |
| * |
| * Like Result::store above, the declaration below is only to document |
| * the expected method signature. |
| */ |
| static Arg get(ThreadContext *tc, typename ABI::Position &position); |
| }; |
| |
| |
| /* |
| * This struct template provides a default allocate() method in case the |
| * Result template doesn't provide one. This is the default in cases where the |
| * return type doesn't affect how arguments are laid out. |
| */ |
| template <typename ABI, typename Ret, typename Enabled=void> |
| struct ResultAllocator |
| { |
| static void |
| allocate(ThreadContext *tc, typename ABI::Position &position) |
| {} |
| }; |
| |
| /* |
| * If the return type *does* affect how the arguments are laid out, the ABI |
| * can implement an allocate() method for the various return types, and this |
| * specialization will call into it. |
| */ |
| template <typename ABI, typename Ret> |
| struct ResultAllocator<ABI, Ret, decltype((void)&Result<ABI, Ret>::allocate)> |
| { |
| static void |
| allocate(ThreadContext *tc, typename ABI::Position &position) |
| { |
| Result<ABI, Ret>::allocate(tc, position); |
| } |
| }; |
| |
| |
| /* |
| * These templates implement a variadic argument mechanism for guest ABI |
| * functions. A function might be written like this: |
| * |
| * void |
| * func(ThreadContext *tc, VarArgs<Addr, int> varargs) |
| * { |
| * warn("Address = %#x, int = %d.", |
| * varargs.get<Addr>(), varargs.get<int>()); |
| * } |
| * |
| * where an object of type VarArgs<...> is its last argument. The types given |
| * to the template specify what types the function might need to retrieve from |
| * varargs. The varargs object will then have get<> methods for each of those |
| * types. |
| * |
| * Note that each get<> will happen live. If you modify values through the |
| * ThreadContext *tc and then run get<>(), you may alter one of your arguments. |
| * If you're going to use tc to modify state, it would be a good idea to use |
| * get<>() as soon as possible to avoid corrupting the functions arguments. |
| */ |
| |
| // A recursive template which defines virtual functions to retrieve each of the |
| // requested types. This provides the ABI agnostic interface the function uses. |
| template <typename ...Types> |
| class VarArgsBase; |
| |
| template <typename First, typename ...Types> |
| class VarArgsBase<First, Types...> : public VarArgsBase<Types...> |
| { |
| public: |
| // The virtual function takes a reference parameter so that the different |
| // _getImpl methods can co-exist through overloading. |
| virtual void _getImpl(First &) = 0; |
| |
| // Make sure base class _getImpl-es aren't hidden by this one. |
| using VarArgsBase<Types...>::_getImpl; |
| }; |
| |
| // The base case of the recursion. |
| template <> |
| class VarArgsBase<> |
| { |
| protected: |
| // This just gives the "using" statement in the non base case something to |
| // refer to. |
| void _getImpl(); |
| }; |
| |
| |
| // A recursive template which defines the ABI specific implementation of the |
| // interface defined above. |
| // |
| // The types in Types are consumed one by one, and by |
| // the time we get down to the base case we'd have lost track of the complete |
| // set we need to know what interface to inherit. The Base parameter keeps |
| // track of that through the recursion. |
| template <typename ABI, typename Base, typename ...Types> |
| class VarArgsImpl; |
| |
| template <typename ABI, typename Base, typename First, typename ...Types> |
| class VarArgsImpl<ABI, Base, First, Types...> : |
| public VarArgsImpl<ABI, Base, Types...> |
| { |
| protected: |
| // Bring forward the base class constructor. |
| using VarArgsImpl<ABI, Base, Types...>::VarArgsImpl; |
| // Make sure base class _getImpl-es don't get hidden by ours. |
| using VarArgsImpl<ABI, Base, Types...>::_getImpl; |
| |
| // Implement a version of _getImple, using the ABI specialized version of |
| // the Argument class. |
| void |
| _getImpl(First &first) override |
| { |
| first = Argument<ABI, First>::get(this->tc, this->position); |
| } |
| }; |
| |
| // The base case of the recursion, which inherits from the interface class. |
| template <typename ABI, typename Base> |
| class VarArgsImpl<ABI, Base> : public Base |
| { |
| protected: |
| // Declare state to pass to the Argument<>::get methods. |
| ThreadContext *tc; |
| typename ABI::Position position; |
| |
| // Give the "using" statement in our subclass something to refer to. |
| void _getImpl(); |
| |
| public: |
| VarArgsImpl(ThreadContext *_tc, const typename ABI::Position &_pos) : |
| tc(_tc), position(_pos) |
| {} |
| }; |
| |
| // A wrapper which provides a nice interface to the virtual functions, and a |
| // hook for the Argument template mechanism. |
| template <typename ...Types> |
| class VarArgs |
| { |
| private: |
| // This points to the implementation which knows how to read arguments |
| // based on the ABI being used. |
| std::shared_ptr<VarArgsBase<Types...>> _ptr; |
| |
| public: |
| VarArgs(VarArgsBase<Types...> *ptr) : _ptr(ptr) {} |
| |
| // This template is a friendlier wrapper around the virtual functions the |
| // raw interface provides. This version lets you pick a type which it then |
| // returns, instead of having to pre-declare a variable to pass in. |
| template <typename Arg> |
| Arg |
| get() |
| { |
| Arg arg; |
| _ptr->_getImpl(arg); |
| return arg; |
| } |
| }; |
| |
| template <typename T> |
| struct IsVarArgs : public std::false_type {}; |
| |
| template <typename ...Types> |
| struct IsVarArgs<VarArgs<Types...>> : public std::true_type {}; |
| |
| template <typename ...Types> |
| std::ostream & |
| operator << (std::ostream &os, const VarArgs<Types...> &va) |
| { |
| os << "..."; |
| return os; |
| } |
| |
| // The ABI independent hook which tells the GuestABI mechanism what to do with |
| // a VarArgs argument. It constructs the underlying implementation which knows |
| // about the ABI, and installs it in the VarArgs wrapper to give to the |
| // function. |
| template <typename ABI, typename ...Types> |
| struct Argument<ABI, VarArgs<Types...>> |
| { |
| static VarArgs<Types...> |
| get(ThreadContext *tc, typename ABI::Position &position) |
| { |
| using Base = VarArgsBase<Types...>; |
| using Impl = VarArgsImpl<ABI, Base, Types...>; |
| return VarArgs<Types...>(new Impl(tc, position)); |
| } |
| }; |
| |
| |
| /* |
| * These functions will likely be common among all ABIs and implement the |
| * mechanism of gathering arguments, calling the target function, and then |
| * storing the result. They might need to be overridden if, for instance, |
| * the location of arguments need to be determined in a different order. |
| * For example, there might be an ABI which gathers arguments starting |
| * from the last in the list instead of the first. This is unlikely but |
| * still possible to support by redefining these functions.. |
| */ |
| |
| // With no arguments to gather, call the target function and store the |
| // result. |
| template <typename ABI, typename Ret> |
| static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type |
| callFrom(ThreadContext *tc, typename ABI::Position &position, |
| std::function<Ret(ThreadContext *)> target) |
| { |
| Ret ret = target(tc); |
| Result<ABI, Ret>::store(tc, ret); |
| return ret; |
| } |
| |
| // With no arguments to gather and nothing to return, call the target function. |
| template <typename ABI> |
| static void |
| callFrom(ThreadContext *tc, typename ABI::Position &position, |
| std::function<void(ThreadContext *)> target) |
| { |
| target(tc); |
| } |
| |
| // Recursively gather arguments for target from tc until we get to the base |
| // case above. |
| template <typename ABI, typename Ret, typename NextArg, typename ...Args> |
| static typename std::enable_if<!std::is_void<Ret>::value, Ret>::type |
| callFrom(ThreadContext *tc, typename ABI::Position &position, |
| std::function<Ret(ThreadContext *, NextArg, Args...)> target) |
| { |
| // Extract the next argument from the thread context. |
| NextArg next = Argument<ABI, NextArg>::get(tc, position); |
| |
| // Build a partial function which adds the next argument to the call. |
| std::function<Ret(ThreadContext *, Args...)> partial = |
| [target,next](ThreadContext *_tc, Args... args) { |
| return target(_tc, next, args...); |
| }; |
| |
| // Recursively handle any remaining arguments. |
| return callFrom<ABI, Ret, Args...>(tc, position, partial); |
| } |
| |
| // Recursively gather arguments for target from tc until we get to the base |
| // case above. This version is for functions that don't return anything. |
| template <typename ABI, typename NextArg, typename ...Args> |
| static void |
| callFrom(ThreadContext *tc, typename ABI::Position &position, |
| std::function<void(ThreadContext *, NextArg, Args...)> target) |
| { |
| // Extract the next argument from the thread context. |
| NextArg next = Argument<ABI, NextArg>::get(tc, position); |
| |
| // Build a partial function which adds the next argument to the call. |
| std::function<void(ThreadContext *, Args...)> partial = |
| [target,next](ThreadContext *_tc, Args... args) { |
| target(_tc, next, args...); |
| }; |
| |
| // Recursively handle any remaining arguments. |
| callFrom<ABI, Args...>(tc, position, partial); |
| } |
| |
| |
| |
| /* |
| * These functions are like the ones above, except they print the arguments |
| * a target function would be called with instead of actually calling it. |
| */ |
| |
| // With no arguments to print, add the closing parenthesis and return. |
| template <typename ABI, typename Ret> |
| static void |
| dumpArgsFrom(int count, std::ostream &os, ThreadContext *tc, |
| typename ABI::Position &position) |
| { |
| os << ")"; |
| } |
| |
| // Recursively gather arguments for target from tc until we get to the base |
| // case above, and append those arguments to the string stream being |
| // constructed. |
| template <typename ABI, typename Ret, typename NextArg, typename ...Args> |
| static void |
| dumpArgsFrom(int count, std::ostream &os, ThreadContext *tc, |
| typename ABI::Position &position) |
| { |
| // Either open the parenthesis or add a comma, depending on where we are |
| // in the argument list. |
| os << (count ? ", " : "("); |
| |
| // Extract the next argument from the thread context. |
| NextArg next = Argument<ABI, NextArg>::get(tc, position); |
| |
| // Add this argument to the list. |
| os << next; |
| |
| // Recursively handle any remaining arguments. |
| dumpArgsFrom<ABI, Ret, Args...>(count + 1, os, tc, position); |
| } |
| |
| } // namespace GuestABI |
| |
| |
| // These functions wrap a simulator level function with the given signature. |
| // The wrapper takes one argument, a thread context to extract arguments from |
| // and write a result (if any) back to. For convenience, the wrapper also |
| // returns the result of the wrapped function. |
| |
| template <typename ABI, typename Ret, typename ...Args> |
| Ret |
| invokeSimcall(ThreadContext *tc, |
| std::function<Ret(ThreadContext *, Args...)> target) |
| { |
| // Default construct a Position to track consumed resources. Built in |
| // types will be zero initialized. |
| auto position = GuestABI::PositionInitializer<ABI>::init(tc); |
| GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position); |
| return GuestABI::callFrom<ABI, Ret, Args...>(tc, position, target); |
| } |
| |
| template <typename ABI, typename Ret, typename ...Args> |
| Ret |
| invokeSimcall(ThreadContext *tc, Ret (*target)(ThreadContext *, Args...)) |
| { |
| return invokeSimcall<ABI>( |
| tc, std::function<Ret(ThreadContext *, Args...)>(target)); |
| } |
| |
| template <typename ABI, typename ...Args> |
| void |
| invokeSimcall(ThreadContext *tc, |
| std::function<void(ThreadContext *, Args...)> target) |
| { |
| // Default construct a Position to track consumed resources. Built in |
| // types will be zero initialized. |
| auto position = GuestABI::PositionInitializer<ABI>::init(tc); |
| GuestABI::callFrom<ABI, Args...>(tc, position, target); |
| } |
| |
| template <typename ABI, typename ...Args> |
| void |
| invokeSimcall(ThreadContext *tc, void (*target)(ThreadContext *, Args...)) |
| { |
| invokeSimcall<ABI>( |
| tc, std::function<void(ThreadContext *, Args...)>(target)); |
| } |
| |
| |
| // These functions also wrap a simulator level function. Instead of running the |
| // function, they return a string which shows what arguments the function would |
| // be invoked with if it were called from the given context. |
| |
| template <typename ABI, typename Ret, typename ...Args> |
| std::string |
| dumpSimcall(std::string name, ThreadContext *tc, |
| std::function<Ret(ThreadContext *, Args...)> target= |
| std::function<Ret(ThreadContext *, Args...)>()) |
| { |
| auto position = GuestABI::PositionInitializer<ABI>::init(tc); |
| std::ostringstream ss; |
| |
| GuestABI::ResultAllocator<ABI, Ret>::allocate(tc, position); |
| ss << name; |
| GuestABI::dumpArgsFrom<ABI, Ret, Args...>(0, ss, tc, position); |
| return ss.str(); |
| } |
| |
| template <typename ABI, typename Ret, typename ...Args> |
| std::string |
| dumpSimcall(std::string name, ThreadContext *tc, |
| Ret (*target)(ThreadContext *, Args...)) |
| { |
| return dumpSimcall<ABI>( |
| name, tc, std::function<Ret(ThreadContext *, Args...)>(target)); |
| } |
| |
| #endif // __SIM_GUEST_ABI_HH__ |