Merge.
Merge.
1.1 --- a/extensions/tf2/CDetour/detourhelpers.h Wed Feb 25 19:22:36 2009 -0500
1.2 +++ b/extensions/tf2/CDetour/detourhelpers.h Wed Feb 25 19:22:47 2009 -0500
1.3 @@ -26,13 +26,13 @@
1.4 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.5 * or <http://www.sourcemod.net/license.php>.
1.6 *
1.7 - * Version: $Id$
1.8 + * Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
1.9 */
1.10
1.11 #ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
1.12 #define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
1.13
1.14 -#if defined PLATFORM_POSIX
1.15 +#if defined PLATFORM_LINUX
1.16 #include <sys/mman.h>
1.17 #define PAGE_SIZE 4096
1.18 #define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
1.19 @@ -52,7 +52,7 @@
1.20
1.21 inline void ProtectMemory(void *addr, int length, int prot)
1.22 {
1.23 -#if defined PLATFORM_POSIX
1.24 +#if defined PLATFORM_LINUX
1.25 void *addr2 = (void *)ALIGN(addr);
1.26 mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
1.27 #elif defined PLATFORM_WINDOWS
2.1 --- a/extensions/tf2/CDetour/detours.cpp Wed Feb 25 19:22:36 2009 -0500
2.2 +++ b/extensions/tf2/CDetour/detours.cpp Wed Feb 25 19:22:47 2009 -0500
2.3 @@ -26,7 +26,7 @@
2.4 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
2.5 * or <http://www.sourcemod.net/license.php>.
2.6 *
2.7 -* Version: $Id$
2.8 +* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
2.9 */
2.10
2.11 #include "detours.h"
2.12 @@ -34,7 +34,6 @@
2.13
2.14 ISourcePawnEngine *CDetourManager::spengine = NULL;
2.15 IGameConfig *CDetourManager::gameconf = NULL;
2.16 -int CDetourManager::returnValue = 0;
2.17
2.18 void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
2.19 {
2.20 @@ -42,9 +41,9 @@
2.21 CDetourManager::gameconf = gameconf;
2.22 }
2.23
2.24 -CDetour *CDetourManager::CreateDetour(void *callbackfunction, size_t paramsize, const char *signame)
2.25 +CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
2.26 {
2.27 - CDetour *detour = new CDetour(callbackfunction, paramsize, signame);
2.28 + CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
2.29 if (detour)
2.30 {
2.31 if (!detour->Init(spengine, gameconf))
2.32 @@ -59,50 +58,17 @@
2.33 return NULL;
2.34 }
2.35
2.36 -void CDetourManager::DeleteDetour(CDetour *detour)
2.37 -{
2.38 - delete detour;
2.39 -}
2.40 -
2.41 -CBlocker * CDetourManager::CreateFunctionBlock( const char *signame, bool isVoid )
2.42 -{
2.43 - CBlocker *block = new CBlocker(signame, isVoid);
2.44 -
2.45 - if (block)
2.46 - {
2.47 - if (!block->Init(spengine, gameconf))
2.48 - {
2.49 - delete block;
2.50 - return NULL;
2.51 - }
2.52 -
2.53 - return block;
2.54 - }
2.55 -
2.56 - return NULL;
2.57 -}
2.58 -
2.59 -void CDetourManager::DeleteFunctionBlock(CBlocker *block)
2.60 -{
2.61 - delete block;
2.62 -}
2.63 -
2.64 -CDetour::CDetour(void *callbackfunction, size_t paramsize, const char *signame)
2.65 +CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
2.66 {
2.67 enabled = false;
2.68 detoured = false;
2.69 detour_address = NULL;
2.70 - detour_callback = NULL;
2.71 + detour_trampoline = NULL;
2.72 this->signame = signame;
2.73 - this->callbackfunction = callbackfunction;
2.74 + this->detour_callback = callbackfunction;
2.75 spengine = NULL;
2.76 gameconf = NULL;
2.77 - this->paramsize = paramsize;
2.78 -}
2.79 -
2.80 -CDetour::~CDetour()
2.81 -{
2.82 - DeleteDetour();
2.83 + this->trampoline = trampoline;
2.84 }
2.85
2.86 bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
2.87 @@ -121,6 +87,12 @@
2.88 return enabled;
2.89 }
2.90
2.91 +void CDetour::Destroy()
2.92 +{
2.93 + DeleteDetour();
2.94 + delete this;
2.95 +}
2.96 +
2.97 bool CDetour::IsEnabled()
2.98 {
2.99 return enabled;
2.100 @@ -148,7 +120,6 @@
2.101 detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
2.102 }
2.103
2.104 - //detour_callback = spengine->ExecAlloc(100);
2.105 JitWriter wr;
2.106 JitWriter *jit = ≀
2.107 jit_uint32_t CodeSize = 0;
2.108 @@ -158,47 +129,6 @@
2.109
2.110 jit_rewind:
2.111
2.112 - /* Push all our params onto the stack */
2.113 - for (size_t i=0; i<paramsize; i++)
2.114 - {
2.115 -#if defined PLATFORM_WINDOWS
2.116 - IA32_Push_Rm_Disp8_ESP(jit, (paramsize*4));
2.117 -#elif defined PLATFORM_LINUX
2.118 - IA32_Push_Rm_Disp8_ESP(jit, 4 +(paramsize*4));
2.119 -#endif
2.120 - }
2.121 -
2.122 - /* Push thisptr onto the stack */
2.123 -#if defined PLATFORM_WINDOWS
2.124 - IA32_Push_Reg(jit, REG_ECX);
2.125 -#elif defined PLATFORM_LINUX
2.126 - IA32_Push_Rm_Disp8_ESP(jit, 4 + (paramsize*4));
2.127 -#endif
2.128 -
2.129 - jitoffs_t call = IA32_Call_Imm32(jit, 0);
2.130 - IA32_Write_Jump32_Abs(jit, call, callbackfunction);
2.131 -
2.132 - /* Pop thisptr */
2.133 -#if defined PLATFORM_LINUX
2.134 - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
2.135 -#elif defined PLATFORM_WINDOWS
2.136 - IA32_Pop_Reg(jit, REG_ECX);
2.137 -#endif
2.138 -
2.139 - /* Pop params from the stack */
2.140 - for (size_t i=0; i<paramsize; i++)
2.141 - {
2.142 - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
2.143 - }
2.144 -
2.145 - //If TempDetour returns non-zero we want to load something into eax and return this value
2.146 -
2.147 - //test eax, eax
2.148 - IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
2.149 -
2.150 - //jnz _skip
2.151 - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
2.152 -
2.153 /* Patch old bytes in */
2.154 if (wr.outbase != NULL)
2.155 {
2.156 @@ -207,15 +137,8 @@
2.157 wr.outptr += detour_restore.bytes;
2.158
2.159 /* Return to the original function */
2.160 - call = IA32_Jump_Imm32(jit, 0);
2.161 + jitoffs_t call = IA32_Jump_Imm32(jit, 0);
2.162 IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
2.163 -
2.164 - //_skip:
2.165 - //mov eax, [g_returnvalue]
2.166 - //ret
2.167 - IA32_Send_Jump8_Here(jit, jmp);
2.168 - IA32_Mov_Eax_Mem(jit, (jit_int32_t)&CDetourManager::returnValue);
2.169 - IA32_Return(jit);
2.170
2.171 if (wr.outbase == NULL)
2.172 {
2.173 @@ -223,15 +146,32 @@
2.174 wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
2.175 spengine->SetReadWrite(wr.outbase);
2.176 wr.outptr = wr.outbase;
2.177 - detour_callback = wr.outbase;
2.178 + detour_trampoline = wr.outbase;
2.179 goto jit_rewind;
2.180 }
2.181
2.182 spengine->SetReadExecute(wr.outbase);
2.183
2.184 + *trampoline = detour_trampoline;
2.185 +
2.186 return true;
2.187 }
2.188
2.189 +void CDetour::DeleteDetour()
2.190 +{
2.191 + if (detoured)
2.192 + {
2.193 + DisableDetour();
2.194 + }
2.195 +
2.196 + if (detour_trampoline)
2.197 + {
2.198 + /* Free the allocated trampoline memory */
2.199 + spengine->FreePageMemory(detour_trampoline);
2.200 + detour_trampoline = NULL;
2.201 + }
2.202 +}
2.203 +
2.204 void CDetour::EnableDetour()
2.205 {
2.206 if (!detoured)
2.207 @@ -241,132 +181,12 @@
2.208 }
2.209 }
2.210
2.211 -void CDetour::DeleteDetour()
2.212 -{
2.213 - if (detoured)
2.214 - {
2.215 - DisableDetour();
2.216 - }
2.217 -
2.218 - if (detour_callback)
2.219 - {
2.220 - /* Free the gate */
2.221 - spengine->FreePageMemory(detour_callback);
2.222 - detour_callback = NULL;
2.223 - }
2.224 -}
2.225 -
2.226 void CDetour::DisableDetour()
2.227 {
2.228 if (detoured)
2.229 {
2.230 /* Remove the patch */
2.231 - /* This may screw up */
2.232 ApplyPatch(detour_address, 0, &detour_restore, NULL);
2.233 detoured = false;
2.234 }
2.235 }
2.236 -
2.237 -CBlocker::CBlocker( const char *signame, bool isVoid )
2.238 -{
2.239 - this->isVoid = isVoid;
2.240 - isEnabled = false;
2.241 - isValid = false;
2.242 -
2.243 - spengine = NULL;
2.244 - gameconf = NULL;
2.245 - block_address = NULL;
2.246 - block_sig = signame;
2.247 -
2.248 - if (isVoid)
2.249 - {
2.250 - /* Void functions we only patch in a 'ret' (1 byte) */
2.251 - block_restore.bytes = 1;
2.252 - }
2.253 - else
2.254 - {
2.255 - /* Normal functions need an mov eax, value */
2.256 - block_restore.bytes = 6;
2.257 - }
2.258 -}
2.259 -
2.260 -void CBlocker::EnableBlock( int returnValue )
2.261 -{
2.262 - if (!isValid || isEnabled)
2.263 - {
2.264 - return;
2.265 - }
2.266 -
2.267 - /* First, save restore bits */
2.268 - for (size_t i=0; i<block_restore.bytes; i++)
2.269 - {
2.270 - block_restore.patch[i] = ((unsigned char *)block_address)[i];
2.271 - }
2.272 -
2.273 - JitWriter wr;
2.274 - JitWriter *jit = ≀
2.275 - wr.outbase = (jitcode_t)block_address;
2.276 - wr.outptr = wr.outbase;
2.277 -
2.278 - if (isVoid)
2.279 - {
2.280 - IA32_Return(jit);
2.281 - }
2.282 - else
2.283 - {
2.284 - IA32_Mov_Reg_Imm32(jit, REG_EAX, returnValue);
2.285 - IA32_Return(jit);
2.286 - }
2.287 -
2.288 - isEnabled = true;
2.289 -}
2.290 -
2.291 -void CBlocker::DisableBlock()
2.292 -{
2.293 - if (!isValid || !isEnabled)
2.294 - {
2.295 - return;
2.296 - }
2.297 -
2.298 - /* First, save restore bits */
2.299 - for (size_t i=0; i<block_restore.bytes; i++)
2.300 - {
2.301 - ((unsigned char *)block_address)[i] = block_restore.patch[i];
2.302 - }
2.303 -
2.304 - isEnabled = false;
2.305 -}
2.306 -
2.307 -CBlocker::~CBlocker()
2.308 -{
2.309 - if (!isValid || !isEnabled)
2.310 - {
2.311 - return;
2.312 - }
2.313 -
2.314 - DisableBlock();
2.315 -}
2.316 -
2.317 -bool CBlocker::Init( ISourcePawnEngine *spengine, IGameConfig *gameconf )
2.318 -{
2.319 - this->spengine = spengine;
2.320 - this->gameconf = gameconf;
2.321 -
2.322 - if (!gameconf->GetMemSig(block_sig, &block_address))
2.323 - {
2.324 - g_pSM->LogError(myself, "Could not locate %s - Disabling blocker", block_sig);
2.325 - isValid = false;
2.326 - return false;
2.327 - }
2.328 -
2.329 - if (!block_address)
2.330 - {
2.331 - g_pSM->LogError(myself, "Sigscan for %s failed - Disabling blocker", block_sig);
2.332 - isValid = false;
2.333 - return false;
2.334 - }
2.335 -
2.336 - isValid = true;
2.337 -
2.338 - return true;
2.339 -}
3.1 --- a/extensions/tf2/CDetour/detours.h Wed Feb 25 19:22:36 2009 -0500
3.2 +++ b/extensions/tf2/CDetour/detours.h Wed Feb 25 19:22:47 2009 -0500
3.3 @@ -26,7 +26,7 @@
3.4 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
3.5 * or <http://www.sourcemod.net/license.php>.
3.6 *
3.7 -* Version: $Id$
3.8 +* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
3.9 */
3.10
3.11 #ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
3.12 @@ -40,9 +40,103 @@
3.13 /**
3.14 * CDetours class for SourceMod Extensions by pRED*
3.15 * detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
3.16 - * asm.h/c from devmaster.net (thanks cybermind)
3.17 + * asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
3.18 + * Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
3.19 + * Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
3.20 */
3.21
3.22 +#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
3.23 +#define DETOUR_STATIC_CALL(name) (name##_Actual)
3.24 +
3.25 +#define DETOUR_DECL_STATIC0(name, ret) \
3.26 +ret (*name##_Actual)(void) = NULL; \
3.27 +ret name(void)
3.28 +
3.29 +#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
3.30 +ret (*name##_Actual)(p1type) = NULL; \
3.31 +ret name(p1type p1name)
3.32 +
3.33 +#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
3.34 +ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
3.35 +ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
3.36 +
3.37 +#define DETOUR_DECL_MEMBER0(name, ret) \
3.38 +class name##Class \
3.39 +{ \
3.40 +public: \
3.41 + ret name(); \
3.42 + static ret (name##Class::* name##_Actual)(void); \
3.43 +}; \
3.44 +ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
3.45 +ret name##Class::name()
3.46 +
3.47 +#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
3.48 +class name##Class \
3.49 +{ \
3.50 +public: \
3.51 + ret name(p1type p1name); \
3.52 + static ret (name##Class::* name##_Actual)(p1type); \
3.53 +}; \
3.54 +ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
3.55 +ret name##Class::name(p1type p1name)
3.56 +
3.57 +#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
3.58 +class name##Class \
3.59 +{ \
3.60 +public: \
3.61 + ret name(p1type p1name, p2type p2name); \
3.62 + static ret (name##Class::* name##_Actual)(p1type, p2type); \
3.63 +}; \
3.64 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
3.65 +ret name##Class::name(p1type p1name, p2type p2name)
3.66 +
3.67 +#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
3.68 +class name##Class \
3.69 +{ \
3.70 +public: \
3.71 + ret name(p1type p1name, p2type p2name, p3type p3name); \
3.72 + static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
3.73 +}; \
3.74 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
3.75 +ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
3.76 +
3.77 +#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
3.78 +class name##Class \
3.79 +{ \
3.80 +public: \
3.81 + ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
3.82 + static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
3.83 +}; \
3.84 +ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
3.85 +ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
3.86 +
3.87 +
3.88 +#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
3.89 +#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
3.90 +
3.91 +#define GET_STATIC_CALLBACK(name) (void *)&name
3.92 +#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
3.93 +
3.94 +#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
3.95 +#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
3.96 +
3.97 +
3.98 +class GenericClass {};
3.99 +typedef void (GenericClass::*VoidFunc)();
3.100 +
3.101 +inline void *GetCodeAddr(VoidFunc mfp)
3.102 +{
3.103 + return *(void **)&mfp;
3.104 +}
3.105 +
3.106 +/**
3.107 + * Converts a member function pointer to a void pointer.
3.108 + * This relies on the assumption that the code address lies at mfp+0
3.109 + * This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
3.110 + * Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
3.111 + */
3.112 +#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
3.113 +
3.114 class CDetourManager;
3.115
3.116 class CDetour
3.117 @@ -57,11 +151,12 @@
3.118 void EnableDetour();
3.119 void DisableDetour();
3.120
3.121 + void Destroy();
3.122 +
3.123 friend class CDetourManager;
3.124
3.125 protected:
3.126 - CDetour(void *callbackfunction, size_t paramsize, const char *signame);
3.127 - ~CDetour();
3.128 + CDetour(void *callbackfunction, void **trampoline, const char *signame);
3.129
3.130 bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
3.131 private:
3.132 @@ -74,42 +169,16 @@
3.133 bool detoured;
3.134
3.135 patch_t detour_restore;
3.136 + /* Address of the detoured function */
3.137 void *detour_address;
3.138 + /* Address of the allocated trampoline function */
3.139 + void *detour_trampoline;
3.140 + /* Address of the callback handler */
3.141 void *detour_callback;
3.142 -
3.143 + /* The function pointer used to call our trampoline */
3.144 + void **trampoline;
3.145 +
3.146 const char *signame;
3.147 -
3.148 - void *callbackfunction;
3.149 -
3.150 - size_t paramsize;
3.151 -
3.152 - ISourcePawnEngine *spengine;
3.153 - IGameConfig *gameconf;
3.154 -};
3.155 -
3.156 -class CBlocker
3.157 -{
3.158 -public:
3.159 - void EnableBlock(int returnValue = 0);
3.160 - void DisableBlock();
3.161 -
3.162 - friend class CDetourManager;
3.163 -
3.164 -protected:
3.165 - CBlocker(const char *signame, bool isVoid);
3.166 - ~CBlocker();
3.167 -
3.168 - bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
3.169 -
3.170 -private:
3.171 - bool isValid;
3.172 - bool isEnabled;
3.173 - bool isVoid;
3.174 - patch_t block_restore;
3.175 - void *block_address;
3.176 -
3.177 - const char *block_sig;
3.178 -
3.179 ISourcePawnEngine *spengine;
3.180 IGameConfig *gameconf;
3.181 };
3.182 @@ -118,25 +187,13 @@
3.183 {
3.184 public:
3.185
3.186 - /**
3.187 - * Return Types for Detours
3.188 - */
3.189 - enum DetourReturn
3.190 - {
3.191 - DetourReturn_Ignored = 0, /** Ignore our result and let the original function run */
3.192 - DetourReturn_Override = 1, /** Block the original function from running and use our return value */
3.193 - };
3.194 -
3.195 static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
3.196
3.197 /**
3.198 * Creates a new detour
3.199 - * @param callbackfunction Void pointer to your detour callback function. This should be a static function.
3.200 - * It should have pointer to the thisptr as the first param and then the same params
3.201 - * as the original function. Use void * for unknown types.
3.202 - * @param paramsize This is usually the number of params the function has (not including thisptr). If the function
3.203 - * passes complex types by value you need to add the sizeof() the type (aligned to 4 bytes).
3.204 - * Ie: passing something of size 8 would count as 2 in the param count.
3.205 + *
3.206 + * @param callbackfunction Void pointer to your detour callback function.
3.207 + * @param trampoline Address of the trampoline pointer
3.208 * @param signame Section name containing a signature to fetch from the gamedata file.
3.209 * @return A new CDetour pointer to control your detour.
3.210 *
3.211 @@ -144,37 +201,34 @@
3.212 *
3.213 * CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
3.214 *
3.215 - * Callback:
3.216 - * DetourReturn ConnectClientDetour(void *CBaseServer, void *netaddr_s, int something, int something2, int something3, char const* name, char const* pass, const char* steamcert, int len);
3.217 + * Define a new class with the required function and a member function pointer to the same type:
3.218 + *
3.219 + * class CBaseServerDetour
3.220 + * {
3.221 + * public:
3.222 + * bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
3.223 + * static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
3.224 + * }
3.225 + *
3.226 + * void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
3.227 + * void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
3.228 *
3.229 * Creation:
3.230 - * CDetourManager::CreateDetour((void *)&ConnectClientDetour, 8, "ConnectClient");
3.231 - */
3.232 - static CDetour *CreateDetour(void *callbackfunction, size_t paramsize, const char *signame);
3.233 -
3.234 - /**
3.235 - * Deletes a detour
3.236 - */
3.237 - static void DeleteDetour(CDetour *detour);
3.238 -
3.239 - /**
3.240 - * Creates a function blocker. This is slightly faster than a detour because it avoids a call.
3.241 + * CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
3.242 + *
3.243 + * Usage:
3.244 *
3.245 - * @param signame Section name containing a signature to fetch from the gamedata file.
3.246 - * @param isVoid Specifies if the function can return void.
3.247 - */
3.248 - static CBlocker *CreateFunctionBlock(const char *signame, bool isVoid);
3.249 -
3.250 - /**
3.251 - * Delete a function blocker.
3.252 + * CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
3.253 + * {
3.254 + * //pre hook code
3.255 + * bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
3.256 + * //post hook code
3.257 + * return result;
3.258 + * }
3.259 + *
3.260 + * Note we changed the netadr_s reference into a void* to avoid needing to define the type
3.261 */
3.262 - static void DeleteFunctionBlock(CBlocker *block);
3.263 -
3.264 -
3.265 - /**
3.266 - * Global DetourReturn value to use for the current hook
3.267 - */
3.268 - static int returnValue;
3.269 + static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
3.270
3.271 friend class CBlocker;
3.272 friend class CDetour;
3.273 @@ -184,13 +238,4 @@
3.274 static IGameConfig *gameconf;
3.275 };
3.276
3.277 -typedef bool DetourReturn;
3.278 -
3.279 -#define DETOUR_RESULT_IGNORED false
3.280 -#define DETOUR_RESULT_OVERRIDE true
3.281 -
3.282 -#define SET_DETOUR_RETURN_VALUE(value) CDetourManager::returnValue=(int)value
3.283 -#define RETURN_DETOUR(result) return result
3.284 -#define RETURN_DETOUR_VALUE(result,value) do { SET_DETOUR_RETURN_VALUE(value); return (result); } while(0)
3.285 -
3.286 #endif // _INCLUDE_SOURCEMOD_DETOURS_H_
4.1 --- a/extensions/tf2/asm/asm.c Wed Feb 25 19:22:36 2009 -0500
4.2 +++ b/extensions/tf2/asm/asm.c Wed Feb 25 19:22:47 2009 -0500
4.3 @@ -1,5 +1,91 @@
4.4 #include "asm.h"
4.5
4.6 +#ifndef WIN32
4.7 +#define _GNU_SOURCE
4.8 +#include <dlfcn.h>
4.9 +#include <string.h>
4.10 +
4.11 +#define REG_EAX 0
4.12 +#define REG_ECX 1
4.13 +#define REG_EDX 2
4.14 +#define REG_EBX 3
4.15 +
4.16 +#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
4.17 +#endif
4.18 +
4.19 +extern void Msg( const char *, ... );
4.20 +
4.21 +/**
4.22 +* Checks if a call to a fpic thunk has just been written into dest.
4.23 +* If found replaces it with a direct mov that sets the required register to the value of pc.
4.24 +*
4.25 +* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
4.26 +* @param pc The program counter value that needs to be set (usually the next address from the source).
4.27 +* @noreturn
4.28 +*/
4.29 +void check_thunks(unsigned char *dest, unsigned char *pc)
4.30 +{
4.31 +#if defined WIN32
4.32 + return;
4.33 +#else
4.34 + /* Step write address back 4 to the start of the function address */
4.35 + unsigned char *writeaddr = dest - 4;
4.36 + unsigned char *calloffset = *(unsigned char **)writeaddr;
4.37 + unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
4.38 +
4.39 + /* Lookup name of function being called */
4.40 + if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
4.41 + {
4.42 + //a thunk maybe?
4.43 + char movByte = IA32_MOV_REG_IMM;
4.44 +
4.45 + /* Calculate the correct mov opcode */
4.46 + switch (*(calladdr+1))
4.47 + {
4.48 + case 0x04:
4.49 + {
4.50 + movByte += REG_EAX;
4.51 + break;
4.52 + }
4.53 + case 0x1C:
4.54 + {
4.55 + movByte += REG_EBX;
4.56 + break;
4.57 + }
4.58 + case 0x0C:
4.59 + {
4.60 + movByte += REG_ECX;
4.61 + break;
4.62 + }
4.63 + case 0x14:
4.64 + {
4.65 + movByte += REG_EDX;
4.66 + break;
4.67 + }
4.68 + default:
4.69 + {
4.70 + Msg("Unknown thunk: %c\n", *(calladdr+1));
4.71 + break;
4.72 + }
4.73 + }
4.74 +
4.75 + /* Move our write address back one to where the call opcode was */
4.76 + writeaddr--;
4.77 +
4.78 +
4.79 + /* Write our mov */
4.80 + *writeaddr = movByte;
4.81 + writeaddr++;
4.82 +
4.83 + /* Write the value - The provided program counter value */
4.84 + *(void **)writeaddr = (void *)pc;
4.85 + writeaddr += 4;
4.86 + }
4.87 +
4.88 + return;
4.89 +#endif
4.90 +}
4.91 +
4.92 //if dest is NULL, returns minimum number of bytes needed to be copied
4.93 //if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
4.94 //http://www.devmaster.net/forums/showthread.php?t=2311
4.95 @@ -195,9 +281,15 @@
4.96 //Fix CALL/JMP offset
4.97 if ((opcode & 0xFE) == 0xE8) {
4.98 if (operandSize == 4)
4.99 + {
4.100 *(long*)dest = ((func + *(long*)func) - dest);
4.101 +
4.102 + //pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
4.103 + check_thunks(dest+4, func+4);
4.104 + }
4.105 else
4.106 *(short*)dest = ((func + *(short*)func) - dest);
4.107 +
4.108 } else {
4.109 if (operandSize == 4)
4.110 *(unsigned long*)dest = *(unsigned long*)func;
5.1 --- a/extensions/tf2/asm/asm.h Wed Feb 25 19:22:36 2009 -0500
5.2 +++ b/extensions/tf2/asm/asm.h Wed Feb 25 19:22:47 2009 -0500
5.3 @@ -17,6 +17,8 @@
5.4 extern "C" {
5.5 #endif
5.6
5.7 +void check_thunks(unsigned char *dest, unsigned char *pc);
5.8 +
5.9 //if dest is NULL, returns minimum number of bytes needed to be copied
5.10 //if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
5.11 //http://www.devmaster.net/forums/showthread.php?t=2311
6.1 --- a/extensions/tf2/criticals.cpp Wed Feb 25 19:22:36 2009 -0500
6.2 +++ b/extensions/tf2/criticals.cpp Wed Feb 25 19:22:47 2009 -0500
6.3 @@ -39,40 +39,6 @@
6.4
6.5 IForward *g_critForward = NULL;
6.6
6.7 -void InitialiseDetours()
6.8 -{
6.9 - calcIsAttackCriticalDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCritical");
6.10 - calcIsAttackCriticalMeleeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalMelee");
6.11 - calcIsAttackCriticalKnifeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalKnife");
6.12 -
6.13 - bool HookCreated = false;
6.14 -
6.15 - if (calcIsAttackCriticalDetour != NULL)
6.16 - {
6.17 - calcIsAttackCriticalDetour->EnableDetour();
6.18 - HookCreated = true;
6.19 - }
6.20 -
6.21 - if (calcIsAttackCriticalMeleeDetour != NULL)
6.22 - {
6.23 - calcIsAttackCriticalMeleeDetour->EnableDetour();
6.24 - HookCreated = true;
6.25 - }
6.26 -
6.27 - if (calcIsAttackCriticalKnifeDetour != NULL)
6.28 - {
6.29 - calcIsAttackCriticalKnifeDetour->EnableDetour();
6.30 - HookCreated = true;
6.31 - }
6.32 -
6.33 - if (!HookCreated)
6.34 - {
6.35 - g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks");
6.36 - return;
6.37 - }
6.38 -
6.39 -}
6.40 -
6.41 int CheckBaseHandle(CBaseHandle &hndl)
6.42 {
6.43 if (!hndl.IsValid())
6.44 @@ -106,9 +72,9 @@
6.45 return index;
6.46 }
6.47
6.48 -DetourReturn TempDetour(void *pWeapon)
6.49 +DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelper, bool)
6.50 {
6.51 - edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pWeapon);
6.52 + edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)this);
6.53
6.54 if (!pEdict)
6.55 {
6.56 @@ -132,7 +98,7 @@
6.57
6.58 int returnValue=0;
6.59
6.60 - CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + info.actual_offset);
6.61 + CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)this + info.actual_offset);
6.62 int index = CheckBaseHandle(hndl);
6.63
6.64 g_critForward->PushCell(index); //Client index
6.65 @@ -146,18 +112,52 @@
6.66
6.67 if (result)
6.68 {
6.69 - RETURN_DETOUR_VALUE(DETOUR_RESULT_OVERRIDE, returnValue);
6.70 + return !!returnValue;
6.71 }
6.72 else
6.73 {
6.74 - RETURN_DETOUR_VALUE(DETOUR_RESULT_IGNORED, returnValue);
6.75 + return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelper)();
6.76 }
6.77
6.78 }
6.79
6.80 +void InitialiseDetours()
6.81 +{
6.82 + calcIsAttackCriticalDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelper, "CalcCritical");
6.83 + calcIsAttackCriticalMeleeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelper, "CalcCriticalMelee");
6.84 + calcIsAttackCriticalKnifeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelper, "CalcCriticalKnife");
6.85 +
6.86 + bool HookCreated = false;
6.87 +
6.88 + if (calcIsAttackCriticalDetour != NULL)
6.89 + {
6.90 + calcIsAttackCriticalDetour->EnableDetour();
6.91 + HookCreated = true;
6.92 + }
6.93 +
6.94 + if (calcIsAttackCriticalMeleeDetour != NULL)
6.95 + {
6.96 + calcIsAttackCriticalMeleeDetour->EnableDetour();
6.97 + HookCreated = true;
6.98 + }
6.99 +
6.100 + if (calcIsAttackCriticalKnifeDetour != NULL)
6.101 + {
6.102 + calcIsAttackCriticalKnifeDetour->EnableDetour();
6.103 + HookCreated = true;
6.104 + }
6.105 +
6.106 + if (!HookCreated)
6.107 + {
6.108 + g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks");
6.109 + return;
6.110 + }
6.111 +
6.112 +}
6.113 +
6.114 void RemoveDetours()
6.115 {
6.116 - CDetourManager::DeleteDetour(calcIsAttackCriticalDetour);
6.117 - CDetourManager::DeleteDetour(calcIsAttackCriticalMeleeDetour);
6.118 - CDetourManager::DeleteDetour(calcIsAttackCriticalKnifeDetour);
6.119 + calcIsAttackCriticalDetour->Destroy();
6.120 + calcIsAttackCriticalMeleeDetour->Destroy();
6.121 + calcIsAttackCriticalKnifeDetour->Destroy();
6.122 }
7.1 --- a/extensions/tf2/criticals.h Wed Feb 25 19:22:36 2009 -0500
7.2 +++ b/extensions/tf2/criticals.h Wed Feb 25 19:22:47 2009 -0500
7.3 @@ -40,8 +40,6 @@
7.4 void InitialiseDetours();
7.5 void RemoveDetours();
7.6
7.7 -bool TempDetour(void *pWeapon);
7.8 -
7.9 extern IForward *g_critForward;
7.10
7.11 extern IServerGameEnts *gameents;
8.1 --- a/extensions/tf2/extension.cpp Wed Feb 25 19:22:36 2009 -0500
8.2 +++ b/extensions/tf2/extension.cpp Wed Feb 25 19:22:47 2009 -0500
8.3 @@ -90,7 +90,7 @@
8.4 char conf_error[255] = "";
8.5 if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error)))
8.6 {
8.7 - if (conf_error)
8.8 + if (conf_error[0])
8.9 {
8.10 UTIL_Format(error, maxlength, "Could not read sm-tf2.games.txt: %s", conf_error);
8.11 }
9.1 --- a/gamedata/sdktools.games.ep2.txt Wed Feb 25 19:22:36 2009 -0500
9.2 +++ b/gamedata/sdktools.games.ep2.txt Wed Feb 25 19:22:47 2009 -0500
9.3 @@ -318,8 +318,8 @@
9.4 }
9.5 "CommitSuicide"
9.6 {
9.7 - "windows" "388"
9.8 - "linux" "388"
9.9 + "windows" "390"
9.10 + "linux" "390"
9.11 }
9.12 "GetVelocity"
9.13 {
10.1 --- a/gamedata/sm-tf2.games.txt Wed Feb 25 19:22:36 2009 -0500
10.2 +++ b/gamedata/sm-tf2.games.txt Wed Feb 25 19:22:47 2009 -0500
10.3 @@ -6,39 +6,39 @@
10.4 {
10.5 "Burn"
10.6 {
10.7 - "library" "server"
10.8 + "library" "server"
10.9 "windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\x8B\x01\x8B\x90\x2A\x2A\x00\x00\xFF\xD2\x84\xC0"
10.10 "linux" "@_ZN15CTFPlayerShared4BurnEP9CTFPlayerP13CTFWeaponBase"
10.11 }
10.12 "RemoveDisguise"
10.13 {
10.14 - "library" "server"
10.15 + "library" "server"
10.16 "windows" "\x51\x56\x8B\xF1\x8B\x46\x2A\x57\x8D\x7E\x2A\x8D\x4C\x24\x08\x83\xE0\xF7"
10.17 "linux" "@_ZN15CTFPlayerShared14RemoveDisguiseEv"
10.18 }
10.19 "Disguise"
10.20 {
10.21 - "library" "server"
10.22 + "library" "server"
10.23 "windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\xE8\x2A\x2A\x2A\x2A\x8B\x8E\x2A\x2A\x00\x00\x8B\x89\x2A\x2A\x00\x00"
10.24 "linux" "@_ZN15CTFPlayerShared8DisguiseEii"
10.25 }
10.26 "CalcCritical"
10.27 {
10.28 - "library" "server"
10.29 + "library" "server"
10.30 "linux" "@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv"
10.31 "windows" "\x83\xEC\x08\x53\x56\x6A\x00"
10.32 }
10.33 "CalcCriticalMelee"
10.34 {
10.35 - "library" "server"
10.36 + "library" "server"
10.37 "linux" "@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv"
10.38 "windows" "\x83\xEC\x08\x53\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xD8"
10.39 }
10.40 "CalcCriticalKnife"
10.41 {
10.42 - "library" "server"
10.43 + "library" "server"
10.44 "linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
10.45 - "windows" "\x33\xC0\x83\xB9\x30\x13\x00\x00\x01\x0F\x94\xC0\xC3"
10.46 + "windows" "\x8B\x81\xF0\x13\x00\x00\x83\xF8\xFF\x74\x29\x8B\x15"
10.47 }
10.48
10.49 }