1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-02-20 13:54:14 +01:00

Merged hookman_autogen into trunk

--HG--
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40581
This commit is contained in:
Pavol Marko 2007-11-26 14:03:25 +00:00
parent 12cb24aed8
commit 59bd50c69d
30 changed files with 9097 additions and 28 deletions

View File

@ -35,6 +35,11 @@
// 1 - standard
#define SH_HOOKMAN_VERSION 1
// Hookmanautogen versions
// 1 - initial
#define SH_HOOKMANAUTOGEN_IFACE_VERSION 1
#define SH_HOOKMANAUTOGEN_IMPL_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -173,7 +178,13 @@ namespace SourceHook
PassFlag_ODtor = (1<<2), /**< Object has a destructor */
PassFlag_OCtor = (1<<3), /**< Object has a normal non-trivial constructor */
PassFlag_AssignOp = (1<<4), /**< Object has a non-trivial assignment operator */
PassFlag_CCtor = (1<<5) /**< Object has a copy constructor (which takes const Object& as only parameter) */
PassFlag_CCtor = (1<<5), /**< Object has a copy constructor (which takes const Object& as only parameter) */
// The following two flags are only relevant for byval return types.
// SH tries to auto-detect these
// If you want to override SH's auto-detection, pass them in yourself
PassFlag_RetMem = (1<<6), /**< Object is returned in memory (through hidden first param */
PassFlag_RetReg = (1<<7) /**< Object is returned in EAX(:EDX) */
};
size_t size; //!< Size of the data being passed
@ -196,9 +207,13 @@ namespace SourceHook
{
enum CallConvention
{
CallConv_Unknown, /**< Unknown -- no extra info available */
CallConv_ThisCall, /**< This call (object pointer required) */
CallConv_Cdecl, /**< Standard C call */
CallConv_Unknown, /**< Unknown -- no extra info available (0)*/
CallConv_ThisCall, /**< This call (object pointer required) (1)*/
CallConv_Cdecl, /**< C call (2)*/
CallConv_StdCall, /**< Windows "stdcall" (3)*/
CallConv_HasVarArgs = (1<<16), /**< Has variable arguments */
CallConv_HasVafmt = CallConv_HasVarArgs | (1<<17) /**< last params: const char*, ... */
};
int numOfParams; //!< number of parameters
@ -462,6 +477,17 @@ namespace SourceHook
virtual void EndContext(IHookContext *pCtx) = 0;
};
class IHookManagerAutoGen
{
public:
virtual int GetIfaceVersion() = 0;
virtual int GetImplVersion() = 0;
virtual HookManagerPubFunc MakeHookMan(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx) = 0;
virtual void ReleaseHookMan(HookManagerPubFunc pubFunc) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
// These have to be able to return references. If T is a reference, the pointers returned
// from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier<T>::type.
@ -1014,7 +1040,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf) - 1, fmt, ap); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
buf[sizeof(buf) - 1] = 0; \
va_end(ap);
@ -6737,204 +6763,408 @@ namespace SourceHook
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)())
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
}
#endif

View File

@ -35,6 +35,11 @@
// 1 - standard
#define SH_HOOKMAN_VERSION 1
// Hookmanautogen versions
// 1 - initial
#define SH_HOOKMANAUTOGEN_IFACE_VERSION 1
#define SH_HOOKMANAUTOGEN_IMPL_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -173,7 +178,13 @@ namespace SourceHook
PassFlag_ODtor = (1<<2), /**< Object has a destructor */
PassFlag_OCtor = (1<<3), /**< Object has a normal non-trivial constructor */
PassFlag_AssignOp = (1<<4), /**< Object has a non-trivial assignment operator */
PassFlag_CCtor = (1<<5) /**< Object has a copy constructor (which takes const Object& as only parameter) */
PassFlag_CCtor = (1<<5), /**< Object has a copy constructor (which takes const Object& as only parameter) */
// The following two flags are only relevant for byval return types.
// SH tries to auto-detect these
// If you want to override SH's auto-detection, pass them in yourself
PassFlag_RetMem = (1<<6), /**< Object is returned in memory (through hidden first param */
PassFlag_RetReg = (1<<7) /**< Object is returned in EAX(:EDX) */
};
size_t size; //!< Size of the data being passed
@ -196,9 +207,13 @@ namespace SourceHook
{
enum CallConvention
{
CallConv_Unknown, /**< Unknown -- no extra info available */
CallConv_ThisCall, /**< This call (object pointer required) */
CallConv_Cdecl, /**< Standard C call */
CallConv_Unknown, /**< Unknown -- no extra info available (0)*/
CallConv_ThisCall, /**< This call (object pointer required) (1)*/
CallConv_Cdecl, /**< C call (2)*/
CallConv_StdCall, /**< Windows "stdcall" (3)*/
CallConv_HasVarArgs = (1<<16), /**< Has variable arguments */
CallConv_HasVafmt = CallConv_HasVarArgs | (1<<17) /**< last params: const char*, ... */
};
int numOfParams; //!< number of parameters
@ -462,6 +477,17 @@ namespace SourceHook
virtual void EndContext(IHookContext *pCtx) = 0;
};
class IHookManagerAutoGen
{
public:
virtual int GetIfaceVersion() = 0;
virtual int GetImplVersion() = 0;
virtual HookManagerPubFunc MakeHookMan(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx) = 0;
virtual void ReleaseHookMan(HookManagerPubFunc pubFunc) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
// These have to be able to return references. If T is a reference, the pointers returned
// from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier<T>::type.
@ -1014,7 +1040,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf) - 1, fmt, ap); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
buf[sizeof(buf) - 1] = 0; \
va_end(ap);
@ -1415,11 +1441,23 @@ namespace SourceHook
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType@[$2,1,$1:, class Param$2@]>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(@[$2,1,$1:Param$2, @]...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType@[$2,1,$1:, class Param$2@]>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(@[$2,1,$1|, :Param$2@]))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType@[$2,1,$1:, class Param$2@]>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(@[$2,1,$1:Param$2, @]...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
@]
}

View File

@ -103,6 +103,20 @@ namespace SourceHook
insert(begin(), obj);
}
void push_sorted(const T &obj)
{
iterator iter;
for (iter = begin(); iter != end(); ++iter)
{
if (obj < *iter)
{
insert(iter, obj);
return;
}
}
push_back(obj);
}
size_t size() const
{
return m_Size;
@ -301,6 +315,7 @@ namespace SourceHook
return *this;
}
};
}; //NAMESPACE
#endif //_INCLUDE_CSDM_LIST_H

View File

@ -38,11 +38,12 @@
// We need to align addr down to pagesize on linux
// We assume PAGESIZE is a power of two
# define SH_LALIGN(x) (void*)((intptr_t)(x) & ~(PAGESIZE-1))
# define SH_LALDIF(x) ((intptr_t)(x) & (PAGESIZE-1))
# define SH_LALDIF(x) ((intptr_t)(x) % PAGESIZE)
# else
# error Unsupported OS/Compiler
# endif
#include "sh_list.h"
namespace SourceHook
{

288
sourcehook/sh_pagealloc.h Normal file
View File

@ -0,0 +1,288 @@
#ifndef __SH_PAGEALLOC_H__
#define __SH_PAGEALLOC_H__
# if /********/ defined _WIN32
# include <windows.h>
# elif /******/ defined __linux__
# include <sys/mman.h>
# include <unistd.h>
# else
# error Unsupported OS/Compiler
# endif
namespace SourceHook
{
/*
Class which lets us allocate memory regions in special pages only meant for on the fly code generation.
If we alloc with malloc and then set the page access type to read/exec only, other regions returned by
malloc that are in the same page would lose their write access as well and the process could crash.
Allocating one page per code generation session is usually a waste of memory and on some platforms also
a waste of virtual address space (Windows VirtualAlloc has a granularity of 64K).
IMPORTANT: the memory that Alloc() returns is not a in a defined state!
It could be in read+exec OR read+write mode.
-> call SetRE() or SetRW() before using allocated memory!
*/
class CPageAlloc
{
struct AllocationUnit
{
size_t begin_offset;
size_t size;
AllocationUnit(size_t p_offs, size_t p_size) : begin_offset(p_offs), size(p_size)
{
}
bool operator < (const AllocationUnit &other) const
{
return begin_offset < other.begin_offset;
}
};
typedef List<AllocationUnit> AUList;
struct AllocatedRegion
{
void *startPtr;
size_t size;
bool isolated; // may contain only one AU
size_t minAlignment;
AUList allocUnits;
void CheckGap(size_t gap_begin, size_t gap_end, size_t reqsize,
size_t &smallestgap_pos, size_t &smallestgap_size, size_t &outAlignBytes)
{
size_t gapsize = gap_end - gap_begin;
// How many bytes do we actually need here?
// = requested size + alignment bytes
size_t neededSize = reqsize;
size_t alignBytes = minAlignment - ((reinterpret_cast<intptr_t>(startPtr) + gap_begin) % minAlignment);
alignBytes %= minAlignment;
neededSize += alignBytes;
if (gapsize >= neededSize)
{
if (gapsize < smallestgap_size)
{
smallestgap_size = gapsize;
smallestgap_pos = gap_begin;
outAlignBytes = alignBytes;
}
}
}
bool TryAlloc(size_t reqsize, void * &outAddr)
{
// Check for isolated
if (isolated && !allocUnits.empty())
return false;
// Find the smallest gap where req fits
size_t lastend = 0;
size_t smallestgap_pos = size + 1;
size_t smallestgap_size = size + 1;
size_t alignmentbytes = 0;
for (AUList::iterator iter = allocUnits.begin(); iter != allocUnits.end(); ++iter)
{
CheckGap(lastend, iter->begin_offset, reqsize, smallestgap_pos, smallestgap_size, alignmentbytes);
lastend = iter->begin_offset + iter->size;
}
CheckGap(lastend, size, reqsize, smallestgap_pos, smallestgap_size, alignmentbytes);
if (smallestgap_pos < size)
{
outAddr = reinterpret_cast<void*>(reinterpret_cast<char*>(startPtr) + smallestgap_pos + alignmentbytes);
allocUnits.push_sorted( AllocationUnit(smallestgap_pos, reqsize + alignmentbytes) );
return true;
}
else
{
return false;
}
}
bool TryFree(void *addr)
{
if (addr < startPtr || addr >= reinterpret_cast<void*>(reinterpret_cast<char*>(startPtr) + size))
return false;
intptr_t start = reinterpret_cast<intptr_t>(startPtr);
for (AUList::iterator iter = allocUnits.begin(); iter != allocUnits.end(); ++iter)
{
size_t AUBegin = start + iter->begin_offset;
void *alignedAUBegin = reinterpret_cast<void*>(
AUBegin + ((minAlignment - AUBegin % minAlignment) % minAlignment)
);
if (addr == alignedAUBegin)
{
allocUnits.erase(iter);
return true;
}
}
return false;
}
bool Contains(void *addr)
{
return addr >= startPtr && addr < reinterpret_cast<void*>(reinterpret_cast<char*>(startPtr) + size);
}
void FreeRegion()
{
#ifdef __linux__
munmap(startPtr, size);
#else
VirtualFree(startPtr, 0, MEM_RELEASE);
#endif
}
};
typedef List<AllocatedRegion> ARList;
size_t m_MinAlignment;
size_t m_PageSize;
ARList m_Regions;
bool AddRegion(size_t minSize, bool isolated)
{
AllocatedRegion newRegion;
newRegion.startPtr = 0;
newRegion.isolated = isolated;
newRegion.minAlignment = m_MinAlignment;
// Compute real size -> align up to m_PageSize boundary
newRegion.size = minSize - (minSize % m_PageSize);
if (newRegion.size < minSize)
newRegion.size += m_PageSize;
#ifdef __linux__
newRegion.startPtr = mmap(0, newRegion.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
newRegion.startPtr = VirtualAlloc(NULL, newRegion.size, MEM_COMMIT, PAGE_READWRITE);
#endif
if (newRegion.startPtr)
{
m_Regions.push_back(newRegion);
return true;
}
else
{
return false;
}
}
void *AllocPriv(size_t size, bool isolated)
{
void *addr;
if (!isolated)
{
for (ARList::iterator iter = m_Regions.begin(); iter != m_Regions.end(); ++iter)
{
if (iter->TryAlloc(size, addr))
return addr;
}
}
if (!AddRegion(size, isolated))
return NULL;
bool tmp = m_Regions.back().TryAlloc(size, addr);
SH_ASSERT(tmp, ("TryAlloc fails after AddRegion"));
return tmp ? addr : NULL;
}
public:
CPageAlloc(size_t minAlignment = 1 /* power of 2 */ ) : m_MinAlignment(minAlignment)
{
#ifdef __linux__
m_PageSize = sysconf(_SC_PAGESIZE);
#else
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
m_PageSize = sysInfo.dwPageSize;
#endif
}
~CPageAlloc()
{
// Free all regions
for (ARList::iterator iter = m_Regions.begin(); iter != m_Regions.end(); ++iter)
{
iter->FreeRegion();
}
}
void *Alloc(size_t size)
{
return AllocPriv(size, false);
}
void *AllocIsolated(size_t size)
{
return AllocPriv(size, true);
}
void Free(void *ptr)
{
for (ARList::iterator iter = m_Regions.begin(); iter != m_Regions.end(); ++iter)
{
if (iter->TryFree(ptr))
{
if (iter->allocUnits.empty())
{
iter->FreeRegion();
m_Regions.erase(iter);
}
break;
}
}
}
void SetRE(void *ptr)
{
for (ARList::iterator iter = m_Regions.begin(); iter != m_Regions.end(); ++iter)
{
if (iter->Contains(ptr))
{
SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_EXEC);
break;
}
}
}
void SetRW(void *ptr)
{
for (ARList::iterator iter = m_Regions.begin(); iter != m_Regions.end(); ++iter)
{
if (iter->Contains(ptr))
{
SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_WRITE);
break;
}
}
}
size_t GetPageSize()
{
return m_PageSize;
}
};
}
#endif

View File

@ -151,6 +151,25 @@ namespace SourceHook
return true;
}
bool CProto::ExactlyEqual(const CProto &other) const
{
if (m_Version != other.m_Version ||
m_NumOfParams != other.m_NumOfParams ||
m_Convention != other.m_Convention ||
GetRet() != other.GetRet())
{
return false;
}
for (int i = 0; i < m_NumOfParams; ++i)
{
if(GetParam(i) != other.GetParam(i))
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// CHookManager

View File

@ -35,6 +35,11 @@
// 1 - standard
#define SH_HOOKMAN_VERSION 1
// Hookmanautogen versions
// 1 - initial
#define SH_HOOKMANAUTOGEN_IFACE_VERSION 1
#define SH_HOOKMANAUTOGEN_IMPL_VERSION 1
// The value of SH_GLOB_SHPTR has to be a pointer to SourceHook::ISourceHook
// It's used in various macros
#ifndef SH_GLOB_SHPTR
@ -173,7 +178,13 @@ namespace SourceHook
PassFlag_ODtor = (1<<2), /**< Object has a destructor */
PassFlag_OCtor = (1<<3), /**< Object has a normal non-trivial constructor */
PassFlag_AssignOp = (1<<4), /**< Object has a non-trivial assignment operator */
PassFlag_CCtor = (1<<5) /**< Object has a copy constructor (which takes const Object& as only parameter) */
PassFlag_CCtor = (1<<5), /**< Object has a copy constructor (which takes const Object& as only parameter) */
// The following two flags are only relevant for byval return types.
// SH tries to auto-detect these
// If you want to override SH's auto-detection, pass them in yourself
PassFlag_RetMem = (1<<6), /**< Object is returned in memory (through hidden first param */
PassFlag_RetReg = (1<<7) /**< Object is returned in EAX(:EDX) */
};
size_t size; //!< Size of the data being passed
@ -196,9 +207,13 @@ namespace SourceHook
{
enum CallConvention
{
CallConv_Unknown, /**< Unknown -- no extra info available */
CallConv_ThisCall, /**< This call (object pointer required) */
CallConv_Cdecl, /**< Standard C call */
CallConv_Unknown, /**< Unknown -- no extra info available (0)*/
CallConv_ThisCall, /**< This call (object pointer required) (1)*/
CallConv_Cdecl, /**< C call (2)*/
CallConv_StdCall, /**< Windows "stdcall" (3)*/
CallConv_HasVarArgs = (1<<16), /**< Has variable arguments */
CallConv_HasVafmt = CallConv_HasVarArgs | (1<<17) /**< last params: const char*, ... */
};
int numOfParams; //!< number of parameters
@ -462,6 +477,17 @@ namespace SourceHook
virtual void EndContext(IHookContext *pCtx) = 0;
};
class IHookManagerAutoGen
{
public:
virtual int GetIfaceVersion() = 0;
virtual int GetImplVersion() = 0;
virtual HookManagerPubFunc MakeHookMan(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx) = 0;
virtual void ReleaseHookMan(HookManagerPubFunc pubFunc) = 0;
};
// For META_RESULT_ORIG_RET and META_RESULT_OVERRIDE_RET:
// These have to be able to return references. If T is a reference, the pointers returned
// from the SH_GLOB_SHPTR are pointers to instances of ReferenceCarrier<T>::type.
@ -1014,7 +1040,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
char buf[::SourceHook::STRBUF_LEN]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, sizeof(buf) - 1, fmt, ap); \
vsnprintf(buf, sizeof(buf), fmt, ap); \
buf[sizeof(buf) - 1] = 0; \
va_end(ap);
@ -6737,204 +6763,408 @@ namespace SourceHook
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)())
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...))
{
return OverrideFunctor<RetType>();
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
template <class Iface, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class Param9, class Param10, class Param11, class Param12, class Param13, class Param14, class Param15, class Param16>
Iface *RecallGetIface(ISourceHook *shptr, RetType (Iface::*mfp)(Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10, Param11, Param12, Param13, Param14, Param15, Param16, ...))
{
return reinterpret_cast<Iface*>(shptr->GetIfacePtr());
}
}
#endif

View File

