Merge.
authorDavid Anderson <dvander@alliedmods.net>
Wed Feb 25 19:22:47 2009 -0500 (2009-02-25)
changeset 2604d1e000a860e0
parent 2603 fa286305bd3f
parent 2601 a022964a0803
child 2605 99655b775e43
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 = &wr;
   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 = &wr;
   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  		}