Elfspy/Hook.h

122 lines
3.6 KiB
C
Raw Normal View History

2016-09-16 17:45:35 +02:00
#ifndef ELFSPY_HOOK_H
#define ELFSPY_HOOK_H
#include "elfspy/HookImpl.h"
#include "elfspy/GOTEntry.h"
#include "elfspy/Function.h"
#include "elfspy/MethodInfo.h"
#include "elfspy/Thunk.h"
namespace spy
{
/**
* @namespace spy
* @class Hook
* An instance is a function that is executed after a call to a
* function/method and before it is run, essentially injected between the two.
* It is very lightweight as it only holds reference(s) to static data members.
* Calling convention is unified between methods and functions so that methods
* are functions where the first type in Args... is the class type.
*/
template <typename CRTP, typename ReturnType, typename... ArgTypes>
class Hook : public HookImpl<CRTP, ReturnType, ArgTypes...>
{
public:
using Result = ReturnType;
/**
* typedefs to re-export variadic ArgTypes to other variadic templates
*/
template <template <typename...> class Other, typename... Extra>
struct Export
{
using Type = Other<Extra..., ArgTypes...>;
};
template <template <size_t, typename...> class Other>
struct ExportN
{
template <size_t N>
using Type = Other<N, ArgTypes...>;
};
/**
* construct from function pointer
*/
2016-09-17 22:46:34 +02:00
Hook(const char* name, ReturnType (*function)(ArgTypes...));
2016-09-16 17:45:35 +02:00
/**
* construct from method pointer
*/
2016-09-17 22:46:34 +02:00
Hook(const char* name, MethodInfo<ReturnType, ArgTypes...> method);
2016-09-16 17:45:35 +02:00
/// restore original function
~Hook();
/**
* invoke the original function
* @param args arguments to pass
* @return return value of function
*/
static ReturnType invoke_real(ArgTypes... args);
operator const GOTEntry&() const;
private:
static GOTEntry got_entry_;
2016-09-17 22:46:34 +02:00
static const char* name_;
2016-09-16 17:45:35 +02:00
using Base = HookImpl<CRTP, ReturnType, ArgTypes...>;
};
template <typename CRTP, typename ReturnType, typename... ArgTypes>
GOTEntry Hook<CRTP, ReturnType, ArgTypes...>::got_entry_;
2016-09-17 22:46:34 +02:00
template <typename CRTP, typename ReturnType, typename... ArgTypes>
const char* Hook<CRTP, ReturnType, ArgTypes...>::name_ = "no name";
2016-09-16 17:45:35 +02:00
template <typename CRTP, typename ReturnType, typename... ArgTypes>
2016-09-17 22:46:34 +02:00
Hook<CRTP, ReturnType, ArgTypes...>::Hook(const char* name,
ReturnType (*function)(ArgTypes...))
2016-09-16 17:45:35 +02:00
{
2016-09-17 22:46:34 +02:00
name_ = name;
2016-09-16 17:45:35 +02:00
// use union to get and convert address of function
Function<ReturnType, ArgTypes...> converter;
converter.address_ = function;
2016-09-17 22:46:34 +02:00
got_entry_.set(converter.pointer_, name);
2016-09-16 17:45:35 +02:00
converter.address_ = &Base::thunk;
converter.pointer_ = got_entry_.spy_with(converter.pointer_);
Base::patch_ = Base::real_ = converter.address_;
}
template <typename CRTP, typename ReturnType, typename... ArgTypes>
inline Hook<CRTP, ReturnType, ArgTypes...>::
2016-09-17 22:46:34 +02:00
Hook(const char* name, MethodInfo<ReturnType, ArgTypes...> method)
2016-09-16 17:45:35 +02:00
{
2016-09-17 22:46:34 +02:00
name_ = name;
got_entry_.set(method.address_, name);
2016-09-16 17:45:35 +02:00
if (method.vtable_entry_) {
got_entry_.make_entry(method.vtable_entry_);
}
Function<ReturnType, ArgTypes...> converter;
converter.address_ = &Base::thunk;
converter.pointer_ = got_entry_.spy_with(converter.pointer_);
Base::patch_ = Base::real_ = converter.address_;
}
template <typename CRTP, typename ReturnType, typename... ArgTypes>
inline Hook<CRTP, ReturnType, ArgTypes...>::~Hook()
{
got_entry_.restore();
}
template <typename CRTP, typename ReturnType, typename... ArgTypes>
inline ReturnType Hook<CRTP, ReturnType, ArgTypes...>::invoke_real(ArgTypes... args)
{
return (*Base::real_)(args...);
}
template <typename CRTP, typename ReturnType, typename... ArgTypes>
inline Hook<CRTP, ReturnType, ArgTypes...>::operator const GOTEntry&() const
{
return got_entry_;
}
} // namespace spy
#endif