@ -0,0 +1,2030 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* Contributor(s): Borja "faluco" Ferav (many thanks for assitance!)
* David "BAILOPAN" Anderson
* ============================
*/
// recommended literature:
// http://www.cs.umbc.edu/~chang/cs313.s02/stack.shtml
// http://www.angelcode.com/dev/callconv/callconv.html
// http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-1.html
#include "sourcehook_impl.h"
#include "sourcehook_hookmangen.h"
#include "sourcehook_hookmangen_x86.h"
#include "sh_memory.h"
#include <stdarg.h> // we might need the address of vsnprintf
#include <stdio.h>
#if SH_COMP == SH_COMP_MSVC
# define GCC_ONLY(x)
# define MSVC_ONLY(x) x
#elif SH_COMP == SH_COMP_GCC
# define GCC_ONLY(x) x
# define MSVC_ONLY(x)
#endif
// :TODO: test BIG vtable indices
namespace SourceHook
{
namespace Impl
{
CPageAlloc GenBuffer::ms_Allocator(16);
template <class T>
jit_int32_t DownCastPtr(T ptr)
{
return reinterpret_cast<jit_int32_t>(ptr);
}
jit_uint32_t DownCastSize(size_t size)
{
return static_cast<jit_uint32_t>(size);
}
GenContext::GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr)
: m_GeneratedPubFunc(NULL), m_OrigProto(proto), m_Proto(proto), m_VtblOffs(vtbl_offs),
m_VtblIdx(vtbl_idx), m_SHPtr(pSHPtr), m_pHI(NULL), m_HookfuncVfnptr(NULL), m_RegCounter(0)
{
m_pHI = new void*;
m_HookfuncVfnptr = new void*;
m_BuiltPI = new ProtoInfo;
m_BuiltPI_Params = NULL;
m_BuiltPI_Params2 = NULL;
}
GenContext::~GenContext()
{
Clear();
delete m_pHI;
delete m_HookfuncVfnptr;
delete m_BuiltPI;
}
void GenContext::Clear()
{
m_HookFunc.clear();
m_PubFunc.clear();
if (m_BuiltPI_Params)
{
delete m_BuiltPI_Params;
m_BuiltPI_Params = NULL;
}
if (m_BuiltPI_Params2)
{
delete m_BuiltPI_Params2;
m_BuiltPI_Params2 = NULL;
}
}
void GenContext::BuildProtoInfo()
{
m_BuiltPI->convention = m_Proto.GetConvention();
m_BuiltPI->numOfParams = m_Proto.GetNumOfParams();
m_BuiltPI->retPassInfo.size = m_Proto.GetRet().size;
m_BuiltPI->retPassInfo.type = m_Proto.GetRet().type;
m_BuiltPI->retPassInfo.flags = m_Proto.GetRet().flags;
m_BuiltPI->retPassInfo2.pNormalCtor = m_Proto.GetRet().pNormalCtor;
m_BuiltPI->retPassInfo2.pCopyCtor = m_Proto.GetRet().pCopyCtor;
m_BuiltPI->retPassInfo2.pDtor = m_Proto.GetRet().pDtor;
m_BuiltPI->retPassInfo2.pAssignOperator = m_Proto.GetRet().pAssignOperator;
if (m_BuiltPI_Params)
delete m_BuiltPI_Params;
m_BuiltPI_Params = new PassInfo[m_BuiltPI->numOfParams + 1];
if (m_BuiltPI_Params2)
delete m_BuiltPI_Params2;
m_BuiltPI_Params2 = new PassInfo::V2Info[m_BuiltPI->numOfParams + 1];
m_BuiltPI_Params[0].size = 1; // Version 1
m_BuiltPI_Params[0].type = 0;
m_BuiltPI_Params[0].flags = 0;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
m_BuiltPI_Params[i+1].size = m_Proto.GetParam(i).size;
m_BuiltPI_Params[i+1].type = m_Proto.GetParam(i).type;
m_BuiltPI_Params[i+1].flags = m_Proto.GetParam(i).flags;
m_BuiltPI_Params2[i+1].pNormalCtor = m_Proto.GetParam(i).pNormalCtor;
m_BuiltPI_Params2[i+1].pCopyCtor = m_Proto.GetParam(i).pCopyCtor;
m_BuiltPI_Params2[i+1].pDtor = m_Proto.GetParam(i).pDtor;
m_BuiltPI_Params2[i+1].pAssignOperator = m_Proto.GetParam(i).pAssignOperator;
}
m_BuiltPI->paramsPassInfo = m_BuiltPI_Params;
m_BuiltPI->paramsPassInfo2 = m_BuiltPI_Params2;
}
jit_int32_t GenContext::GetRealSize(const IntPassInfo &info)
{
if (info.flags & (PassInfo::PassFlag_ByRef | PassFlag_ForcedByRef))
{
return SIZE_PTR;
}
return static_cast<jit_int32_t>(info.size);
}
jit_int32_t GenContext::AlignSize(jit_int32_t x, jit_int32_t boundary)
{
if (x % boundary != 0)
x = (x & ~(boundary-1)) + boundary;
return x;
}
// Computes size on the stack
jit_int32_t GenContext::GetParamStackSize(const IntPassInfo &info)
{
// Align up to 4 byte boundaries
return AlignSize(GetRealSize(info), 4);
}
jit_int8_t GenContext::NextRegEBX_ECX_EDX()
{
switch ((m_RegCounter++) % 3)
{
case 0:
return REG_EBX;
case 1:
return REG_ECX;
case 2:
default:
m_RegCounter = 0;
return REG_EDX;
}
}
void GenContext::BitwiseCopy_Setup()
{
//cld
//push edi
//push esi
IA32_Cld(&m_HookFunc);
IA32_Push_Reg(&m_HookFunc, REG_EDI);
IA32_Push_Reg(&m_HookFunc, REG_ESI);
}
void GenContext::BitwiseCopy_Do(size_t size)
{
jit_uint32_t dwords = DownCastSize(size) / 4;
jit_uint32_t bytes = DownCastSize(size) % 4;
//if dwords
// mov ecx, <dwords>
// rep movsd
//if bytes
// mov ecx, <bytes>
// rep movsb
//pop esi
//pop edi
if (dwords)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, dwords);
IA32_Rep(&m_HookFunc);
IA32_Movsd(&m_HookFunc);
}
if (bytes)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, bytes);
IA32_Rep(&m_HookFunc);
IA32_Movsb(&m_HookFunc);
}
IA32_Pop_Reg(&m_HookFunc, REG_ESI);
IA32_Pop_Reg(&m_HookFunc, REG_EDI);
}
jit_int32_t GenContext::AlignStackBeforeCall(int paramsize, int flags)
{
paramsize +=
GCC_ONLY( ((flags & AlignStack_GCC_ThisOnStack)!=0 ? SIZE_PTR : 0) + )
MSVC_ONLY( ((flags & AlignStack_MSVC_ThisOnStack)!=0 ? SIZE_PTR : 0) + )
((flags & AlignStack_MemRet)!=0 ? SIZE_PTR : 0);
// At the beginning of the hookfunc, the stack is aligned to a 16 bytes boundary.
// Then, m_BytesPushedAfterInitialAlignment were pushed (can also be 0).
// After this function is called, paramsize bytes will be pushed onto the stack
// After that, the alignment has to be a 16 bytes boundary again.
// How many bytes we would subtract if the alignment was alright now:
int subtractFromEsp = 16 - (paramsize % 16);
if (subtractFromEsp == 16)
subtractFromEsp = 0;
// But: there might be bytes pushed alreay!
subtractFromEsp -= m_BytesPushedAfterInitialAlignment;
// For example: paramsize was 0 and m_BytesPushedAfterInitialAlignment was 4.
// we then have to push another 12 bytes to reach 16 bytes alignment again.
if (subtractFromEsp < 0)
subtractFromEsp = 16 - ((-subtractFromEsp) % 16);
if (subtractFromEsp != 0)
IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, subtractFromEsp, MOD_REG);
return subtractFromEsp;
}
void GenContext::AlignStackAfterCall(jit_int32_t numofbytes)
{
if (numofbytes != 0)
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, numofbytes, MOD_REG);
}
void GenContext::CheckAlignmentBeforeCall()
{
#if 0
IA32_Test_Rm_Imm32(&m_HookFunc, REG_ESP, 15, MOD_REG);
IA32_Jump_Cond_Imm8(&m_HookFunc, CC_Z, 1);
IA32_Int3(&m_HookFunc);
#endif
}
short GenContext::GetParamsTotalStackSize()
{
short acc = 0;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
acc += GetParamStackSize(m_Proto.GetParam(i));
}
return acc;
}
short GenContext::GetForcedByRefParamOffset(int p)
{
short off = 0;
for (int i = 0; i < p; ++i)
{
if (m_Proto.GetParam(i).flags & PassFlag_ForcedByRef)
off += AlignSize(static_cast<jit_int32_t>(m_Proto.GetParam(i).size), 4);
}
return off;
}
short GenContext::GetForcedByRefParamsSize()
{
return GetForcedByRefParamOffset(m_Proto.GetNumOfParams());
}
jit_int32_t GenContext::PushRef(jit_int32_t param_offset, const IntPassInfo &pi)
{
// push [ebp+<offset>]
IA32_Push_Rm_DispAuto(&m_HookFunc, REG_EBP, param_offset);
return SIZE_PTR;
}
jit_int32_t GenContext::PushBasic(jit_int32_t param_offset, const IntPassInfo &pi)
{
int reg;
int reg2;
switch (pi.size)
{
default:
SH_ASSERT(0, ("Unsupported!"));
return 0;
case 1:
reg = NextRegEBX_ECX_EDX();
//movzx reg, BYTE PTR [ebp+<offset>]
//push reg
IA32_Movzx_Reg32_Rm8_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 2:
reg = NextRegEBX_ECX_EDX();
//movzx reg, WORD PTR [ebp+<offset>]
//push reg
m_HookFunc.write_ubyte(IA32_16BIT_PREFIX);
IA32_Movzx_Reg32_Rm16_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 4:
reg = NextRegEBX_ECX_EDX();
//mov reg, DWORD PTR [ebp+<offset>]
//push reg
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 8:
reg = NextRegEBX_ECX_EDX();
reg2 = NextRegEBX_ECX_EDX();
//mov reg, DWORD PTR [ebp+<offset>+4]
//mov reg2, DWORD PTR [ebp+<offset>]
//push reg
//push reg2
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset+4);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg2, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
IA32_Push_Reg(&m_HookFunc, reg2);
return 8;
}
}
jit_int32_t GenContext::PushFloat(jit_int32_t param_offset, const IntPassInfo &pi)
{
switch (pi.size)
{
default:
SH_ASSERT(0, ("Unsupported!"));
return 0;
case 4:
//fld DWORD PTR [ebp+<offset>]
//push reg
//fstp DWORD PTR [esp]
IA32_Fld_Mem32_DispAuto(&m_HookFunc, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, NextRegEBX_ECX_EDX());
IA32_Fstp_Mem32_ESP(&m_HookFunc);
return 4;
case 8:
//fld QWORD PTR [ebp+<offset>]
//sub esp, 8
//fstp QWORD PTR [esp]
IA32_Fld_Mem64_DispAuto(&m_HookFunc, REG_EBP, param_offset);
IA32_Sub_Rm_Imm8(&m_HookFunc, REG_ESP, 8, MOD_REG);
IA32_Fstp_Mem64_ESP(&m_HookFunc);
return 8;
}
}
jit_int32_t GenContext::PushObject(jit_int32_t param_offset, const IntPassInfo &pi, jit_int32_t place_fbrr)
{
if ((pi.flags & PassFlag_ForcedByRef) == 0)
{
// make room on the stack
// sub esp, <size>
IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, GetParamStackSize(pi), MOD_REG);
}
// if there is a copy constructor..
if (pi.pCopyCtor)
{
// :TODO: alignment here?
// can't use normal alignment methods
// because an unknown number of bytes has been pushed already (the other params)
// save eax
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// compute dest addr to ECX
// = forcedbyref ? ebp+place_fbrr : esp+12
if (pi.flags & PassFlag_ForcedByRef)
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, place_fbrr);
else
IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_ECX, REG_NOIDX, REG_ESP, NOSCALE, 4);
// compute src addr to EAX
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, param_offset);
// push params (gcc: also this)
IA32_Push_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
// call
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EDX, DownCastPtr(pi.pCopyCtor));
IA32_Call_Reg(&m_HookFunc, REG_EDX);
// gcc: clean up stack
GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, 2 * SIZE_PTR, MOD_REG));
// restore eax
IA32_Pop_Reg(&m_HookFunc, REG_EAX);
}
else
{
// bitwise copy
BitwiseCopy_Setup();
//if forcedbyref:
// lea edi, [ebp_place_fbrr]
//else
// lea edi, [esp+8] - bc_setup pushed two regs onto the stack!
//lea esi, [ebp+<offs>]
if (pi.flags & PassFlag_ForcedByRef)
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, place_fbrr);
else
IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, param_offset);
BitwiseCopy_Do(pi.size);
}
// forcedref: push reference to ebp+place_fbrr
if (pi.flags & PassFlag_ForcedByRef)
{
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, place_fbrr);
IA32_Push_Reg(&m_HookFunc, REG_ECX);
return SIZE_PTR;
}
return GetParamStackSize(pi);
}
void GenContext::DestroyParams(jit_int32_t fbrr_base)
{
for (int i = m_Proto.GetNumOfParams() - 1; i >= 0; --i)
{
const IntPassInfo &pi = m_Proto.GetParam(i);
if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) &&
(pi.flags & PassInfo::PassFlag_ByVal) && (pi.flags & PassFlag_ForcedByRef))
{
// Actually, this is only for GCC (see line above: ForcedByRef)
jit_int32_t tmpAlign = AlignStackBeforeCall(0, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, fbrr_base + GetForcedByRefParamOffset(i));
IA32_Push_Reg(&m_HookFunc, REG_ECX);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
IA32_Pop_Reg(&m_HookFunc, REG_ECX);
AlignStackAfterCall(tmpAlign);
}
}
}
// May not touch eax!
jit_int32_t GenContext::PushParams(jit_int32_t param_base_offset, jit_int32_t save_ret_to, int v_place_for_memret,
jit_int32_t v_place_fbrr_base)
{
jit_int32_t added_to_stack = 0;
jit_int32_t ret = 0;
// compute the offset _after_ the last parameter
jit_int32_t cur_offset = param_base_offset;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
cur_offset += GetParamStackSize(m_Proto.GetParam(i));
}
// push parameters in reverse order
for (int i = m_Proto.GetNumOfParams() - 1; i >= 0; --i)
{
const IntPassInfo &pi = m_Proto.GetParam(i);
cur_offset -= GetParamStackSize(pi);
if (pi.flags & PassInfo::PassFlag_ByVal)
{
switch (pi.type)
{
case PassInfo::PassType_Basic:
ret = PushBasic(cur_offset, pi);
break;
case PassInfo::PassType_Float:
ret = PushFloat(cur_offset, pi);
break;
case PassInfo::PassType_Object:
ret = PushObject(cur_offset, pi, v_place_fbrr_base + GetForcedByRefParamOffset(i));
break;
}
}
else if (pi.flags & PassInfo::PassFlag_ByRef)
{
ret = PushRef(cur_offset, pi);
}
else
{
SH_ASSERT(0, ("Unsupported!"));
}
added_to_stack += ret;
}
return added_to_stack;
}
// It is IMPORTANT that PushMemRetPtr doesn't touch ecx and eax
jit_int32_t GenContext::PushMemRetPtr(jit_int32_t save_ret_to, jit_int32_t v_place_for_memret)
{
// Memory return support
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
{
// push address where to save it!
int reg = REG_EDX;
IA32_Lea_DispRegImmAuto(&m_HookFunc, reg, REG_EBP,
MemRetWithTempObj() ? v_place_for_memret : save_ret_to);
IA32_Push_Reg(&m_HookFunc, reg);
return (SH_COMP==SH_COMP_MSVC) ? 4 : 0; // varargs funcs on msvc might need this.
// gcc doesn't: callee cleans the memret ptr, caller the other params :s
}
return 0;
}
void GenContext::SaveRetVal(int v_where, int v_place_for_memret)
{
size_t size = GetRealSize(m_Proto.GetRet());
if (size == 0)
{
// No return value -> nothing
return;
}
if (m_Proto.GetRet().flags & PassInfo::PassFlag_ByRef)
{
// mov [ebp + v_plugin_ret], eax
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
return;
}
// else: ByVal
// Memory return:
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
{
if (MemRetWithTempObj())
{
// *v_where = *v_place_for_memret
// if we have an assign operator, use that
if (m_Proto.GetRet().pAssignOperator)
{
// lea edx, [ebp + v_place_for_memret] <-- src addr
// lea ecx, [ebp + v_where] <-- dest addr
// push edx
// gcc: push ecx
// call it
// gcc: clean up
jit_int32_t tmpAlign = AlignStackBeforeCall(SIZE_PTR, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_place_for_memret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_where);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, 2 * SIZE_PTR, MOD_REG));
AlignStackAfterCall(tmpAlign);
}
else
{
// bitwise copy
BitwiseCopy_Setup();
//lea edi, [evp+v_where] <-- destination
//lea esi, [ebp+v_place_for_memret] <-- src
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_where);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_place_for_memret);
BitwiseCopy_Do(m_Proto.GetRet().size);
}
// Then: destruct *v_place_for_memret if required
if (m_Proto.GetRet().pDtor)
{
//lea ecx, [ebp+v_place_for_memret]
//gcc: push ecx
//call it
//gcc: clean up
jit_int32_t tmpAlign = AlignStackBeforeCall(0, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_place_for_memret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pDtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
AlignStackAfterCall(tmpAlign);
}
}
else
{
// Already copied to correct address -> we're done
return;
}
}
if (m_Proto.GetRet().type == PassInfo::PassType_Float)
{
if (size == 4)
IA32_Fstp_Mem32_DispAuto(&m_HookFunc, REG_EBP, v_where);
else if (size == 8)
IA32_Fstp_Mem64_DispAuto(&m_HookFunc, REG_EBP, v_where);
}
else if (m_Proto.GetRet().type == PassInfo::PassType_Basic)
{
if (size <= 4)
{
// size <= 4: return in EAX
// We align <4 sizes up to 4
// mov [ebp + v_plugin_ret], eax
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
}
else if (size <= 8)
{
// size <= 4: return in EAX:EDX
// We align 4<x<8 sizes up to 8
// mov [ebp + v_plugin_ret], eax
// mov [ebp + v_plugin_ret + 4], edx
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EDX, v_where + 4);
}
}
else if (m_Proto.GetRet().type == PassInfo::PassType_Object)
{
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetReg)
{
if (size <= 4)
{
// size <= 4: return in EAX
// We align <4 sizes up to 4
// mov [ebp + v_plugin_ret], eax
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
}
else if (size <= 8)
{
// size <= 4: return in EAX:EDX
// We align 4<x<8 sizes up to 8
// mov [ebp + v_plugin_ret], eax
// mov [ebp + v_plugin_ret + 4], edx
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EDX, v_where + 4);
}
else
{
SH_ASSERT(0, ("RetReg and size > 8 !"));
}
}
}
}
bool GenContext::MemRetWithTempObj()
{
// Memory return AND (has destructor OR has assign operator)
return ((m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
&& (m_Proto.GetRet().flags & (PassInfo::PassFlag_ODtor | PassInfo::PassFlag_AssignOp)));
}
void GenContext::ProcessPluginRetVal(int v_cur_res, int v_pContext, int v_plugin_ret)
{
// only for non-void functions!
if (m_Proto.GetRet().size == 0)
return;
// if (cur_res >= MRES_OVERRIDE)
// *reinterpret_cast<my_rettype*>(pContext->GetOverrideRetPtr()) = plugin_ret;
// eax = cur_res
// cmp eax,MRES_OVERRIDE
// jnge thelabel
// pContext->GetOverrideRetPtr() --> overrideretptr in eax
// *eax = plugin_ret
// thelabel:
//
jitoffs_t tmppos, counter;
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Cmp_Rm_Imm32(&m_HookFunc, MOD_REG, REG_EAX, MRES_OVERRIDE);
tmppos = IA32_Jump_Cond_Imm8(&m_HookFunc, CC_NGE, 0);
m_HookFunc.start_count(counter);
// eax = pContext->GetOverrideRetPtr() no alignment needs
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax + 4]
// call eax
// gcc: clean up
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
// vtbloffs=0, vtblidx=1
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EAX, 4);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
// *eax = plugin_ret
if (m_Proto.GetRet().flags & PassInfo::PassFlag_ByRef)
{
// mov ecx, [ebp+v_plugin_ret]
// mov [eax], ecx
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_plugin_ret);
IA32_Mov_Rm_Reg(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
}
else
{
if (m_Proto.GetRet().pAssignOperator)
{
// lea edx, [ebp + v_plugin_ret]
// push edx <-- src addr
// msvc: ecx = eax <-- dest addr
// gcc: push eax <-- dest addr
// call it
// gcc: clean up
jit_int32_t tmpAlign = AlignStackBeforeCall(SIZE_PTR, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_plugin_ret);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
#if SH_COMP == SH_COMP_MSVC
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ECX, REG_EAX, MOD_REG);
#elif SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_EAX);
#endif
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, 2 * SIZE_PTR, MOD_REG));
AlignStackAfterCall(tmpAlign);
}
else
{
// bitwise copy
BitwiseCopy_Setup();
//mov edi, eax <-- destination
//lea esi, [ebp+v_plugin_ret] <-- src
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDI, REG_EAX, MOD_REG);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_plugin_ret);
BitwiseCopy_Do(m_Proto.GetRet().size);
}
}
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
}
void GenContext::PrepareReturn(int v_status, int v_pContext, int v_retptr)
{
// only for non-void functions!
if (m_Proto.GetRet().size == 0)
return;
// retptr = status >= MRES_OVERRIDE ? pContext->GetOverrideRetPtr() : pContext->GetOrigRetPtr()
// OverrideRetPtr: vtblidx = 1
// OrigRetPtr: vtbldix = 2
// vtblidx = (status >= MRES_OVERRIDE) ? 1 : 2
//
// eax = pContext->GetOverrideRetPtr()
// ECX = pContext
// gcc: push ecx
// eax = (status < MRES_OVERRIDE) ? 1 : 0
// xor eax, eax
// cmp [ebp + v_status], MRES_OVERRIDE
// setl al <-- setcc optimization for ternary operators,
// lea eax, [4*eax + 0x4]
// edx = [ecx]
// add edx, eax
// mov edx, [edx]
// call edx
// gcc: clean up
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Xor_Reg_Rm(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
IA32_Cmp_Rm_Disp8_Imm8(&m_HookFunc, REG_EBP, v_status, MRES_OVERRIDE);
IA32_SetCC_Rm8(&m_HookFunc, REG_EAX, CC_L);
IA32_Lea_Reg_RegMultImm32(&m_HookFunc, REG_EAX, REG_EAX, SCALE4, 4);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
IA32_Add_Reg_Rm(&m_HookFunc, REG_EDX, REG_EAX, MOD_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDX, REG_EDX, MOD_MEM_REG);
IA32_Call_Reg(&m_HookFunc, REG_EDX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_retptr);
}
void GenContext::DoReturn(int v_retptr, int v_memret_outaddr)
{
size_t size = m_Proto.GetRet().size;
if (!size)
return;
// Get real ret pointer into ecx
// mov ecx, [ebp + v_ret_ptr]
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_retptr);
if (m_Proto.GetRet().flags & PassInfo::PassFlag_ByRef)
{
// mov eax, [ecx]
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
return;
}
// else: byval
if (m_Proto.GetRet().type == PassInfo::PassType_Float)
{
if (size == 4)
IA32_Fld_Mem32(&m_HookFunc, REG_ECX);
else if (size == 8)
IA32_Fld_Mem64(&m_HookFunc, REG_ECX);
}
else if (m_Proto.GetRet().type == PassInfo::PassType_Basic ||
((m_Proto.GetRet().type == PassInfo::PassType_Object) && (m_Proto.GetRet().flags & PassInfo::PassFlag_RetReg)) )
{
if (size <= 4)
{
// size <= 4: return in EAX
// We align <4 sizes up to 4
// mov eax, [ecx]
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
}
else if (size <= 8)
{
// size <= 4: return in EAX:EDX
// We align 4<x<8 sizes up to 8
// mov eax, [ecx]
// mov edx, [ecx+4]
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_ECX, 4);
}
else
{
// size >8: return in memory
// handled later
}
}
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
{
// *memret_outaddr = plugin_ret
if (m_Proto.GetRet().pCopyCtor)
{
// mov edx, ecx <-- src ( we set ecx to [ebp+v_retptr] before )
// push edx <-- src addr
// msvc: ecx = [ebp + v_memret_outaddr] <-- dest addr
// gcc: push [ebp + v_memret_outaddr] <-- dest addr
// call it
// gcc: clean up
jit_int32_t tmpAlign = AlignStackBeforeCall(SIZE_PTR, AlignStack_GCC_ThisOnStack);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDX, REG_ECX, MOD_REG);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
#if SH_COMP == SH_COMP_MSVC
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_memret_outaddr);
#elif SH_COMP == SH_COMP_GCC
IA32_Push_Rm_DispAuto(&m_HookFunc, REG_EBP, v_memret_outaddr);
#endif
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pCopyCtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, 2 * SIZE_PTR, MOD_REG));
AlignStackAfterCall(tmpAlign);
}
else
{
// bitwise copy
BitwiseCopy_Setup();
//mov edi, [ebp+v_memret_outaddr] <-- destination
//mov esi, ecx <-- src ( we set ecx to [ebp+v_retptr] before )
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EDI, REG_EBP, v_memret_outaddr);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ESI, REG_ECX, MOD_REG);
BitwiseCopy_Do(m_Proto.GetRet().size);
}
// In both cases: return the pointer in EAX
// mov eax, [ebp + v_memret_outaddr]
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_memret_outaddr);
}
}
void GenContext::GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter,
int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base, jit_int32_t v_va_buf)
{
jitoffs_t counter, tmppos;
jitoffs_t counter2, tmppos2;
jitoffs_t loop_begin_counter;
// prev_res = MRES_IGNORED
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_prev_res);
m_HookFunc.start_count(loop_begin_counter);
// eax = pContext->GetNext()
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax]
// call eax
// gcc: clean up
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
// vtbloffs=0, vtblidx=0
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_EAX, MOD_MEM_REG);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
// quit on zero
// test eax, eax
// jz exit
IA32_Test_Rm_Reg(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_Z, 0);
m_HookFunc.start_count(counter);
// prev_res = MRES_IGNORED
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_cur_res);
// iter->call()
// push params
// ecx = eax
// gcc: push ecx
// eax = [ecx]
// eax = [eax+2*SIZE_PTR]
// call eax
// gcc: clean up
jit_int32_t caller_clean_bytes = 0; // gcc always, msvc never (hooks never have varargs!)
jit_int32_t alignBytes = AlignStackBeforeCall(
GetParamsTotalStackSize() + ((m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)!=0 ? SIZE_PTR : 0),
AlignStack_GCC_ThisOnStack | ((m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem) == 0 ? 0 : AlignStack_MemRet)
);
// vafmt: push va_buf
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)
{
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_va_buf);
IA32_Push_Reg(&m_HookFunc, REG_ECX);
caller_clean_bytes += SIZE_PTR;
}
caller_clean_bytes += PushParams(base_param_offset, v_plugin_ret, v_place_for_memret, v_place_fbrr_base);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ECX, REG_EAX, MOD_REG);
if (SH_COMP == SH_COMP_GCC)
IA32_Push_Reg(&m_HookFunc, REG_ECX);
caller_clean_bytes += PushMemRetPtr(v_plugin_ret, v_place_for_memret);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EAX, 2*SIZE_PTR);
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
AlignStackAfterCall(alignBytes);
// cleanup (gcc only)
// params + thisptr
if (SH_COMP == SH_COMP_GCC)
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, caller_clean_bytes + SIZE_PTR, MOD_REG);
DestroyParams(v_place_fbrr_base);
SaveRetVal(v_plugin_ret, v_place_for_memret);
// process meta return:
// prev_res = cur_res
// if (cur_res > status) status = cur_res;
//
// eax = cur_res
// edx = status
// prev_res = eax
// cmp eax,edx
// jng thelabel
// status = eax
// thelabel:
//
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EDX, REG_EBP, v_status);
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_prev_res);
IA32_Cmp_Reg_Rm(&m_HookFunc, REG_EAX, REG_EDX, MOD_REG);
tmppos2 = IA32_Jump_Cond_Imm8(&m_HookFunc, CC_NG, 0);
m_HookFunc.start_count(counter2);
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_status);
m_HookFunc.end_count(counter2);
m_HookFunc.rewrite(tmppos2, static_cast<jit_uint8_t>(counter2));
// process retval for non-void functions
ProcessPluginRetVal(v_cur_res, v_pContext, v_plugin_ret);
// jump back to loop begin
tmppos2 = IA32_Jump_Imm32(&m_HookFunc, 0);
m_HookFunc.end_count(loop_begin_counter);
m_HookFunc.rewrite(tmppos2, static_cast<jit_int32_t>(-loop_begin_counter));
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_int32_t>(counter));
}
void GenContext::GenerateCallOrig(int v_status, int v_pContext, int param_base_offs, int v_this,
int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base, jit_int32_t v_va_buf)
{
jitoffs_t counter, tmppos;
jitoffs_t counter2, tmppos2;
jitoffs_t counter3, tmppos3;
// if (status != MRES_SUPERCEDE && pConteext->ShouldCallOrig())
// *v_orig_ret = orig_call()
// else
// *v_orig_ret = *v_override_ret
// mov eax, status
// cmp eax, MRES_SUPERCEDE
// je dont_call
// call pContext->ShouldCallOrig()
// test al, al !! important: al, not eax! bool is only stored in the LSbyte
// jz dont_call
//
// orig_call()
// SaveRet(v_orig_ret)
// jmp skip_dont_call:
//
// dont_call:
// *v_orig_ret = *v_override_ret
// skip_dont_call:
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_status);
IA32_Cmp_Rm_Imm32(&m_HookFunc, MOD_REG, REG_EAX, MRES_SUPERCEDE);
tmppos = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_E, 0);
m_HookFunc.start_count(counter);
// eax = pContext->ShouldCallOrig()
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax + 3*SIZE_PTR]
// call eax
// gcc: clean up
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
// vtbloffs=0, vtblidx=3
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_Disp8(&m_HookFunc, REG_EAX, REG_EAX, 3*SIZE_PTR);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
IA32_Test_Rm_Reg8(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos2 = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_Z, 0);
m_HookFunc.start_count(counter2);
jit_int32_t caller_clean_bytes = 0; // gcc always, msvc when cdecl-like (varargs)
jit_int32_t alignBytes = AlignStackBeforeCall(
GetParamsTotalStackSize() + ((m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)!=0 ? 2*SIZE_PTR : 0),
AlignStack_GCC_ThisOnStack |
((m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem) == 0 ? 0 : AlignStack_MemRet) |
((m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs) == 0 ? 0 : AlignStack_MSVC_ThisOnStack)
);
// vafmt: push va_buf, then "%s"
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)
{
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_va_buf);
IA32_Push_Reg(&m_HookFunc, REG_ECX);
IA32_Push_Imm32(&m_HookFunc, DownCastPtr("%s"));
caller_clean_bytes += 2*SIZE_PTR;
}
// push params
caller_clean_bytes += PushParams(param_base_offs, v_orig_ret, v_place_for_memret, v_place_fbrr_base);
// thisptr
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_this);
if (SH_COMP == SH_COMP_GCC)
{
// on gcc/mingw, this is the first parameter
IA32_Push_Reg(&m_HookFunc, REG_ECX);
// on msvc without varargs, simply leave it in ecx
// actually, if we're returning in memory, this pointer is the second param
// and the memret pointer is the real first parameter
caller_clean_bytes += PushMemRetPtr(v_orig_ret, v_place_for_memret);
}
else
{
// On msvc, if we're returning in memory, the memret pointer is the first parameter
caller_clean_bytes += PushMemRetPtr(v_orig_ret, v_place_for_memret);
// actually, with varargs, the this pointer is the first param and the memret ptr
// is the second one
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs)
{
IA32_Push_Reg(&m_HookFunc, REG_ECX);
}
}
// call
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_vfnptr_origentry);
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
AlignStackAfterCall(alignBytes);
// cleanup
if (SH_COMP == SH_COMP_GCC || (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs))
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, caller_clean_bytes + SIZE_PTR, MOD_REG);
DestroyParams(v_place_fbrr_base);
// save retval
SaveRetVal(v_orig_ret, v_place_for_memret);
// Skip don't call variant
tmppos3 = IA32_Jump_Imm32(&m_HookFunc, 0);
m_HookFunc.start_count(counter3);
// don't call:
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_uint32_t>(counter));
m_HookFunc.end_count(counter2);
m_HookFunc.rewrite(tmppos2, static_cast<jit_uint32_t>(counter2));
// *v_orig_ret = *v_override_ret
if (m_Proto.GetRet().flags & PassInfo::PassFlag_ByRef)
{
// mov ecx, [ebp + v_override_ret]
// mov [ebp + v_orig_ret], ecx
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret);
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_ECX, v_orig_ret);
}
else
{
if (m_Proto.GetRet().pAssignOperator)
{
// lea edx, [ebp + v_override_ret] <-- src addr
// lea ecx, [ebp + v_orig_ret] <-- dest addr
// push edx <-- src addr
// gcc: push ecx
// call it
// gcc: clean up
jit_int32_t tmpAlign = AlignStackBeforeCall(SIZE_PTR, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_override_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, 2*SIZE_PTR, MOD_REG));
AlignStackAfterCall(tmpAlign);
}
else
{
// bitwise copy
BitwiseCopy_Setup();
//lea edi, [ebp+v_orig_ret] <-- destination
//lea esi, [ebp+v_override_ret] <-- src
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_orig_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_override_ret);
BitwiseCopy_Do(m_Proto.GetRet().size);
}
}
// skip don't call label target:
m_HookFunc.end_count(counter3);
m_HookFunc.rewrite(tmppos3, static_cast<jit_uint32_t>(counter3));
}
// Sets *v_pContext to return value
void GenContext::CallSetupHookLoop(int v_orig_ret, int v_override_ret,
int v_cur_res, int v_prev_res, int v_status, int v_vfnptr_origentry,
int v_this, int v_pContext)
{
// call shptr->SetupHookLoop(ms_HI, ourvfnptr, reinterpret_cast<void*>(this),
// &vfnptr_origentry, &status, &prev_res, &cur_res, &orig_ret, &override_ret);
// The last two params are null for void funcs.
if (m_Proto.GetRet().size == 0)
{
// void
IA32_Push_Imm8(&m_HookFunc, 0); // orig_ret
IA32_Push_Imm8(&m_HookFunc, 0); // override_ret
}
else
{
// orig_ret and override_ret
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, v_override_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_orig_ret);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
}
// cur_res and prev_res
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EDX, REG_EBP, v_prev_res);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
// status and vfnptr_origentry
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EAX, REG_EBP, v_status);
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EDX, REG_EBP, v_vfnptr_origentry);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
// this
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_this);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// our vfn ptr
// *(this + vtbloffs) + SIZE_PTR*vtblidx
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_this); // get this into ecx (gcc!)
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_ECX, m_VtblOffs);
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_EAX, m_VtblIdx * SIZE_PTR, MOD_REG);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// *m_pHI
IA32_Mov_Rm_Imm32(&m_HookFunc, REG_EDX, DownCastPtr(m_pHI), MOD_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_EDX, MOD_MEM_REG);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// set up thisptr
#if SH_COMP == SH_COMP_GCC
// on gcc/mingw, this is the first parameter
GCC_ONLY(IA32_Push_Imm32(&m_HookFunc, DownCastPtr(m_SHPtr)));
#elif SH_COMP == SH_COMP_MSVC
// on msvc, it's ecx
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, DownCastPtr(m_SHPtr));
#endif
// call the function. vtbloffs = 0, vtblidx = 19
// get vtptr into edx -- we know shptr on jit time -> dereference it here!
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX,
(*reinterpret_cast<jit_uint32_t**>(m_SHPtr))[19]);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
// 9 params + hidden thisptr param
GCC_ONLY(IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 10*SIZE_PTR, MOD_REG));
// store return value
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_pContext);
}
void GenContext::CallEndContext(int v_pContext)
{
// call endcontext:
// shptr->EndContext(pContex)
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_pContext);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// thisptr
#if SH_COMP == SH_COMP_GCC
// on gcc/mingw, this is the first parameter
IA32_Push_Imm32(&m_HookFunc, DownCastPtr(m_SHPtr));
#elif SH_COMP == SH_COMP_MSVC
// on msvc, it's ecx
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, DownCastPtr(m_SHPtr));
#endif
// get vtptr into edx -- we know shptr on jit time -> dereference it here!
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX,
(*reinterpret_cast<jit_uint32_t**>(m_SHPtr))[20]);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
// 1 param + hidden thisptr param
GCC_ONLY(IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 2*SIZE_PTR, MOD_REG));
}
void GenContext::ResetFrame(jit_int32_t startOffset)
{
m_HookFunc_FrameOffset = startOffset;
m_HookFunc_FrameVarsSize = 0;
}
jit_int32_t GenContext::AddVarToFrame(jit_int32_t size)
{
m_HookFunc_FrameOffset -= size;
m_HookFunc_FrameVarsSize += size;
return m_HookFunc_FrameOffset;
}
jit_int32_t GenContext::ComputeVarsSize()
{
return m_HookFunc_FrameVarsSize;
}
void * GenContext::GenerateHookFunc()
{
// prologue
IA32_Push_Reg(&m_HookFunc, REG_EBP);
IA32_Push_Reg(&m_HookFunc, REG_EBX);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EBP, REG_ESP, MOD_REG);
jit_int32_t v_this = 0;
jit_int32_t param_base_offs = 0;
if (SH_COMP == SH_COMP_GCC || (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs))
{
// gcc or msvc with varargs:
v_this = 12; // first param
param_base_offs = 16;
ResetFrame(0);
}
else
{
// on msvc without varargs, save thisptr
v_this = -4;
param_base_offs = 12;
IA32_Push_Reg(&m_HookFunc, REG_ECX);
ResetFrame(-4); // start placing local vars on offset -4
// because there already is the thisptr variable
}
// ********************** stack frame **********************
// MSVC without varargs
// second param (gcc: first real param) ebp + 16
// first param (gcc: thisptr) ebp + 12
// ret address: ebp + 8
// caller's ebp ebp + 4
// saved ebx ebp
// MSVC ONLY: current this ebp - 4
// void *vfnptr_origentry ebp - 4 -4
// META_RES status = MRES_IGNORED ebp - 8 -4
// META_RES prev_res ebp - 12 -4
// META_RES cur_res ebp - 16 -4
// IMyDelegate *iter ebp - 20 -4
// IHookContext *pContext ebp - 24 -4
// == 3 ptrs + 3 enums = 24 bytes
//
// non-void: add:
// my_rettype *ret_ptr ebp - 28 -4
// my_rettype orig_ret ebp - 28 - sizeof(my_rettype) -4
// my_rettype override_ret ebp - 28 - sizeof(my_rettype)*2 -4
// my_rettype plugin_ret ebp - 28 - sizeof(my_rettype)*3 -4
// == + 3 * sizeof(my_rettype) bytes
// if required:
// my_rettype place_for_memret ebp - 28 - sizeof(my_rettype)*4 -4
// gcc only: if required:
// place forced byref params ebp - 28 - sizeof(my_rettype)*{4 or 5}
//
// varargs:
// va_list argptr
// char va_buf[something];
const jit_int8_t v_vfnptr_origentry = AddVarToFrame(SIZE_PTR);
const jit_int8_t v_status = AddVarToFrame(sizeof(META_RES));
const jit_int8_t v_prev_res = AddVarToFrame(sizeof(META_RES));
const jit_int8_t v_cur_res = AddVarToFrame(sizeof(META_RES));
const jit_int8_t v_iter = AddVarToFrame(SIZE_PTR);
const jit_int8_t v_pContext = AddVarToFrame(SIZE_PTR);
// Memory return: first param is the address
jit_int32_t v_memret_addr = 0;
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
{
if (SH_COMP == SH_COMP_GCC)
{
// gcc: now: first param = mem ret addr
// second param = this pointer
// third param = actual first param
v_memret_addr = 12;
v_this += 4;
param_base_offs += SIZE_PTR;
}
else // MSVC
{
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs)
{
// varargs -> cdecl
// msvc: now:
// first param = this pointer
// second param = mem ret addr
// third param = actual first param
// params_base_offs is already updated to point to after the this pointer
v_memret_addr = param_base_offs;
param_base_offs += SIZE_PTR;
}
else
{
v_memret_addr = param_base_offs;
param_base_offs += SIZE_PTR;
}
}
}
jit_int32_t v_ret_ptr = 0;
jit_int32_t v_orig_ret = 0;
jit_int32_t v_override_ret = 0;
jit_int32_t v_plugin_ret = 0;
if (m_Proto.GetRet().size != 0)
{
v_ret_ptr = AddVarToFrame(SIZE_PTR);
v_orig_ret = AddVarToFrame(GetParamStackSize(m_Proto.GetRet()));
v_override_ret = AddVarToFrame(GetParamStackSize(m_Proto.GetRet()));
v_plugin_ret = AddVarToFrame(GetParamStackSize(m_Proto.GetRet()));
}
jit_int32_t v_place_for_memret = 0;
if (MemRetWithTempObj())
{
v_place_for_memret = AddVarToFrame(GetParamStackSize(m_Proto.GetRet()));
}
jit_int32_t v_place_fbrr_base = 0;
if (SH_COMP == SH_COMP_GCC && GetForcedByRefParamsSize())
{
v_place_fbrr_base = AddVarToFrame(GetForcedByRefParamsSize());
}
// Only exists for varargs functions
jit_int32_t v_va_argptr = 0;
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs)
{
v_va_argptr = AddVarToFrame(SIZE_PTR);
}
jit_int32_t v_va_buf = 0;
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)
{
v_va_buf = AddVarToFrame(SourceHook::STRBUF_LEN);
}
IA32_Sub_Rm_Imm32(&m_HookFunc, REG_ESP, ComputeVarsSize(), MOD_REG);
// Initial stack alignment
IA32_And_Rm_Imm32(&m_HookFunc, REG_ESP, MOD_REG, -16);
m_BytesPushedAfterInitialAlignment = 0;
// init status localvar
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_status);
// VarArgs: init argptr & format
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs)
{
// argptr = first vararg param
// lea eax, [ebp + param_base_offs + paramssize]
// mov argptr, eax
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, param_base_offs + GetParamsTotalStackSize() + SIZE_PTR); // +SIZE_PTR: last const char * is not in protoinfo
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_va_argptr);
}
if (m_Proto.GetConvention() & ProtoInfo::CallConv_HasVafmt)
{
// vsnprintf
jit_int32_t tmpAlign = AlignStackBeforeCall(SIZE_PTR*3 + sizeof(size_t), 0);
// push valist, fmt param, maxsize, buffer
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Rm_DispAuto(&m_HookFunc, REG_EBP, param_base_offs + GetParamsTotalStackSize()); // last given param (+4-4, see above)
IA32_Push_Imm32(&m_HookFunc, SourceHook::STRBUF_LEN - 1);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_va_buf);
IA32_Push_Reg(&m_HookFunc, REG_ECX);
// call
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(&vsnprintf));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// Clean up (cdecl)
IA32_Add_Rm_Imm32(&m_HookFunc, REG_ESP, 0x10, MOD_REG);
AlignStackAfterCall(tmpAlign);
// Set trailing zero
IA32_Xor_Reg_Rm(&m_HookFunc, REG_EDX, REG_EDX, MOD_REG);
IA32_Mov_Rm8_Reg8_DispAuto(&m_HookFunc, REG_EBP, REG_EDX, v_va_buf + SourceHook::STRBUF_LEN - 1);
}
// Call constructors for ret vars if required
if((m_Proto.GetRet().flags & PassInfo::PassFlag_ByVal) &&
m_Proto.GetRet().pNormalCtor)
{
jit_int32_t tmpAlign = AlignStackBeforeCall(0, AlignStack_GCC_ThisOnStack);
// orig_reg
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
// override_reg
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
// plugin_ret
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_plugin_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
AlignStackAfterCall(tmpAlign);
// _don't_ call a constructor for v_place_for_memret !
}
// ********************** SetupHookLoop **********************
CallSetupHookLoop(v_orig_ret, v_override_ret, v_cur_res, v_prev_res, v_status, v_vfnptr_origentry,
v_this, v_pContext);
// ********************** call pre hooks **********************
GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs,
v_plugin_ret, v_place_for_memret, v_place_fbrr_base, v_va_buf);
// ********************** call orig func **********************
GenerateCallOrig(v_status, v_pContext, param_base_offs, v_this, v_vfnptr_origentry, v_orig_ret,
v_override_ret, v_place_for_memret, v_place_fbrr_base, v_va_buf);
// ********************** call post hooks **********************
GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs,
v_plugin_ret, v_place_for_memret, v_place_fbrr_base, v_va_buf);
// ********************** end context and return **********************
PrepareReturn(v_status, v_pContext, v_ret_ptr);
CallEndContext(v_pContext);
// Call destructors of byval object params which have a destructor
jit_int32_t tmpAlign = AlignStackBeforeCall(0, AlignStack_GCC_ThisOnStack);
jit_int32_t cur_param_pos = param_base_offs;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
const IntPassInfo &pi = m_Proto.GetParam(i);
// GCC: NOT of forced byref params. the caller destructs those.
if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) &&
(pi.flags & PassInfo::PassFlag_ByVal) && !(pi.flags & PassFlag_ForcedByRef))
{
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, cur_param_pos);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor));
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
}
cur_param_pos += GetParamStackSize(pi);
}
AlignStackAfterCall(tmpAlign);
DoReturn(v_ret_ptr, v_memret_addr);
// Call destructors of orig_ret/ ...
if((m_Proto.GetRet().flags & PassInfo::PassFlag_ByVal) &&
m_Proto.GetRet().pDtor)
{
// Preserve return value in EAX(:EDX)
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
m_BytesPushedAfterInitialAlignment += 8;
jit_int32_t tmpAlign = AlignStackBeforeCall(0, AlignStack_GCC_ThisOnStack);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_plugin_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pDtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pDtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX));
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pDtor));
CheckAlignmentBeforeCall();
IA32_Call_Reg(&m_HookFunc, REG_EAX);
GCC_ONLY(IA32_Pop_Reg(&m_HookFunc, REG_ECX));
AlignStackAfterCall(tmpAlign);
IA32_Pop_Reg(&m_HookFunc, REG_EDX);
IA32_Pop_Reg(&m_HookFunc, REG_EAX);
m_BytesPushedAfterInitialAlignment -= 8;
}
// epilogue
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ESP, REG_EBP, MOD_REG);
IA32_Pop_Reg(&m_HookFunc, REG_EBX);
IA32_Pop_Reg(&m_HookFunc, REG_EBP);
if (SH_COMP == SH_COMP_MSVC && !(m_Proto.GetConvention() & ProtoInfo::CallConv_HasVarArgs))
{
// msvc without varargs:
// callee cleans the stack
short cleansize = GetParamsTotalStackSize();
// Memory return: address is first param
if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem)
cleansize += SIZE_PTR;
IA32_Return_Popstack(&m_HookFunc, cleansize);
}
else
{
// gcc or msvc with varargs: caller cleans the stack
// exception: gcc removes the memret addr on memret:
if (SH_COMP == SH_COMP_GCC && (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem))
IA32_Return_Popstack(&m_HookFunc, SIZE_PTR);
else
IA32_Return(&m_HookFunc);
}
// Store pointer for later use
// m_HookfuncVfnPtr is a pointer to a void* because SH expects a pointer
// into the hookman's vtable
*m_HookfuncVfnptr = reinterpret_cast<void*>(m_HookFunc.GetData());
m_HookFunc.SetRE();
return m_HookFunc.GetData();
}
// Pre-condition: GenerateHookFunc() has been called!
void * GenContext::GeneratePubFunc()
{
jitoffs_t counter, tmppos;
// The pubfunc is a static cdecl function.
// C Code:
// int HookManPubFunc(
// bool store, ebp + 8
// IHookManagerInfo *hi ebp + 12
// )
// {
// if (store)
// *m_pHI = hi;
// if (hi)
// hi->SetInfo(HOOKMAN_VERSION, m_VtblOffs, m_VtblIdx, m_Proto.GetProto(), m_HookfuncVfnptr)
// }
// prologue
IA32_Push_Reg(&m_PubFunc, REG_EBP);
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EBP, REG_ESP, MOD_REG);
// save store in eax, hi in ecx
IA32_Movzx_Reg32_Rm8_Disp8(&m_PubFunc, REG_EAX, REG_EBP, 8);
IA32_Mov_Reg_Rm_DispAuto(&m_PubFunc, REG_ECX, REG_EBP, 12);
// Check for store == 0
IA32_Test_Rm_Reg8(&m_PubFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm8(&m_PubFunc, CC_Z, 0);
m_PubFunc.start_count(counter);
// nonzero -> store hi
IA32_Mov_Rm_Imm32(&m_PubFunc, REG_EDX, DownCastPtr(m_pHI), MOD_REG);
IA32_Mov_Rm_Reg(&m_PubFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
// zero
m_PubFunc.end_count(counter);
m_PubFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
// check for hi == 0
IA32_Test_Rm_Reg(&m_PubFunc, REG_ECX, REG_ECX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm8(&m_PubFunc, CC_Z, 0);
m_PubFunc.start_count(counter);
// nonzero -> call vfunc
// push params in reverse order
IA32_Push_Imm32(&m_PubFunc, DownCastPtr(m_HookfuncVfnptr));
IA32_Push_Imm32(&m_PubFunc, DownCastPtr(m_BuiltPI));
IA32_Push_Imm32(&m_PubFunc, m_VtblIdx);
IA32_Push_Imm32(&m_PubFunc, m_VtblOffs);
IA32_Push_Imm32(&m_PubFunc, SH_HOOKMAN_VERSION);
// hi == this is in ecx
// on gcc/mingw, ecx is the first parameter
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_PubFunc, REG_ECX);
#endif
// call the function. vtbloffs = 0, vtblidx = 0
// get vtptr into edx
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
// get funcptr into eax
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EAX, REG_EDX, MOD_MEM_REG);
IA32_Call_Reg(&m_PubFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
#if SH_COMP == SH_COMP_GCC
// 5 params + hidden thisptr param
IA32_Add_Rm_Imm8(&m_PubFunc, REG_ESP, 6*SIZE_MWORD, MOD_REG);
#endif
// zero
m_PubFunc.end_count(counter);
m_PubFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
// return value
IA32_Xor_Reg_Rm(&m_PubFunc, REG_EAX, REG_EAX, MOD_REG);
// epilogue
IA32_Mov_Reg_Rm(&m_PubFunc, REG_ESP, REG_EBP, MOD_REG);
IA32_Pop_Reg(&m_PubFunc, REG_EBP);
IA32_Return(&m_PubFunc);
m_PubFunc.SetRE();
return m_PubFunc;
}
bool GenContext::PassInfoSupported(const IntPassInfo &pi, bool is_ret)
{
// :TODO: Error returns
if (pi.type != PassInfo::PassType_Basic &&
pi.type != PassInfo::PassType_Float &&
pi.type != PassInfo::PassType_Object)
{
return false;
}
if (pi.type == PassInfo::PassType_Object &&
(pi.flags & PassInfo::PassFlag_ByVal))
{
if ((pi.flags & PassInfo::PassFlag_CCtor) && !pi.pCopyCtor)
{
return false;
}
if ((pi.flags & PassInfo::PassFlag_ODtor) && !pi.pDtor)
{
return false;
}
if ((pi.flags & PassInfo::PassFlag_AssignOp) && !pi.pAssignOperator)
{
return false;
}
if ((pi.flags & PassInfo::PassFlag_OCtor) && !pi.pNormalCtor)
{
return false;
}
}
if ((pi.flags & (PassInfo::PassFlag_ByVal | PassInfo::PassFlag_ByRef)) == 0)
{
return false; // Neither byval nor byref!
}
return true;
}
void GenContext::AutoDetectRetType()
{
IntPassInfo &pi = m_Proto.GetRet();
// Only relevant for byval types
if (pi.flags & PassInfo::PassFlag_ByVal)
{
// Basic + float:
if (pi.type == PassInfo::PassType_Basic ||
pi.type == PassInfo::PassType_Float)
{
// <= 8 bytes:
// _always_ in registers, no matter what the user says
if (pi.size <= 8)
{
pi.flags &= ~PassInfo::PassFlag_RetMem;
pi.flags |= PassInfo::PassFlag_RetReg;
}
else
{
// Does this even exist? No idea, if it does: in memory!
pi.flags &= ~PassInfo::PassFlag_RetReg;
pi.flags |= PassInfo::PassFlag_RetMem;
}
}
// Object:
else if (pi.type == PassInfo::PassType_Object)
{
// If the user says nothing, auto-detect
if ((pi.flags & (PassInfo::PassFlag_RetMem | PassInfo::PassFlag_RetReg)) == 0)
{
#if SH_COMP == SH_COMP_MSVC
// MSVC seems to return _all_ structs, classes, unions in memory
pi.flags |= PassInfo::PassFlag_RetMem;
#elif SH_COMP == SH_COMP_GCC
// Same goes for GCC :)
pi.flags |= PassInfo::PassFlag_RetMem;
#endif
}
}
}
else
{
// byref: make sure that the flag is _not_ set
pi.flags &= ~PassInfo::PassFlag_RetMem;
pi.flags |= PassInfo::PassFlag_RetReg;
}
}
void GenContext::AutoDetectParamFlags()
{
#if SH_COMP == SH_COMP_GCC
// On GCC, all objects are passed by reference if they have a destructor
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
IntPassInfo &pi = m_Proto.GetParam(i);
if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ByVal) &&
(pi.flags & PassInfo::PassFlag_ODtor))
{
pi.flags |= PassFlag_ForcedByRef;
}
}
#endif
}
HookManagerPubFunc GenContext::Generate()
{
Clear();
// Check conditions:
// -1) good proto version
// 0) we don't support unknown passtypes, convention, ...
// 1) we don't support functions which return objects by value or take parameters by value
// that have a constructor, a destructor or an overloaded assignment op
// (we wouldn't know how to call it!)
if (m_Proto.GetVersion() < 1)
{
return NULL;
}
AutoDetectRetType();
AutoDetectParamFlags();
// Basically, we only support ThisCall/thiscall with varargs
if ((m_Proto.GetConvention() & (~ProtoInfo::CallConv_HasVafmt)) != ProtoInfo::CallConv_ThisCall)
{
return NULL;
}
if (m_Proto.GetRet().size != 0 && !PassInfoSupported(m_Proto.GetRet(), true))
{
return NULL;
}
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
if (!PassInfoSupported(m_Proto.GetParam(i), false))
return NULL;
}
BuildProtoInfo();
GenerateHookFunc();
return fastdelegate::detail::horrible_cast<HookManagerPubFunc>(GeneratePubFunc());
}
HookManagerPubFunc GenContext::GetPubFunc()
{
if (m_GeneratedPubFunc == 0)
m_GeneratedPubFunc = Generate();
return m_GeneratedPubFunc;
}
bool GenContext::Equal(const CProto &proto, int vtbl_offs, int vtbl_idx)
{
return (m_OrigProto.ExactlyEqual(proto) && m_VtblOffs == vtbl_offs && m_VtblIdx == vtbl_idx);
}
bool GenContext::Equal(HookManagerPubFunc other)
{
return m_GeneratedPubFunc == other;
}
// *********************************** class GenContextContainer
CHookManagerAutoGen::CHookManagerAutoGen(ISourceHook *pSHPtr) : m_pSHPtr(pSHPtr)
{
}
CHookManagerAutoGen::~CHookManagerAutoGen()
{
for (List<StoredContext>::iterator iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
{
delete iter->m_GenContext;
}
}
int CHookManagerAutoGen::GetIfaceVersion()
{
return SH_HOOKMANAUTOGEN_IFACE_VERSION;
}
int CHookManagerAutoGen::GetImplVersion()
{
return SH_HOOKMANAUTOGEN_IMPL_VERSION;
}
HookManagerPubFunc CHookManagerAutoGen::MakeHookMan(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx)
{
CProto mproto(proto);
for (List<StoredContext>::iterator iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
{
if (iter->m_GenContext->Equal(mproto, vtbl_offs, vtbl_idx))
{
iter->m_RefCnt++;
return iter->m_GenContext->GetPubFunc();
}
}
// Not found yet -> new one
StoredContext sctx;
sctx.m_RefCnt = 1;
sctx.m_GenContext = new GenContext(proto, vtbl_offs, vtbl_idx, m_pSHPtr);
if (sctx.m_GenContext->GetPubFunc() == NULL)
{
return NULL;
}
else
{
m_Contexts.push_back(sctx);
return sctx.m_GenContext->GetPubFunc();
}
}
void CHookManagerAutoGen::ReleaseHookMan(HookManagerPubFunc pubFunc)
{
for (List<StoredContext>::iterator iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
{
if (iter->m_GenContext->Equal(pubFunc))
{
iter->m_RefCnt--;
if (iter->m_RefCnt == 0)
{
delete iter->m_GenContext;
m_Contexts.erase(iter);
}
break;
}
}
}
}
}

View File

@ -0,0 +1,299 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_HOOKMANGEN_H__
#define __SOURCEHOOK_HOOKMANGEN_H__
#include "sh_pagealloc.h"
namespace SourceHook
{
namespace Impl
{
// Code gen stuff
#if SH_COMP == SH_COMP_GCC
#include <stdint.h>
typedef int8_t jit_int8_t;
typedef uint8_t jit_uint8_t;
typedef int32_t jit_int32_t;
typedef uint32_t jit_uint32_t;
typedef int64_t jit_int64_t;
typedef uint64_t jit_uint64_t;
#elif SH_COMP == SH_COMP_MSVC
typedef __int8 jit_int8_t;
typedef unsigned __int8 jit_uint8_t;
typedef __int32 jit_int32_t;
typedef unsigned __int32 jit_uint32_t;
typedef __int64 jit_int64_t;
typedef unsigned __int64 jit_uint64_t;
#endif
typedef unsigned int jitoffs_t;
typedef signed int jitrel_t;
class GenBuffer
{
static CPageAlloc ms_Allocator;
unsigned char *m_pData;
jitoffs_t m_Size;
jitoffs_t m_AllocatedSize;
public:
GenBuffer() : m_pData(NULL), m_Size(0), m_AllocatedSize(0)
{
}
~GenBuffer()
{
clear();
}
jitoffs_t GetSize()
{
return m_Size;
}
unsigned char *GetData()
{
return m_pData;
}
template <class PT> void push(PT what)
{
push((const unsigned char *)&what, sizeof(PT));
}
void push(const unsigned char *data, jitoffs_t size)
{
jitoffs_t newSize = m_Size + size;
if (newSize > m_AllocatedSize)
{
m_AllocatedSize = newSize > m_AllocatedSize*2 ? newSize : m_AllocatedSize*2;
if (m_AllocatedSize < 64)
m_AllocatedSize = 64;
unsigned char *newBuf;
newBuf = reinterpret_cast<unsigned char*>(ms_Allocator.Alloc(m_AllocatedSize));
ms_Allocator.SetRW(newBuf);
if (!newBuf)
{
SH_ASSERT(0, ("bad_alloc: couldn't allocate 0x%08X bytes of memory\n", m_AllocatedSize));
return;
}
memset((void*)newBuf, 0xCC, m_AllocatedSize); // :TODO: remove this !
memcpy((void*)newBuf, (const void*)m_pData, m_Size);
if (m_pData)
{
ms_Allocator.SetRE(reinterpret_cast<void*>(m_pData));
ms_Allocator.SetRW(newBuf);
ms_Allocator.Free(reinterpret_cast<void*>(m_pData));
}
m_pData = newBuf;
}
memcpy((void*)(m_pData + m_Size), (const void*)data, size);
m_Size = newSize;
}
template <class PT> void rewrite(jitoffs_t offset, PT what)
{
rewrite(offset, (const unsigned char *)&what, sizeof(PT));
}
void rewrite(jitoffs_t offset, const unsigned char *data, jitoffs_t size)
{
SH_ASSERT(offset + size <= m_AllocatedSize, ("rewrite too far"));
memcpy((void*)(m_pData + offset), (const void*)data, size);
}
void clear()
{
if (m_pData)
ms_Allocator.Free(reinterpret_cast<void*>(m_pData));
m_pData = NULL;
m_Size = 0;
m_AllocatedSize = 0;
}
void SetRE()
{
ms_Allocator.SetRE(reinterpret_cast<void*>(m_pData));
}
operator void *()
{
return reinterpret_cast<void*>(GetData());
}
void write_ubyte(jit_uint8_t x) { push(x); }
void write_byte(jit_uint8_t x) { push(x); }
void write_ushort(unsigned short x) { push(x); }
void write_short(signed short x) { push(x); }
void write_uint32(jit_uint32_t x) { push(x); }
void write_int32(jit_uint32_t x) { push(x); }
jitoffs_t get_outputpos()
{
return m_Size;
}
void start_count(jitoffs_t &offs)
{
offs = get_outputpos();
}
void end_count(jitoffs_t &offs)
{
offs = get_outputpos() - offs;
}
};
class GenContext
{
const static int SIZE_MWORD = 4;
const static int SIZE_PTR = sizeof(void*);
const static int PassFlag_ForcedByRef = (1<<30); // ByVal in source, but actually passed by reference (GCC) -> private pass, destruct
HookManagerPubFunc m_GeneratedPubFunc;
CProto m_OrigProto; // original passed-in prototype
CProto m_Proto;
int m_VtblOffs;
int m_VtblIdx;
ISourceHook *m_SHPtr;
GenBuffer m_HookFunc;
GenBuffer m_PubFunc;
ProtoInfo *m_BuiltPI;
PassInfo *m_BuiltPI_Params;
PassInfo::V2Info *m_BuiltPI_Params2;
// For hookfunc
void **m_pHI;
void **m_HookfuncVfnptr;
// Level 3 - Helpers
int m_RegCounter;
jit_int8_t NextRegEBX_ECX_EDX();
int m_BytesPushedAfterInitialAlignment;
enum AlignStackFlags
{
AlignStack_GCC_ThisOnStack = 1,
AlignStack_MSVC_ThisOnStack = 2,
AlignStack_MemRet = 4
};
jit_int32_t AlignStackBeforeCall(int paramsize, int flags);
void AlignStackAfterCall(jit_int32_t numofbytes);
void CheckAlignmentBeforeCall();
// size info
jit_int32_t GetRealSize(const IntPassInfo &info); // checks for reference
jit_int32_t AlignSize(jit_int32_t x, jit_int32_t boundary); // align a size
jit_int32_t GetParamStackSize(const IntPassInfo &info); // get the size of a param in the param stack
short GetParamsTotalStackSize(); // sum(GetParamStackSize(param[i]), 0 <= i < numOfParams)
// Helpers
void BitwiseCopy_Setup();
void BitwiseCopy_Do(size_t size);
// HookFunc frame
jit_int32_t m_HookFunc_FrameOffset;
jit_int32_t m_HookFunc_FrameVarsSize;
void ResetFrame(jit_int32_t startOffset);
jit_int32_t AddVarToFrame(jit_int32_t size);
jit_int32_t ComputeVarsSize();
// Param push
short GetForcedByRefParamsSize(); // sum(param[i] is forcedbyref ? GetStackSize(param[i]) : 0, 0 <= i < numOfParams)
short GetForcedByRefParamOffset(int p); // sum(param[i] is forcedbyref ? GetStackSize(param[i]) : 0, 0 <= i < p)
jit_int32_t PushParams(jit_int32_t param_base_offset, jit_int32_t save_ret_to,
jit_int32_t v_place_for_memret, jit_int32_t v_place_fbrr_base); // save_ret_to and v_place_for_memret only used for memory returns
jit_int32_t PushRef(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushBasic(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushFloat(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushObject(jit_int32_t param_offset, const IntPassInfo &pi, jit_int32_t v_place_fbrr);
jit_int32_t PushMemRetPtr(jit_int32_t save_ret_to, jit_int32_t v_place_for_memret);
void DestroyParams(jit_int32_t fbrr_base);
// Ret val processing
void SaveRetVal(jit_int32_t v_where, jit_int32_t v_place_for_memret);
void ProcessPluginRetVal(jit_int32_t v_cur_res, jit_int32_t v_pContext, jit_int32_t v_plugin_ret);
void PrepareReturn(jit_int32_t v_status, jit_int32_t v_pContext, jit_int32_t v_retptr);
void DoReturn(jit_int32_t v_retptr, jit_int32_t v_memret_outaddr);
bool MemRetWithTempObj(); // do we do a memory return AND need a temporary place for it?
// Call hooks
void GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter,
int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base, jit_int32_t v_va_buf);
// Call orig
void GenerateCallOrig(int v_status, int v_pContext, int param_base_offs, int v_this,
int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base, jit_int32_t v_va_buf);
// Hook loop
void CallSetupHookLoop(int v_orig_ret, int v_override_ret,
int v_cur_res, int v_prev_res, int v_status, int v_vnfptr_origentry,
int v_this, int v_pContext);
void CallEndContext(int v_pContext);
// Level 2 -> called from Generate()
void AutoDetectRetType();
void AutoDetectParamFlags();
bool PassInfoSupported(const IntPassInfo &pi, bool is_ret);
void Clear();
void BuildProtoInfo();
void *GenerateHookFunc();
void *GeneratePubFunc();
HookManagerPubFunc Generate();
public:
// Level 1 -> Public interface
GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr);
~GenContext();
bool Equal(const CProto &proto, int vtbl_offs, int vtbl_idx);
bool Equal(HookManagerPubFunc other);
HookManagerPubFunc GetPubFunc();
};
class CHookManagerAutoGen : public IHookManagerAutoGen
{
struct StoredContext
{
int m_RefCnt;
GenContext *m_GenContext;
};
List<StoredContext> m_Contexts;
ISourceHook *m_pSHPtr;
public:
CHookManagerAutoGen(ISourceHook *pSHPtr);
~CHookManagerAutoGen();
int GetIfaceVersion();
int GetImplVersion();
HookManagerPubFunc MakeHookMan(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx);
void ReleaseHookMan(HookManagerPubFunc pubFunc);
};
}
}
#endif

View File

@ -0,0 +1,1611 @@
/* ======== SourceHook ========
* vim: set ts=4 :
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* No warranties of any kind
*
* License: zlib/libpng
*
* from the SourcePawn JIT SDK
* ============================
*/
#ifndef __SOURCEHOOK_HOOKMANGEN_X86_H__
#define __SOURCEHOOK_HOOKMANGEN_X86_H__
#include <limits.h>
#undef REG_EAX
#undef REG_ECX
#undef REG_EDX
#undef REG_EBX
#undef REG_ESP
#undef REG_SIB
#undef REG_EBP
#undef REG_ESI
#undef REG_EDI
//MOD R/M
#define MOD_MEM_REG 0
#define MOD_DISP8 1
#define MOD_DISP32 2
#define MOD_REG 3
//SIB
#define NOSCALE 0
#define SCALE2 1
#define SCALE4 2
#define SCALE8 3
//Register codes
#define REG_EAX 0
#define REG_ECX 1
#define REG_EDX 2
#define REG_EBX 3
#define REG_ESP 4
#define REG_SIB 4
#define REG_NOIDX 4
#define REG_IMM_BASE 5
#define REG_EBP 5
#define REG_ESI 6
#define REG_EDI 7
#define IA32_16BIT_PREFIX 0x66
//condition codes (for example, Jcc opcodes)
#define CC_B 0x2
#define CC_NAE CC_B
#define CC_NB 0x3
#define CC_AE CC_NB
#define CC_E 0x4
#define CC_Z CC_E
#define CC_NE 0x5
#define CC_NZ CC_NE
#define CC_NA 0x6
#define CC_BE CC_NA
#define CC_A 0x7
#define CC_NBE CC_A
#define CC_L 0xC
#define CC_NGE CC_L
#define CC_NL 0xD
#define CC_GE CC_NL
#define CC_NG 0xE
#define CC_LE CC_NG
#define CC_G 0xF
#define CC_NLE CC_G
//Opcodes with encoding information
#define IA32_XOR_RM_REG 0x31 // encoding is /r
#define IA32_XOR_REG_RM 0x33 // encoding is /r
#define IA32_XOR_EAX_IMM32 0x35 // encoding is /r
#define IA32_XOR_RM_IMM32 0x81 // encoding is /6
#define IA32_XOR_RM_IMM8 0x83 // encoding is /6
#define IA32_ADD_RM_REG 0x01 // encoding is /r
#define IA32_ADD_REG_RM 0x03 // encoding is /r
#define IA32_ADD_RM_IMM32 0x81 // encoding is /0
#define IA32_ADD_RM_IMM8 0x83 // encoding is /0
#define IA32_ADD_EAX_IMM32 0x05 // no extra encoding
#define IA32_SUB_RM_REG 0x29 // encoding is /r
#define IA32_SUB_REG_RM 0x2B // encoding is /r
#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 <imm8>
#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 <imm32>
#define IA32_SBB_REG_RM 0x1B // encoding is /r
#define IA32_SBB_RM_IMM8 0x83 // encoding is <imm32>
#define IA32_JMP_IMM32 0xE9 // encoding is imm32
#define IA32_JMP_IMM8 0xEB // encoding is imm8
#define IA32_JMP_RM 0xFF // encoding is /4
#define IA32_CALL_IMM32 0xE8 // relative call, <imm32>
#define IA32_CALL_RM 0xFF // encoding is /2
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
#define IA32_MOV_RM8_REG 0x88 // encoding is /r
#define IA32_MOV_RM_REG 0x89 // encoding is /r
#define IA32_MOV_REG_RM 0x8B // encoding is /r
#define IA32_MOV_REG8_RM8 0x8A // encoding is /r
#define IA32_MOV_RM8_REG8 0x88 // encoding is /r
#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0
#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 <imm32>
#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 <imm8>
#define IA32_CMP_AL_IMM32 0x3C // no extra encoding
#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding
#define IA32_CMP_RM_REG 0x39 // encoding is /r
#define IA32_CMP_REG_RM 0x3B // encoding is /r
#define IA32_CMPSB 0xA6 // no extra encoding
#define IA32_TEST_RM_REG8 0x84 // encoding is /r
#define IA32_TEST_RM_REG 0x85 // encoding is /r
#define IA32_TEST_RM_IMM32 0xF7 // encoding is /0 <imm32>
#define IA32_JCC_IMM 0x70 // encoding is +cc <imm8>
#define IA32_JCC_IMM32_1 0x0F // opcode part 1
#define IA32_JCC_IMM32_2 0x80 // encoding is +cc <imm32>
#define IA32_RET 0xC3 // no extra encoding
#define IA32_RETN 0xC2 // encoding is <imm16>
#define IA32_NEG_RM 0xF7 // encoding is /3
#define IA32_INC_REG 0x40 // encoding is +r
#define IA32_INC_RM 0xFF // encoding is /0
#define IA32_DEC_REG 0x48 // encoding is +r
#define IA32_DEC_RM 0xFF // encoding is /1
#define IA32_OR_REG_RM 0x0B // encoding is /r
#define IA32_AND_REG_RM 0x23 // encoding is /r
#define IA32_AND_EAX_IMM32 0x25 // encoding is <imm32>
#define IA32_AND_RM_IMM32 0x81 // encoding is /4
#define IA32_AND_RM_IMM8 0x83 // encoding is /4
#define IA32_NOT_RM 0xF7 // encoding is /2
#define IA32_DIV_RM 0xF7 // encoding is /6
#define IA32_MUL_RM 0xF7 // encoding is /4
#define IA32_IDIV_RM 0xF7 // encoding is /7
#define IA32_IMUL_RM 0xF7 // encoding is /5
#define IA32_IMUL_REG_IMM32 0x69 // encoding is /r
#define IA32_IMUL_REG_IMM8 0x6B // encoding is /r
#define IA32_IMUL_REG_RM_1 0x0F // encoding is _2
#define IA32_IMUL_REG_RM_2 0xAF // encoding is /r
#define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 <ib>
#define IA32_SHR_RM_1 0xD1 // encoding is /5
#define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 <ib>
#define IA32_SHL_RM_1 0xD1 // encoding is /4
#define IA32_SAR_RM_CL 0xD3 // encoding is /7
#define IA32_SAR_RM_1 0xD1 // encoding is /7
#define IA32_SHR_RM_CL 0xD3 // encoding is /5
#define IA32_SHL_RM_CL 0xD3 // encoding is /4
#define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 <ib>
#define IA32_SETCC_RM8_1 0x0F // opcode part 1
#define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits)
#define IA32_CMOVCC_RM_1 0x0F // opcode part 1
#define IA32_CMOVCC_RM_2 0x40 // encoding is +cc /r
#define IA32_XCHG_EAX_REG 0x90 // encoding is +r
#define IA32_LEA_REG_MEM 0x8D // encoding is /r
#define IA32_POP_REG 0x58 // encoding is +r
#define IA32_PUSH_REG 0x50 // encoding is +r
#define IA32_PUSH_RM 0xFF // encoding is /6
#define IA32_PUSH_IMM32 0x68 // encoding is <imm32>
#define IA32_PUSH_IMM8 0x6A // encoding is <imm8>
#define IA32_REP 0xF3 // no extra encoding
#define IA32_MOVSD 0xA5 // no extra encoding
#define IA32_MOVSB 0xA4 // no extra encoding
#define IA32_STOSD 0xAB // no extra encoding
#define IA32_CLD 0xFC // no extra encoding
#define IA32_PUSHAD 0x60 // no extra encoding
#define IA32_POPAD 0x61 // no extra encoding
#define IA32_NOP 0x90 // no extra encoding
#define IA32_INT3 0xCC // no extra encoding
#define IA32_FSTP_MEM32 0xD9 // encoding is /3
#define IA32_FSTP_MEM64 0xDD // encoding is /3
#define IA32_FLD_MEM32 0xD9 // encoding is /0
#define IA32_FLD_MEM64 0xDD // encoding is /0
#define IA32_FILD_MEM32 0xDB // encoding is /0
#define IA32_FADD_MEM32 0xD8 // encoding is /0
#define IA32_FADD_FPREG_ST0_1 0xDC // opcode part 1
#define IA32_FADD_FPREG_ST0_2 0xC0 // encoding is +r
#define IA32_FSUB_MEM32 0xD8 // encoding is /4
#define IA32_FMUL_MEM32 0xD8 // encoding is /1
#define IA32_FDIV_MEM32 0xD8 // encoding is /6
#define IA32_FSTCW_MEM16_1 0x9B // opcode part 1
#define IA32_FSTCW_MEM16_2 0xD9 // encoding is /7
#define IA32_FLDCW_MEM16 0xD9 // encoding is /5
#define IA32_FISTP_MEM32 0xDB // encoding is /3
#define IA32_FUCOMIP_1 0xDF // opcode part 1
#define IA32_FUCOMIP_2 0xE8 // encoding is +r
#define IA32_FSTP_FPREG_1 0xDD // opcode part 1
#define IA32_FSTP_FPREG_2 0xD8 // encoding is +r
#define IA32_MOVZX_R32_RM8_1 0x0F // opcode part 1
#define IA32_MOVZX_R32_RM8_2 0xB6 // encoding is /r
#define IA32_MOVZX_R32_RM16_1 0x0F // opcode part 1
#define IA32_MOVZX_R32_RM16_2 0xB7 // encoding is /r
namespace SourceHook
{
namespace Impl
{
typedef GenBuffer JitWriter;
inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm)
{
jit_uint8_t modrm = (mode << 6);
modrm |= (reg << 3);
modrm |= (rm);
return modrm;
}
//mode is the scaling method - NOSCALE ... SCALE8
//index is the register that is scaled
//base is the base register
inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t base)
{
jit_uint8_t sib = (mode << 6);
sib |= (index << 3);
sib |= (base);
return sib;
}
inline void IA32_Int3(JitWriter *jit)
{
jit->write_ubyte(IA32_INT3);
}
/***********************
* INCREMENT/DECREMENT *
***********************/
inline void IA32_Inc_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_INC_REG+reg);
}
inline void IA32_Inc_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, reg));
jit->write_byte(disp);
}
inline void IA32_Inc_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, reg));
jit->write_int32(disp);
}
inline void IA32_Inc_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB));
jit->write_ubyte(ia32_sib(scale, reg, base));
}
inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_DEC_REG+reg);
}
inline void IA32_Dec_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, reg));
jit->write_byte(disp);
}
inline void IA32_Dec_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 1, reg));
jit->write_int32(disp);
}
inline void IA32_Dec_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 1, REG_SIB));
jit->write_ubyte(ia32_sib(scale, reg, base));
}
/****************
* BINARY LOGIC *
****************/
inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode)
{
jit->write_ubyte(IA32_XOR_RM_REG);
jit->write_ubyte(ia32_modrm(dest_mode, src, dest));
}
inline void IA32_Xor_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode)
{
jit->write_ubyte(IA32_XOR_REG_RM);
jit->write_ubyte(ia32_modrm(dest_mode, dest, src));
}
inline void IA32_Xor_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_XOR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
jit->write_byte(value);
}
inline void IA32_Xor_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_XOR_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
jit->write_int32(value);
}
inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_XOR_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_NEG_RM);
jit->write_ubyte(ia32_modrm(mode, 3, reg));
}
inline void IA32_Or_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_OR_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_And_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_AND_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_AND_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
jit->write_int32(value);
}
inline void IA32_And_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_AND_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
jit->write_byte(value);
}
inline void IA32_And_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_AND_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_NOT_RM);
jit->write_ubyte(ia32_modrm(mode, 2, reg));
}
inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 5, dest));
jit->write_ubyte(value);
}
inline void IA32_Shr_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_1);
jit->write_ubyte(ia32_modrm(mode, 5, dest));
}
inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 4, dest));
jit->write_ubyte(value);
}
inline void IA32_Shl_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_1);
jit->write_ubyte(ia32_modrm(mode, 4, dest));
}
inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 7, dest));
jit->write_ubyte(value);
}
inline void IA32_Sar_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 7, reg));
}
inline void IA32_Sar_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_1);
jit->write_ubyte(ia32_modrm(mode, 7, dest));
}
inline void IA32_Shr_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
}
inline void IA32_Shl_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_XCHG_EAX_REG+reg);
}
/**********************
* ARITHMETIC (BASIC) *
**********************/
inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_byte(value);
}
inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_int32(value);
}
inline void IA32_Add_Rm_ImmAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode)
{
if (value >= SCHAR_MIN && value <= SCHAR_MAX)
IA32_Add_Rm_Imm8(jit, reg, static_cast<jit_int8_t>(value), mode);
else
IA32_Add_Rm_Imm32(jit, reg, value, mode);
}
inline void IA32_Add_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_ADD_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp8);
}
inline void IA32_Sub_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp8);
}
inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
jit->write_int32(val);
}
inline void IA32_Sub_Rm_ImmAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode)
{
if (val >= SCHAR_MIN && val <= SCHAR_MAX)
IA32_Sub_Rm_Imm8(jit, reg, static_cast<jit_int8_t>(val), mode);
else
IA32_Sub_Rm_Imm32(jit, reg, val, mode);
}
inline void IA32_Sbb_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SBB_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Sbb_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_int8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SBB_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 3, dest));
jit->write_byte(value);
}
inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_DIV_RM);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
}
inline void IA32_IDiv_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IDIV_RM);
jit->write_ubyte(ia32_modrm(mode, 7, reg));
}
inline void IA32_Mul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MUL_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_IMul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IMUL_RM);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
}
inline void IA32_IMul_Reg_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_IMUL_REG_IMM8);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_byte(value);
}
inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_IMUL_REG_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_int32(value);
}
inline void IA32_IMul_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IMUL_REG_RM_1);
jit->write_ubyte(IA32_IMUL_REG_RM_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_ADD_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp);
}
inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_ADD_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_byte(val);
}
inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_int32(val);
}
inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, dest));
jitoffs_t ptr = jit->get_outputpos();
jit->write_int32(0);
return ptr;
}
inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest));
jit->write_int32(disp32);
jit->write_byte(val);
}
inline void IA32_Add_RmEBP_Imm8_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, dest));
jit->write_byte(disp8);
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 5, dest));
jit->write_int32(disp32);
jit->write_byte(val);
}
inline void IA32_Sub_RmEBP_Imm8_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_byte(val);
}
/**
* Memory Instructions
*/
inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
}
inline void IA32_Lea_Reg_DispEBPRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_byte(0);
}
inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_byte(val);
}
inline void IA32_Lea_Reg_DispRegMultImm32(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_int32(val);
}
inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, REG_IMM_BASE));
jit->write_int32(val);
}
inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base));
jit->write_byte(val);
}
inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base));
jit->write_int32(val);
}
inline void IA32_Lea_DispRegImmAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
{
if (val >= SCHAR_MIN && val <= SCHAR_MAX)
IA32_Lea_DispRegImm8(jit, dest, src_base, static_cast<jit_int8_t>(val));
else
IA32_Lea_DispRegImm32(jit, dest, src_base, val);
}
/**
* Stack Instructions
*/
inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_POP_REG+reg);
}
inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_PUSH_REG+reg);
}
inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val)
{
jit->write_ubyte(IA32_PUSH_IMM8);
jit->write_byte(val);
}
inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val)
{
jit->write_ubyte(IA32_PUSH_IMM32);
jit->write_int32(val);
}
inline void IA32_Pushad(JitWriter *jit)
{
jit->write_ubyte(IA32_PUSHAD);
}
inline void IA32_Popad(JitWriter *jit)
{
jit->write_ubyte(IA32_POPAD);
}
inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg));
jit->write_byte(disp8);
}
inline void IA32_Push_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp32)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 6, reg));
jit->write_int32(disp32);
}
inline void IA32_Push_Rm_DispAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Push_Rm_Disp8(jit, reg, static_cast<jit_int8_t>(disp));
else
IA32_Push_Rm_Disp32(jit, reg, disp);
}
inline void IA32_Push_Rm_Disp8_ESP(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
/**
* Moving from REGISTER/MEMORY to REGISTER
*/
inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Mov_Reg8_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Mov_Reg_RmESP(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_ESP));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Mov_Reg8_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
}
inline void IA32_Mov_Reg_Rm_Disp_Reg_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
jit->write_byte(disp8);
}
inline void IA32_Mov_Reg_RmEBP_Disp_Reg(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
jit->write_byte(0);
}
inline void IA32_Mov_Reg_Rm_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Mov_Reg_Rm(jit, dest, src, MOD_MEM_REG);
else if (disp <= SCHAR_MAX)
IA32_Mov_Reg_Rm_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Mov_Reg_Rm_Disp32(jit, dest, src, disp);
}
/**
* Moving from REGISTER to REGISTER/MEMORY
*/
inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM8_REG8);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Mov_Rm8_Reg8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_RM8_REG8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp);
}
inline void IA32_Mov_Rm8_Reg8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_RM8_REG8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, src, dest));
jit->write_int32(disp);
}
inline void IA32_Mov_Rm8_Reg8_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Mov_Rm8_Reg8_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Mov_Rm8_Reg8_Disp32(jit, dest, src, disp);
}
inline void IA32_Mov_RmESP_Reg(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_ESP));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp);
}
inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP32, src, dest));
jit->write_int32(disp);
}
inline void IA32_Mov_Rm_Reg_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Mov_Rm_Reg_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Mov_Rm_Reg_Disp32(jit, dest, src, disp);
}
inline void IA32_Mov_RmEBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
inline void IA32_Mov_Rm8EBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM8_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
inline void IA32_Mov_Rm16EBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_16BIT_PREFIX);
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
/**
* Moving from IMMEDIATE to REGISTER
*/
inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num)
{
jitoffs_t offs;
jit->write_ubyte(IA32_MOV_REG_IMM+dest);
offs = jit->get_outputpos();
jit->write_int32(num);
return offs;
}
inline void IA32_Mov_Rm_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, dest));
jit->write_int32(val);
}
inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_int32(val);
}
inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest));
jit->write_int32(disp32);
jit->write_int32(val);
}
inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_int32(val);
}
inline void IA32_Mov_ESP_Disp8_Imm32(JitWriter *jit, jit_int8_t disp8, jit_int32_t val)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
jit->write_int32(val);
}
/**
* Floating Point Instructions
*/
inline void IA32_Fstcw_Mem16_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTCW_MEM16_1);
jit->write_ubyte(IA32_FSTCW_MEM16_2);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 7, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fldcw_Mem16_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FLDCW_MEM16);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 5, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fldcw_Mem16_Disp8_ESP(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_FLDCW_MEM16);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
inline void IA32_Fistp_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FISTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fistp_Mem32_Disp8_Esp(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_FISTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
inline void IA32_Fucomip_ST0_FPUreg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FUCOMIP_1);
jit->write_ubyte(IA32_FUCOMIP_2+reg);
}
inline void IA32_Fadd_FPUreg_ST0(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FADD_FPREG_ST0_1);
jit->write_ubyte(IA32_FADD_FPREG_ST0_2+reg);
}
inline void IA32_Fadd_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FADD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fadd_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FADD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fsub_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FSUB_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 4, src));
jit->write_byte(val);
}
inline void IA32_Fmul_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FMUL_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, src));
jit->write_byte(val);
}
inline void IA32_Fdiv_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FDIV_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, src));
jit->write_byte(val);
}
inline void IA32_Fild_Mem32(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FILD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_FSTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
}
inline void IA32_Fstp_Mem32_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_int32_t disp)
{
jit->write_ubyte(IA32_FSTP_MEM32);
if (disp > SCHAR_MIN && disp < SCHAR_MAX)
{
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, dest));
jit->write_byte(static_cast<jit_int8_t>(disp));
}
else
{
jit->write_ubyte(ia32_modrm(MOD_DISP32, 3, dest));
jit->write_byte(disp);
}
}
inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_FSTP_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
}
inline void IA32_Fstp_Mem64_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_int32_t disp)
{
jit->write_ubyte(IA32_FSTP_MEM64);
if (disp > SCHAR_MIN && disp < SCHAR_MAX)
{
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, dest));
jit->write_byte(static_cast<jit_int8_t>(disp));
}
else
{
jit->write_ubyte(ia32_modrm(MOD_DISP32, 3, dest));
jit->write_byte(disp);
}
}
inline void IA32_Fstp_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fstp_Mem64_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTP_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fstp_FPUreg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FSTP_FPREG_1);
jit->write_ubyte(IA32_FSTP_FPREG_2+reg);
}
inline void IA32_Fld_Mem32(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fld_Mem64(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
jit->write_int32(val);
}
inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
jit->write_int32(val);
}
inline void IA32_Fld_Mem32_DispAuto(JitWriter *jit, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Fld_Mem32(jit, src);
else if (disp <= SCHAR_MAX)
IA32_Fld_Mem32_Disp8(jit, src, static_cast<jit_int8_t>(disp));
else
IA32_Fld_Mem32_Disp32(jit, src, disp);
}
inline void IA32_Fld_Mem64_DispAuto(JitWriter *jit, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Fld_Mem64(jit, src);
else if (disp <= SCHAR_MAX)
IA32_Fld_Mem64_Disp8(jit, src, static_cast<jit_int8_t>(disp));
else
IA32_Fld_Mem64_Disp32(jit, src, disp);
}
/**
* Move data with zero extend
*/
inline void IA32_Movzx_Reg32_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Movzx_Reg32_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Movzx_Reg32_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Movzx_Reg32_Rm8_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Movzx_Reg32_Rm8_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Movzx_Reg32_Rm8_Disp32(jit, dest, src, disp);
}
inline void IA32_Movzx_Reg32_Rm16(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Movzx_Reg32_Rm16_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Movzx_Reg32_Rm16_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Movzx_Reg32_Rm16_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Movzx_Reg32_Rm16_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Movzx_Reg32_Rm16_Disp32(jit, dest, src, disp);
}
/**
* Branching/Jumping
*/
inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM+cond);
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM32);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM8);
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM32_1);
jit->write_ubyte(IA32_JCC_IMM32_2+cond);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_JMP_RM);
jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg));
}
inline void IA32_Jump_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_JMP_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_CALL_IMM32);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_CALL_RM);
jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg));
}
inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CALL_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_Return(JitWriter *jit)
{
jit->write_ubyte(IA32_RET);
}
inline void IA32_Return_Popstack(JitWriter *jit, unsigned short bytes)
{
jit->write_ubyte(IA32_RETN);
jit->write_ushort(bytes);
}
inline void IA32_Test_Rm_Reg(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode)
{
jit->write_ubyte(IA32_TEST_RM_REG);
jit->write_ubyte(ia32_modrm(mode, reg2, reg1));
}
inline void IA32_Test_Rm_Reg8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode)
{
jit->write_ubyte(IA32_TEST_RM_REG8);
jit->write_ubyte(ia32_modrm(mode, reg2, reg1));
}
inline void IA32_Test_Rm_Imm32(JitWriter *jit, jit_uint8_t operand1, jit_int32_t imm_operand, jit_uint8_t mode)
{
jit->write_ubyte(IA32_TEST_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, operand1));
jit->write_int32(imm_operand);
}
inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CMP_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Cmp_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Cmp_Reg_Rm_ESP(JitWriter *jit, jit_uint8_t cmpreg)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, cmpreg, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2));
jit->write_byte(disp8);
}
inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8)
{
jit->write_ubyte(IA32_CMP_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 7, rm));
jit->write_byte(imm8);
}
inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32)
{
jit->write_ubyte(IA32_CMP_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 7, rm));
jit->write_int32(imm32);
}
inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8, jit_int32_t imm32)
{
jit->write_ubyte(IA32_CMP_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg));
jit->write_byte(disp8);
jit->write_int32(imm32);
}
inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8)
{
jit->write_ubyte(IA32_CMP_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg));
jit->write_byte(disp);
jit->write_byte(imm8);
}
inline void IA32_Cmp_Al_Imm8(JitWriter *jit, jit_int8_t value)
{
jit->write_ubyte(IA32_CMP_AL_IMM32);
jit->write_byte(value);
}
inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_CMP_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond)
{
jit->write_ubyte(IA32_SETCC_RM8_1);
jit->write_ubyte(IA32_SETCC_RM8_2+cond);
jit->write_ubyte(ia32_modrm(MOD_REG, 0, reg));
}
inline void IA32_CmovCC_Rm(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond)
{
jit->write_ubyte(IA32_CMOVCC_RM_1);
jit->write_ubyte(IA32_CMOVCC_RM_2+cond);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_CmovCC_Rm_Disp8(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond, jit_int8_t disp)
{
jit->write_ubyte(IA32_CMOVCC_RM_1);
jit->write_ubyte(IA32_CMOVCC_RM_2+cond);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(disp);
}
inline void IA32_Cmpsb(JitWriter *jit)
{
jit->write_ubyte(IA32_CMPSB);
}
inline void IA32_Rep(JitWriter *jit)
{
jit->write_ubyte(IA32_REP);
}
inline void IA32_Movsd(JitWriter *jit)
{
jit->write_ubyte(IA32_MOVSD);
}
inline void IA32_Movsb(JitWriter *jit)
{
jit->write_ubyte(IA32_MOVSB);
}
inline void IA32_Stosd(JitWriter *jit)
{
jit->write_ubyte(IA32_STOSD);
}
inline void IA32_Cld(JitWriter *jit)
{
jit->write_ubyte(IA32_CLD);
}
}
}
#endif //_INCLUDE_JIT_X86_MACROS_H

