From c5b8d2fecb50cb0b263982ba0d3d0a4e9a376217 Mon Sep 17 00:00:00 2001 From: Dr!fter Date: Wed, 28 Aug 2013 14:20:20 -0400 Subject: [PATCH] More return struct fixes. Add Vector and Vector * return support. Change vfunc_call to use template. Update makefile --- Makefile | 2 +- msvc10/sdk.vcxproj | 1 - msvc10/sdk.vcxproj.filters | 1 - natives.cpp | 56 ++++++++++- vfunc_call.h | 130 ++++++++++++++++++++++++- vhook.cpp | 195 +++++++++++++++++++++++++++++++++++-- vhook.h | 43 ++++++-- 7 files changed, 406 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index ba8cbf6..6ba8f57 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ PROJECT = dhooks #Uncomment for Metamod: Source enabled extension USEMETA = true -OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp $(SMSDK)/public/jit/x86/assembler-x86.cpp listeners.cpp natives.cpp vfunc_call.cpp +OBJECTS = sdk/smsdk_ext.cpp extension.cpp vhook.cpp $(SMSDK)/public/jit/x86/assembler-x86.cpp listeners.cpp natives.cpp ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### diff --git a/msvc10/sdk.vcxproj b/msvc10/sdk.vcxproj index c7cf75e..63c52c2 100644 --- a/msvc10/sdk.vcxproj +++ b/msvc10/sdk.vcxproj @@ -886,7 +886,6 @@ - diff --git a/msvc10/sdk.vcxproj.filters b/msvc10/sdk.vcxproj.filters index a218cab..4da95fe 100644 --- a/msvc10/sdk.vcxproj.filters +++ b/msvc10/sdk.vcxproj.filters @@ -11,7 +11,6 @@ - diff --git a/natives.cpp b/natives.cpp index 9b4b11c..9029f2d 100644 --- a/natives.cpp +++ b/natives.cpp @@ -947,6 +947,58 @@ cell_t Native_GetParamObjectPtrString(IPluginContext *pContext, const cell_t *pa } return 1; } + +// DHookGetReturnVector(Handle:hReturn, Float:vec[3]) +cell_t Native_GetReturnVector(IPluginContext *pContext, const cell_t *params) +{ + HookReturnStruct *returnStruct; + + if(!GetHandleIfValidOrError(g_HookReturnHandle, (void **)&returnStruct, pContext, params[1])) + { + return 0; + } + + cell_t *buffer; + pContext->LocalToPhysAddr(params[2], &buffer); + + if(returnStruct->type == ReturnType_Vector || returnStruct->type == ReturnType_VectorPtr) + { + buffer[0] = sp_ftoc((*(Vector **)returnStruct->orgResult)->x); + buffer[1] = sp_ftoc((*(Vector **)returnStruct->orgResult)->y); + buffer[2] = sp_ftoc((*(Vector **)returnStruct->orgResult)->z); + + return 1; + } + return pContext->ThrowNativeError("Return type is not a vector type"); +} + +//DHookSetReturnVector(Handle:hReturn, Float:vec[3]) +cell_t Native_SetReturnVector(IPluginContext *pContext, const cell_t *params) +{ + HookReturnStruct *returnStruct; + + if(!GetHandleIfValidOrError(g_HookReturnHandle, (void **)&returnStruct, pContext, params[1])) + { + return 0; + } + + cell_t *buffer; + pContext->LocalToPhysAddr(params[2], &buffer); + + if(returnStruct->type == ReturnType_Vector || returnStruct->type == ReturnType_VectorPtr) + { + if(*(Vector **)returnStruct->newResult != NULL) + { + delete *(Vector **)returnStruct->newResult; + } + + *(Vector **)returnStruct->newResult = new Vector(sp_ctof(buffer[0]), sp_ctof(buffer[1]), sp_ctof(buffer[2])); + + return 1; + } + return pContext->ThrowNativeError("Return type is not a vector type"); +} + //native bool:DHookIsNullParam(Handle:hParams, num); cell_t Native_IsNullParam(IPluginContext *pContext, const cell_t *params) { @@ -986,8 +1038,8 @@ sp_nativeinfo_t g_Natives[] = {"DHookSetReturn", Native_SetReturn}, {"DHookSetParam", Native_SetParam}, {"DHookGetParamVector", Native_GetParamVector}, - /*{"DHookGetReturnVector", Native_GetReturnVector}, - {"DHookSetReturnVector", Native_SetReturnVector},*/ + {"DHookGetReturnVector", Native_GetReturnVector}, + {"DHookSetReturnVector", Native_SetReturnVector}, {"DHookSetParamVector", Native_SetParamVector}, {"DHookGetParamString", Native_GetParamString}, {"DHookGetReturnString", Native_GetReturnString}, diff --git a/vfunc_call.h b/vfunc_call.h index 28a11fb..07ca195 100644 --- a/vfunc_call.h +++ b/vfunc_call.h @@ -2,6 +2,134 @@ #define _INCLUDE_VFUNC_CALL_H_ #include "vhook.h" +#include "extension.h" + +#define PARAMINFO_SWITCH(passType) \ + paramInfo[i].flags = dg->params.Element(i).flag; \ + paramInfo[i].size = dg->params.Element(i).size; \ + paramInfo[i].type = passType; + +#define VSTK_PARAM_SWITCH(paramType) \ + if(paramStruct->isChanged[i]) \ + { \ + *(paramType *)vptr = (paramType)(paramStruct->newParams[i]); \ + } \ + else \ + { \ + *(paramType *)vptr = (paramType)(paramStruct->orgParams[i]); \ + } \ + if(i + 1 != dg->params.Count()) \ + { \ + vptr += dg->params.Element(i).size; \ + } \ + break; +#define VSTK_PARAM_SWITCH_FLOAT() \ + if(paramStruct->isChanged[i]) \ + { \ + *(float *)vptr = *(float *)(paramStruct->newParams[i]); \ + } \ + else \ + { \ + *(float *)vptr = *(float *)(paramStruct->orgParams[i]); \ + } \ + if(i + 1 != dg->params.Count()) \ + { \ + vptr += dg->params.Element(i).size; \ + } \ + break; + +template +T CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface) +{ + SourceMod::PassInfo *paramInfo = NULL; + SourceMod::PassInfo returnInfo; + + if(dg->returnType != ReturnType_Void) + { + returnInfo.flags = dg->returnFlag; + returnInfo.size = sizeof(T); + if( dg->returnType != ReturnType_Vector) + { + returnInfo.type = PassType_Basic; + } + else + { + returnInfo.type = PassType_Object; + } + } + + ICallWrapper *pCall; + + size_t size = GetStackArgsSize(dg); + + unsigned char *vstk = (unsigned char *)malloc(sizeof(void *) + size); + unsigned char *vptr = vstk; + + *(void **)vptr = iface; + + if(paramStruct) + { + vptr += sizeof(void *); + paramInfo = (SourceMod::PassInfo *)malloc(sizeof(SourceMod::PassInfo) * dg->params.Count()); + for(int i = 0; i < dg->params.Count(); i++) + { + switch(dg->params.Element(i).type) + { + case HookParamType_Int: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(int); + case HookParamType_Bool: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(cell_t); + case HookParamType_Float: + PARAMINFO_SWITCH(PassType_Float); + VSTK_PARAM_SWITCH_FLOAT(); + case HookParamType_String: + PARAMINFO_SWITCH(PassType_Object); + VSTK_PARAM_SWITCH(int); + case HookParamType_StringPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(string_t *); + case HookParamType_CharPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(char *); + case HookParamType_VectorPtr: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(Vector *); + case HookParamType_CBaseEntity: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(CBaseEntity *); + case HookParamType_Edict: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(edict_t *); + default: + PARAMINFO_SWITCH(PassType_Basic); + VSTK_PARAM_SWITCH(void *); + } + } + } + + T ret = 0; + if(dg->returnType == ReturnType_Void) + { + pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, NULL, paramInfo, dg->params.Count()); + pCall->Execute(vstk, NULL); + } + else + { + pCall = g_pBinTools->CreateVCall(dg->offset, 0, 0, &returnInfo, paramInfo, dg->params.Count()); + pCall->Execute(vstk, &ret); + } + + pCall->Destroy(); + free(vstk); + + if(paramInfo != NULL) + { + free(paramInfo); + } + + return ret; +} -void *CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStruct, void *iface); #endif diff --git a/vhook.cpp b/vhook.cpp index 08f1378..0c9a6f7 100644 --- a/vhook.cpp +++ b/vhook.cpp @@ -53,6 +53,10 @@ DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *rem { protoInfo.SetReturnType(sizeof(string_t), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL);//We have to be 4 really... or else RIP } + else if(this->callback->returnType == ReturnType_Vector) + { + protoInfo.SetReturnType(sizeof(Vector), SourceHook::PassInfo::PassType_Object, setup->returnFlag, NULL, NULL, NULL, NULL); + } else { protoInfo.SetReturnType(sizeof(void *), SourceHook::PassInfo::PassType_Basic, setup->returnFlag, NULL, NULL, NULL, NULL); @@ -105,16 +109,29 @@ size_t GetStackArgsSize(DHooksCallback *dg) { res += dg->params.Element(i).size; } + + if(dg->returnType == ReturnType_Vector)//Account for result vector ptr. + { + res += sizeof(void *); + } return res; } HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t argStackSize) { HookParamsStruct *params = new HookParamsStruct(); params->dg = dg; - params->orgParams = (void **)malloc(argStackSize); + if(dg->returnType != ReturnType_Vector) + { + params->orgParams = (void **)malloc(argStackSize); + memcpy(params->orgParams, argStack, argStackSize); + } + else //Offset result ptr + { + params->orgParams = (void **)malloc(argStackSize-sizeof(void *)); + memcpy(params->orgParams, argStack+sizeof(void *), argStackSize); + } params->newParams = (void **)malloc(dg->params.Count() * sizeof(void *)); params->isChanged = (bool *)malloc(dg->params.Count() * sizeof(bool)); - memcpy(params->orgParams, argStack, argStackSize); for(int i = 0; i < dg->params.Count(); i++) { params->newParams[i] = NULL; @@ -128,6 +145,7 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg) res->isChanged = false; res->type = dg->returnType; res->newResult = malloc(sizeof(void *)); + *(void **)res->newResult = NULL; res->orgResult = malloc(sizeof(void *)); if(g_SHPtr->GetOrigRet() && dg->post) @@ -137,7 +155,6 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg) case ReturnType_String: *(string_t *)res->orgResult = META_RESULT_ORIG_RET(string_t); break; - //ReturnType_Vector, case ReturnType_Int: *(int *)res->orgResult = META_RESULT_ORIG_RET(int); break; @@ -147,7 +164,14 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg) case ReturnType_Float: *(float *)res->orgResult = META_RESULT_ORIG_RET(float); break; + case ReturnType_Vector: + { + Vector vec = META_RESULT_ORIG_RET(Vector); + *(Vector **)res->orgResult = new Vector(vec); + break; + } default: + *(void **)res->orgResult = malloc(sizeof(void **)); *(void **)res->orgResult = META_RESULT_ORIG_RET(void *); break; } @@ -264,7 +288,7 @@ void *Callback(DHooksCallback *dg, void **argStack) g_SHPtr->DoRecall(); g_SHPtr->SetRes(MRES_SUPERCEDE); mres = MRES_SUPERCEDE; - ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); break; case MRES_ChangedOverride: if(dg->returnType != ReturnType_Void) @@ -284,7 +308,7 @@ void *Callback(DHooksCallback *dg, void **argStack) g_SHPtr->DoRecall(); g_SHPtr->SetRes(MRES_SUPERCEDE); mres = MRES_SUPERCEDE; - CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); break; case MRES_Override: if(dg->returnType != ReturnType_Void) @@ -418,7 +442,7 @@ void *Callback_float(DHooksCallback *dg, void **argStack) g_SHPtr->DoRecall(); g_SHPtr->SetRes(MRES_SUPERCEDE); mres = MRES_SUPERCEDE; - ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + *(float *)ret = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); break; case MRES_ChangedOverride: if(dg->returnType != ReturnType_Void) @@ -438,7 +462,7 @@ void *Callback_float(DHooksCallback *dg, void **argStack) g_SHPtr->DoRecall(); g_SHPtr->SetRes(MRES_SUPERCEDE); mres = MRES_SUPERCEDE; - CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); break; case MRES_Override: if(dg->returnType != ReturnType_Void) @@ -497,3 +521,160 @@ void *Callback_float(DHooksCallback *dg, void **argStack) } return *(float *)ret; } +Vector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep) +{ + Vector *vec_result = (Vector *)argStack[0]; // Save the result + + HookReturnStruct *returnStruct = NULL; + HookParamsStruct *paramStruct = NULL; + Handle_t rHndl; + Handle_t pHndl; + + #ifndef __linux__ + *argsizep = GetStackArgsSize(dg); + #else + size_t argsize = GetStackArgsSize(dg); + #endif + + if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) + { + dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + } + + returnStruct = GetReturnStruct(dg); + rHndl = handlesys->CreateHandle(g_HookReturnHandle, returnStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); + + if(!rHndl) + { + dg->plugin_callback->Cancel(); + if(returnStruct) + { + delete returnStruct; + } + g_SHPtr->SetRes(MRES_IGNORED); + return NULL; + } + dg->plugin_callback->PushCell(rHndl); + + #ifndef __linux__ + if(*argsizep > 0) + { + paramStruct = GetParamStruct(dg, argStack, *argsizep); + #else + if(argsize > 0) + { + paramStruct = GetParamStruct(dg, argStack, argsize); + #endif + pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); + if(!pHndl) + { + dg->plugin_callback->Cancel(); + if(returnStruct) + { + delete returnStruct; + } + if(paramStruct) + { + delete paramStruct; + } + g_SHPtr->SetRes(MRES_IGNORED); + return NULL; + } + dg->plugin_callback->PushCell(pHndl); + } + cell_t result = (cell_t)MRES_Ignored; + META_RES mres = MRES_IGNORED; + dg->plugin_callback->Execute(&result); + + void *ret = g_SHPtr->GetOverrideRetPtr(); + ret = vec_result; + switch((MRESReturn)result) + { + case MRES_Handled: + case MRES_ChangedHandled: + g_SHPtr->DoRecall(); + g_SHPtr->SetRes(MRES_SUPERCEDE); + mres = MRES_SUPERCEDE; + *vec_result = CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + break; + case MRES_ChangedOverride: + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + *vec_result = **(Vector **)returnStruct->newResult; + } + else //Throw an error if no override was set + { + g_SHPtr->SetRes(MRES_IGNORED); + mres = MRES_IGNORED; + dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Tried to override return value without return value being set"); + break; + } + } + g_SHPtr->DoRecall(); + g_SHPtr->SetRes(MRES_SUPERCEDE); + mres = MRES_SUPERCEDE; + CallVFunction(dg, paramStruct, g_SHPtr->GetIfacePtr()); + break; + case MRES_Override: + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + g_SHPtr->SetRes(MRES_OVERRIDE); + mres = MRES_OVERRIDE; + *vec_result = **(Vector **)returnStruct->newResult; + } + else //Throw an error if no override was set + { + g_SHPtr->SetRes(MRES_IGNORED); + mres = MRES_IGNORED; + dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Tried to override return value without return value being set"); + } + } + break; + case MRES_Supercede: + if(dg->returnType != ReturnType_Void) + { + if(returnStruct->isChanged) + { + g_SHPtr->SetRes(MRES_SUPERCEDE); + mres = MRES_SUPERCEDE; + *vec_result = **(Vector **)returnStruct->newResult; + } + else //Throw an error if no override was set + { + g_SHPtr->SetRes(MRES_IGNORED); + mres = MRES_IGNORED; + dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Tried to override return value without return value being set"); + } + } + break; + default: + g_SHPtr->SetRes(MRES_IGNORED); + mres = MRES_IGNORED; + break; + } + + HandleSecurity sec(dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity()); + + if(returnStruct) + { + handlesys->FreeHandle(rHndl, &sec); + } + if(paramStruct) + { + handlesys->FreeHandle(pHndl, &sec); + } + + if(dg->returnType == ReturnType_Void || mres <= MRES_HANDLED) + { + META_CONPRINT("Returning now\n"); + vec_result->x = 0; + vec_result->y = 0; + vec_result->z = 0; + return vec_result; + } + return vec_result; +} diff --git a/vhook.h b/vhook.h index 7bf630a..8aa7d97 100644 --- a/vhook.h +++ b/vhook.h @@ -91,7 +91,7 @@ class HookReturnStruct public: ~HookReturnStruct() { - if(this->type != ReturnType_CharPtr && this->type != ReturnType_StringPtr) + if(this->type != ReturnType_CharPtr && this->type != ReturnType_StringPtr && this->type != ReturnType_Vector && this->type != ReturnType_VectorPtr) { free(this->newResult); } @@ -105,6 +105,18 @@ public: { delete *(string_t **)this->newResult; } + else if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr) + { + delete *(Vector **)this->newResult; + } + } + if(this->type == ReturnType_Vector || this->type == ReturnType_VectorPtr) + { + delete *(Vector **)this->orgResult; + } + else if(this->type != ReturnType_String && this->type != ReturnType_Int && this->type != ReturnType_Bool && this->type != ReturnType_Float) + { + free(*(void **)this->orgResult); } free(this->orgResult); } @@ -149,6 +161,7 @@ public: #ifndef __linux__ void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep); float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep); +Vector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep); #else void *Callback(DHooksCallback *dg, void **stack); float Callback_float(DHooksCallback *dg, void **stack); @@ -181,23 +194,35 @@ static void *GenerateThunk(ReturnType type) return base; } #else +// HUGE THANKS TO BAILOPAN (dvander)! static void *GenerateThunk(ReturnType type) { MacroAssemblerX86 masm; - + static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max + static const size_t kReserve = ke::Align(kStackNeeded+8, 16)-8; + masm.push(ebp); masm.movl(ebp, esp); - masm.subl(esp, 4); - masm.push(esp); - masm.lea(eax, Operand(ebp, 8)); - masm.push(eax); - masm.push(ecx); + masm.subl(esp, kReserve); + masm.lea(eax, Operand(esp, 3 * 4)); // ptr to 2nd var after argument space + masm.movl(Operand(esp, 2 * 4), eax); // set the ptr as the third argument + masm.lea(eax, Operand(ebp, 8)); // grab the incoming caller argument vector + masm.movl(Operand(esp, 1 * 4), eax); // set that as the 2nd argument + masm.movl(Operand(esp, 0 * 4), ecx); // set |this| as the 1st argument if(type == ReturnType_Float) + { masm.call(ExternalAddress(Callback_float)); + } + else if(type == ReturnType_Vector) + { + masm.call(ExternalAddress(Callback_vector)); + } else + { masm.call(ExternalAddress(Callback)); - masm.addl(esp, 12); - masm.pop(ecx); // grab arg size + } + masm.movl(ecx, Operand(esp, 3*4)); + masm.addl(esp, kReserve); masm.pop(ebp); // restore ebp masm.pop(edx); // grab return address in edx masm.addl(esp, ecx); // remove arguments