1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-29 11:24:19 +01:00
HLMetaModOfficial/core/sourcehook/generate/sh_memfuncinfo.hxx
David Anderson e19413dd5b Some reorganization.
--HG--
rename : sourcemm/IPluginManager.h => core/IPluginManager.h
rename : sourcemm/ISmmAPI.h => core/ISmmAPI.h
rename : sourcemm/ISmmPlugin.h => core/ISmmPlugin.h
rename : sourcemm/ISmmPluginExt.h => core/ISmmPluginExt.h
rename : sourcemm/LICENSE.txt => core/LICENSE.txt
rename : sourcemm/Makefile => core/Makefile
rename : sourcemm/changelog.txt => core/changelog.txt
rename : sourcemm/episode1/console.cpp => core/episode1/console.cpp
rename : sourcemm/episode1/console.h => core/episode1/console.h
rename : sourcemm/episode1/convar_smm.h => core/episode1/convar_smm.h
rename : sourcemm/episode1/msvc8/sourcemm.sln => core/episode1/msvc8/sourcemm.sln
rename : sourcemm/episode1/msvc8/sourcemm.vcproj => core/episode1/msvc8/sourcemm.vcproj
rename : sourcemm/episode1/provider_ep1.cpp => core/episode1/provider_ep1.cpp
rename : sourcemm/episode1/provider_ep1.h => core/episode1/provider_ep1.h
rename : sourcemm/episode1/vsp_listener.cpp => core/episode1/vsp_listener.cpp
rename : sourcemm/episode1/vsp_listener.h => core/episode1/vsp_listener.h
rename : sourcemm/metamod.cpp => core/metamod.cpp
rename : sourcemm/metamod.h => core/metamod.h
rename : sourcemm/metamod_console.cpp => core/metamod_console.cpp
rename : sourcemm/metamod_console.h => core/metamod_console.h
rename : sourcemm/metamod_oslink.cpp => core/metamod_oslink.cpp
rename : sourcemm/metamod_oslink.h => core/metamod_oslink.h
rename : sourcemm/metamod_plugins.cpp => core/metamod_plugins.cpp
rename : sourcemm/metamod_plugins.h => core/metamod_plugins.h
rename : sourcemm/metamod_provider.h => core/metamod_provider.h
rename : sourcemm/metamod_util.cpp => core/metamod_util.cpp
rename : sourcemm/metamod_util.h => core/metamod_util.h
rename : sourcemm/episode2/console.cpp => core/provider/console.cpp
rename : sourcemm/episode2/console.h => core/provider/console.h
rename : sourcemm/episode2/msvc8/sourcemm.sln => core/provider/msvc8/sourcemm.sln
rename : sourcemm/episode2/msvc8/sourcemm.vcproj => core/provider/msvc8/sourcemm.vcproj
rename : sourcemm/episode2/msvc9/sourcemm.sln => core/provider/msvc9/sourcemm.sln
rename : sourcemm/episode2/msvc9/sourcemm.vcproj => core/provider/msvc9/sourcemm.vcproj
rename : sourcemm/episode2/provider_ep2.cpp => core/provider/provider_ep2.cpp
rename : sourcemm/episode2/provider_ep2.h => core/provider/provider_ep2.h
rename : sourcemm/episode2/vsp_listener.cpp => core/provider/vsp_listener.cpp
rename : sourcemm/episode2/vsp_listener.h => core/provider/vsp_listener.h
rename : sourcehook/FastDelegate.h => core/sourcehook/FastDelegate.h
rename : sourcehook/generate/FastDelegate.h => core/sourcehook/generate/FastDelegate.h
rename : sourcehook/generate/FastDelegate.hxx => core/sourcehook/generate/FastDelegate.hxx
rename : sourcehook/generate/generate => core/sourcehook/generate/generate
rename : sourcehook/generate/generate.bat => core/sourcehook/generate/generate.bat
rename : sourcehook/generate/sh_memfuncinfo.h => core/sourcehook/generate/sh_memfuncinfo.h
rename : sourcehook/generate/sh_memfuncinfo.hxx => core/sourcehook/generate/sh_memfuncinfo.hxx
rename : sourcehook/generate/shworker.bin => core/sourcehook/generate/shworker.bin
rename : sourcehook/generate/shworker.exe => core/sourcehook/generate/shworker.exe
rename : sourcehook/generate/shworker/Makefile => core/sourcehook/generate/shworker/Makefile
rename : sourcehook/generate/shworker/fd_hopter.cpp => core/sourcehook/generate/shworker/fd_hopter.cpp
rename : sourcehook/generate/shworker/msvc7/shworker.vcproj => core/sourcehook/generate/shworker/msvc7/shworker.vcproj
rename : sourcehook/generate/shworker/msvc8/shworker.vcproj => core/sourcehook/generate/shworker/msvc8/shworker.vcproj
rename : sourcehook/generate/shworker/shworker.cpp => core/sourcehook/generate/shworker/shworker.cpp
rename : sourcehook/generate/sourcehook.h => core/sourcehook/generate/sourcehook.h
rename : sourcehook/generate/sourcehook.hxx => core/sourcehook/generate/sourcehook.hxx
rename : sourcehook/sh_list.h => core/sourcehook/sh_list.h
rename : sourcehook/sh_memfuncinfo.h => core/sourcehook/sh_memfuncinfo.h
rename : sourcehook/sh_memory.h => core/sourcehook/sh_memory.h
rename : sourcehook/sh_pagealloc.h => core/sourcehook/sh_pagealloc.h
rename : sourcehook/sh_stack.h => core/sourcehook/sh_stack.h
rename : sourcehook/sh_string.h => core/sourcehook/sh_string.h
rename : sourcehook/sh_tinyhash.h => core/sourcehook/sh_tinyhash.h
rename : sourcehook/sh_vector.h => core/sourcehook/sh_vector.h
rename : sourcehook/sourcehook.cpp => core/sourcehook/sourcehook.cpp
rename : sourcehook/sourcehook.h => core/sourcehook/sourcehook.h
rename : sourcehook/sourcehook_hookmangen.cpp => core/sourcehook/sourcehook_hookmangen.cpp
rename : sourcehook/sourcehook_hookmangen.h => core/sourcehook/sourcehook_hookmangen.h
rename : sourcehook/sourcehook_hookmangen_x86.h => core/sourcehook/sourcehook_hookmangen_x86.h
rename : sourcehook/sourcehook_impl.h => core/sourcehook/sourcehook_impl.h
rename : sourcehook/sourcehook_impl_chook.h => core/sourcehook/sourcehook_impl_chook.h
rename : sourcehook/sourcehook_impl_chookidman.h => core/sourcehook/sourcehook_impl_chookidman.h
rename : sourcehook/sourcehook_impl_chookmaninfo.h => core/sourcehook/sourcehook_impl_chookmaninfo.h
rename : sourcehook/sourcehook_impl_ciface.h => core/sourcehook/sourcehook_impl_ciface.h
rename : sourcehook/sourcehook_impl_cproto.h => core/sourcehook/sourcehook_impl_cproto.h
rename : sourcehook/sourcehook_impl_cvfnptr.h => core/sourcehook/sourcehook_impl_cvfnptr.h
rename : sourcehook/sourcehook_pibuilder.h => core/sourcehook/sourcehook_pibuilder.h
rename : sourcehook/test/Makefile => core/sourcehook/test/Makefile
rename : sourcehook/test/generate.bat => core/sourcehook/test/generate.bat
rename : sourcehook/test/main.cpp => core/sourcehook/test/main.cpp
rename : sourcehook/test/msvc7/test.vcproj => core/sourcehook/test/msvc7/test.vcproj
rename : sourcehook/test/msvc8/test.vcproj => core/sourcehook/test/msvc8/test.vcproj
rename : sourcehook/test/sourcehook_test.h => core/sourcehook/test/sourcehook_test.h
rename : sourcehook/test/test1.cpp => core/sourcehook/test/test1.cpp
rename : sourcehook/test/test2.cpp => core/sourcehook/test/test2.cpp
rename : sourcehook/test/test3.cpp => core/sourcehook/test/test3.cpp
rename : sourcehook/test/test4.cpp => core/sourcehook/test/test4.cpp
rename : sourcehook/test/testbail.cpp => core/sourcehook/test/testbail.cpp
rename : sourcehook/test/testbail.h => core/sourcehook/test/testbail.h
rename : sourcehook/test/testbail2.cpp => core/sourcehook/test/testbail2.cpp
rename : sourcehook/test/testevents.h => core/sourcehook/test/testevents.h
rename : sourcehook/test/testhookmangen.cpp => core/sourcehook/test/testhookmangen.cpp
rename : sourcehook/test/testhookmangen.h => core/sourcehook/test/testhookmangen.h
rename : sourcehook/test/testhookmangen.hxx => core/sourcehook/test/testhookmangen.hxx
rename : sourcehook/test/testlist.cpp => core/sourcehook/test/testlist.cpp
rename : sourcehook/test/testmanual.cpp => core/sourcehook/test/testmanual.cpp
rename : sourcehook/test/testmulti.cpp => core/sourcehook/test/testmulti.cpp
rename : sourcehook/test/testrecall.cpp => core/sourcehook/test/testrecall.cpp
rename : sourcehook/test/testreentr.cpp => core/sourcehook/test/testreentr.cpp
rename : sourcehook/test/testref.cpp => core/sourcehook/test/testref.cpp
rename : sourcehook/test/testrefret.cpp => core/sourcehook/test/testrefret.cpp
rename : sourcehook/test/testvphooks.cpp => core/sourcehook/test/testvphooks.cpp
rename : sourcemm/svn_version.h => core/svn_version.h
rename : sourcemm/svn_version.tpl => core/svn_version.tpl
rename : sourcemm/version.rc => core/version.rc
2008-11-14 04:04:02 -06:00

