mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-01-19 08:52:34 +01:00
First version of automatic hookman/hookfunc generation functionality + test
Currently supports (msvc): all params, ret types: integeral, floating-point Todo: other rettypes (pod/objects, ctors/dtors), gcc support, integration with ISourceHook::AddHook --HG-- branch : hookman_autogen extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/hookman_autogen%40532
This commit is contained in:
parent
f440bbd1b2
commit
7fa9f150fb
1292
sourcehook/sourcehook_hookmangen.cpp
Normal file
1292
sourcehook/sourcehook_hookmangen.cpp
Normal file
@ -0,0 +1,1292 @@
|
||||
/* ======== 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_hookmangen.h"
|
||||
#include "sourcehook_hookmangen_x86.h"
|
||||
#include "sh_memory.h"
|
||||
|
||||
// :TODO: test BIG vtable indices
|
||||
|
||||
namespace SourceHook
|
||||
{
|
||||
namespace Impl
|
||||
{
|
||||
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_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)
|
||||
{
|
||||
return SIZE_PTR;
|
||||
}
|
||||
return static_cast<jit_int32_t>(info.size);
|
||||
}
|
||||
|
||||
// Computes size on the stack
|
||||
jit_int32_t GenContext::GetStackSize(const IntPassInfo &info)
|
||||
{
|
||||
// Align up to 4 byte boundaries
|
||||
jit_int32_t rs = GetRealSize(info);
|
||||
if (rs % 4 != 0)
|
||||
rs = (rs & ~(3)) + 4;
|
||||
return rs;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// make room on the stack
|
||||
// sub esp, <size>
|
||||
IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, GetStackSize(pi), MOD_REG);
|
||||
|
||||
// if there is a copy constructor..
|
||||
if (pi.pCopyCtor)
|
||||
{
|
||||
// save eax
|
||||
// push src addr
|
||||
// this= target addr = esp+12
|
||||
// call copy constructor
|
||||
// restore eax
|
||||
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EAX);
|
||||
IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_ECX, REG_NOIDX, REG_ESP, NOSCALE, 4);
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, param_offset);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EAX);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EDX, DownCastPtr(pi.pCopyCtor));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EDX);
|
||||
|
||||
IA32_Pop_Reg(&m_HookFunc, REG_EAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_uint32_t dwords = DownCastSize(pi.size) / 4;
|
||||
jit_uint32_t bytes = DownCastSize(pi.size) % 4;
|
||||
|
||||
// bitwise copy
|
||||
|
||||
//cld
|
||||
//push edi
|
||||
//push esi
|
||||
//lea edi, [esp+8]
|
||||
//lea esi, [ebp+<offs>]
|
||||
//if dwords
|
||||
// mov ecx, <dwords>
|
||||
// rep movsd
|
||||
//if bytes
|
||||
// mov ecx, <bytes>
|
||||
// rep movsb
|
||||
//pop esi
|
||||
//pop edi
|
||||
|
||||
IA32_Cld(&m_HookFunc);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EDI);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ESI);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
return DownCastSize(pi.size);
|
||||
}
|
||||
|
||||
// May not touch eax!
|
||||
jit_int32_t GenContext::PushParams(jit_int32_t param_base_offset)
|
||||
{
|
||||
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 += GetStackSize(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 -= GetStackSize(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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pi.flags & PassInfo::PassFlag_ByRef)
|
||||
{
|
||||
PushRef(cur_offset, pi);
|
||||
}
|
||||
else
|
||||
{
|
||||
SH_ASSERT(0, ("Unsupported!"));
|
||||
}
|
||||
added_to_stack += ret;
|
||||
}
|
||||
return added_to_stack;
|
||||
}
|
||||
|
||||
void GenContext::SaveRetVal(int v_where)
|
||||
{
|
||||
// :TODO: assign op support
|
||||
// :TODO: memory return support
|
||||
|
||||
size_t size = m_Proto.GetRet().size;
|
||||
if (size == 0)
|
||||
{
|
||||
// No return value -> nothing
|
||||
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
|
||||
{
|
||||
// size >8: return in memory
|
||||
// :TODO:
|
||||
// add flag: MSVC_RetInMemory?
|
||||
}
|
||||
}
|
||||
// :TODO: object
|
||||
}
|
||||
|
||||
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()
|
||||
// ECX = pContext
|
||||
// gcc: push ecx
|
||||
// eax = [ecx]
|
||||
// eax = [eax + 4]
|
||||
// call eax
|
||||
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// *eax = plugin_ret
|
||||
if (m_Proto.GetRet().pAssignOperator)
|
||||
{
|
||||
// lea edx, [ebp + v_plugin_ret]
|
||||
// msvc: ecx = eax <-- dest addr
|
||||
// gcc: push eax <-- dest addr
|
||||
// push edx <-- src addr
|
||||
// call it
|
||||
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_plugin_ret);
|
||||
#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_Push_Reg(&m_HookFunc, REG_EDX);
|
||||
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_uint32_t dwords = DownCastSize(m_Proto.GetRet().size) / 4;
|
||||
jit_uint32_t bytes = DownCastSize(m_Proto.GetRet().size) % 4;
|
||||
|
||||
// bitwise copy
|
||||
|
||||
//cld
|
||||
//push edi
|
||||
//push esi
|
||||
//mov edi, eax <-- destination
|
||||
//lea esi, [ebp+v_plugin_ret] <-- src
|
||||
//if dwords
|
||||
// mov ecx, <dwords>
|
||||
// rep movsd
|
||||
//if bytes
|
||||
// mov ecx, <bytes>
|
||||
// rep movsb
|
||||
//pop esi
|
||||
//pop edi
|
||||
|
||||
IA32_Cld(&m_HookFunc);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EDI);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ESI);
|
||||
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDI, REG_EAX, MOD_REG);
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_plugin_ret);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
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);
|
||||
|
||||
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_retptr);
|
||||
}
|
||||
|
||||
void GenContext::DoReturn(int v_retptr)
|
||||
{
|
||||
size_t size = m_Proto.GetRet().size;
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
// :TODO: assign op support
|
||||
// :TODO: memory return support
|
||||
|
||||
// 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().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)
|
||||
{
|
||||
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
|
||||
// :TODO:
|
||||
// add flag: MSVC_RetInMemory?
|
||||
}
|
||||
}
|
||||
// :TODO: object
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
jit_int32_t gcc_clean_bytes = PushParams(base_param_offset);
|
||||
|
||||
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);
|
||||
#endif
|
||||
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);
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
|
||||
SaveRetVal(v_plugin_ret);
|
||||
|
||||
// cleanup
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
// params + thisptr
|
||||
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG);
|
||||
#endif
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
short GenContext::GetParamsStackSize()
|
||||
{
|
||||
short acc = 0;
|
||||
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
|
||||
{
|
||||
acc += GetStackSize(m_Proto.GetParam(i));
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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*PTR_SIZE]
|
||||
// call eax
|
||||
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// push params
|
||||
jit_int32_t gcc_clean_bytes = PushParams(param_base_offs);
|
||||
|
||||
// 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, simply leave it in ecx
|
||||
#endif
|
||||
|
||||
// call
|
||||
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_vfnptr_origentry);
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
|
||||
// cleanup
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
// params + thisptr
|
||||
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG);
|
||||
#endif
|
||||
|
||||
// save retval
|
||||
SaveRetVal(v_orig_ret);
|
||||
|
||||
// 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().pAssignOperator)
|
||||
{
|
||||
// lea edx, [ebp + v_override_ret] <-- src addr
|
||||
// lea ecx, [ebp + v_orig_ret] <-- dest addr
|
||||
// gcc: push ecx
|
||||
// push edx <-- src addr
|
||||
// call it
|
||||
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_override_ret);
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#endif
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EDX);
|
||||
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_uint32_t dwords = DownCastSize(m_Proto.GetRet().size) / 4;
|
||||
jit_uint32_t bytes = DownCastSize(m_Proto.GetRet().size) % 4;
|
||||
|
||||
// bitwise copy
|
||||
|
||||
//cld
|
||||
//push edi
|
||||
//push esi
|
||||
//lea edi, [ebp+v_orig_ret] <-- destination
|
||||
//lea esi, [ebp+v_override_ret] <-- src
|
||||
//if dwords
|
||||
// mov ecx, <dwords>
|
||||
// rep movsd
|
||||
//if bytes
|
||||
// mov ecx, <bytes>
|
||||
// rep movsb
|
||||
//pop esi
|
||||
//pop edi
|
||||
|
||||
IA32_Cld(&m_HookFunc);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_EDI);
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ESI);
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_orig_ret);
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_override_ret);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
// 9 params + hidden thisptr param
|
||||
IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 10*SIZE_PTR, MOD_REG);
|
||||
#endif
|
||||
|
||||
// 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
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
// 1 param + hidden thisptr param
|
||||
IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 2*SIZE_PTR, MOD_REG);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char * 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);
|
||||
|
||||
// on msvc, save thisptr
|
||||
#if SH_COMP == SH_COMP_MSVC
|
||||
const jit_int8_t v_this = -4;
|
||||
const int addstackoffset = -4;
|
||||
IA32_Push_Reg(&m_HookFunc, REG_ECX);
|
||||
#elif SH_COMP == SH_COMP_GCC
|
||||
const jit_int8_t v_this = 8; // first param
|
||||
const int addstackoffset = 0;
|
||||
#endif
|
||||
|
||||
|
||||
// ********************** stack frame **********************
|
||||
// MSVC
|
||||
// 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
|
||||
|
||||
const jit_int8_t v_vfnptr_origentry = -4 + addstackoffset;
|
||||
const jit_int8_t v_status = -8 + addstackoffset;
|
||||
const jit_int8_t v_prev_res = -12 + addstackoffset;
|
||||
const jit_int8_t v_cur_res = -16 + addstackoffset;
|
||||
const jit_int8_t v_iter = -20 + addstackoffset;
|
||||
const jit_int8_t v_pContext = -24 + addstackoffset;
|
||||
|
||||
#if SH_COMP == SH_COMP_GCC
|
||||
const jit_int32_t param_base_offs = 16;
|
||||
#elif SH_COMP == SH_COMP_MSVC
|
||||
const jit_int32_t param_base_offs = 12;
|
||||
#endif
|
||||
|
||||
jit_int32_t v_ret_ptr = -28 + addstackoffset;
|
||||
jit_int32_t v_orig_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 1;
|
||||
jit_int32_t v_override_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 2;
|
||||
jit_int32_t v_plugin_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 3;
|
||||
|
||||
// Hash for temporary storage for byval params with copy constructors
|
||||
// (param, offset into stack)
|
||||
short usedStackBytes = 3*SIZE_MWORD + 3*SIZE_PTR + // vfnptr_origentry, status, prev_res, cur_res, iter, pContext
|
||||
3 * GetStackSize(m_Proto.GetRet()) + (m_Proto.GetRet().size == 0 ? 0 : SIZE_PTR) // ret_ptr, orig_ret, override_ret, plugin_ret
|
||||
- addstackoffset; // msvc: current thisptr
|
||||
|
||||
IA32_Sub_Rm_Imm32(&m_HookFunc, REG_ESP, usedStackBytes, MOD_REG);
|
||||
|
||||
// init status localvar
|
||||
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_status);
|
||||
|
||||
// Call constructors for ret vars if required
|
||||
if(m_Proto.GetRet().pNormalCtor)
|
||||
{
|
||||
// :TODO: Gcc version
|
||||
|
||||
// orig_reg
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
|
||||
// override_reg
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret);
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
|
||||
// plugin_ret
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_plugin_ret);
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
}
|
||||
|
||||
// ********************** 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);
|
||||
|
||||
// ********************** call orig func **********************
|
||||
GenerateCallOrig(v_status, v_pContext, param_base_offs, v_this, v_vfnptr_origentry, v_orig_ret,
|
||||
v_override_ret);
|
||||
|
||||
// ********************** call post hooks **********************
|
||||
GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs,
|
||||
v_plugin_ret);
|
||||
|
||||
// ********************** 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 cur_param_pos = param_base_offs;
|
||||
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
|
||||
{
|
||||
const IntPassInfo &pi = m_Proto.GetParam(i);
|
||||
if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) &&
|
||||
(pi.flags & PassInfo::PassFlag_ByVal))
|
||||
{
|
||||
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, cur_param_pos);
|
||||
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor));
|
||||
IA32_Call_Reg(&m_HookFunc, REG_EAX);
|
||||
}
|
||||
cur_param_pos += GetStackSize(pi);
|
||||
}
|
||||
|
||||
DoReturn(v_ret_ptr);
|
||||
|
||||
// !! :TODO: Call destructors of orig_ret/ ...
|
||||
|
||||
// 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);
|
||||
IA32_Return_Popstack(&m_HookFunc, GetParamsStackSize());
|
||||
|
||||
// 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());
|
||||
return m_HookFunc.GetData();
|
||||
}
|
||||
|
||||
// Pre-condition: GenerateHookFunc() has been called!
|
||||
unsigned char * 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);
|
||||
|
||||
SetMemAccess(reinterpret_cast<void*>(m_PubFunc.GetData()), m_PubFunc.GetSize(),
|
||||
SH_MEM_READ | SH_MEM_EXEC);
|
||||
|
||||
return m_PubFunc;
|
||||
}
|
||||
|
||||
bool GenContext::PassInfoSupported(const IntPassInfo &pi, bool is_ret)
|
||||
{
|
||||
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.pNormalCtor)
|
||||
return false;
|
||||
|
||||
if ((pi.flags & PassInfo::PassFlag_ODtor) && !pi.pDtor)
|
||||
return false;
|
||||
|
||||
// only care for assignop and normalctor for return types
|
||||
if (is_ret && (pi.flags & PassInfo::PassFlag_AssignOp) && !pi.pAssignOperator)
|
||||
return false;
|
||||
|
||||
if (is_ret && (pi.flags & PassInfo::PassFlag_CCtor) && !pi.pNormalCtor)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pi.flags & (PassInfo::PassFlag_ByVal | PassInfo::PassFlag_ByRef)) == 0)
|
||||
{
|
||||
return false; // Neither byval nor byref!
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (m_Proto.GetConvention() != ProtoInfo::CallConv_Cdecl &&
|
||||
m_Proto.GetConvention() != 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 reinterpret_cast<HookManagerPubFunc>(GeneratePubFunc());
|
||||
}
|
||||
}
|
||||
}
|
232
sourcehook/sourcehook_hookmangen.h
Normal file
232
sourcehook/sourcehook_hookmangen.h
Normal file
@ -0,0 +1,232 @@
|
||||
/* ======== 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 "sourcehook_impl.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace SourceHook
|
||||
{
|
||||
namespace Impl
|
||||
{
|
||||
|
||||
// Code gen stuff
|
||||
#if defined HAVE_STDINT_H && !defined WIN32
|
||||
#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 defined WIN32
|
||||
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
|
||||
{
|
||||
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;
|
||||
try
|
||||
{
|
||||
//!!!! Better use of pages! or something!
|
||||
newBuf = reinterpret_cast<unsigned char*>(VirtualAlloc(NULL, m_AllocatedSize, MEM_COMMIT, PAGE_READWRITE));
|
||||
}
|
||||
catch (std::bad_alloc)
|
||||
{
|
||||
newBuf = NULL;
|
||||
}
|
||||
if (!newBuf)
|
||||
{
|
||||
SH_ASSERT(0, ("bad_alloc: couldn't allocate 0x%08X bytes of memory\n", m_AllocatedSize));
|
||||
return;
|
||||
}
|
||||
memcpy((void*)newBuf, (const void*)m_pData, m_Size);
|
||||
if (m_pData)
|
||||
VirtualFree(m_pData, 0, MEM_RELEASE);
|
||||
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)
|
||||
VirtualFree(m_pData, 0, MEM_RELEASE);
|
||||
m_pData = NULL;
|
||||
m_Size = 0;
|
||||
m_AllocatedSize = 0;
|
||||
}
|
||||
|
||||
operator unsigned char *()
|
||||
{
|
||||
return 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;
|
||||
}
|
||||
// :TODO: real buffer which uses virtualalloc correctly
|
||||
};
|
||||
|
||||
class GenContext
|
||||
{
|
||||
const static int SIZE_MWORD = 4;
|
||||
const static int SIZE_PTR = sizeof(void*);
|
||||
|
||||
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();
|
||||
|
||||
// size info
|
||||
jit_int32_t GetRealSize(const IntPassInfo &info);
|
||||
jit_int32_t GetStackSize(const IntPassInfo &info);
|
||||
short GetParamsStackSize(); // sum(GetStackSize(i), 0 <= i < numOfParams)
|
||||
|
||||
|
||||
// Param push
|
||||
jit_int32_t PushParams(jit_int32_t param_base_offset);
|
||||
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);
|
||||
|
||||
// Ret val processing
|
||||
void SaveRetVal(int v_where);
|
||||
void ProcessPluginRetVal(int v_cur_res, int v_pContext, int v_plugin_ret);
|
||||
|
||||
void PrepareReturn(int v_status, int v_pContext, int v_retptr);
|
||||
void DoReturn(int v_retptr);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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()
|
||||
bool PassInfoSupported(const IntPassInfo &pi, bool is_ret);
|
||||
void Clear();
|
||||
void BuildProtoInfo();
|
||||
unsigned char *GenerateHookFunc();
|
||||
unsigned char *GeneratePubFunc();
|
||||
public:
|
||||
// Level 1 -> Public interface
|
||||
GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr);
|
||||
~GenContext();
|
||||
|
||||
HookManagerPubFunc Generate();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
1585
sourcehook/sourcehook_hookmangen_x86.h
Normal file
1585
sourcehook/sourcehook_hookmangen_x86.h
Normal file
@ -0,0 +1,1585 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT SDK
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOURCEHOOK_HOOKMANGEN_X86_H__
|
||||
#define __SOURCEHOOK_HOOKMANGEN_X86_H__
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
//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_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;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* 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_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_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
|
6
sourcehook/test/generate.bat
Normal file
6
sourcehook/test/generate.bat
Normal file
@ -0,0 +1,6 @@
|
||||
:: Generates everything
|
||||
:: Usage:
|
||||
:: generate.bat <num-of-arguments>
|
||||
|
||||
|
||||
..\generate\shworker iter testhookmangen.hxx testhookmangen.h %1
|
@ -46,6 +46,7 @@ DECL_TEST(Multi);
|
||||
DECL_TEST(Ref);
|
||||
DECL_TEST(RefRet);
|
||||
DECL_TEST(VPHooks);
|
||||
DECL_TEST(HookManGen);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -68,6 +69,7 @@ int main(int argc, char *argv[])
|
||||
DO_TEST(Ref);
|
||||
DO_TEST(RefRet);
|
||||
DO_TEST(VPHooks);
|
||||
DO_TEST(HookManGen);
|
||||
|
||||
cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
|
||||
cout << "Total: " << passed + failed << endl;
|
||||
|
@ -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
|
||||
|
@ -31,9 +31,25 @@ struct State
|
||||
return (typeid(other) == typeid(this)) ? true : false;
|
||||
}
|
||||
|
||||
virtual bool Ignore()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void Dump() = 0;
|
||||
};
|
||||
|
||||
struct IgnoreState : public State
|
||||
{
|
||||
virtual bool Ignore()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual void Dump()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::list<State*> StateList;
|
||||
namespace
|
||||
{
|
||||
@ -53,6 +69,8 @@ namespace
|
||||
State *cs = va_arg(argptr, State*);
|
||||
if (!cs)
|
||||
break;
|
||||
if (cs->Ignore())
|
||||
continue;
|
||||
requiredstates.push_back(cs);
|
||||
}
|
||||
va_end(argptr);
|
||||
@ -86,6 +104,14 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok && g_Verbose)
|
||||
{
|
||||
std::cout << std::endl << "FAIL: Should be:" << std::endl;
|
||||
DumpStates(&requiredstates);
|
||||
std::cout << std::endl << "FAIL: Is:" << std::endl;
|
||||
DumpStates(sl);
|
||||
}
|
||||
|
||||
for (StateList::iterator iter = requiredstates.begin(); iter != requiredstates.end(); ++iter)
|
||||
delete *iter;
|
||||
for (StateList::iterator iter = sl->begin(); iter != sl->end(); ++iter)
|
||||
|
470
sourcehook/test/testhookmangen.cpp
Normal file
470
sourcehook/test/testhookmangen.cpp
Normal file
@ -0,0 +1,470 @@
|
||||
#include <string>
|
||||
#include "sourcehook.h"
|
||||
#include "sourcehook_test.h"
|
||||
#include "testevents.h"
|
||||
#include "sourcehook_hookmangen.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
|
||||
{
|
||||
#include "testhookmangen.h"
|
||||
|
||||
StateList g_States;
|
||||
SourceHook::ISourceHook *g_SHPtr;
|
||||
SourceHook::Plugin g_PLID;
|
||||
|
||||
// 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
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
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*/);
|
||||
|
||||
template <int MYSIZE>
|
||||
struct Object
|
||||
{
|
||||
char x[MYSIZE];
|
||||
|
||||
Object(char initch)
|
||||
{
|
||||
memset(reinterpret_cast<void*>(x), initch, MYSIZE);
|
||||
if (!g_Inside_LeafFunc)
|
||||
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
|
||||
}
|
||||
|
||||
Object()
|
||||
{
|
||||
if (!g_Inside_LeafFunc)
|
||||
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)
|
||||
ADD_STATE(State_ObjCCtor_Called(MYSIZE));
|
||||
}
|
||||
|
||||
~Object()
|
||||
{
|
||||
if (!g_Inside_LeafFunc)
|
||||
ADD_STATE(State_ObjODtor_Called(MYSIZE));
|
||||
}
|
||||
|
||||
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!";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
// "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];
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
bool TestHookManGen(std::string &error)
|
||||
{
|
||||
GET_SHPTR(g_SHPtr);
|
||||
g_PLID = 1337;
|
||||
|
||||
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));
|
||||
|
||||
char a = 5;
|
||||
double b = 233.33;
|
||||
THGM_DO_TEST_void(7, (a, b));
|
||||
|
||||
POD<7> pod7 = {78};
|
||||
THGM_DO_TEST_void(8, (pod7));
|
||||
|
||||
POD<600> pod600 = {34};
|
||||
THGM_DO_TEST_void(9, (pod600));
|
||||
|
||||
THGM_DO_TEST_void(10, (pod600));
|
||||
|
||||
// Test11: Special: constructors/destructors
|
||||
PtrBuf_Clear();
|
||||
Object<3> obj3(33);
|
||||
Object<600> obj600(21);
|
||||
|
||||
CHECK_STATES((&g_States,
|
||||
new State_ObjOCtor_Called(3),
|
||||
new State_ObjOCtor_Called(600),
|
||||
NULL), "Test11 Part0");
|
||||
|
||||
setuppi_11();
|
||||
g_Genc11 = new SourceHook::Impl::GenContext(&protoinfo_11, 0, 0, g_SHPtr);
|
||||
g_Genc_ad11.set(g_Genc11);
|
||||
SourceHook::HookManagerPubFunc myhookman11 = g_Genc11->Generate();
|
||||
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_Deleg1_11(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_Deleg1_11(pTest11, 0, ParamState_m11 (obj3, obj600)),
|
||||
new State_ObjODtor_Called(3),
|
||||
|
||||
new State_ObjCCtor_Called(3),
|
||||
new State_Deleg2_11(pTest11, 1, ParamState_m11 (obj3, obj600)),
|
||||
new State_ObjODtor_Called(3),
|
||||
|
||||
new State_ObjCCtor_Called(3),
|
||||
new State_Deleg3_11(pTest11, 2, ParamState_m11 (obj3, obj600)),
|
||||
new State_ObjODtor_Called(3),
|
||||
|
||||
new State_ObjCCtor_Called(3),
|
||||
new State_Deleg4_11(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_Deleg1_11(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_Deleg3_11(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_Deleg4_11(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);
|
||||
|
||||
THGM_DO_TEST(101, ());
|
||||
|
||||
THGM_DO_TEST(102, ());
|
||||
|
||||
THGM_DO_TEST(103, ());
|
||||
|
||||
THGM_DO_TEST(104, ());
|
||||
|
||||
THGM_DO_TEST(105, ());
|
||||
|
||||
// Shutdown now!
|
||||
// If we don't SH will auto-shutdown _after_ genc's destructor is called
|
||||
// -> crash
|
||||
|
||||
Test_CompleteShutdown(g_SHPtr);
|
||||
return true;
|
||||
}
|
2090
sourcehook/test/testhookmangen.h
Normal file
2090
sourcehook/test/testhookmangen.h
Normal file
@ -0,0 +1,2090 @@
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
void *FindFuncAddr(T mfp)
|
||||
{
|
||||
if (sizeof(mfp) != sizeof(void*))
|
||||
return NULL;
|
||||
else
|
||||
return fastdelegate::detail::horrible_cast<void*>(mfp);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Stores parameter status
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState1<dummy, p1> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState2<dummy, p1, p2> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p1 >::type>::Incr(m_1);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState3<dummy, p1, p2, p3> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p1 >::type>::Incr(m_1);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p2 >::type>::Incr(m_2);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState4<dummy, p1, p2, p3, p4> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p1 >::type>::Incr(m_1);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p2 >::type>::Incr(m_2);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p3 >::type>::Incr(m_3);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState5<dummy, p1, p2, p3, p4, p5> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p1 >::type>::Incr(m_1);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p2 >::type>::Incr(m_2);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p3 >::type>::Incr(m_3);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p4 >::type>::Incr(m_4);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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)
|
||||
{
|
||||
}
|
||||
|
||||
ParamState6<dummy, p1, p2, p3, p4, p5, p6> & operator() (int incrsteps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p1 >::type>::Incr(m_1);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p2 >::type>::Incr(m_2);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p3 >::type>::Incr(m_3);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p4 >::type>::Incr(m_4);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<StripRef< p5 >::type>::Incr(m_5);
|
||||
|
||||
for (i = 0; i < incrsteps; ++i)
|
||||
Increment<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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[0+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[0+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 0, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST0(id, ret_type) \
|
||||
struct TestClass##id; \
|
||||
typedef ParamState0<0 > ParamState_m##id; \
|
||||
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call() \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
|
||||
g_Inside_LeafFunc = false; \
|
||||
if (ms_DoRecall) \
|
||||
{ \
|
||||
\
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, ()); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[0+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[0+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 0, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#define THGM_SETUP_PI0(id) \
|
||||
void setuppi_##id() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
}
|
||||
|
||||
|
||||
|
||||
#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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[1+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[1+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 1, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST1(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[1+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[1+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 1, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#define THGM_SETUP_PI1(id, p1_type, p1_passtype, p1_flags) \
|
||||
void setuppi_##id() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[2+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[2+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 2, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST2(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[2+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[2+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 2, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#define THGM_SETUP_PI2(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags) \
|
||||
void setuppi_##id() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[3+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[3+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 3, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST3(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[3+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[3+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 3, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#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() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[4+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[4+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 4, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST4(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[4+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[4+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 4, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#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() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[5+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[5+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 5, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST5(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[5+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[5+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 5, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#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() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; paraminfos_##id[5].size = sizeof(p5_type); paraminfos_##id[5].type = p5_passtype; paraminfos_##id[5].flags = p5_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[6+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[6+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 6, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST6(id, ret_type, 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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[6+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[6+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { 6, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#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() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; paraminfos_##id[5].size = sizeof(p5_type); paraminfos_##id[5].type = p5_passtype; paraminfos_##id[5].flags = p5_flags; paraminfos_##id[6].size = sizeof(p6_type); paraminfos_##id[6].type = p6_passtype; paraminfos_##id[6].flags = p6_flags; \
|
||||
\
|
||||
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[6].pNormalCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::NormalConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[6].pCopyCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::CopyConstructor) : NULL; \
|
||||
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : NULL; paraminfos2_##id[6].pDtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::Destructor) : NULL; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
|
||||
void setupri_##id() \
|
||||
{ \
|
||||
protoinfo_##id.retPassInfo.size = sizeof(ret_type); \
|
||||
protoinfo_##id.retPassInfo.type = ret_passtype; \
|
||||
protoinfo_##id.retPassInfo.flags = ret_flags; \
|
||||
\
|
||||
protoinfo_##id.retPassInfo2.pNormalCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL; \
|
||||
protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL; \
|
||||
protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : 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(); \
|
||||
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
|
||||
g_Genc_ad##id.set(g_Genc##id); \
|
||||
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
|
||||
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 - no hooks */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
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 " Part2"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
\
|
||||
/* no hooks - hook3 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part3"); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
\
|
||||
/* 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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part5"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
THGM_REMOVE_HOOK(id, 2); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
/* hook1, hook2 - hook3, hook4 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_ADD_HOOK(id, 2); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_ADD_HOOK(id, 4); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Deleg4_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg4_##id(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);
|
||||
|
||||
|
||||
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
|
||||
CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \
|
||||
CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall");
|
||||
|
||||
#define THGM_DO_TEST(id, call_params) \
|
||||
setuppi_##id(); \
|
||||
setupri_##id(); \
|
||||
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
|
||||
g_Genc_ad##id.set(g_Genc##id); \
|
||||
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
|
||||
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 - no hooks */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_CALLS(id, call_params, 0, 0, "Part2"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
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 " Part2"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
\
|
||||
/* no hooks - hook3 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_CALLS(id, call_params, 0, 0, "Part3"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part3"); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
\
|
||||
/* 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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part5"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
THGM_REMOVE_HOOK(id, 2); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
/* hook1, hook2 - hook3, hook4 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_ADD_HOOK(id, 2); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_ADD_HOOK(id, 4); \
|
||||
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Deleg4_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg4_##id(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);
|
578
sourcehook/test/testhookmangen.hxx
Normal file
578
sourcehook/test/testhookmangen.hxx
Normal file
@ -0,0 +1,578 @@
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
void *FindFuncAddr(T mfp)
|
||||
{
|
||||
if (sizeof(mfp) != sizeof(void*))
|
||||
return NULL;
|
||||
else
|
||||
return fastdelegate::detail::horrible_cast<void*>(mfp);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Stores parameter status
|
||||
@[$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)@]
|
||||
{
|
||||
}
|
||||
|
||||
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<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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_IGNORED); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META(MRES_SUPERCEDE); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[$1+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[$1+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { $1, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
|
||||
#define THGM_MAKE_TEST$1(id, ret_type@[$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_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
|
||||
MAKE_STATE_3(State_Deleg4_##id, 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 0; \
|
||||
} \
|
||||
\
|
||||
struct Delegate1 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg1_##id(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(MRES_IGNORED, 1, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 1); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate2 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg2_##id(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(MRES_SUPERCEDE, 2, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate3 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg3_##id(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(MRES_IGNORED, 3, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_IGNORED, 3); \
|
||||
} \
|
||||
}; \
|
||||
struct Delegate4 : public MyDelegate \
|
||||
{ \
|
||||
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
|
||||
{ \
|
||||
g_Inside_LeafFunc = true; \
|
||||
ADD_STATE(State_Deleg4_##id(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(MRES_SUPERCEDE, 4, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
|
||||
} \
|
||||
else \
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
|
||||
}; \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
bool TestClass##id::ms_DoRecall = false; \
|
||||
\
|
||||
SourceHook::PassInfo paraminfos_##id[$1+1]; \
|
||||
SourceHook::PassInfo::V2Info paraminfos2_##id[$1+1]; \
|
||||
SourceHook::ProtoInfo protoinfo_##id = { $1, {0, 0, 0}, paraminfos_##id, \
|
||||
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
|
||||
\
|
||||
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
|
||||
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
|
||||
|
||||
#define THGM_SETUP_PI$1(id@[$2,1,$1:, p$2_type, p$2_passtype, p$2_flags@]) \
|
||||
void setuppi_##id() \
|
||||
{ \
|
||||
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
|
||||
\
|
||||
@[$2,1,$1: paraminfos_##id[$2].size = sizeof(p$2_type); paraminfos_##id[$2].type = p$2_passtype; paraminfos_##id[$2].flags = p$2_flags; @] \
|
||||
\
|
||||
@[$2,1,$1: paraminfos2_##id[$2].pNormalCtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::NormalConstructor) : NULL; @] \
|
||||
@[$2,1,$1: paraminfos2_##id[$2].pCopyCtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::CopyConstructor) : NULL; @] \
|
||||
@[$2,1,$1: paraminfos2_##id[$2].pDtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::Destructor) : NULL; @] \
|
||||
}
|
||||
|
||||
@]
|
||||
|
||||
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
|
||||
void setupri_##id() \
|
||||
{ \
|
||||
protoinfo_##id.retPassInfo.size = sizeof(ret_type); \
|
||||
protoinfo_##id.retPassInfo.type = ret_passtype; \
|
||||
protoinfo_##id.retPassInfo.flags = ret_flags; \
|
||||
\
|
||||
protoinfo_##id.retPassInfo2.pNormalCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL; \
|
||||
protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL; \
|
||||
protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : 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(); \
|
||||
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
|
||||
g_Genc_ad##id.set(g_Genc##id); \
|
||||
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
|
||||
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 - no hooks */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
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 " Part2"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
\
|
||||
/* no hooks - hook3 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part3"); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
\
|
||||
/* 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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part5"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
THGM_REMOVE_HOOK(id, 2); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
/* hook1, hook2 - hook3, hook4 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_ADD_HOOK(id, 2); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_ADD_HOOK(id, 4); \
|
||||
THGM_CALLS_void(id, call_params); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Deleg4_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg4_##id(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);
|
||||
|
||||
|
||||
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
|
||||
CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \
|
||||
CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall");
|
||||
|
||||
#define THGM_DO_TEST(id, call_params) \
|
||||
setuppi_##id(); \
|
||||
setupri_##id(); \
|
||||
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
|
||||
g_Genc_ad##id.set(g_Genc##id); \
|
||||
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
|
||||
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 - no hooks */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_CALLS(id, call_params, 0, 0, "Part2"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
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 " Part2"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
\
|
||||
/* no hooks - hook3 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_CALLS(id, call_params, 0, 0, "Part3"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part3"); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
\
|
||||
/* 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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params), \
|
||||
NULL), "Test" #id " Part5"); \
|
||||
THGM_REMOVE_HOOK(id, 1); \
|
||||
THGM_REMOVE_HOOK(id, 2); \
|
||||
THGM_REMOVE_HOOK(id, 3); \
|
||||
/* hook1, hook2 - hook3, hook4 */ \
|
||||
PtrBuf_Clear(); \
|
||||
THGM_ADD_HOOK(id, 1); \
|
||||
THGM_ADD_HOOK(id, 2); \
|
||||
THGM_ADD_HOOK(id, 3); \
|
||||
THGM_ADD_HOOK(id, 4); \
|
||||
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
|
||||
CHECK_STATES((&g_States, \
|
||||
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
|
||||
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
|
||||
new State_Deleg4_##id(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_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
|
||||
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
|
||||
new State_Deleg4_##id(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);
|
Loading…
x
Reference in New Issue
Block a user