View File

@ -26,6 +26,21 @@ namespace SourceHook
void *pCopyCtor;
void *pDtor;
void *pAssignOperator;
bool operator == (const IntPassInfo &other) const
{
return size == other.size
&& type == other.type
&& flags == other.flags
&& pNormalCtor == other.pNormalCtor
&& pDtor == other.pDtor
&& pAssignOperator == other.pAssignOperator;
}
bool operator != (const IntPassInfo &other) const
{
return !(*this == other);
}
};
class CProto
@ -72,6 +87,8 @@ namespace SourceHook
bool operator == (const CProto &other) const;
bool ExactlyEqual(const CProto &other) const;
int GetVersion() const
{
return m_Version;
@ -87,11 +104,21 @@ namespace SourceHook
return m_ParamsPassInfo[i];
}
IntPassInfo & GetParam(int i)
{
return m_ParamsPassInfo[i];
}
const IntPassInfo & GetRet() const
{
return m_RetPassInfo;
}
IntPassInfo & GetRet()
{
return m_RetPassInfo;
}
int GetConvention() const
{
return m_Convention;

View File

@ -0,0 +1,109 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_PIBUILDER_H__
#define __SOURCEHOOK_PIBUILDER_H__
#include "sourcehook.h"
#include "sh_vector.h"
namespace SourceHook
{
// Helper class: protocol information builder
class CProtoInfoBuilder
{
ProtoInfo m_PI;
CVector<PassInfo> m_Params;
CVector<PassInfo::V2Info> m_Params2;
public:
CProtoInfoBuilder(int cc)
{
memset(reinterpret_cast<void*>(&m_PI), 0, sizeof(ProtoInfo));
m_PI.convention = cc;
// dummy 0 params
PassInfo dummy;
PassInfo::V2Info dummy2;
memset(reinterpret_cast<void*>(&dummy), 0, sizeof(PassInfo));
memset(reinterpret_cast<void*>(&dummy2), 0, sizeof(PassInfo::V2Info));
dummy.size = 1; // Version1
m_Params.push_back(dummy);
m_Params2.push_back(dummy2);
}
void SetReturnType(size_t size, PassInfo::PassType type, int flags,
void *pNormalCtor, void *pCopyCtor, void *pDtor, void *pAssignOperator)
{
if (pNormalCtor)
flags |= PassInfo::PassFlag_OCtor;
if (pCopyCtor)
flags |= PassInfo::PassFlag_CCtor;
if (pDtor)
flags |= PassInfo::PassFlag_ODtor;
if (pAssignOperator)
flags |= PassInfo::PassFlag_AssignOp;
m_PI.retPassInfo.size = size;
m_PI.retPassInfo.type = type;
m_PI.retPassInfo.flags = flags;
m_PI.retPassInfo2.pNormalCtor = pNormalCtor;
m_PI.retPassInfo2.pCopyCtor = pCopyCtor;
m_PI.retPassInfo2.pDtor = pDtor;
m_PI.retPassInfo2.pAssignOperator = pAssignOperator;
}
void AddParam(size_t size, PassInfo::PassType type, int flags,
void *pNormalCtor, void *pCopyCtor, void *pDtor, void *pAssignOperator)
{
PassInfo pi;
PassInfo::V2Info pi2;
if (pNormalCtor)
flags |= PassInfo::PassFlag_OCtor;
if (pCopyCtor)
flags |= PassInfo::PassFlag_CCtor;
if (pDtor)
flags |= PassInfo::PassFlag_ODtor;
if (pAssignOperator)
flags |= PassInfo::PassFlag_AssignOp;
pi.size = size;
pi.type = type;
pi.flags = flags;
pi2.pNormalCtor = pNormalCtor;
pi2.pCopyCtor = pCopyCtor;
pi2.pDtor = pDtor;
pi2.pAssignOperator = pAssignOperator;
m_Params.push_back(pi);
m_Params2.push_back(pi2);
++m_PI.numOfParams;
}
operator ProtoInfo*()
{
m_PI.paramsPassInfo = &(m_Params[0]);
m_PI.paramsPassInfo2 = &(m_Params2[0]);
return &m_PI;
}
};
}
#endif

View File

@ -9,7 +9,7 @@ INCLUDE = -I. -I..
MAX_PARAMS=20
BINARY = sourcehook_test
OBJECTS = main.cpp sourcehook.cpp $(shell ls -t test*.cpp)
OBJECTS = main.cpp sourcehook.cpp ../sourcehook_hookmangen.cpp $(shell ls -t test*.cpp)
HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h
ifeq "$(DEBUG)" "true"
@ -20,7 +20,7 @@ else
CFLAGS = $(OPT_FLAGS)
endif
CFLAGS += -Wall
CFLAGS += -Wall -Wno-non-virtual-dtor
# Also, enable SH_ASSERT
CFLAGS += -DSH_DEBUG

View File

@ -0,0 +1,6 @@
:: Generates everything
:: Usage:
:: generate.bat <num-of-arguments>
..\generate\shworker iter testhookmangen.hxx testhookmangen.h %1

View File

@ -13,6 +13,7 @@
#include "sourcehook_impl.h"
#include "sourcehook.h"
#include "sourcehook_hookmangen.h"
using namespace std;
bool g_Verbose;
@ -46,6 +47,8 @@ DECL_TEST(Multi);
DECL_TEST(Ref);
DECL_TEST(RefRet);
DECL_TEST(VPHooks);
DECL_TEST(CPageAlloc); // in testhookmangen.cpp
DECL_TEST(HookManGen);
int main(int argc, char *argv[])
{
@ -68,6 +71,8 @@ int main(int argc, char *argv[])
DO_TEST(Ref);
DO_TEST(RefRet);
DO_TEST(VPHooks);
DO_TEST(CPageAlloc);
DO_TEST(HookManGen);
cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
cout << "Total: " << passed + failed << endl;
@ -107,3 +112,14 @@ void Test_UnpausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug)
{
static_cast<SourceHook::Impl::CSourceHookImpl *>(shptr)->UnpausePlugin(plug);
}
SourceHook::IHookManagerAutoGen *Test_HMAG_Factory(SourceHook::ISourceHook *shptr)
{
return new SourceHook::Impl::CHookManagerAutoGen(shptr);
}
void Test_HMAG_Delete(SourceHook::IHookManagerAutoGen *ptr)
{
delete static_cast<SourceHook::Impl::CHookManagerAutoGen*>(ptr);
}

View File

@ -248,6 +248,9 @@
<File
RelativePath="..\..\sourcehook.cpp">
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.cpp">
</File>
<File
RelativePath="..\test1.cpp">
</File>
@ -266,6 +269,9 @@
<File
RelativePath="..\testbail2.cpp">
</File>
<File
RelativePath="..\testhookmangen.cpp">
</File>
<File
RelativePath="..\testlist.cpp">
</File>
@ -306,6 +312,12 @@
<File
RelativePath="..\..\sh_list.h">
</File>
<File
RelativePath="..\..\sh_memory.h">
</File>
<File
RelativePath="..\..\sh_pagealloc.h">
</File>
<File
RelativePath="..\..\sh_stack.h">
</File>
@ -321,6 +333,12 @@
<File
RelativePath="..\..\sourcehook.h">
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.h">
</File>
<File
RelativePath="..\..\sourcehook_hookmangen_x86.h">
</File>
<File
RelativePath="..\..\sourcehook_impl.h">
</File>
@ -345,6 +363,9 @@
<File
RelativePath="..\..\sourcehook_impl_cvfnptr.h">
</File>
<File
RelativePath="..\..\sourcehook_pibuilder.h">
</File>
<File
RelativePath="..\sourcehook_test.h">
</File>
@ -354,6 +375,9 @@
<File
RelativePath="..\testevents.h">
</File>
<File
RelativePath="..\testhookmangen.h">
</File>
<Filter
Name="generate"
Filter="">
@ -378,6 +402,9 @@ popd
Outputs="..\sourcehook.h"/>
</FileConfiguration>
</File>
<File
RelativePath="..\testhookmangen.hxx">
</File>
</Filter>
</Filter>
<Filter

View File

@ -303,6 +303,7 @@
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
@ -371,6 +372,10 @@
RelativePath="..\..\sourcehook.cpp"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.cpp"
>
</File>
<File
RelativePath="..\test1.cpp"
>
@ -395,6 +400,10 @@
RelativePath="..\testbail2.cpp"
>
</File>
<File
RelativePath="..\testhookmangen.cpp"
>
</File>
<File
RelativePath="..\testlist.cpp"
>
@ -472,6 +481,14 @@
RelativePath="..\..\sourcehook.h"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen.h"
>
</File>
<File
RelativePath="..\..\sourcehook_hookmangen_x86.h"
>
</File>
<File
RelativePath="..\..\sourcehook_impl.h"
>
@ -500,6 +517,10 @@
RelativePath="..\..\sourcehook_impl_cvfnptr.h"
>
</File>
<File
RelativePath="..\..\sourcehook_pibuilder.h"
>
</File>
<File
RelativePath="..\sourcehook_test.h"
>
@ -512,6 +533,10 @@
RelativePath="..\testevents.h"
>
</File>
<File
RelativePath="..\testhookmangen.h"
>
</File>
<Filter
Name="generate"
>
@ -536,6 +561,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\testhookmangen.hxx"
>
</File>
</Filter>
</Filter>
<Filter

View File

@ -17,6 +17,7 @@ struct CAutoPtrDestruction
CAutoPtrDestruction(T *p) : m_Ptr(p) { }
~CAutoPtrDestruction() { if (m_Ptr) delete m_Ptr; }
void clear() { m_Ptr = NULL; }
void set(T *ptr) { m_Ptr = ptr; }
};
struct CSHPtrAutoDestruction
@ -33,3 +34,16 @@ void Test_CompleteShutdown(SourceHook::ISourceHook *shptr);
void Test_UnloadPlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
void Test_PausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
void Test_UnpausePlugin(SourceHook::ISourceHook *shptr, SourceHook::Plugin plug);
SourceHook::IHookManagerAutoGen *Test_HMAG_Factory(SourceHook::ISourceHook *pSHPtr);
void Test_HMAG_Delete(SourceHook::IHookManagerAutoGen *ptr);
struct CHMAGAutoDestruction
{
SourceHook::IHookManagerAutoGen *m_Ptr;
CHMAGAutoDestruction(SourceHook::IHookManagerAutoGen *ptr) : m_Ptr(ptr) {}
~CHMAGAutoDestruction() { Test_HMAG_Delete(m_Ptr); }
};
#define GET_HMAG(var, shptr) var = Test_HMAG_Factory(shptr); CHMAGAutoDestruction __hmagautodestruction(var);