333 lines
9.9 KiB
C++

/* ======== SourceHook ========
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
/**
* @brief This file provides a way for getting information about a member function.
* @file sh_memfuncinfo.h
*/
#ifndef __SHINT_MEMFUNC_INFO_H__
#define __SHINT_MEMFUNC_INFO_H__
namespace SourceHook
{
// Don Clugston:
// implicit_cast< >
// I believe this was originally going to be in the C++ standard but
// was left out by accident. It's even milder than static_cast.
// I use it instead of static_cast<> to emphasize that I'm not doing
// anything nasty.
// Usage is identical to static_cast<>
template <class OutputClass, class InputClass>
inline OutputClass implicit_cast(InputClass input){
return input;
}
struct MemFuncInfo
{
bool isVirtual; // Is the function virtual?
int thisptroffs; // The this pointer the function expects to be called with
// If -1, you need to call the GetFuncInfo_GetThisPtr function
int vtblindex; // The function's index in the vtable (0-based, 1=second entry, 2=third entry, ...)
int vtbloffs; // The vtable pointer
};
// Ideas by Don Clugston.
// Check out his excellent paper: http://www.codeproject.com/cpp/FastDelegate.asp
template<int N> struct MFI_Impl
{
template<class MFP> static inline void GetFuncInfo(MFP *mfp, MemFuncInfo &out)
{
static char weird_memfunc_pointer_exclamation_mark_arrow_error[N-1000];
}
};
# if SH_COMP == SH_COMP_GCC
template<> struct MFI_Impl<2*SH_PTRSIZE> // All of these have size==8/16
{
struct GCC_MemFunPtr
{
union
{
void *funcadr; // always even
intptr_t vtable_index_plus1; // = vindex+1, always odd
};
intptr_t delta;
};
template<class MFP> static inline void GetFuncInfo(MFP mfp, MemFuncInfo &out)
{
GCC_MemFunPtr *mfp_detail = (GCC_MemFunPtr*)&mfp;
out.thisptroffs = mfp_detail->delta;
if (mfp_detail->vtable_index_plus1 & 1)
{
out.vtblindex = (mfp_detail->vtable_index_plus1 - 1) / SH_PTRSIZE;
out.vtbloffs = 0;
out.isVirtual = true;
}
else
out.isVirtual = false;
}
};
# elif SH_COMP == SH_COMP_MSVC
namespace
{
int MFI_GetVtblOffset(void *mfp)
{
unsigned char *addr = (unsigned char*)mfp;
if (*addr == 0xE9) // Jmp
{
// May or may not be!
// Check where it'd jump
addr += 5 /*size of the instruction*/ + *(unsigned long*)(addr + 1);
}
// Check whether it's a virtual function call
// They look like this:
// 004125A0 8B 01 mov eax,dword ptr [ecx]
// 004125A2 FF 60 04 jmp dword ptr [eax+4]
// ==OR==
// 00411B80 8B 01 mov eax,dword ptr [ecx]
// 00411B82 FF A0 18 03 00 00 jmp dword ptr [eax+318h]
// However, for vararg functions, they look like this:
// 0048F0B0 8B 44 24 04 mov eax,dword ptr [esp+4]
// 0048F0B4 8B 00 mov eax,dword ptr [eax]
// 0048F0B6 FF 60 08 jmp dword ptr [eax+8]
// ==OR==
// 0048F0B0 8B 44 24 04 mov eax,dword ptr [esp+4]
// 0048F0B4 8B 00 mov eax,dword ptr [eax]
// 00411B82 FF A0 18 03 00 00 jmp dword ptr [eax+318h]
// With varargs, the this pointer is passed as if it was the first argument
bool ok = false;
if (addr[0] == 0x8B && addr[1] == 0x44 && addr[2] == 0x24 && addr[3] == 0x04 &&
addr[4] == 0x8B && addr[5] == 0x00)
{
addr += 6;
ok = true;
}
else if (addr[0] == 0x8B && addr[1] == 0x01)
{
addr += 2;
ok = true;
}
if (!ok)
return -1;
if (*addr++ == 0xFF)
{
if (*addr == 0x60)
{
return *++addr / 4;
}
else if (*addr == 0xA0)
{
return *((unsigned int*)++addr) / 4;
}
else if (*addr == 0x20)
return 0;
else
return -1;
}
return -1;
}
}
template<> struct MFI_Impl<1*SH_PTRSIZE> // simple ones
{
template<class MFP> static inline void GetFuncInfo(MFP mfp, MemFuncInfo &out)
{
out.vtblindex = MFI_GetVtblOffset(*(void**)&mfp);
out.isVirtual = out.vtblindex >= 0 ? true : false;
out.thisptroffs = 0;
out.vtbloffs = 0;
}
};
template<> struct MFI_Impl<2*SH_PTRSIZE> // more complicated ones!
{
struct MSVC_MemFunPtr2
{
void *funcadr;
int delta;
};
template<class MFP> static inline void GetFuncInfo(MFP mfp, MemFuncInfo &out)
{
out.vtblindex = MFI_GetVtblOffset(*(void**)&mfp);
out.isVirtual = out.vtblindex >= 0 ? true : false;
out.thisptroffs = reinterpret_cast<MSVC_MemFunPtr2*>(&mfp)->delta;
out.vtbloffs = 0;
}
};
// By Don Clugston, adapted
template<> struct MFI_Impl<3*SH_PTRSIZE> // WOW IT"S GETTING BIGGER OMGOMOGMG
{
class __single_inheritance GenericClass;
class GenericClass {};
struct MicrosoftVirtualMFP {
void (GenericClass::*codeptr)(); // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int vtable_index; // or 0 if no virtual inheritance
};
struct GenericVirtualClass : virtual public GenericClass
{
typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();
GenericVirtualClass * GetThis() { return this; }
};
template<class MFP> static inline void GetFuncInfo(MFP mfp, MemFuncInfo &out)
{
out.vtblindex = MFI_GetVtblOffset(*(void**)&mfp);
out.isVirtual = out.vtblindex >= 0 ? true : false;
// This pointer
/*
union {
MFP func;
GenericClass* (T::*ProbeFunc)();
MicrosoftVirtualMFP s;
} u;
u.func = mfp;
union {
GenericVirtualClass::ProbePtrType virtfunc;
MicrosoftVirtualMFP s;
} u2;
// Check that the horrible_cast<>s will work
typedef int ERROR_CantUsehorrible_cast[sizeof(mfp)==sizeof(u.s)
&& sizeof(mfp)==sizeof(u.ProbeFunc)
&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];
// Unfortunately, taking the address of a MF prevents it from being inlined, so
// this next line can't be completely optimised away by the compiler.
u2.virtfunc = &GenericVirtualClass::GetThis;
u.s.codeptr = u2.s.codeptr;
out.thisptroffs = (reinterpret_cast<T*>(NULL)->*u.ProbeFunc)();
*/
out.thisptroffs = -1;
out.vtbloffs = 0;
}
};
// Don: Nasty hack for Microsoft and Intel (IA32 and Itanium)
// unknown_inheritance classes go here
// This is probably the ugliest bit of code I've ever written. Look at the casts!
// There is a compiler bug in MSVC6 which prevents it from using this code.
template<> struct MFI_Impl<4*SH_PTRSIZE> // THE BIGGEST ONE!!!1GABEN
{
template<class MFP> static inline void GetFuncInfo(MFP mfp, MemFuncInfo &out)
{
out.vtblindex = MFI_GetVtblOffset(*(void**)&mfp);
out.isVirtual = out.vtblindex >= 0 ? true : false;
// The member function pointer is 16 bytes long. We can't use a normal cast, but
// we can use a union to do the conversion.
union {
MFP func;
// In VC++ and ICL, an unknown_inheritance member pointer
// is internally defined as:
struct {
void *m_funcaddress; // points to the actual member function
int delta; // #bytes to be added to the 'this' pointer
int vtordisp; // #bytes to add to 'this' to find the vtable
int vtable_index; // or 0 if no virtual inheritance
} s;
} u;
// Check that the horrible_cast will work
typedef int ERROR_CantUsehorrible_cast[sizeof(u.func)==sizeof(u.s)? 1 : -1];
u.func = mfp;
int virtual_delta = 0;
if (u.s.vtable_index) { // Virtual inheritance is used
/*
// First, get to the vtable.
// It is 'vtordisp' bytes from the start of the class.
int * vtable = *reinterpret_cast<int **>(
reinterpret_cast<char *>(thisptr) + u.s.vtordisp );
// 'vtable_index' tells us where in the table we should be looking.
virtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>(
reinterpret_cast<const char *>(vtable) + u.s.vtable_index);
// The int at 'virtual_delta' gives us the amount to add to 'this'.
// Finally we can add the three components together. Phew!
out.thisptr = reinterpret_cast<void *>(
reinterpret_cast<char *>(thisptr) + u.s.delta + virtual_delta);
*/
out.vtbloffs = u.s.vtordisp;
out.thisptroffs = -1;
}
else
{
out.vtbloffs = out.vtblindex < 0 ? 0 : u.s.delta;
out.thisptroffs = u.s.delta;
}
};
};
# else
# error Unsupported compiler
# endif
// This version does not take a this pointer
// Useful for hookdecls, as they ensure that mfp is correct through a static_cast
template<class X> inline void GetFuncInfo(X mfp, MemFuncInfo &out)
{
MFI_Impl<sizeof(mfp)>::GetFuncInfo(mfp, out);
}
// Versions which do take a this
@[$1,0,$a:
template<class X, class Y, class RetType@[$1!=0:, @]@[$2,1,$1|, :class Param$2@]>
inline void GetFuncInfo(Y *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]), MemFuncInfo &out)
{
RetType(Y::*mfp2)(@[$2,1,$1|, :Param$2@]) = mfp;
MFI_Impl<sizeof(mfp2)>::GetFuncInfo(mfp2, out);
}
template<class X, class Y, class RetType@[$1!=0:, @]@[$2,1,$1|, :class Param$2@]>
inline void GetFuncInfo(Y *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]) const, MemFuncInfo &out)
{
RetType(Y::*mfp2)(@[$2,1,$1|, :Param$2@]) const = mfp;
MFI_Impl<sizeof(mfp2)>::GetFuncInfo(mfp2, out);
}
@]
// GCC & MSVC 7.1 need this, MSVC 7.0 doesn't like it
#if SH_COMP != SH_COMP_MSVC || _MSC_VER > 1300
@[$1,0,$a:
template<class X, class Y, class RetType@[$1!=0:, @]@[$2,1,$1|, :class Param$2@]>
inline void GetFuncInfo(Y *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...), MemFuncInfo &out)
{
RetType(Y::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...) = mfp;
MFI_Impl<sizeof(mfp2)>::GetFuncInfo(mfp2, out);
}
template<class X, class Y, class RetType@[$1!=0:, @]@[$2,1,$1|, :class Param$2@]>
inline void GetFuncInfo(Y *ptr, RetType(X::*mfp)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...) const, MemFuncInfo &out)
{
RetType(Y::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]...) const = mfp;
MFI_Impl<sizeof(mfp2)>::GetFuncInfo(mfp2, out);
}
@]
#endif
}
#endif