#ifndef ELFSPY_SPY_H #define ELFSPY_SPY_H #include "elfspy/Hook.h" #include "elfspy/Method.h" namespace spy { void initialise(int argc, char** argv); namespace impl { /** * @namespace spy * @namespace impl * class Function * A Hook for functions. Uses curiously recurring template pattern to create a * unique type for each function pointer it is instantiated with */ template struct Function { // use CRTP as Hook uses static members template struct Instance : public Hook, R, Args...> { using Base = Hook, R, Args...>; Instance(const char* name) :Base(name, FUNC) { } }; }; /** * @namespace spy * @namespace impl * class MutableMethod * A Hook for non const methods. Uses curiously recurring template pattern to * create a unique type for each method pointer it is instantiated with */ template struct MutableMethod { template struct Instance : public Hook, R, T*, Args...> { using Base = Hook, R, T*, Args...>; Instance(const char* name) :Base(name, Method(METHOD).resolve()) { } }; }; /** * @namespace spy * @namespace impl * class ConstMethod * A Hook for const methods. Uses curiously recurring template pattern to * create a unique type for each method pointer it is instantiated with */ template struct ConstMethod { template struct Instance : public Hook, R, T*, Args...> { using Base = Hook, R, T*, Args...>; Instance(const char* name) :Base(name, Method(METHOD).resolve()) { } }; }; /** * @namespace spy * @namespace impl * class VolatileMethod * A Hook for volatile methods. Uses curiously recurring template pattern to * create a unique type for each method pointer it is instantiated with */ template struct VolatileMethod { template struct Instance : public Hook, R, T*, Args...> { using Base = Hook, R, T*, Args...>; Instance(const char* name) :Base(name, Method(METHOD).resolve()) { } }; }; /** * @namespace spy * @namespace impl * class ConstVolatileMethod * A Hook for volatile methods. Uses curiously recurring template pattern to * create a unique type for each method pointer it is instantiated with */ template struct ConstVolatileMethod { template struct Instance : public Hook, R, T*, Args...> { using Base = Hook, R, T*, Args...>; Instance(const char* name) :Base(name, Method(METHOD).resolve()) { } }; }; /** * @brief * overloaded function only to get the right decltype depending on the * argument passed for the SPY macro. Hence no definition is provided. */ template auto create(R (*)(Args...)) -> Function; template auto create(R (T::*)(Args...)) -> MutableMethod; template auto create(R (T::*)(Args...) const) -> ConstMethod; template auto create(R (T::*)(Args...) volatile) -> VolatileMethod; template auto create(R (T::*)(Args...) const volatile) -> ConstVolatileMethod; } // namespace impl } // namespace spy /** * @def SPY(F) * Macro SPY captures signature of F whether F is a function or a method, and * injects a Hook for F into the Global Offset Table which is invoked between a * program's calls to F and the invocations of F. * SPY returns a (derived) instance of Hook that can be used to add Hooks to. */ #define SPY(F) decltype(spy::impl::create(F))::Instance(#F) #endif