View File

@ -178,7 +178,7 @@ bool TestVafmtAndOverload(std::string &error)
tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf,
tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf);
char refbuf[SourceHook::STRBUF_LEN];
char refbuf[SourceHook::STRBUF_LEN];
for (int i = 0; i < (SourceHook::STRBUF_LEN - 1); ++i)
refbuf[i] = (i % 10) + '0';
refbuf[SourceHook::STRBUF_LEN - 1] = 0;

View File

@ -19,6 +19,19 @@
extern bool g_Verbose;
static unsigned int MakeHash(const char *name)
{
int a = 0;
unsigned int res = 0xFFFFFFFF;
while (*name)
{
res ^= ((unsigned int)*name << ((a++ % 4)*8));
++name;
}
return res;
}
struct State
{
virtual ~State()
@ -28,10 +41,27 @@ struct State
virtual bool IsEqual(State *other)
{
return (typeid(other) == typeid(this)) ? true : false;
return (MakeHash(GetName()) == MakeHash(other->GetName())) ? true : false;
}
virtual bool Ignore()
{
return false;
}
virtual void Dump() = 0;
virtual const char *GetName() = 0;
};
struct IgnoreState : public State
{
virtual bool Ignore()
{
return true;
}
virtual void Dump()
{
}
};
typedef std::list<State*> StateList;
@ -53,6 +83,8 @@ namespace
State *cs = va_arg(argptr, State*);
if (!cs)
break;
if (cs->Ignore())
continue;
requiredstates.push_back(cs);
}
va_end(argptr);
@ -112,19 +144,21 @@ namespace
#define MAKE_STATE(name) struct name : State { \
virtual void Dump() { \
std::cout << " " << #name << std::endl; } \
const char *GetName() { return #name; } \
};
#define MAKE_STATE_1(name, p1_type) struct name : State { \
p1_type m_Param1; \
name(p1_type param1) : m_Param1(param1) {} \
virtual bool IsEqual(State *other) { \
name *other2 = dynamic_cast<name*>(other); \
if (!other2) \
if (MakeHash(GetName()) != MakeHash(other->GetName())) \
return false; \
name *other2 = static_cast<name*>(other); \
return other2->m_Param1 == m_Param1;\
} \
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << std::endl; } \
const char *GetName() { return #name; } \
}
#define MAKE_STATE_2(name, p1_type, p2_type) struct name : State { \
@ -132,13 +166,14 @@ namespace
p2_type m_Param2; \
name(p1_type param1, p2_type param2) : m_Param1(param1), m_Param2(param2) {} \
virtual bool IsEqual(State *other) { \
name *other2 = dynamic_cast<name*>(other); \
if (!other2) \
if (MakeHash(GetName()) != MakeHash(other->GetName())) \
return false; \
name *other2 = static_cast<name*>(other); \
return other2->m_Param1 == m_Param1 && other2->m_Param2 == m_Param2;\
} \
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << "; Param2=" << m_Param2 << std::endl; } \
const char *GetName() { return #name; } \
}
#define MAKE_STATE_3(name, p1_type, p2_type, p3_type) struct name : State { \
@ -147,13 +182,31 @@ namespace
p3_type m_Param3; \
name(p1_type param1, p2_type param2, p3_type param3) : m_Param1(param1), m_Param2(param2), m_Param3(param3) {} \
virtual bool IsEqual(State *other) { \
name *other2 = dynamic_cast<name*>(other); \
if (!other2) \
if (MakeHash(GetName()) != MakeHash(other->GetName())) \
return false; \
name *other2 = static_cast<name*>(other); \
return other2->m_Param1 == m_Param1 && other2->m_Param2 == m_Param2 && other2->m_Param3 == m_Param3;\
} \
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << "; Param2=" << m_Param2 << "; Param3=" << m_Param3 << std::endl; } \
const char *GetName() { return #name; } \
}
#define MAKE_STATE_4(name, p1_type, p2_type, p3_type, p4_type) struct name : State { \
p1_type m_Param1; \
p2_type m_Param2; \
p3_type m_Param3; \
p4_type m_Param4; \
name(p1_type param1, p2_type param2, p3_type param3, p4_type param4) : m_Param1(param1), m_Param2(param2), m_Param3(param3), m_Param4(param4) {} \
virtual bool IsEqual(State *other) { \
if (MakeHash(GetName()) != MakeHash(other->GetName())) \
return false; \
name *other2 = static_cast<name*>(other); \
return other2->m_Param1 == m_Param1 && other2->m_Param2 == m_Param2 && other2->m_Param3 == m_Param3 && other2->m_Param4 == m_Param4;\
} \
virtual void Dump() { \
std::cout << " " << #name << "; Param1=" << m_Param1 << "; Param2=" << m_Param2 << "; Param3=" << m_Param3 << "; Param4=" << m_Param4 << std::endl; } \
const char *GetName() { return #name; } \
}
#define CHECK_COND(c, err) if (!(c)) { error = err; return false; }

View File

@ -0,0 +1,1229 @@
#include <string>
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testevents.h"
#include "sh_memory.h"
#include "sh_pagealloc.h"
#include "sourcehook_pibuilder.h"
// TESTHOOKMANGEN
// Test automatic hookman generation
// Tests void and non-void functions
// 0 to 6 params:
// integer-type, float-type, plain-old-data struct and objects with ctors/dtors
// both byval and byref
// also tests ignore/supercede
// also tests recalls
// :TODO: test override as well
namespace
{
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
SourceHook::IHookManagerAutoGen *g_HMAGPtr;
// PtrBuf(ptr) gives ptrs unique numbers
// in the order they appear
SourceHook::List<const void*> g_PtrHash;
bool g_Inside_LeafFunc = false; // inside a hook or a func
bool g_Silent_CtorDtor = false; // inside a hook or a func
// POD / Object types
template <int MYSIZE>
struct POD
{
char x[MYSIZE];
bool operator==(const POD<MYSIZE> &other)
{
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
}
bool operator==(char other)
{
for (int i = 0; i < MYSIZE; ++i)
{
if (x[i] != other)
return false;
}
return true;
}
};
template <int MYSIZE>
std::ostream& operator <<(std::ostream &os, const POD<MYSIZE> &obj)
{
os << "Some POD!";
return os;
}
MAKE_STATE_1(State_ObjOCtor_Called, int /*MYSIZE*/);
MAKE_STATE_1(State_ObjCCtor_Called, int /*MYSIZE*/);
MAKE_STATE_1(State_ObjODtor_Called, int /*MYSIZE*/);
MAKE_STATE_1(State_ObjAssignOp_Called, int /*MYSIZE*/);
template <int MYSIZE>
struct Object
{
char x[MYSIZE];
Object(char initch)
{
memset(reinterpret_cast<void*>(x), initch, MYSIZE);
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
}
Object()
{
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
}
Object(const Object<MYSIZE> & other)
{
memcpy(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE);
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
ADD_STATE(State_ObjCCtor_Called(MYSIZE));
}
~Object()
{
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
ADD_STATE(State_ObjODtor_Called(MYSIZE));
}
Object & operator = (const Object &other)
{
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
ADD_STATE(State_ObjAssignOp_Called(MYSIZE));
memcpy(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE);
return *this;
}
bool operator==(const Object<MYSIZE> &other)
{
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
}
};
template <int MYSIZE>
std::ostream& operator <<(std::ostream &os, const Object<MYSIZE> &obj)
{
os << "Some Obj" << static_cast<int>(obj.x[0]);
return os;
}
// Because of some weird bug in MSVC < 1400
#define MAKE_PODRET(size) \
struct PodRet##size \
{ \
POD<size> actPod; \
bool operator==(const PodRet##size &other) { return actPod == other.actPod; } \
bool operator==(char other) { return actPod == other; } \
}; \
std::ostream& operator <<(std::ostream &os, const PodRet##size &obj) \
{ \
os << obj.actPod; \
return os; \
} \
template <> struct MakeRet< PodRet##size > \
{ \
static PodRet##size Do(int a) \
{ \
PodRet##size x; \
memset(reinterpret_cast<void*>(x.actPod.x), a, size); \
return x; \
} \
};
#define MAKE_OBJRET(size) \
struct ObjRet##size \
{ \
Object<size> actObj; \
bool operator==(const ObjRet##size &other) { return actObj == other.actObj; } \
bool operator==(char other) { return actObj == other; } \
}; \
std::ostream& operator <<(std::ostream &os, const ObjRet##size &obj) \
{ \
os << obj.actObj; \
return os; \
} \
template <> struct MakeRet< ObjRet##size > \
{ \
static ObjRet##size Do(int a) NO_OPTIMIZE \
{ \
ObjRet##size *x = new ObjRet##size; /* ptr: otherwise gcc optimizes away the temp obj */ \
CAutoPtrDestruction< ObjRet##size > apd(x); \
memset(reinterpret_cast<void*>(x->actObj.x), a, size); \
return *x; \
} \
};
// "Increment" something: (reproducible change for recall tests)
// integer: ++
// float: += 1.3
// pod/object: x[i]++, 0 <= i < MYSIZE
template <class T>
struct Increment
{
static void Incr(T &what)
{
++what;
}
};
template<>
struct Increment<float>
{
static void Incr(float &what)
{
what += 1.3f;
}
};
template<>
struct Increment<double>
{
static void Incr(double &what)
{
what += 1.3;
}
};
template<int MYSIZE>
struct Increment< POD<MYSIZE> >
{
static void Incr(POD<MYSIZE> &what)
{
for (int i = 0; i < MYSIZE; ++i)
++ what.x[i];
}
};
template<int MYSIZE>
struct Increment< Object<MYSIZE> >
{
static void Incr(Object<MYSIZE> &what)
{
for (int i = 0; i < MYSIZE; ++i)
++ what.x[i];
}
};
template<>
struct Increment<std::string>
{
static void Incr(std::string &what)
{
what += "!";
}
};
#include "testhookmangen.h"
template <class T>
int PtrBuf(T ptr)
{
int a = 0;
const void *vptr = reinterpret_cast<const void*>(ptr);
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end(); ++iter)
{
if (*iter == vptr)
return a;
else
++a;
}
g_PtrHash.push_back(vptr);
return static_cast<int>(g_PtrHash.size()) - 1;
}
template <class T>
T PtrBufPtr(T ptr)
{
PtrBuf(ptr);
return ptr;
}
void PtrBuf_Clear(int leave_in = 0)
{
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end();)
{
if (--leave_in < 0)
iter = g_PtrHash.erase(iter);
else
++iter;
}
}
// MyDelegate base class for other delegates
class MyDelegate : public SourceHook::ISHDelegate
{
// Unneeded
// because we don't use old SH_REMOVE_HOOK syntax
virtual bool IsEqual(SourceHook::ISHDelegate *pOtherDeleg)
{
return false;
}
virtual void DeleteThis()
{
delete this;
}
};
THGM_MAKE_TEST0_void(0);
THGM_SETUP_PI0(0);
THGM_MAKE_TEST1_void(1, char);
THGM_SETUP_PI1(1, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(2, short);
THGM_SETUP_PI1(2, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(3, int);
THGM_SETUP_PI1(3, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(4, float);
THGM_SETUP_PI1(4, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(5, double);
THGM_SETUP_PI1(5, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST5_void(6, char, short, int, float, double);
THGM_SETUP_PI5(6,
char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_MAKE_TEST2_void(7, char&, double&);
THGM_SETUP_PI2(7,
char&, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByRef,
double&, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByRef
);
THGM_MAKE_TEST1_void(8, POD<7>);
THGM_SETUP_PI1(8, POD<7>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(9, POD<600>);
THGM_SETUP_PI1(9, POD<600>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(10, POD<600> &);
THGM_SETUP_PI1(10, POD<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef);
THGM_MAKE_TEST2_void(11, Object<3>, Object<600>&);
THGM_SETUP_PI2(11,
Object<3>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor,
Object<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor
);
THGM_MAKE_TEST0(101, char);
THGM_SETUP_PI0(101);
THGM_SETUP_RI(101, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(102, short);
THGM_SETUP_PI0(102);
THGM_SETUP_RI(102, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(103, int);
THGM_SETUP_PI0(103);
THGM_SETUP_RI(103, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(104, float);
THGM_SETUP_PI0(104);
THGM_SETUP_RI(104, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(105, double);
THGM_SETUP_PI0(105);
THGM_SETUP_RI(105, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
// pod 1-13
MAKE_PODRET(1);
THGM_MAKE_TEST1(106, PodRet1, int);
THGM_SETUP_PI1(106,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(106, PodRet1, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
MAKE_PODRET(4);
THGM_MAKE_TEST1(107, PodRet4, int);
THGM_SETUP_PI1(107,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(107, PodRet4, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
MAKE_PODRET(8);
THGM_MAKE_TEST1(108, PodRet8, int);
THGM_SETUP_PI1(108,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(108, PodRet8, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
MAKE_PODRET(13);
THGM_MAKE_TEST1(109, PodRet13, int);
THGM_SETUP_PI1(109,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(109, PodRet13, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
MAKE_OBJRET(13);
THGM_MAKE_TEST1(110, ObjRet13, int);
THGM_SETUP_PI1(110,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(110, ObjRet13, SourceHook::PassInfo::PassType_Object,
SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
MAKE_OBJRET(111);
ObjRet111 g_O111_0;
ObjRet111 g_O111_1;
ObjRet111 g_O111_2;
ObjRet111 g_O111_3;
ObjRet111 g_O111_4;
template <>
struct MakeRet< ObjRet111& >
{
static ObjRet111 &Do(int a)
{
switch (a)
{
case 0:
return g_O111_0;
case 1:
return g_O111_1;
case 2:
return g_O111_2;
case 3:
return g_O111_3;
default:
return g_O111_4;
}
}
};
THGM_MAKE_TEST0(111, ObjRet111& );
THGM_SETUP_PI0(111);
THGM_SETUP_RI(111, ObjRet111& , SourceHook::PassInfo::PassType_Object,
SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
THGM_MAKE_TEST3_void(150, int, double, int);
THGM_SETUP_PI3(150,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
// vafmt tests
THGM_MAKE_TEST0_vafmt_void(200);
THGM_SETUP_PI0(200);
THGM_MAKE_TEST1_vafmt_void(201, char);
THGM_SETUP_PI1(201, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_vafmt_void(203, int);
THGM_SETUP_PI1(203, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST5_vafmt_void(206, char, short, int, float, double);
THGM_SETUP_PI5(206,
char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_MAKE_TEST2_vafmt_void(207, char&, double&);
THGM_SETUP_PI2(207,
char&, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByRef,
double&, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByRef
);
THGM_MAKE_TEST1_vafmt_void(208, POD<7>);
THGM_SETUP_PI1(208, POD<7>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_vafmt_void(210, POD<600> &);
THGM_SETUP_PI1(210, POD<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef)
THGM_MAKE_TEST1_vafmt(211, int, int);
THGM_SETUP_PI1(211,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(211, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_vafmt(212, double, int);
THGM_SETUP_PI1(212,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(212, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_vafmt(213, PodRet8, int);
THGM_SETUP_PI1(213,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_SETUP_RI(213, PodRet8, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_vafmt_void(214, Object<133>);
THGM_SETUP_PI1(214, Object<133>, SourceHook::PassInfo::PassType_Object,
SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
MAKE_STATE(State_Hello_Func4_Called);
MAKE_STATE(State_Hello_Func79_Called);
MAKE_STATE(State_Hello_Func4_PreHook);
MAKE_STATE(State_Hello_Func79_PreHook);
// Test for larger vtable indices
class Hello
{
public:
virtual void Func0() {}
virtual void Func1() {}
virtual void Func2() {}
virtual void Func3() {}
virtual void Func4()
{
ADD_STATE(State_Hello_Func4_Called);
}
virtual void Func5() {}
virtual void Func6() {}
virtual void Func7() {}
virtual void Func8() {}
virtual void Func9() {}
virtual void Func10() {}
virtual void Func11() {}
virtual void Func12() {}
virtual void Func13() {}
virtual void Func14() {}
virtual void Func15() {}
virtual void Func16() {}
virtual void Func17() {}
virtual void Func18() {}
virtual void Func19() {}
virtual void Func20() {}
virtual void Func21() {}
virtual void Func22() {}
virtual void Func23() {}
virtual void Func24() {}
virtual void Func25() {}
virtual void Func26() {}
virtual void Func27() {}
virtual void Func28() {}
virtual void Func29() {}
virtual void Func30() {}
virtual void Func31() {}
virtual void Func32() {}
virtual void Func33() {}
virtual void Func34() {}
virtual void Func35() {}
virtual void Func36() {}
virtual void Func37() {}
virtual void Func38() {}
virtual void Func39() {}
virtual void Func40() {}
virtual void Func41() {}
virtual void Func42() {}
virtual void Func43() {}
virtual void Func44() {}
virtual void Func45() {}
virtual void Func46() {}
virtual void Func47() {}
virtual void Func48() {}
virtual void Func49() {}
virtual void Func50() {}
virtual void Func51() {}
virtual void Func52() {}
virtual void Func53() {}
virtual void Func54() {}
virtual void Func55() {}
virtual void Func56() {}
virtual void Func57() {}
virtual void Func58() {}
virtual void Func59() {}
virtual void Func60() {}
virtual void Func61() {}
virtual void Func62() {}
virtual void Func63() {}
virtual void Func64() {}
virtual void Func65() {}
virtual void Func66() {}
virtual void Func67() {}
virtual void Func68() {}
virtual void Func69() {}
virtual void Func70() {}
virtual void Func71() {}
virtual void Func72() {}
virtual void Func73() {}
virtual void Func74() {}
virtual void Func75() {}
virtual void Func76() {}
virtual void Func77() {}
virtual void Func78() {}
virtual void Func79()
{
ADD_STATE(State_Hello_Func79_Called);
}
};
class Hello_Func4_Deleg : public MyDelegate
{
virtual void Func()
{
ADD_STATE(State_Hello_Func4_PreHook);
}
};
class Hello_Func79_Deleg : public MyDelegate
{
int a;
virtual void Func()
{
ADD_STATE(State_Hello_Func79_PreHook);
}
};
bool Tests1(std::string &error)
{
THGM_DO_TEST_void(0, ());
THGM_DO_TEST_void(1, (100));
THGM_DO_TEST_void(2, (0x1F00));
THGM_DO_TEST_void(3, (0x1F000000));
THGM_DO_TEST_void(4, (0.5f));
THGM_DO_TEST_void(5, (5.5));
THGM_DO_TEST_void(6, (100, 0x1f00, 0x1f000000, 0.5f, 5.5));
return true;
}
bool Tests2(std::string &error)
{
char a = 5;
double b = 233.33;
THGM_DO_TEST_void(7, (a, b));
POD<7> pod7 = MakeRet< POD<7> >::Do(78);
THGM_DO_TEST_void(8, (pod7));
POD<600> pod600 = MakeRet< POD<600> >::Do(34);
THGM_DO_TEST_void(9, (pod600));
THGM_DO_TEST_void(10, (pod600));
// Test11: Special: constructors/destructors
PtrBuf_Clear();
Object<3> *obj3_real = new Object<3>(33);
Object<600> *obj600_real = new Object<600>(21);
Object<3> & obj3 = *obj3_real;
Object<600> & obj600 = *obj600_real;
CHECK_STATES((&g_States,
new State_ObjOCtor_Called(3),
new State_ObjOCtor_Called(600),
NULL), "Test11 Part0");
setuppi_11();
SourceHook::HookManagerPubFunc myhookman11 = g_HMAGPtr->MakeHookMan(protoinfo_11, 0, 0); \
CAutoReleaseHookMan arhm_11(myhookman11); \
int hook1_11, hook2_11, hook3_11, hook4_11;
TestClass11 *pTest11 = new TestClass11;
CAutoPtrDestruction<TestClass11> apd11(pTest11);
/* no hooks - no hooks */
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part1");
g_Inside_LeafFunc = false;
/* hook1 - no hooks */
THGM_ADD_HOOK(11, 1);
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(1, pTest11, 0, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part2");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(11, 1);
/* hook1, hook2 - hook3, hook4 */
THGM_ADD_HOOK(11, 1);
THGM_ADD_HOOK(11, 2);
THGM_ADD_HOOK(11, 3);
THGM_ADD_HOOK(11, 4);
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(1, pTest11, 0, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(2, pTest11, 1, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(3, pTest11, 2, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(4, pTest11, 3, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part3");
g_Inside_LeafFunc = false;
/* hook1 - hook3, hook4 WITH RECALLS */
THGM_REMOVE_HOOK(11, 2);
PtrBuf_Clear();
TestClass11::ms_DoRecall = true;
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg_11(1, pTest11, 0 /* first deleg ptr */, ParamState_m11 (obj3, obj600)),
// recall !
// second hookfunc -> new copy
new State_ObjCCtor_Called(3),
// in second hookfunc now
// -> calls orig func
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)(1)),
new State_ObjODtor_Called(3),
// calls first posthook
new State_ObjCCtor_Called(3),
new State_Deleg_11(3, pTest11, 1 /* second deleg ptr */, ParamState_m11 (obj3, obj600)(1)),
// recall!
// third hookfunc -> new copy
new State_ObjCCtor_Called(3),
// calls second posthook
new State_ObjCCtor_Called(3),
new State_Deleg_11(4, pTest11, 2 /* third deleg ptr */, ParamState_m11 (obj3, obj600)(2)),
// recall!
// fourth hookfunc -> new copy
new State_ObjCCtor_Called(3),
// has nothing to do though!
// fourth hookfunc done -> ret
new State_ObjODtor_Called(3),
// third hookfunc done -> ret
new State_ObjODtor_Called(3),
// ret from hookhandler which did the recall
new State_ObjODtor_Called(3),
// second hookfunc done -> ret
new State_ObjODtor_Called(3),
// ret from hookhandler which did the recall
new State_ObjODtor_Called(3),
// deleg1's instance
new State_ObjODtor_Called(3),
// first hookfunc done -> ret
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part4");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(11, 1);
THGM_REMOVE_HOOK(11, 3);
THGM_REMOVE_HOOK(11, 4);
delete obj3_real;
delete obj600_real;
CHECK_STATES((&g_States,
new State_ObjODtor_Called(3),
new State_ObjODtor_Called(600),
NULL), "Test11 Part100");
return true;
}
bool Tests3(std::string &error)
{
THGM_DO_TEST(101, ());
THGM_DO_TEST(102, ());
THGM_DO_TEST(103, ());
THGM_DO_TEST(104, ());
THGM_DO_TEST(105, ());
// pod returns
THGM_DO_TEST(106, (5));
THGM_DO_TEST(107, (5));
THGM_DO_TEST(108, (5));
THGM_DO_TEST(109, (5));
return true;
}
bool Tests4(std::string &error)
{
// Test110: Special: constructors/destructors on return
PtrBuf_Clear();
ObjRet13 *obj13_real = new ObjRet13;
ObjRet13 &obj13 = *obj13_real;
CHECK_STATES((&g_States,
new State_ObjOCtor_Called(13),
NULL), "Test110 Part0");
setuppi_110();
setupri_110();
SourceHook::HookManagerPubFunc myhookman110 = g_HMAGPtr->MakeHookMan(protoinfo_110, 0, 0); \
CAutoReleaseHookMan arhm_110(myhookman110); \
int hook1_110, hook2_110, hook3_110, hook4_110;
TestClass110 *pTest110 = new TestClass110;
CAutoPtrDestruction<TestClass110> apd110(pTest110);
/* no hooks - no hooks */
PtrBuf_Clear();
obj13 = pTest110->Func(5);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_Func110(pTest110, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in our stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
NULL), "Test" "110" " Part1");
g_Inside_LeafFunc = false;
/* hook1 - no hooks */
THGM_ADD_HOOK(110, 1);
PtrBuf_Clear();
obj13 = pTest110->Func(5);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
// HookFunc: construct orig_ret/override_ret/plugin_ret objects
new State_ObjOCtor_Called(13),
new State_ObjOCtor_Called(13),
new State_ObjOCtor_Called(13),
// Calling delegate
new State_Deleg_110(1, pTest110, 0, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// Calling orig function Func110
new State_Func110(pTest110, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: orig_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// hookfunc is returning:
new State_ObjCCtor_Called(13), // copy to temp object in our stack
// hookfunc cleans up its stack -> destroys plugin_ret/override_ret/orig_ret
new State_ObjODtor_Called(13),
new State_ObjODtor_Called(13),
new State_ObjODtor_Called(13),
// we are in our function: assign
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
NULL), "Test" "11" " Part2");
CHECK_COND(obj13 == 0, "Test" "11" " Part 2.1");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(110, 1);
/* hook1, hook2 - hook3, hook4 */
THGM_ADD_HOOK(110, 1);
THGM_ADD_HOOK(110, 2);
THGM_ADD_HOOK(110, 3);
THGM_ADD_HOOK(110, 4);
PtrBuf_Clear();
obj13 = pTest110->Func(5);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
// HookFunc: construct orig_ret/override_ret/plugin_ret objects
new State_ObjOCtor_Called(13),
new State_ObjOCtor_Called(13),
new State_ObjOCtor_Called(13),
// Calling delegate1
new State_Deleg_110(1, pTest110, 0, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// Calling delegate2
new State_Deleg_110(2, pTest110, 1, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// hookfunc finds out that the hook wanted to SUPERCEDE --> copy to override_Ret
new State_ObjAssignOp_Called(13),
// SUPERCEDE -> orig function is not called
// instead: orig_ret = override_ret
new State_ObjAssignOp_Called(13),
// Calling delegate3
new State_Deleg_110(3, pTest110, 2, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// Calling delegate4
new State_Deleg_110(4, pTest110, 3, ParamState_m110 (5)),
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
// back in hookfunc
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
// hookfunc finds out that the hook wanted to SUPERCEDE --> copy to override_Ret (yes really, we overwrite the old value!)
new State_ObjAssignOp_Called(13),
// hookfunc is returning:
new State_ObjCCtor_Called(13), // copy to temp object in our stack
// hookfunc cleans up its stack -> destroys plugin_ret/override_ret/orig_ret
new State_ObjODtor_Called(13),
new State_ObjODtor_Called(13),
new State_ObjODtor_Called(13),
// we are in our function: assign
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
NULL), "Test" "11" " Part3");
CHECK_COND(obj13 == 4, "Test" "11" " Part 3.1");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(110, 1);
THGM_REMOVE_HOOK(110, 2);
THGM_REMOVE_HOOK(110, 3);
THGM_REMOVE_HOOK(110, 4);
delete obj13_real;
CHECK_STATES((&g_States,
new State_ObjODtor_Called(13),
NULL), "Test110 Part100");
THGM_DO_TEST_void(150, (5, 5.5, 6));
return true;
}
bool Tests5(std::string &error)
{
// RefRet
THGM_DO_TEST(111, ());
// Vafmt
THGM_DO_TEST_void(200, ("Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST_void(201, (100, "Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST_void(203, (0x1F000000, "Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST_void(206, (100, 0x1f00, 0x1f000000, 0.5f, 5.5, "Hello %s%d%s", "BA", 1, "L!"));
char a = 5;
double b = 233.33;
THGM_DO_TEST_void(207, (a, b, "Hello %s%d%s", "BA", 1, "L!"));
POD<7> pod7 = MakeRet< POD<7> >::Do(78);
THGM_DO_TEST_void(208, (pod7, "Hello %s%d%s", "BA", 1, "L!"));
POD<600> pod600 = MakeRet< POD<600> >::Do(34);
THGM_DO_TEST_void(210, (pod600, "Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST(211, (5, "Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST(212, (5, "Hello %s%d%s", "BA", 1, "L!"));
THGM_DO_TEST(213, (5, "Hello %s%d%s", "BA", 1, "L!"));
// Silence Object's ctors/dtors: we only want a forced byref param
g_Silent_CtorDtor = true;
Object<133> *myobj133 = new Object<133>;
THGM_DO_TEST_void(214, (*myobj133, "Hello %s%d%s", "BA", 1, "L!"));
delete myobj133;
g_Silent_CtorDtor = false;
// Test for high vtable indices
Hello *pHello = new Hello;
SourceHook::CProtoInfoBuilder helloPi(SourceHook::ProtoInfo::CallConv_ThisCall);
SourceHook::HookManagerPubFunc helloHM_4 = g_HMAGPtr->MakeHookMan(helloPi, 0, 4);
SourceHook::HookManagerPubFunc helloHM_79 = g_HMAGPtr->MakeHookMan(helloPi, 0, 79);
pHello->Func4();
pHello->Func79();
SH_CALL(pHello, &Hello::Func4)();
SH_CALL(pHello, &Hello::Func79)();
CHECK_STATES((&g_States,
new State_Hello_Func4_Called,
new State_Hello_Func79_Called,
new State_Hello_Func4_Called,
new State_Hello_Func79_Called,
NULL), "Test" "Hello" " Part1");
int helloHook4 = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pHello),
0, helloHM_4, new Hello_Func4_Deleg, false);
int helloHook79 = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pHello),
0, helloHM_79, new Hello_Func79_Deleg, false);
pHello->Func4();
pHello->Func79();
SH_CALL(pHello, &Hello::Func4)();
SH_CALL(pHello, &Hello::Func79)();
CHECK_STATES((&g_States,
new State_Hello_Func4_PreHook,
new State_Hello_Func4_Called,
new State_Hello_Func79_PreHook,
new State_Hello_Func79_Called,
new State_Hello_Func4_Called,
new State_Hello_Func79_Called,
NULL), "Test" "Hello" " Part2");
g_SHPtr->RemoveHookByID(helloHook4);
g_SHPtr->RemoveHookByID(helloHook79);
g_HMAGPtr->ReleaseHookMan(helloHM_4);
g_HMAGPtr->ReleaseHookMan(helloHM_79);
return true;
}
}
bool TestHookManGen(std::string &error)
{
GET_SHPTR(g_SHPtr);
GET_HMAG(g_HMAGPtr, g_SHPtr);
g_PLID = 1337;
// 5 Global constructors (g_O111_*)
CHECK_STATES((&g_States,
new State_ObjOCtor_Called(111),
new State_ObjOCtor_Called(111),
new State_ObjOCtor_Called(111),
new State_ObjOCtor_Called(111),
new State_ObjOCtor_Called(111),
NULL), "GlobCtors");
if (!Tests1(error))
return false;
if (!Tests2(error))
return false;
if (!Tests3(error))
return false;
if (!Tests4(error))
return false;
if (!Tests5(error))
return false;
// Shutdown now!
// If we don't SH will auto-shutdown _after_ genc's destructor is called
// -> crash
Test_CompleteShutdown(g_SHPtr);
CHECK_COND(sizeof(PodRet1) == 1, "WTF!");
CHECK_COND(sizeof(PodRet4) == 4, "WTF!");
CHECK_COND(sizeof(PodRet8) == 8, "WTF!");
CHECK_COND(sizeof(PodRet13) == 13, "WTF!");
return true;
}
bool TestCPageAlloc(std::string &error)
{
using namespace SourceHook;
CPageAlloc alloc;
int i;
size_t ps = alloc.GetPageSize();
char *test1[8];
for (i = 0; i < 8; ++i)
test1[i] = (char*) alloc.Alloc(ps / 4);
CHECK_COND(test1[1] == test1[0] + ps/4, "Part 1.1");
CHECK_COND(test1[2] == test1[1] + ps/4, "Part 1.2");
CHECK_COND(test1[3] == test1[2] + ps/4, "Part 1.3");
CHECK_COND(test1[5] == test1[4] + ps/4, "Part 1.4");
CHECK_COND(test1[6] == test1[5] + ps/4, "Part 1.5");
CHECK_COND(test1[7] == test1[6] + ps/4, "Part 1.6");
void *test2 = alloc.Alloc(ps * 3);
alloc.SetRW(test2);
memset(test2, 0, ps * 3); // should not crash :)
alloc.SetRE(test2);
alloc.Free(test2);
// Dealloc a ps/4 block and place two ps/8 blocks into it
alloc.Free(test1[2]);
char *test3[2];
test3[0] = (char*) alloc.Alloc(ps / 8);
test3[1] = (char*) alloc.Alloc(ps / 8);
CHECK_COND(test3[0] == test1[2], "Part 2.1");
CHECK_COND(test3[1] == test1[2] + ps/8, "Part 2.2");
// Isolated
char *test4[8];
for (i = 0; i < 8; ++i)
test4[i] = (char*) alloc.AllocIsolated(ps / 4);
// -> The difference is at least one page
CHECK_COND(static_cast<size_t>(abs(test4[1] - test4[0])) >= ps, "Part 3.1");
CHECK_COND(static_cast<size_t>(abs(test4[2] - test4[1])) >= ps, "Part 3.2");
CHECK_COND(static_cast<size_t>(abs(test4[3] - test4[2])) >= ps, "Part 3.3");
CHECK_COND(static_cast<size_t>(abs(test4[5] - test4[4])) >= ps, "Part 3.4");
CHECK_COND(static_cast<size_t>(abs(test4[6] - test4[5])) >= ps, "Part 3.5");
CHECK_COND(static_cast<size_t>(abs(test4[7] - test4[6])) >= ps, "Part 3.6");
// Thus i can set everything except for test4[2] to RE and still write to test4[2]
alloc.SetRW(test4[2]);
alloc.SetRE(test4[0]);
alloc.SetRE(test4[1]);
alloc.SetRE(test4[3]);
alloc.SetRE(test4[4]);
alloc.SetRE(test4[5]);
alloc.SetRE(test4[6]);
alloc.SetRE(test4[7]);
memset((void*)test4[2], 0, ps / 4);
// alignement tests
CPageAlloc alloc1(1);
CPageAlloc alloc4(4);
CPageAlloc alloc16(16);
void *last1 = alloc1.Alloc(1);
void *last4 = alloc4.Alloc(4);
void *last16 = alloc16.Alloc(16);
void *cur;
for (int i = 0; i < 20; ++i)
{
cur = alloc1.Alloc(1);
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last1) + 1, "Part 4.1");
last1 = cur;
cur = alloc4.Alloc(1);
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last4) + 4, "Part 4.2");
last4 = cur;
cur = alloc16.Alloc(1);
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last16) + 16, "Part 4.3");
last16 = cur;
}
alloc16.Free(alloc16.Alloc(1));
return true;
}

View File

@ -0,0 +1,2192 @@
struct CAutoReleaseHookMan
{
SourceHook::HookManagerPubFunc m_Ptr;
CAutoReleaseHookMan(SourceHook::HookManagerPubFunc ptr) : m_Ptr(ptr)
{
}
~CAutoReleaseHookMan()
{
g_HMAGPtr->ReleaseHookMan(m_Ptr);
}
};
// Strip &
template <class T> struct StripRef
{
typedef T type;
};
template <class T> struct StripRef<T&>
{
typedef T type;
};
// Address of constructor/destructor
// (using wrappers)
template <class T>
class Ctor_Thunk
{
public:
void NormalConstructor()
{
new(this) T;
}
void CopyConstructor(const T &other)
{
new(this) T(other);
}
void Destructor()
{
reinterpret_cast<T*>(this)->~T();
}
const T& AssignOp(const T &other)
{
return (*reinterpret_cast<T*>(this) = other);
}
};
template <class T>
void *FindFuncAddr(T mfp)
{
union
{
T a;
void *b;
} u;
u.a = mfp;
return u.b;
}
// Reference carrier
template <class T> struct MyRefCarrier
{
typedef T type;
};
template <class T> struct MyRefCarrier<T&>
{
class type
{
T *m_StoredRef;
public:
type() : m_StoredRef(NULL)
{
}
type(T& ref) : m_StoredRef(&ref)
{
}
T& operator= (T& ref)
{
m_StoredRef = &ref;
return ref;
}
operator T& () const
{
return *m_StoredRef;
}
bool operator== (const typename MyRefCarrier<T&>::type &other)
{
return m_StoredRef == other.m_StoredRef;
}
friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier<T&>::type &obj)
{
os << *obj.m_StoredRef;
return os;
}
};
};
#if SH_COMP==SH_COMP_GCC
#define NO_OPTIMIZE __attribute__((noinline))
#else
#define NO_OPTIMIZE
#endif
// Return value maker
template <class T>
struct MakeRet
{
static T Do(int a)
{
return a;
}
};
template <int SIZE>
struct MakeRet< POD<SIZE> >
{
static POD<SIZE> Do(int a)
{
POD<SIZE> x;
memset(reinterpret_cast<void*>(x.x), a, SIZE);
return x;
}
};
// Stores parameter status
template <class T>
bool EqualToMyFmtString(T sth)
{
return false;
}
bool EqualToMyFmtString(std::string &sth)
{
if (sth == "Hello %s%d%s")
sth = "Hello BA1L!";
return true;
}
template<int dummy>
struct ParamState0
{
bool operator==(const ParamState0<dummy> &other)
{
return true
;
}
ParamState0(...)
{
}
ParamState0<dummy> & operator() (int incrsteps)
{
return *this;
}
};
std::ostream& operator <<(std::ostream &os,const ParamState0<0> &obj)
{
;
return os;
}
template<int dummy, class p1>
struct ParamState1
{
typename MyRefCarrier<p1>::type m_1;
bool operator==(const ParamState1<dummy, p1> &other)
{
return true
&& m_1 == other.m_1
;
}
ParamState1(p1 a1, ...) : m_1(a1)
{
EqualToMyFmtString(m_1);
}
ParamState1<dummy, p1> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
return *this;
}
};
template<class p1>
std::ostream& operator <<(std::ostream &os,const ParamState1<0, p1> &obj)
{
os << obj.m_1;
return os;
}
template<int dummy, class p1, class p2>
struct ParamState2
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2;
bool operator==(const ParamState2<dummy, p1, p2> &other)
{
return true
&& m_2 == other.m_2 && m_2 == other.m_2
;
}
ParamState2(p1 a1, p2 a2, ...) : m_1(a1), m_2(a2)
{
EqualToMyFmtString(m_1);
EqualToMyFmtString(m_2);
}
ParamState2<dummy, p1, p2> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p2 >::type >::Incr(m_2);
return *this;
}
};
template<class p1, class p2>
std::ostream& operator <<(std::ostream &os,const ParamState2<0, p1, p2> &obj)
{
os << obj.m_1<< obj.m_2;
return os;
}
template<int dummy, class p1, class p2, class p3>
struct ParamState3
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3;
bool operator==(const ParamState3<dummy, p1, p2, p3> &other)
{
return true
&& m_3 == other.m_3 && m_3 == other.m_3 && m_3 == other.m_3
;
}
ParamState3(p1 a1, p2 a2, p3 a3, ...) : m_1(a1), m_2(a2), m_3(a3)
{
EqualToMyFmtString(m_1);
EqualToMyFmtString(m_2);
EqualToMyFmtString(m_3);
}
ParamState3<dummy, p1, p2, p3> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p2 >::type >::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p3 >::type >::Incr(m_3);
return *this;
}
};
template<class p1, class p2, class p3>
std::ostream& operator <<(std::ostream &os,const ParamState3<0, p1, p2, p3> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4>
struct ParamState4
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4;
bool operator==(const ParamState4<dummy, p1, p2, p3, p4> &other)
{
return true
&& m_4 == other.m_4 && m_4 == other.m_4 && m_4 == other.m_4 && m_4 == other.m_4
;
}
ParamState4(p1 a1, p2 a2, p3 a3, p4 a4, ...) : m_1(a1), m_2(a2), m_3(a3), m_4(a4)
{
EqualToMyFmtString(m_1);
EqualToMyFmtString(m_2);
EqualToMyFmtString(m_3);
EqualToMyFmtString(m_4);
}
ParamState4<dummy, p1, p2, p3, p4> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p2 >::type >::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p3 >::type >::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p4 >::type >::Incr(m_4);
return *this;
}
};
template<class p1, class p2, class p3, class p4>
std::ostream& operator <<(std::ostream &os,const ParamState4<0, p1, p2, p3, p4> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4, class p5>
struct ParamState5
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4; typename MyRefCarrier<p5>::type m_5;
bool operator==(const ParamState5<dummy, p1, p2, p3, p4, p5> &other)
{
return true
&& m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5
;
}
ParamState5(p1 a1, p2 a2, p3 a3, p4 a4, p5 a5, ...) : m_1(a1), m_2(a2), m_3(a3), m_4(a4), m_5(a5)
{
EqualToMyFmtString(m_1);
EqualToMyFmtString(m_2);
EqualToMyFmtString(m_3);
EqualToMyFmtString(m_4);
EqualToMyFmtString(m_5);
}
ParamState5<dummy, p1, p2, p3, p4, p5> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p2 >::type >::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p3 >::type >::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p4 >::type >::Incr(m_4);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p5 >::type >::Incr(m_5);
return *this;
}
};
template<class p1, class p2, class p3, class p4, class p5>
std::ostream& operator <<(std::ostream &os,const ParamState5<0, p1, p2, p3, p4, p5> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4<< obj.m_5;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4, class p5, class p6>
struct ParamState6
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4; typename MyRefCarrier<p5>::type m_5; typename MyRefCarrier<p6>::type m_6;
bool operator==(const ParamState6<dummy, p1, p2, p3, p4, p5, p6> &other)
{
return true
&& m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6
;
}
ParamState6(p1 a1, p2 a2, p3 a3, p4 a4, p5 a5, p6 a6, ...) : m_1(a1), m_2(a2), m_3(a3), m_4(a4), m_5(a5), m_6(a6)
{
EqualToMyFmtString(m_1);
EqualToMyFmtString(m_2);
EqualToMyFmtString(m_3);
EqualToMyFmtString(m_4);
EqualToMyFmtString(m_5);
EqualToMyFmtString(m_6);
}
ParamState6<dummy, p1, p2, p3, p4, p5, p6> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p1 >::type >::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p2 >::type >::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p3 >::type >::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p4 >::type >::Incr(m_4);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p5 >::type >::Incr(m_5);
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p6 >::type >::Incr(m_6);
return *this;
}
};
template<class p1, class p2, class p3, class p4, class p5, class p6>
std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, p5, p6> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4<< obj.m_5<< obj.m_6;
return os;
}
#define CAT2(a, b) a##b
#define CAT3(a, b, c) a##b##c
#define CAT4(a, b, c, d) a##b##c##d
// hook1: pre ignore
// hook2: pre supercede
// hook3: post ignore
// hook4: post supercede
#define THGM_MAKE_TEST0_void(id) \
struct TestClass##id; \
typedef ParamState0<0 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id())); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, ()); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST0(id, ret_type) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState0<0 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id())); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, ()); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST0_vafmt_void(id) \
struct TestClass##id; \
typedef ParamState1<0, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, ("%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST0_vafmt(id, ret_type) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState1<0, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, ("%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI0(id) \
void setuppi_##id() \
{ \
\
}
#define THGM_MAKE_TEST1_void(id, param1) \
struct TestClass##id; \
typedef ParamState1<0, param1 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST1(id, ret_type, param1) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState1<0, param1 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST1_vafmt_void(id, param1) \
struct TestClass##id; \
typedef ParamState2<0, param1, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST1_vafmt(id, ret_type, param1) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState2<0, param1, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI1(id, p1_type, p1_passtype, p1_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_MAKE_TEST2_void(id, param1, param2) \
struct TestClass##id; \
typedef ParamState2<0, param1, param2 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST2(id, ret_type, param1, param2) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState2<0, param1, param2 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST2_vafmt_void(id, param1, param2) \
struct TestClass##id; \
typedef ParamState3<0, param1, param2, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST2_vafmt(id, ret_type, param1, param2) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState3<0, param1, param2, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI2(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p2_type), p2_passtype, p2_flags, \
(p2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_MAKE_TEST3_void(id, param1, param2, param3) \
struct TestClass##id; \
typedef ParamState3<0, param1, param2, param3 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST3(id, ret_type, param1, param2, param3) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState3<0, param1, param2, param3 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST3_vafmt_void(id, param1, param2, param3) \
struct TestClass##id; \
typedef ParamState4<0, param1, param2, param3, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST3_vafmt(id, ret_type, param1, param2, param3) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState4<0, param1, param2, param3, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI3(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p2_type), p2_passtype, p2_flags, \
(p2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p3_type), p3_passtype, p3_flags, \
(p3_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_MAKE_TEST4_void(id, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ParamState4<0, param1, param2, param3, param4 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST4(id, ret_type, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState4<0, param1, param2, param3, param4 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST4_vafmt_void(id, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ParamState5<0, param1, param2, param3, param4, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST4_vafmt(id, ret_type, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState5<0, param1, param2, param3, param4, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI4(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p2_type), p2_passtype, p2_flags, \
(p2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p3_type), p3_passtype, p3_flags, \
(p3_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p4_type), p4_passtype, p4_flags, \
(p4_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_MAKE_TEST5_void(id, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ParamState5<0, param1, param2, param3, param4, param5 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST5(id, ret_type, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState5<0, param1, param2, param3, param4, param5 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST5_vafmt_void(id, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST5_vafmt(id, ret_type, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4, p5, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI5(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags, p5_type, p5_passtype, p5_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p2_type), p2_passtype, p2_flags, \
(p2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p3_type), p3_passtype, p3_flags, \
(p3_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p4_type), p4_passtype, p4_flags, \
(p4_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p5_type), p5_passtype, p5_flags, \
(p5_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_MAKE_TEST6_void(id, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, param6 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST6(id, ret_type, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, param6 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST6_vafmt_void(id, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ParamState7<0, param1, param2, param3, param4, param5, param6, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6, std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6, "%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST6_vafmt(id, ret_type, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState7<0, param1, param2, param3, param4, param5, param6, std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6, std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6, const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6, buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (p1, p2, p3, p4, p5, p6, "%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI6(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags, p5_type, p5_passtype, p5_flags, p6_type, p6_passtype, p6_flags) \
void setuppi_##id() \
{ \
\
protoinfo_##id.AddParam(sizeof(p1_type), p1_passtype, p1_flags, \
(p1_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL, \
(p1_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p2_type), p2_passtype, p2_flags, \
(p2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL, \
(p2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p3_type), p3_passtype, p3_flags, \
(p3_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL, \
(p3_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p4_type), p4_passtype, p4_flags, \
(p4_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL, \
(p4_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p5_type), p5_passtype, p5_flags, \
(p5_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : NULL, \
(p5_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::AssignOp) : NULL \
); \
\
protoinfo_##id.AddParam(sizeof(p6_type), p6_passtype, p6_flags, \
(p6_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::NormalConstructor) : NULL, \
(p6_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::CopyConstructor) : NULL, \
(p6_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::Destructor) : NULL, \
(p6_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::AssignOp) : NULL \
); \
\
}
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
void setupri_##id() \
{ \
protoinfo_##id.SetReturnType(sizeof(ret_type), ret_passtype, ret_flags, \
(ret_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::AssignOp) : NULL \
); \
}
#define THGM_ADD_HOOK(id, num) \
CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pTest##id), \
0, myhookman##id, PtrBufPtr(new TestClass##id::Delegate(num)), num >= 3);
#define THGM_REMOVE_HOOK(id, num) \
g_SHPtr->RemoveHookByID(CAT4(hook, num, _, id));
#define THGM_CALLS_void(id, call_params) \
pTest##id->Func call_params; \
SH_CALL(pTest##id, &TestClass##id::Func) call_params;
#define THGM_DO_TEST_void(id, call_params) \
setuppi_##id(); \
SourceHook::HookManagerPubFunc myhookman##id = g_HMAGPtr->MakeHookMan(protoinfo_##id, 0, 0); \
CAutoReleaseHookMan arhm_##id(myhookman##id); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
/* hook1, hook2 - hook3, hook4 */ \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);
template<class T>
T ComparableRef(T x)
{
return x;
}
template <class T>
T* ComparableRef(T& x)
{
return &x;
}
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
CHECK_COND(ComparableRef<RetType##id>(pTest##id->Func call_params) == ComparableRef<RetType##id>(MakeRet< RetType##id >::Do(exp_ret_norm)), err " /retcallnorm"); \
CHECK_COND(ComparableRef<RetType##id>(SH_CALL(pTest##id, &TestClass##id::Func) call_params) == ComparableRef<RetType##id>(MakeRet< RetType##id >::Do(exp_ret_shcall)), err " /retcallshcall");
#define THGM_DO_TEST(id, call_params) \
setuppi_##id(); \
setupri_##id(); \
SourceHook::HookManagerPubFunc myhookman##id = g_HMAGPtr->MakeHookMan(protoinfo_##id, 0, 0); \
CAutoReleaseHookMan arhm_##id(myhookman##id); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS(id, call_params, 0, 0, "Part1"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part4"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 2, 0, "Part5"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
/* hook1, hook2 - hook3, hook4 */ \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS(id, call_params, 4, 0, "Part7"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);

View File

@ -0,0 +1,584 @@
struct CAutoReleaseHookMan
{
SourceHook::HookManagerPubFunc m_Ptr;
CAutoReleaseHookMan(SourceHook::HookManagerPubFunc ptr) : m_Ptr(ptr)
{
}
~CAutoReleaseHookMan()
{
g_HMAGPtr->ReleaseHookMan(m_Ptr);
}
};
// Strip &
template <class T> struct StripRef
{
typedef T type;
};
template <class T> struct StripRef<T&>
{
typedef T type;
};
// Address of constructor/destructor
// (using wrappers)
template <class T>
class Ctor_Thunk
{
public:
void NormalConstructor()
{
new(this) T;
}
void CopyConstructor(const T &other)
{
new(this) T(other);
}
void Destructor()
{
reinterpret_cast<T*>(this)->~T();
}
const T& AssignOp(const T &other)
{
return (*reinterpret_cast<T*>(this) = other);
}
};
template <class T>
void *FindFuncAddr(T mfp)
{
union
{
T a;
void *b;
} u;
u.a = mfp;
return u.b;
}
// Reference carrier
template <class T> struct MyRefCarrier
{
typedef T type;
};
template <class T> struct MyRefCarrier<T&>
{
class type
{
T *m_StoredRef;
public:
type() : m_StoredRef(NULL)
{
}
type(T& ref) : m_StoredRef(&ref)
{
}
T& operator= (T& ref)
{
m_StoredRef = &ref;
return ref;
}
operator T& () const
{
return *m_StoredRef;
}
bool operator== (const typename MyRefCarrier<T&>::type &other)
{
return m_StoredRef == other.m_StoredRef;
}
friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier<T&>::type &obj)
{
os << *obj.m_StoredRef;
return os;
}
};
};
#if SH_COMP==SH_COMP_GCC
#define NO_OPTIMIZE __attribute__((noinline))
#else
#define NO_OPTIMIZE
#endif
// Return value maker
template <class T>
struct MakeRet
{
static T Do(int a)
{
return a;
}
};
template <int SIZE>
struct MakeRet< POD<SIZE> >
{
static POD<SIZE> Do(int a)
{
POD<SIZE> x;
memset(reinterpret_cast<void*>(x.x), a, SIZE);
return x;
}
};
// Stores parameter status
template <class T>
bool EqualToMyFmtString(T sth)
{
return false;
}
bool EqualToMyFmtString(std::string &sth)
{
if (sth == "Hello %s%d%s")
sth = "Hello BA1L!";
return true;
}
@[$1,0,$a:
template<int dummy@[$2,1,$1:, class p$2@]>
struct ParamState$1
{
@[$2,1,$1:typename MyRefCarrier<p$2>::type m_$2; @]
bool operator==(const ParamState$1<dummy@[$2,1,$1:, p$2@]> &other)
{
return true
@[$2,1,$1: && m_$1 == other.m_$1@]
;
}
ParamState$1(@[$2,1,$1:p$2 a$2, @]...) @[$1!=0::@] @[$2,1,$1|, :m_$2(a$2)@]
{
@[$2,1,$1:
EqualToMyFmtString(m_$2);
@]
}
ParamState$1<dummy@[$2,1,$1:, p$2@]> & operator() (int incrsteps)
{
@[$1!=0:int i;@]
@[$2,1,$1:
for (i = 0; i < incrsteps; ++i)
Increment<typename StripRef< p$2 >::type >::Incr(m_$2);
@]
return *this;
}
};
@[$1!=0:template<@[$2,1,$1|, :class p$2@]>@]
std::ostream& operator <<(std::ostream &os,const ParamState$1<0@[$2,1,$1:, p$2@]> &obj)
{
@[$1!=0:os@] @[$2,1,$1:<< obj.m_$2@];
return os;
}
@]
#define CAT2(a, b) a##b
#define CAT3(a, b, c) a##b##c
#define CAT4(a, b, c, d) a##b##c##d
// hook1: pre ignore
// hook2: pre supercede
// hook3: post ignore
// hook4: post supercede
@[$1,0,$a:
#define THGM_MAKE_TEST$1_void(id@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ParamState$1<0@[$2,1,$1:, param$2@] > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST$1(id, ret_type@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState$1<0@[$2,1,$1:, param$2@] > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall);
#define THGM_MAKE_TEST$1_vafmt_void(id@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ParamState@($1+1)<0@[$2,1,$1:, param$2@], std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(@[$2,1,$1:param$2 p$2, @]const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1:p$2, @]std::string(buf)))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual void Call(@[$2,1,$1:param$2 p$2, @]const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1:p$2, @]buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1:p$2, @]"%s!", buf)); \
} \
else \
RETURN_META((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_MAKE_TEST$1_vafmt(id, ret_type@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ret_type RetType##id; \
typedef ParamState@($1+1)<0@[$2,1,$1:, param$2@], std::string > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_4(State_Deleg_##id, int /*delegnumber*/, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(@[$2,1,$1:param$2 p$2, @]const char *fmt, ...) \
{ \
g_Inside_LeafFunc = true; \
\
char buf[9999]; \
va_list ap; \
va_start(ap, fmt); \
vsnprintf(buf, 9998, fmt, ap); \
buf[9998] = 0; \
va_end(ap); \
\
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1:p$2, @]std::string(buf)))); \
\
return MakeRet< ret_type >::Do(0); \
} \
\
struct Delegate : public MyDelegate \
{ \
int m_DelegNumber; \
Delegate(int num) : m_DelegNumber(num) { } \
\
virtual ret_type Call(@[$2,1,$1:param$2 p$2, @]const char *buf) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg_##id(m_DelegNumber, META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1:p$2, @]buf))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber), &TestClass##id::Func, (@[$2,1,$1:p$2, @]"%s!", buf)); \
} \
else \
RETURN_META_VALUE((m_DelegNumber & 1) ? MRES_IGNORED : MRES_SUPERCEDE, MakeRet< ret_type >::Do(m_DelegNumber)); \
} \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
SourceHook::CProtoInfoBuilder protoinfo_##id(SourceHook::ProtoInfo::CallConv_ThisCall | SourceHook::ProtoInfo::CallConv_HasVafmt);
#define THGM_SETUP_PI$1(id@[$2,1,$1:, p$2_type, p$2_passtype, p$2_flags@]) \
void setuppi_##id() \
{ \
@[$2,1,$1: \
protoinfo_##id.AddParam(sizeof(p$2_type), p$2_passtype, p$2_flags, \
(p$2_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::NormalConstructor) : NULL, \
(p$2_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::CopyConstructor) : NULL, \
(p$2_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::Destructor) : NULL, \
(p$2_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::AssignOp) : NULL \
); \
@] \
}
@]
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
void setupri_##id() \
{ \
protoinfo_##id.SetReturnType(sizeof(ret_type), ret_passtype, ret_flags, \
(ret_flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : NULL, \
(ret_flags & SourceHook::PassInfo::PassFlag_AssignOp) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::AssignOp) : NULL \
); \
}
#define THGM_ADD_HOOK(id, num) \
CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pTest##id), \
0, myhookman##id, PtrBufPtr(new TestClass##id::Delegate(num)), num >= 3);
#define THGM_REMOVE_HOOK(id, num) \
g_SHPtr->RemoveHookByID(CAT4(hook, num, _, id));
#define THGM_CALLS_void(id, call_params) \
pTest##id->Func call_params; \
SH_CALL(pTest##id, &TestClass##id::Func) call_params;
#define THGM_DO_TEST_void(id, call_params) \
setuppi_##id(); \
SourceHook::HookManagerPubFunc myhookman##id = g_HMAGPtr->MakeHookMan(protoinfo_##id, 0, 0); \
CAutoReleaseHookMan arhm_##id(myhookman##id); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
/* hook1, hook2 - hook3, hook4 */ \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);
template<class T>
T ComparableRef(T x)
{
return x;
}
template <class T>
T* ComparableRef(T& x)
{
return &x;
}
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
CHECK_COND(ComparableRef<RetType##id>(pTest##id->Func call_params) == ComparableRef<RetType##id>(MakeRet< RetType##id >::Do(exp_ret_norm)), err " /retcallnorm"); \
CHECK_COND(ComparableRef<RetType##id>(SH_CALL(pTest##id, &TestClass##id::Func) call_params) == ComparableRef<RetType##id>(MakeRet< RetType##id >::Do(exp_ret_shcall)), err " /retcallshcall");
#define THGM_DO_TEST(id, call_params) \
setuppi_##id(); \
setupri_##id(); \
SourceHook::HookManagerPubFunc myhookman##id = g_HMAGPtr->MakeHookMan(protoinfo_##id, 0, 0); \
CAutoReleaseHookMan arhm_##id(myhookman##id); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS(id, call_params, 0, 0, "Part1"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part4"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 2, 0, "Part5"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
/* hook1, hook2 - hook3, hook4 */ \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg_##id(2, pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS(id, call_params, 4, 0, "Part7"); \
CHECK_STATES((&g_States, \
new State_Deleg_##id(1, pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg_##id(3, pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg_##id(4, pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);

View File

@ -49,6 +49,7 @@
#define MMIFACE_SOURCEHOOK "ISourceHook" /**< ISourceHook Pointer */
#define MMIFACE_PLMANAGER "IPluginManager" /**< SourceMM Plugin Functions */
#define MMIFACE_SH_HOOKMANAUTOGEN "IHookManagerAutoGen" /**< SourceHook::IHookManagerAutoGen Pointer */
#define IFACE_MAXNUM 999 /**< Maximum interface version */
namespace SourceMM

View File

@ -17,7 +17,7 @@ HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
sourcehook.cpp episode1/console.cpp episode1/provider_ep1.cpp episode1/vsp_listener.cpp
sourcehook.cpp sourcehook_hookmangen.cpp episode1/console.cpp episode1/provider_ep1.cpp episode1/vsp_listener.cpp
LINK = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
@ -56,6 +56,7 @@ all:
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
ln -sf $(SMM_ROOT)/sourcehook/sourcehook_hookmangen.cpp sourcehook_hookmangen.cpp
$(MAKE) -f Makefile.ep1 sourcemm
rm -rf $(BINARY)
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)

View File

@ -17,7 +17,7 @@ HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
OBJECTS = metamod.cpp metamod_util.cpp metamod_console.cpp metamod_oslink.cpp metamod_plugins.cpp \
sourcehook.cpp episode2/console.cpp episode2/provider_ep2.cpp episode2/vsp_listener.cpp
sourcehook.cpp sourcehook_hookmangen.cpp episode2/console.cpp episode2/provider_ep2.cpp episode2/vsp_listener.cpp
LINK = $(HL2SDK)/linux_sdk/tier1_i486.a vstdlib_i486.so tier0_i486.so -static-libgcc
@ -56,6 +56,7 @@ all:
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
ln -sf $(SMM_ROOT)/sourcehook/sourcehook.cpp sourcehook.cpp
ln -sf $(SMM_ROOT)/sourcehook/sourcehook_hookmangen.cpp sourcehook_hookmangen.cpp
$(MAKE) -f Makefile.ep2 sourcemm
rm -rf $(BINARY)
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)

View File

@ -331,6 +331,11 @@
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
>
</File>
<File
RelativePath="..\..\..\sourcehook\sourcehook_hookmangen.cpp"
>
</File>
</Filter>
</Files>
<Globals>

View File

@ -327,6 +327,10 @@
RelativePath="..\..\..\sourcehook\sourcehook.cpp"
>
</File>
<File
RelativePath="..\..\..\sourcehook\sourcehook_hookmangen.cpp"
>
</File>
</Filter>
</Files>
<Globals>

View File

@ -94,6 +94,7 @@ CreateInterfaceFn physics_factory = NULL;
CreateInterfaceFn filesystem_factory = NULL;
CGlobalVars *gpGlobals = NULL;
CSourceHookImpl g_SourceHook;
CHookManagerAutoGen g_SH_HookManagerAutoGen(&g_SourceHook);
ISourceHook *g_SHPtr = &g_SourceHook;
PluginId g_PLID = Pl_Console;
META_RES last_meta_res;
@ -1090,6 +1091,14 @@ void *MetamodSource::MetaFactory(const char *iface, int *ret, PluginId *id)
}
return static_cast<void *>(static_cast<ISmmPluginManager *>(&g_PluginMngr));
}
else if (strcmp(iface, MMIFACE_SH_HOOKMANAUTOGEN) == 0)
{
if (ret)
{
*ret = IFACE_OK;
}
return static_cast<void *>(static_cast<SourceHook::IHookManagerAutoGen *>(&g_SH_HookManagerAutoGen));
}
CPluginManager::CPlugin *pl;
List<IMetamodListener *>::iterator event;

View File

@ -37,6 +37,7 @@
#include <interface.h>
#include <eiface.h>
#include <sourcehook/sourcehook_impl.h>
#include <sourcehook/sourcehook_hookmangen.h>
#include <sourcehook/sourcehook.h>
#include <ISmmPlugin.h>
#include "metamod_provider.h"