From 7fa9f150fb1898d51c0349ecb09eb0ee5323ea68 Mon Sep 17 00:00:00 2001 From: Pavol Marko Date: Sun, 21 Oct 2007 21:47:53 +0000 Subject: [PATCH] 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 --- sourcehook/sourcehook_hookmangen.cpp | 1292 +++++++++++++++ sourcehook/sourcehook_hookmangen.h | 232 +++ sourcehook/sourcehook_hookmangen_x86.h | 1585 ++++++++++++++++++ sourcehook/test/generate.bat | 6 + sourcehook/test/main.cpp | 2 + sourcehook/test/sourcehook_test.h | 1 + sourcehook/test/testevents.h | 26 + sourcehook/test/testhookmangen.cpp | 470 ++++++ sourcehook/test/testhookmangen.h | 2090 ++++++++++++++++++++++++ sourcehook/test/testhookmangen.hxx | 578 +++++++ 10 files changed, 6282 insertions(+) create mode 100644 sourcehook/sourcehook_hookmangen.cpp create mode 100644 sourcehook/sourcehook_hookmangen.h create mode 100644 sourcehook/sourcehook_hookmangen_x86.h create mode 100644 sourcehook/test/generate.bat create mode 100644 sourcehook/test/testhookmangen.cpp create mode 100644 sourcehook/test/testhookmangen.h create mode 100644 sourcehook/test/testhookmangen.hxx diff --git a/sourcehook/sourcehook_hookmangen.cpp b/sourcehook/sourcehook_hookmangen.cpp new file mode 100644 index 0000000..e00a50d --- /dev/null +++ b/sourcehook/sourcehook_hookmangen.cpp @@ -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 + jit_int32_t DownCastPtr(T ptr) + { + return reinterpret_cast(ptr); + } + + jit_uint32_t DownCastSize(size_t size) + { + return static_cast(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(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+] + 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+] + //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+] + //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+] + //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++4] + //mov reg2, DWORD PTR [ebp+] + //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+] + //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+] + //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, + 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+] + //if dwords + // mov ecx, + // rep movsd + //if bytes + // mov ecx, + // 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 48: 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(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, + // rep movsd + //if bytes + // mov ecx, + // 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(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 48: 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(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(loop_begin_counter)); + + m_HookFunc.end_count(counter); + m_HookFunc.rewrite(tmppos, static_cast(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(counter)); + + m_HookFunc.end_count(counter2); + m_HookFunc.rewrite(tmppos2, static_cast(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, + // rep movsd + //if bytes + // mov ecx, + // 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(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(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(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(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(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(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(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(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(GeneratePubFunc()); + } + } +} \ No newline at end of file diff --git a/sourcehook/sourcehook_hookmangen.h b/sourcehook/sourcehook_hookmangen.h new file mode 100644 index 0000000..4bfeea7 --- /dev/null +++ b/sourcehook/sourcehook_hookmangen.h @@ -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 + 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 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(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 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 \ No newline at end of file diff --git a/sourcehook/sourcehook_hookmangen_x86.h b/sourcehook/sourcehook_hookmangen_x86.h new file mode 100644 index 0000000..5a05acc --- /dev/null +++ b/sourcehook/sourcehook_hookmangen_x86.h @@ -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 . + * + * 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 . + * + */ + +#ifndef __SOURCEHOOK_HOOKMANGEN_X86_H__ +#define __SOURCEHOOK_HOOKMANGEN_X86_H__ + +#include + +//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 +#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 +#define IA32_SBB_REG_RM 0x1B // encoding is /r +#define IA32_SBB_RM_IMM8 0x83 // encoding is +#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, +#define IA32_CALL_RM 0xFF // encoding is /2 +#define IA32_MOV_REG_IMM 0xB8 // encoding is +r +#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 +#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 +#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 +#define IA32_JCC_IMM32_1 0x0F // opcode part 1 +#define IA32_JCC_IMM32_2 0x80 // encoding is +cc +#define IA32_RET 0xC3 // no extra encoding +#define IA32_RETN 0xC2 // encoding is +#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 +#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 +#define IA32_SHR_RM_1 0xD1 // encoding is /5 +#define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 +#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 +#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 +#define IA32_PUSH_IMM8 0x6A // encoding is +#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(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(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(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(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(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(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(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(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(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(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(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(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 diff --git a/sourcehook/test/generate.bat b/sourcehook/test/generate.bat new file mode 100644 index 0000000..f6d3d65 --- /dev/null +++ b/sourcehook/test/generate.bat @@ -0,0 +1,6 @@ +:: Generates everything +:: Usage: +:: generate.bat + + +..\generate\shworker iter testhookmangen.hxx testhookmangen.h %1 \ No newline at end of file diff --git a/sourcehook/test/main.cpp b/sourcehook/test/main.cpp index db203e2..c7946bf 100644 --- a/sourcehook/test/main.cpp +++ b/sourcehook/test/main.cpp @@ -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; diff --git a/sourcehook/test/sourcehook_test.h b/sourcehook/test/sourcehook_test.h index ee5566e..babb5ba 100644 --- a/sourcehook/test/sourcehook_test.h +++ b/sourcehook/test/sourcehook_test.h @@ -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 diff --git a/sourcehook/test/testevents.h b/sourcehook/test/testevents.h index ef7c891..1f9f8bf 100644 --- a/sourcehook/test/testevents.h +++ b/sourcehook/test/testevents.h @@ -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 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) diff --git a/sourcehook/test/testhookmangen.cpp b/sourcehook/test/testhookmangen.cpp new file mode 100644 index 0000000..76646d6 --- /dev/null +++ b/sourcehook/test/testhookmangen.cpp @@ -0,0 +1,470 @@ +#include +#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 g_PtrHash; + + bool g_Inside_LeafFunc = false; // inside a hook or a func + + template + int PtrBuf(T ptr) + { + int a = 0; + + const void *vptr = reinterpret_cast(ptr); + for (SourceHook::List::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(g_PtrHash.size()) - 1; + } + + template + T PtrBufPtr(T ptr) + { + PtrBuf(ptr); + return ptr; + } + + void PtrBuf_Clear(int leave_in = 0) + { + for (SourceHook::List::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end();) + { + if (--leave_in < 0) + iter = g_PtrHash.erase(iter); + else + ++iter; + } + } + + // POD / Object types + template + struct POD + { + char x[MYSIZE]; + + bool operator==(const POD &other) + { + return memcmp(reinterpret_cast(x), reinterpret_cast(other.x), MYSIZE) == 0; + } + }; + + template + std::ostream& operator <<(std::ostream &os, const POD &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 + struct Object + { + char x[MYSIZE]; + + Object(char initch) + { + memset(reinterpret_cast(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 & other) + { + memcpy(reinterpret_cast(x), reinterpret_cast(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 &other) + { + return memcmp(reinterpret_cast(x), reinterpret_cast(other.x), MYSIZE) == 0; + } + }; + + template + std::ostream& operator <<(std::ostream &os, const Object &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 + struct Increment + { + static void Incr(T &what) + { + ++what; + } + }; + + template<> + struct Increment + { + static void Incr(float &what) + { + what += 1.3f; + } + }; + + template<> + struct Increment + { + static void Incr(double &what) + { + what += 1.3; + } + }; + + template + struct Increment< POD > + { + static void Incr(POD &what) + { + for (int i = 0; i < MYSIZE; ++i) + ++ what.x[i]; + } + }; + + template + struct Increment< Object > + { + static void Incr(Object &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 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; +} diff --git a/sourcehook/test/testhookmangen.h b/sourcehook/test/testhookmangen.h new file mode 100644 index 0000000..cd6f3ed --- /dev/null +++ b/sourcehook/test/testhookmangen.h @@ -0,0 +1,2090 @@ +// Strip & +template struct StripRef +{ + typedef T type; +}; + +template struct StripRef +{ + typedef T type; +}; + +// Address of constructor/destructor +// (using wrappers) +template +class Ctor_Thunk +{ +public: + void NormalConstructor() + { + new(this) T; + } + + void CopyConstructor(const T &other) + { + new(this) T(other); + } + + void Destructor() + { + reinterpret_cast(this)->~T(); + } +}; + + +template +void *FindFuncAddr(T mfp) +{ + if (sizeof(mfp) != sizeof(void*)) + return NULL; + else + return fastdelegate::detail::horrible_cast(mfp); +} + +// Reference carrier +template struct MyRefCarrier +{ + typedef T type; +}; + +template struct MyRefCarrier +{ + 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::type &other) + { + return m_StoredRef == other.m_StoredRef; + } + + friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier::type &obj) + { + os << *obj.m_StoredRef; + return os; + } + }; +}; + +// Stores parameter status + + +template +struct ParamState0 +{ + + + bool operator==(const ParamState0 &other) + { + return true + + ; + } + ParamState0() + { + } + + ParamState0 & operator() (int incrsteps) + { + + + + return *this; + } +}; + + +std::ostream& operator <<(std::ostream &os,const ParamState0<0> &obj) +{ + ; + return os; +} + + + +template +struct ParamState1 +{ + typename MyRefCarrier::type m_1; + + bool operator==(const ParamState1 &other) + { + return true + && m_1 == other.m_1 + ; + } + ParamState1(p1 a1) : m_1(a1) + { + } + + ParamState1 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + + return *this; + } +}; + +template +std::ostream& operator <<(std::ostream &os,const ParamState1<0, p1> &obj) +{ + os << obj.m_1; + return os; +} + + + +template +struct ParamState2 +{ + typename MyRefCarrier::type m_1; typename MyRefCarrier::type m_2; + + bool operator==(const ParamState2 &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 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_2); + + + return *this; + } +}; + +template +std::ostream& operator <<(std::ostream &os,const ParamState2<0, p1, p2> &obj) +{ + os << obj.m_1<< obj.m_2; + return os; +} + + + +template +struct ParamState3 +{ + typename MyRefCarrier::type m_1; typename MyRefCarrier::type m_2; typename MyRefCarrier::type m_3; + + bool operator==(const ParamState3 &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 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_2); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_3); + + + return *this; + } +}; + +template +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 +struct ParamState4 +{ + typename MyRefCarrier::type m_1; typename MyRefCarrier::type m_2; typename MyRefCarrier::type m_3; typename MyRefCarrier::type m_4; + + bool operator==(const ParamState4 &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 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_2); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_3); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_4); + + + return *this; + } +}; + +template +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 +struct ParamState5 +{ + typename MyRefCarrier::type m_1; typename MyRefCarrier::type m_2; typename MyRefCarrier::type m_3; typename MyRefCarrier::type m_4; typename MyRefCarrier::type m_5; + + bool operator==(const ParamState5 &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 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_2); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_3); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_4); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_5); + + + return *this; + } +}; + +template +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 +struct ParamState6 +{ + typename MyRefCarrier::type m_1; typename MyRefCarrier::type m_2; typename MyRefCarrier::type m_3; typename MyRefCarrier::type m_4; typename MyRefCarrier::type m_5; typename MyRefCarrier::type m_6; + + bool operator==(const ParamState6 &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 & operator() (int incrsteps) + { + int i; + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_1); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_2); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_3); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_4); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_5); + + for (i = 0; i < incrsteps; ++i) + Increment::type>::Incr(m_6); + + + return *this; + } +}; + +template +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 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 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::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::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::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::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 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::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::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::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::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 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::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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 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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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::type>::Incr(p1);Increment::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 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::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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 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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::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 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::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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 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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::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 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::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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 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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::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 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::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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 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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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::type>::Incr(p1);Increment::type>::Incr(p2);Increment::type>::Incr(p3);Increment::type>::Incr(p4);Increment::type>::Incr(p5);Increment::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 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::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; paraminfos2_##id[6].pNormalCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk::type>::NormalConstructor) : NULL; \ + paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; paraminfos2_##id[6].pCopyCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; paraminfos2_##id[6].pDtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::NormalConstructor) : NULL; \ + protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; \ + } + +#define THGM_ADD_HOOK(id, num) \ + CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast(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 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 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); diff --git a/sourcehook/test/testhookmangen.hxx b/sourcehook/test/testhookmangen.hxx new file mode 100644 index 0000000..80800e7 --- /dev/null +++ b/sourcehook/test/testhookmangen.hxx @@ -0,0 +1,578 @@ +// Strip & +template struct StripRef +{ + typedef T type; +}; + +template struct StripRef +{ + typedef T type; +}; + +// Address of constructor/destructor +// (using wrappers) +template +class Ctor_Thunk +{ +public: + void NormalConstructor() + { + new(this) T; + } + + void CopyConstructor(const T &other) + { + new(this) T(other); + } + + void Destructor() + { + reinterpret_cast(this)->~T(); + } +}; + + +template +void *FindFuncAddr(T mfp) +{ + if (sizeof(mfp) != sizeof(void*)) + return NULL; + else + return fastdelegate::detail::horrible_cast(mfp); +} + +// Reference carrier +template struct MyRefCarrier +{ + typedef T type; +}; + +template struct MyRefCarrier +{ + 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::type &other) + { + return m_StoredRef == other.m_StoredRef; + } + + friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier::type &obj) + { + os << *obj.m_StoredRef; + return os; + } + }; +}; + +// Stores parameter status +@[$1,0,$a: + +template +struct ParamState$1 +{ + @[$2,1,$1:typename MyRefCarrier::type m_$2; @] + + bool operator==(const ParamState$1 &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 & operator() (int incrsteps) + { + @[$1!=0:int i;@] + @[$2,1,$1: + for (i = 0; i < incrsteps; ++i) + Increment::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::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::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::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::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 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::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::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::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::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 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::type>::NormalConstructor) : NULL; @] \ + @[$2,1,$1: paraminfos2_##id[$2].pCopyCtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; @] \ + @[$2,1,$1: paraminfos2_##id[$2].pDtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::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::type>::NormalConstructor) : NULL; \ + protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk::type>::CopyConstructor) : NULL; \ + protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk::type>::Destructor) : NULL; \ + } + +#define THGM_ADD_HOOK(id, num) \ + CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast(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 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 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);