2018-01-25 17:18:30 +01:00
# include <signatures.h>
SignatureGameConfig * g_pSignatures ;
enum ParseState
{
PState_None ,
PState_Root ,
PState_Function ,
PState_Arguments ,
PState_Argument
} ;
ParseState g_ParseState ;
unsigned int g_IgnoreLevel ;
// The parent section type of a platform specific "windows" or "linux" section.
ParseState g_PlatformOnlyState ;
SignatureWrapper * g_CurrentSignature ;
ke : : AString g_CurrentFunctionName ;
2018-04-21 11:50:07 +02:00
ArgumentInfo g_CurrentArgumentInfo ;
2018-01-25 17:18:30 +01:00
SignatureWrapper * SignatureGameConfig : : GetFunctionSignature ( const char * function )
{
auto sig = signatures_ . find ( function ) ;
if ( ! sig . found ( ) )
return nullptr ;
return sig - > value ;
}
/**
* Game config " Functions " section parsing .
*/
SMCResult SignatureGameConfig : : ReadSMC_NewSection ( const SMCStates * states , const char * name )
{
// We're ignoring the parent section. Ignore all child sections as well.
if ( g_IgnoreLevel > 0 )
{
g_IgnoreLevel + + ;
return SMCResult_Continue ;
}
// Handle platform specific sections first.
# if defined WIN32
if ( ! strcmp ( name , " windows " ) )
# elif defined _LINUX
if ( ! strcmp ( name , " linux " ) )
# elif defined _OSX
if ( ! strcmp ( name , " mac " ) )
# endif
{
// We're already in a section for a different OS that we're ignoring. Can't have a section for our OS in here.
if ( g_IgnoreLevel > 0 )
{
2018-04-18 00:47:45 +02:00
smutils - > LogError ( myself , " Unreachable platform specific section in \" %s \" Function: line: %i col: %i " , g_CurrentFunctionName . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
// We don't support nested (useless) sections of the same OS like "windows" { "windows" { "foo" "bar" } }
if ( g_PlatformOnlyState ! = PState_None )
{
smutils - > LogError ( myself , " Duplicate platform specific section for \" %s \" . Already parsing only for that OS: line: %i col: %i " , name , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
// This is a specific block for us.
g_PlatformOnlyState = g_ParseState ;
return SMCResult_Continue ;
}
# if defined WIN32
else if ( ! strcmp ( name , " linux " ) | | ! strcmp ( name , " mac " ) )
# elif defined _LINUX
else if ( ! strcmp ( name , " windows " ) | | ! strcmp ( name , " mac " ) )
# elif defined _OSX
else if ( ! strcmp ( name , " windows " ) | | ! strcmp ( name , " linux " ) )
# endif
{
if ( g_PlatformOnlyState ! = PState_None )
{
2018-04-18 00:47:45 +02:00
smutils - > LogError ( myself , " Unreachable platform specific section in \" %s \" Function: line: %i col: %i " , g_CurrentFunctionName . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
// A specific block for a different platform.
g_IgnoreLevel + + ;
return SMCResult_Continue ;
}
switch ( g_ParseState )
{
case PState_Root :
{
auto sig = signatures_ . find ( name ) ;
if ( sig . found ( ) )
g_CurrentSignature = sig - > value ;
else
g_CurrentSignature = new SignatureWrapper ( ) ;
g_CurrentFunctionName = name ;
g_ParseState = PState_Function ;
break ;
}
case PState_Function :
{
if ( ! strcmp ( name , " arguments " ) )
{
g_ParseState = PState_Arguments ;
}
else
{
smutils - > LogError ( myself , " Unknown subsection \" %s \" (expected \" arguments \" ): line: %i col: %i " , name , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
break ;
}
case PState_Arguments :
{
g_ParseState = PState_Argument ;
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . name = name ;
// Reset the parameter info.
ParamInfo info ;
memset ( & info , 0 , sizeof ( info ) ) ;
info . flags = PASSFLAG_BYVAL ;
g_CurrentArgumentInfo . info = info ;
// See if we already have info about this argument.
for ( auto & arg : g_CurrentSignature - > args ) {
if ( ! arg . name . compare ( name ) ) {
// Continue changing that argument now.
g_CurrentArgumentInfo . info = arg . info ;
break ;
}
2018-01-25 17:18:30 +01:00
}
break ;
}
default :
smutils - > LogError ( myself , " Unknown subsection \" %s \" : line: %i col: %i " , name , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
return SMCResult_Continue ;
}
SMCResult SignatureGameConfig : : ReadSMC_KeyValue ( const SMCStates * states , const char * key , const char * value )
{
// We don't care for anything in this section or subsections.
if ( g_IgnoreLevel > 0 )
return SMCResult_Continue ;
switch ( g_ParseState )
{
case PState_Function :
if ( ! strcmp ( key , " signature " ) )
{
if ( g_CurrentSignature - > address . length ( ) > 0 | | g_CurrentSignature - > offset . length ( ) > 0 )
{
smutils - > LogError ( myself , " Cannot have \" signature \" , \" address \" or \" offset \" keys at the same time in one function: line: %i col: %i " , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
g_CurrentSignature - > signature = value ;
}
else if ( ! strcmp ( key , " address " ) )
{
if ( g_CurrentSignature - > signature . length ( ) > 0 | | g_CurrentSignature - > offset . length ( ) > 0 )
{
smutils - > LogError ( myself , " Cannot have \" signature \" , \" address \" or \" offset \" keys at the same time in one function: line: %i col: %i " , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
g_CurrentSignature - > address = value ;
}
else if ( ! strcmp ( key , " offset " ) )
{
if ( g_CurrentSignature - > address . length ( ) > 0 | | g_CurrentSignature - > signature . length ( ) > 0 )
{
smutils - > LogError ( myself , " Cannot have \" signature \" , \" address \" or \" offset \" keys at the same time in one function: line: %i col: %i " , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
g_CurrentSignature - > offset = value ;
}
else if ( ! strcmp ( key , " callconv " ) )
{
CallingConvention callConv ;
if ( ! strcmp ( value , " cdecl " ) )
callConv = CallConv_CDECL ;
else if ( ! strcmp ( value , " thiscall " ) )
callConv = CallConv_THISCALL ;
else if ( ! strcmp ( value , " stdcall " ) )
callConv = CallConv_STDCALL ;
2019-06-20 02:14:07 +02:00
else if ( ! strcmp ( value , " fastcall " ) )
callConv = CallConv_FASTCALL ;
2018-01-25 17:18:30 +01:00
else
{
smutils - > LogError ( myself , " Invalid calling convention \" %s \" : line: %i col: %i " , value , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
g_CurrentSignature - > callConv = callConv ;
}
else if ( ! strcmp ( key , " hooktype " ) )
{
HookType hookType ;
if ( ! strcmp ( value , " entity " ) )
hookType = HookType_Entity ;
else if ( ! strcmp ( value , " gamerules " ) )
hookType = HookType_GameRules ;
else if ( ! strcmp ( value , " raw " ) )
hookType = HookType_Raw ;
else
{
smutils - > LogError ( myself , " Invalid hook type \" %s \" : line: %i col: %i " , value , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
g_CurrentSignature - > hookType = hookType ;
}
else if ( ! strcmp ( key , " return " ) )
{
g_CurrentSignature - > retType = GetReturnTypeFromString ( value ) ;
if ( g_CurrentSignature - > retType = = ReturnType_Unknown )
{
smutils - > LogError ( myself , " Invalid return type \" %s \" : line: %i col: %i " , value , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
}
else if ( ! strcmp ( key , " this " ) )
{
if ( ! strcmp ( value , " ignore " ) )
g_CurrentSignature - > thisType = ThisPointer_Ignore ;
else if ( ! strcmp ( value , " entity " ) )
g_CurrentSignature - > thisType = ThisPointer_CBaseEntity ;
else if ( ! strcmp ( value , " address " ) )
g_CurrentSignature - > thisType = ThisPointer_Address ;
else
{
smutils - > LogError ( myself , " Invalid this type \" %s \" : line: %i col: %i " , value , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
}
else
{
smutils - > LogError ( myself , " Unknown key in Functions section \" %s \" : line: %i col: %i " , key , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
break ;
case PState_Argument :
if ( ! strcmp ( key , " type " ) )
{
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . info . type = GetHookParamTypeFromString ( value ) ;
if ( g_CurrentArgumentInfo . info . type = = HookParamType_Unknown )
2018-01-25 17:18:30 +01:00
{
2018-04-21 11:50:07 +02:00
smutils - > LogError ( myself , " Invalid argument type \" %s \" for argument \" %s \" : line: %i col: %i " , value , g_CurrentArgumentInfo . name . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
}
else if ( ! strcmp ( key , " size " ) )
{
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . info . size = atoi ( value ) ;
2018-01-25 17:18:30 +01:00
2018-04-21 11:50:07 +02:00
if ( g_CurrentArgumentInfo . info . size < 1 )
2018-01-25 17:18:30 +01:00
{
2018-04-21 11:50:07 +02:00
smutils - > LogError ( myself , " Invalid argument size \" %s \" for argument \" %s \" : line: %i col: %i " , value , g_CurrentArgumentInfo . name . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
}
else if ( ! strcmp ( key , " flags " ) )
{
2018-01-27 17:24:02 +01:00
size_t flags = 0 ;
2018-01-25 17:18:30 +01:00
if ( strstr ( value , " byval " ) )
flags | = PASSFLAG_BYVAL ;
else if ( strstr ( value , " byref " ) )
flags | = PASSFLAG_BYREF ;
else if ( strstr ( value , " byref " ) )
flags | = PASSFLAG_ODTOR ;
else if ( strstr ( value , " octor " ) )
flags | = PASSFLAG_OCTOR ;
else if ( strstr ( value , " oassignop " ) )
flags | = PASSFLAG_OASSIGNOP ;
2018-04-21 10:16:20 +02:00
# ifdef PASSFLAG_OCOPYCTOR
2018-01-25 17:18:30 +01:00
else if ( strstr ( value , " ocopyctor " ) )
flags | = PASSFLAG_OCOPYCTOR ;
2018-04-21 10:16:20 +02:00
# endif
# ifdef PASSFLAG_OUNALIGN
2018-01-25 17:18:30 +01:00
else if ( strstr ( value , " ounalign " ) )
flags | = PASSFLAG_OUNALIGN ;
2018-04-21 10:16:20 +02:00
# endif
2018-01-25 17:18:30 +01:00
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . info . flags = flags ;
2018-01-25 17:18:30 +01:00
}
else if ( ! strcmp ( key , " register " ) )
{
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . info . custom_register = GetCustomRegisterFromString ( value ) ;
2018-01-25 17:18:30 +01:00
2018-04-21 11:50:07 +02:00
if ( g_CurrentArgumentInfo . info . custom_register = = Register_t : : None )
2018-01-25 17:18:30 +01:00
{
smutils - > LogError ( myself , " Invalid register \" %s \" : line: %i col: %i " , value , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
}
else
{
smutils - > LogError ( myself , " Unknown key in Functions section \" %s \" : line: %i col: %i " , key , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
break ;
default :
smutils - > LogError ( myself , " Unknown key in Functions section \" %s \" : line: %i col: %i " , key , states - > line , states - > col ) ;
return SMCResult_HaltFail ;
}
return SMCResult_Continue ;
}
SMCResult SignatureGameConfig : : ReadSMC_LeavingSection ( const SMCStates * states )
{
// We were ignoring this section.
if ( g_IgnoreLevel > 0 )
{
g_IgnoreLevel - - ;
// We were in a subsection of an ignored section. Keep ignoring.
if ( g_IgnoreLevel > 0 )
return SMCResult_Continue ;
}
// We were in a section only for our OS.
if ( g_PlatformOnlyState = = g_ParseState )
{
g_PlatformOnlyState = PState_None ;
return SMCResult_Continue ;
}
switch ( g_ParseState )
{
case PState_Function :
g_ParseState = PState_Root ;
2018-05-20 10:48:56 +02:00
if ( ! g_CurrentSignature - > address . length ( ) & & ! g_CurrentSignature - > signature . length ( ) & & ! g_CurrentSignature - > offset . length ( ) )
2018-01-25 17:18:30 +01:00
{
2018-04-21 09:40:17 +02:00
smutils - > LogError ( myself , " Function \" %s \" doesn't have a \" signature \" , \" offset \" nor \" address \" set: line: %i col: %i " , g_CurrentFunctionName . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
// Save this function signature in our cache.
signatures_ . insert ( g_CurrentFunctionName . chars ( ) , g_CurrentSignature ) ;
g_CurrentFunctionName = nullptr ;
g_CurrentSignature = nullptr ;
break ;
case PState_Arguments :
g_ParseState = PState_Function ;
break ;
case PState_Argument :
g_ParseState = PState_Arguments ;
2018-04-21 11:50:07 +02:00
if ( g_CurrentArgumentInfo . info . type = = HookParamType_Unknown )
2018-01-25 17:18:30 +01:00
{
2018-04-21 11:50:07 +02:00
smutils - > LogError ( myself , " Missing argument type for argument \" %s \" : line: %i col: %i " , g_CurrentArgumentInfo . name . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
// The size wasn't set in the config. See if that's fine and we can guess it from the type.
2018-04-21 11:50:07 +02:00
if ( ! g_CurrentArgumentInfo . info . size )
2018-01-25 17:18:30 +01:00
{
2018-04-21 11:50:07 +02:00
if ( g_CurrentArgumentInfo . info . type = = HookParamType_Object )
2018-01-25 17:18:30 +01:00
{
2018-04-21 11:50:07 +02:00
smutils - > LogError ( myself , " Object param \" %s \" being set with no size: line: %i col: %i " , g_CurrentArgumentInfo . name . chars ( ) , states - > line , states - > col ) ;
2018-01-25 17:18:30 +01:00
return SMCResult_HaltFail ;
}
else
{
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . info . size = GetParamTypeSize ( g_CurrentArgumentInfo . info . type ) ;
2018-01-25 17:18:30 +01:00
}
}
2018-04-21 11:50:07 +02:00
if ( g_CurrentArgumentInfo . info . pass_type = = SourceHook : : PassInfo : : PassType : : PassType_Unknown )
g_CurrentArgumentInfo . info . pass_type = GetParamTypePassType ( g_CurrentArgumentInfo . info . type ) ;
2018-08-08 01:01:56 +02:00
// See if we were changing an existing argument.
bool changed = false ;
for ( auto & arg : g_CurrentSignature - > args )
{
if ( ! arg . name . compare ( g_CurrentArgumentInfo . name ) )
{
arg . info = g_CurrentArgumentInfo . info ;
changed = true ;
break ;
}
}
// This was a new argument. Add it to the end of the list.
if ( ! changed )
g_CurrentSignature - > args . append ( g_CurrentArgumentInfo ) ;
2018-01-25 17:18:30 +01:00
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . name = nullptr ;
2018-01-25 17:18:30 +01:00
break ;
}
return SMCResult_Continue ;
}
void SignatureGameConfig : : ReadSMC_ParseStart ( )
{
g_ParseState = PState_Root ;
g_IgnoreLevel = 0 ;
g_PlatformOnlyState = PState_None ;
g_CurrentSignature = nullptr ;
g_CurrentFunctionName = nullptr ;
2018-04-21 11:50:07 +02:00
g_CurrentArgumentInfo . name = nullptr ;
2018-01-25 17:18:30 +01:00
}
ReturnType SignatureGameConfig : : GetReturnTypeFromString ( const char * str )
{
if ( ! strcmp ( str , " void " ) )
return ReturnType_Void ;
else if ( ! strcmp ( str , " int " ) )
return ReturnType_Int ;
else if ( ! strcmp ( str , " bool " ) )
return ReturnType_Bool ;
else if ( ! strcmp ( str , " float " ) )
return ReturnType_Float ;
else if ( ! strcmp ( str , " string " ) )
return ReturnType_String ;
else if ( ! strcmp ( str , " stringptr " ) )
return ReturnType_StringPtr ;
else if ( ! strcmp ( str , " charptr " ) )
return ReturnType_CharPtr ;
else if ( ! strcmp ( str , " vector " ) )
return ReturnType_Vector ;
else if ( ! strcmp ( str , " vectorptr " ) )
return ReturnType_VectorPtr ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " cbaseentity " ) )
2018-01-25 17:18:30 +01:00
return ReturnType_CBaseEntity ;
else if ( ! strcmp ( str , " edict " ) )
return ReturnType_Edict ;
return ReturnType_Unknown ;
}
HookParamType SignatureGameConfig : : GetHookParamTypeFromString ( const char * str )
{
if ( ! strcmp ( str , " int " ) )
return HookParamType_Int ;
else if ( ! strcmp ( str , " bool " ) )
return HookParamType_Bool ;
else if ( ! strcmp ( str , " float " ) )
return HookParamType_Float ;
else if ( ! strcmp ( str , " string " ) )
return HookParamType_String ;
else if ( ! strcmp ( str , " stringptr " ) )
return HookParamType_StringPtr ;
else if ( ! strcmp ( str , " charptr " ) )
return HookParamType_CharPtr ;
else if ( ! strcmp ( str , " vectorptr " ) )
return HookParamType_VectorPtr ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " cbaseentity " ) )
2018-01-25 17:18:30 +01:00
return HookParamType_CBaseEntity ;
else if ( ! strcmp ( str , " objectptr " ) )
return HookParamType_ObjectPtr ;
else if ( ! strcmp ( str , " edict " ) )
return HookParamType_Edict ;
else if ( ! strcmp ( str , " object " ) )
return HookParamType_Object ;
return HookParamType_Unknown ;
}
Register_t SignatureGameConfig : : GetCustomRegisterFromString ( const char * str )
{
if ( ! strcmp ( str , " al " ) )
return AL ;
else if ( ! strcmp ( str , " cl " ) )
return CL ;
else if ( ! strcmp ( str , " dl " ) )
return DL ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " bl " ) )
2018-01-25 17:18:30 +01:00
return BL ;
else if ( ! strcmp ( str , " ah " ) )
return AH ;
else if ( ! strcmp ( str , " ch " ) )
return CH ;
else if ( ! strcmp ( str , " dh " ) )
return DH ;
else if ( ! strcmp ( str , " bh " ) )
return BH ;
else if ( ! strcmp ( str , " ax " ) )
return AX ;
else if ( ! strcmp ( str , " cx " ) )
return CX ;
else if ( ! strcmp ( str , " dx " ) )
return DX ;
else if ( ! strcmp ( str , " bx " ) )
return BX ;
else if ( ! strcmp ( str , " sp " ) )
return SP ;
else if ( ! strcmp ( str , " bp " ) )
return BP ;
else if ( ! strcmp ( str , " si " ) )
return SI ;
else if ( ! strcmp ( str , " di " ) )
return DI ;
else if ( ! strcmp ( str , " eax " ) )
return EAX ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " ecx " ) )
2018-01-25 17:18:30 +01:00
return ECX ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " edx " ) )
2018-01-25 17:18:30 +01:00
return EDX ;
2018-04-21 09:40:17 +02:00
else if ( ! strcmp ( str , " ebx " ) )
2018-01-25 17:18:30 +01:00
return EBX ;
else if ( ! strcmp ( str , " esp " ) )
return ESP ;
else if ( ! strcmp ( str , " ebp " ) )
return EBP ;
else if ( ! strcmp ( str , " esi " ) )
return ESI ;
else if ( ! strcmp ( str , " edi " ) )
return EDI ;
else if ( ! strcmp ( str , " mm0 " ) )
return MM0 ;
else if ( ! strcmp ( str , " mm1 " ) )
return MM1 ;
else if ( ! strcmp ( str , " mm2 " ) )
return MM2 ;
else if ( ! strcmp ( str , " mm3 " ) )
return MM3 ;
else if ( ! strcmp ( str , " mm4 " ) )
return MM4 ;
else if ( ! strcmp ( str , " mm5 " ) )
return MM5 ;
else if ( ! strcmp ( str , " mm6 " ) )
return MM6 ;
else if ( ! strcmp ( str , " mm7 " ) )
return MM7 ;
else if ( ! strcmp ( str , " xmm0 " ) )
return XMM0 ;
else if ( ! strcmp ( str , " xmm1 " ) )
return XMM1 ;
else if ( ! strcmp ( str , " xmm2 " ) )
return XMM2 ;
else if ( ! strcmp ( str , " xmm3 " ) )
return XMM3 ;
else if ( ! strcmp ( str , " xmm4 " ) )
return XMM4 ;
else if ( ! strcmp ( str , " xmm5 " ) )
return XMM5 ;
else if ( ! strcmp ( str , " xmm6 " ) )
return XMM6 ;
else if ( ! strcmp ( str , " xmm7 " ) )
return XMM7 ;
else if ( ! strcmp ( str , " cs " ) )
return CS ;
else if ( ! strcmp ( str , " ss " ) )
return SS ;
else if ( ! strcmp ( str , " ds " ) )
return DS ;
else if ( ! strcmp ( str , " es " ) )
return ES ;
else if ( ! strcmp ( str , " fs " ) )
return FS ;
else if ( ! strcmp ( str , " gs " ) )
return GS ;
else if ( ! strcmp ( str , " st0 " ) )
return ST0 ;
return Register_t : : None ;
}