Added "psyfork" of gdc and example scripts to tools/ (NPOTB).

This commit is contained in:
Nicholas Hastings 2012-05-27 11:36:49 -04:00
parent 6aca18193a
commit 55b4854cd4
12 changed files with 3765 additions and 0 deletions

22
tools/gdc-psyfork/DOCS Normal file
View File

@ -0,0 +1,22 @@
Based on Fyren's original "gdc" in ../gdc.
This program checks SM gamedata in the given gameconf against the given server (not engine) binary. It only checks vtable offsets and signatures. It also only checks one gameconf per invocation.
Example usage:
LD_LIBRARY_PATH=~/steam/left4dead2/bin/ gdc -g left4dead2 -e l4d2 -f ~/sourcemod-central/gamedata/sdktools.games/engine.l4d2.txt -b ~/steam/left4dead2/left4dead2/bin/server.so -x ~/steam/left4dead2/bin/engine.so -w ~/steam/left4dead2/left4dead2/bin/server.dll -y ~/steam/left4dead2/bin/engine.dll
This will verify the gamedata in engine.l4d2.txt against the L4D2 server and engine binaries.
The command line can get a bit long, but it is meant to be scripted.
The parameters taken (in any order) are:
-g <game name>
-e <engine name>
-f <gameconf file>
-b <linux game binary path>
-x <engine binary path>
-w <windows game binary path>
-y <windows engine binary path>
The file symbols.txt defines the extra information necessary to link up gamedata key names (like "CommitSuicide") with symbols (like "_ZN11CBasePlayer13CommitSuicideEv"). It also needs a "vtsym" key that contains the symbol name of the default class' vtable. Vtable to use for an individual conf key can be overridden by adding a key with name "<keyname>_vt", using the vtable symbol for its class as the value. The symbols.txt itself is a gameconf file.

View File

@ -0,0 +1,562 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <string.h>
#include <stdlib.h>
#include "GameConfigs.h"
#define PSTATE_NONE 0
#define PSTATE_GAMES 1
#define PSTATE_GAMEDEFS 2
#define PSTATE_GAMEDEFS_OFFSETS 3
#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
#define PSTATE_GAMEDEFS_KEYS 5
#define PSTATE_GAMEDEFS_SUPPORTED 6
#define PSTATE_GAMEDEFS_SIGNATURES 7
#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
#define PSTATE_GAMEDEFS_CRC 9
#define PSTATE_GAMEDEFS_CRC_BINARY 10
#define PSTATE_GAMEDEFS_CUSTOM 11
#define WIN 0
#define LIN 1
#define PLATFORM_NAME "linux"
#define PLATFORM_SERVER_BINARY "server_i486.so"
Offset *tempOffset;
Sig *tempSig;
unsigned int s_ServerBinCRC;
bool s_ServerBinCRC_Ok = false;
bool DoesGameMatch(const char *value)
{
if (strcmp(value, game) == 0)
{
return true;
}
return false;
}
bool DoesEngineMatch(const char *value)
{
if (strcmp(value, engine) == 0)
{
return true;
}
return false;
}
CGameConfig::CGameConfig()
{
m_pStrings = new BaseStringTable(512);
m_RefCount = 0;
m_CustomLevel = 0;
m_CustomHandler = NULL;
}
CGameConfig::~CGameConfig()
{
delete m_pStrings;
}
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (m_IgnoreLevel)
{
m_IgnoreLevel++;
return SMCResult_Continue;
}
switch (m_ParseState)
{
case PSTATE_NONE:
{
if (strcmp(name, "Games") == 0)
{
m_ParseState = PSTATE_GAMES;
} else {
m_IgnoreLevel++;
}
break;
}
case PSTATE_GAMES:
{
if (strcmp(name, "*") == 0 ||
strcmp(name, "#default") == 0 ||
DoesGameMatch(name))
{
bShouldBeReadingDefault = true;
m_ParseState = PSTATE_GAMEDEFS;
strncopy(m_Game, name, sizeof(m_Game));
} else {
m_IgnoreLevel++;
}
break;
}
case PSTATE_GAMEDEFS:
{
if (strcmp(name, "Offsets") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
}
else if (strcmp(name, "Keys") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_KEYS;
}
else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
{
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
/* Ignore this section unless we get a game. */
bShouldBeReadingDefault = false;
had_game = false;
matched_game = false;
had_engine = false;
matched_engine = false;
}
else if (strcmp(name, "Signatures") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
}
break;
}
case PSTATE_GAMEDEFS_OFFSETS:
{
m_Prop[0] = '\0';
m_Class[0] = '\0';
tempOffset = new Offset();
tempOffset->setName(name);
m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES:
{
tempSig = new Sig();
tempSig->setName(name);
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
break;
}
/* No sub-sections allowed:
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_SUPPORTED:
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
case PSTATE_GAMEDEFS_CRC_BINARY:
*/
default:
{
/* If we don't know what we got, start ignoring */
m_IgnoreLevel++;
break;
}
}
return SMCResult_Continue;
}
SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (m_IgnoreLevel)
{
return SMCResult_Continue;
}
if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
{
if (strcmp(key, "class") == 0)
{
strncopy(m_Class, value, sizeof(m_Class));
} else if (strcmp(key, "prop") == 0) {
strncopy(m_Prop, value, sizeof(m_Prop));
} else {
int val = atoi(value);
if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
}
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
m_Keys.replace(key, m_pStrings->AddString(value));
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
if (strcmp(key, "game") == 0)
{
had_game = true;
if (DoesGameMatch(value))
{
matched_game = true;
}
if ((!had_engine && matched_game) || (matched_engine && matched_game))
{
bShouldBeReadingDefault = true;
}
}
else if (strcmp(key, "engine") == 0)
{
had_engine = true;
if (DoesEngineMatch(value))
{
matched_engine = true;
}
if ((!had_game && matched_engine) || (matched_game && matched_engine))
{
bShouldBeReadingDefault = true;
}
}
} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
if (strcmp(key, "windows") == 0) tempSig->setWin(value);
else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
else if (strcmp(key, "library") == 0) tempSig->setLib(value);
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
if (strcmp(key, PLATFORM_NAME) == 0
&& s_ServerBinCRC_Ok
&& !bShouldBeReadingDefault)
{
unsigned int crc = 0;
sscanf(value, "%08X", &crc);
if (s_ServerBinCRC == crc)
{
bShouldBeReadingDefault = true;
}
}
} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
}
return SMCResult_Continue;
}
SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
{
if (m_IgnoreLevel)
{
m_IgnoreLevel--;
return SMCResult_Continue;
}
if (m_CustomLevel)
{
m_CustomLevel--;
m_CustomHandler->ReadSMC_LeavingSection(states);
return SMCResult_Continue;
}
switch (m_ParseState)
{
case PSTATE_GAMES:
{
m_ParseState = PSTATE_NONE;
break;
}
case PSTATE_GAMEDEFS:
{
m_ParseState = PSTATE_GAMES;
break;
}
case PSTATE_GAMEDEFS_CUSTOM:
{
m_ParseState = PSTATE_GAMEDEFS;
m_CustomHandler->ReadSMC_ParseEnd(false, false);
break;
}
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_OFFSETS:
{
m_ParseState = PSTATE_GAMEDEFS;
break;
}
case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
{
for (list<Offset>::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++)
{
if (strcmp(it->name, tempOffset->name) == 0)
{
m_Offsets.erase(it);
break;
}
}
m_Offsets.push_back(*tempOffset);
m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
break;
}
case PSTATE_GAMEDEFS_CRC:
case PSTATE_GAMEDEFS_SUPPORTED:
{
if (!bShouldBeReadingDefault)
{
/* If we shouldn't read the rest of this section, set the ignore level. */
m_IgnoreLevel = 1;
m_ParseState = PSTATE_GAMES;
} else {
m_ParseState = PSTATE_GAMEDEFS;
}
break;
}
case PSTATE_GAMEDEFS_CRC_BINARY:
{
m_ParseState = PSTATE_GAMEDEFS_CRC;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES:
{
m_ParseState = PSTATE_GAMEDEFS;
break;
}
case PSTATE_GAMEDEFS_SIGNATURES_SIG:
{
m_Sigs.push_back(*tempSig);
m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
break;
}
}
return SMCResult_Continue;
}
#define MSTATE_NONE 0
#define MSTATE_MAIN 1
#define MSTATE_FILE 2
class MasterReader : public ITextListener_SMC
{
public:
virtual void ReadSMC_ParseStart()
{
state = MSTATE_NONE;
ignoreLevel = 0;
}
virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
{
if (ignoreLevel)
{
return SMCResult_Continue;
}
if (state == MSTATE_NONE)
{
if (strcmp(name, "Game Master") == 0)
{
state = MSTATE_MAIN;
}
else
{
ignoreLevel++;
}
}
else if (state == MSTATE_MAIN)
{
strncopy(cur_file, name, sizeof(cur_file));
had_engine = false;
matched_engine = false;
had_game = false;
matched_game = false;
state = MSTATE_FILE;
}
else if (state == MSTATE_FILE)
{
ignoreLevel++;
}
return SMCResult_Continue;
}
virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
if (ignoreLevel || state != MSTATE_FILE)
{
return SMCResult_Continue;
}
if (strcmp(key, "engine") == 0)
{
had_engine = true;
if (DoesEngineMatch(value))
{
matched_engine = true;
}
}
else if (strcmp(key, "game") == 0)
{
had_game = true;
if (DoesGameMatch(value))
{
matched_game = true;
}
}
return SMCResult_Continue;
}
virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
{
if (ignoreLevel)
{
ignoreLevel--;
return SMCResult_Continue;
}
if (state == MSTATE_FILE)
{
/* The four success conditions:
* 1. Needed nothing.
* 2. Needed game only.
* 3. Needed engine only.
* 4. Needed both engine and game.
* Final result is minimized via k-map.
*/
if ((!had_engine && !had_game) ||
(!had_engine && matched_game) ||
(!had_game && matched_engine) ||
(matched_engine && matched_game))
{
fileList->push_back(cur_file);
}
state = MSTATE_MAIN;
}
else if (state == MSTATE_MAIN)
{
state = MSTATE_NONE;
}
return SMCResult_Continue;
}
public:
list<char*> *fileList;
unsigned int state;
unsigned int ignoreLevel;
char cur_file[PLATFORM_MAX_PATH];
bool had_engine;
bool matched_engine;
bool had_game;
bool matched_game;
};
static MasterReader master_reader;
bool CGameConfig::Reparse(char *error, size_t maxlength)
{
/* Reset cached data */
m_pStrings->Reset();
m_Offsets.clear();
m_Sigs.clear();
m_Keys.clear();
char path[PLATFORM_MAX_PATH];
/* See if we can use the extended gamedata format. */
//TODO pass in path to gamedata somehow
/* Otherwise, it's time to parse the master. */
SMCError err;
SMCStates state = {0, 0};
list<char*> fileList;
master_reader.fileList = &fileList;
err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
if (err != SMCError_Okay)
{
const char *msg = textparsers->GetSMCErrorString(err);
printf("[SM] Error parsing master gameconf file \"%s\":", path);
printf("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
msg ? msg : "Unknown error");
exit(PARSE_ERROR);
}
/* Go through each file we found and parse it. */
list<char*>::iterator iter;
for (iter = fileList.begin(); iter != fileList.end(); iter++)
{
UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
if (!EnterFile(path, error, maxlength))
{
return false;
}
}
return true;
}
bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
{
SMCError err;
SMCStates state = {0, 0};
/* Initialize parse states */
m_IgnoreLevel = 0;
bShouldBeReadingDefault = true;
m_ParseState = PSTATE_NONE;
if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
!= SMCError_Okay)
{
const char *msg;
msg = textparsers->GetSMCErrorString(err);
printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
printf("[SM] Error %d on line %d, col %d: %s\n",
err,
state.line,
state.col,
msg ? msg : "Unknown error");
if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
{
//error occurred while parsing a custom section
m_CustomHandler->ReadSMC_ParseEnd(true, true);
m_CustomHandler = NULL;
m_CustomLevel = 0;
}
exit(PARSE_ERROR);
}
return true;
}
const char *CGameConfig::GetKeyValue(const char *key)
{
int *pkey;
if ((pkey = m_Keys.retrieve(key)) == NULL)
return NULL;
return m_pStrings->GetString(*pkey);
}
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
list<Sig> CGameConfig::GetSigs() { return m_Sigs; }

View File

@ -0,0 +1,242 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_
#include <IGameConfigs.h>
#include <ITextParsers.h>
//#include <sh_list.h>
#include "sm_trie.h"
//#include "sm_globals.h"
#include "sm_memtable.h"
#include "sm_trie_tpl.h"
//#include "ThreadSupport.h"
#include <list>
#include <map>
#include "gdc.h"
#include <limits.h>
#include <string>
#include <cstring>
#include <cstdio>
#define PLATFORM_MAX_PATH PATH_MAX
using std::map;
using std::list;
using namespace SourceMod;
//using namespace SourceHook;
extern char *game;
extern char *engine;
#define PARSE_ERROR -1
struct cmp_str
{
bool operator()(char const *a, char const *b)
{
return std::strcmp(a, b) < 0;
}
};
struct Offset
{
char *name;
char *symbol;
int lin;
int win;
Offset()
{
name = symbol = NULL;
lin = win = -1;
}
~Offset()
{
delete name;
delete symbol;
}
void reset()
{
delete name;
delete symbol;
lin = win = -1;
}
void setName(const char *src)
{
delete name;
name = new char[strlen(src)+1];
strcpy(name, src);
}
void setSymbol(const char *src)
{
delete symbol;
symbol = new char[strlen(src)+1];
strcpy(symbol, src);
}
void setLin(int offs)
{
lin = offs;
}
void setWin(int offs)
{
win = offs;
}
};
enum Library
{
Engine,
Server
};
struct Sig
{
char *name;
char *win;
char *lin;
Library lib;
Sig()
{
name = win = lin = NULL;
lib = (Library) -1;
}
~Sig()
{
delete name;
delete win;
delete lin;
}
void reset()
{
delete name;
delete win;
delete lin;
lib = (Library) -1;
}
void setName(const char *src)
{
delete name;
name = new char[strlen(src)+1];
strcpy(name, src);
}
void setWin(const char *src)
{
delete win;
win = new char[strlen(src)+1];
strcpy(win, src);
}
void setLin(const char *src)
{
delete lin;
lin = new char[strlen(src)+1];
strcpy(lin, src);
}
void setLib(const char *src)
{
if (stricmp(src, "server") == 0) lib = Server;
else if (stricmp(src, "engine") == 0) lib = Engine;
else lib = (Library)-1;
}
};
class SendProp;
class CGameConfig :
public ITextListener_SMC//,
// public IGameConfig
{
public:
CGameConfig();//const char *file);//, const char *game, const char *engine);
~CGameConfig();
public:
bool Reparse(char *error, size_t maxlength);
bool EnterFile(const char *file, char *error, size_t maxlength);
list<Offset> GetOffsets();
list<Sig> GetSigs();
public: //ITextListener_SMC
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public: //IGameConfig
const char *GetKeyValue(const char *key);
bool GetOffset(const char *key, int *value);
SendProp *GetSendProp(const char *key);
bool GetMemSig(const char *key, void **addr);
public:
// void IncRefCount();
// unsigned int DecRefCount();
private:
// bool DoesGameMatch(const char *value);
// bool DoesEngineMatch(const char *value);
public:
BaseStringTable *m_pStrings;
char m_File[PLATFORM_MAX_PATH];
char m_CurFile[PLATFORM_MAX_PATH];
list<Offset> m_Offsets;
list<Sig> m_Sigs;
// map<const char*,const char*,cmp_str> m_Keys;
KTrie<int> m_Keys;
unsigned int m_RefCount;
/* Parse states */
int m_ParseState;
unsigned int m_IgnoreLevel;
char m_Class[64];
char m_Prop[64];
char m_offset[64];
char m_Game[256];
char m_gdcGame[256];
char m_gdcEngine[256];
bool bShouldBeReadingDefault;
bool had_game;
bool matched_game;
bool had_engine;
bool matched_engine;
/* Custom Sections */
unsigned int m_CustomLevel;
ITextListener_SMC *m_CustomHandler;
};
#endif //_INCLUDE_SOURCEMOD_CGAMECONFIGS_H_

View File

@ -0,0 +1,72 @@
# (C)2004-2008 SourceMod Development Team
# Makefile written by David "BAILOPAN" Anderson
#####################################
### EDIT BELOW FOR OTHER PROJECTS ###
#####################################
OBJECTS = gdc.cpp TextParsers.cpp GameConfigs.cpp MemoryUtils.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
##############################################
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
C_GCC4_FLAGS = -fvisibility=hidden
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
CPP = gcc
BINARY = gdc
LINK += -L. -lstdc++ -ldl -lm
INCLUDE += -I. -I../../public -I../../public/sourcepawn -I../../core -I../../core/logic
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
-Wno-uninitialized -mfpmath=sse -msse -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -DPLATFORM_LINUX -m32
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
################################################
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
################################################
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
CFLAGS += $(C_DEBUG_FLAGS)
else
BIN_DIR = Release
CFLAGS += $(C_OPT_FLAGS)
endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(C_GCC4_FLAGS)
CPPFLAGS += $(CPP_GCC4_FLAGS)
endif
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
$(BIN_DIR)/%.o: %.c
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)
$(MAKE) -f Makefile gdc
gdc: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) -f Makefile all DEBUG=true
default: all
clean:
rm -rf $(BIN_DIR)/

View File

@ -0,0 +1,644 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#include "MemoryUtils.h"
#ifdef PLATFORM_LINUX
#include <fcntl.h>
#include <link.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#endif
#ifdef PLATFORM_APPLE
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#endif
MemoryUtils::MemoryUtils()
{
#ifdef PLATFORM_APPLE
/* Get pointer to struct that describes all loaded mach-o images in process */
struct nlist list[2];
memset(list, 0, sizeof(list));
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
nlist("/usr/lib/dyld", list);
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
#endif
}
MemoryUtils::~MemoryUtils()
{
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
for (size_t i = 0; i < m_SymTables.size(); i++)
{
delete m_SymTables[i];
}
m_SymTables.clear();
#endif
}
void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len)
{
size_t size;
size = lseek (fd , 0 , SEEK_END);
lseek(fd, 0, SEEK_SET);
void *map;
char *ptr, *end;
bool found = true;
map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
ptr = (char *)map;
end = ptr + size;
while (ptr < end)
{
found = true;
for (register size_t i = 0; i < len; i++)
{
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
{
found = false;
break;
}
}
if (found)
return ptr;
ptr++;
}
return NULL;
}
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
{
DynLibInfo lib;
bool found;
char *ptr, *end;
memset(&lib, 0, sizeof(DynLibInfo));
if (!GetLibraryInfo(libPtr, lib))
{
return NULL;
}
ptr = reinterpret_cast<char *>(lib.baseAddress);
end = ptr + lib.memorySize - 1;
while (ptr < end)
{
found = true;
for (register size_t i = 0; i < len; i++)
{
if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
{
found = false;
break;
}
}
if (found)
return ptr;
ptr++;
}
return NULL;
}
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{
#ifdef PLATFORM_WINDOWS
return GetProcAddress((HMODULE)handle, symbol);
#elif defined PLATFORM_LINUX
struct link_map *dlmap;
struct stat dlstat;
int dlfile;
uintptr_t map_base;
Elf32_Ehdr *file_hdr;
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
Elf32_Sym *symtab;
const char *shstrtab, *strtab;
uint16_t section_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
AddrTable *table2;
Symbol *symbol_entry;
dlmap = (struct link_map *)handle;
symtab_hdr = NULL;
strtab_hdr = NULL;
table = NULL;
table2 = NULL;
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlmap->l_addr)
{
table = &libtable->table;
table2 = &libtable->table2;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->table2.Initialize();
libtable->lib_base = dlmap->l_addr;
libtable->last_pos = 0;
table = &libtable->table;
table2 = &libtable->table2;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have open the actual library */
dlfile = open(dlmap->l_name, O_RDONLY);
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
{
close(dlfile);
return NULL;
}
/* Map library file into memory */
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
map_base = (uintptr_t)file_hdr;
if (file_hdr == MAP_FAILED)
{
close(dlfile);
return NULL;
}
close(dlfile);
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
section_count = file_hdr->e_shnum;
/* Get ELF section header string table */
shstrtab_hdr = &sections[file_hdr->e_shstrndx];
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
/* Iterate sections while looking for ELF symbol table and string table */
for (uint16_t i = 0; i < section_count; i++)
{
Elf32_Shdr &hdr = sections[i];
const char *section_name = shstrtab + hdr.sh_name;
if (strcmp(section_name, ".symtab") == 0)
{
symtab_hdr = &hdr;
}
else if (strcmp(section_name, ".strtab") == 0)
{
strtab_hdr = &hdr;
}
}
/* Uh oh, we don't have a symbol table or a string table */
if (symtab_hdr == NULL || strtab_hdr == NULL)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
Elf32_Sym &sym = symtab[i];
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
const char *sym_name = strtab + sym.st_name;
Symbol *cur_sym;
/* Skip symbols that are undefined or do not refer to functions or objects */
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
table2->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
// break;
}
}
libtable->last_pos = symbol_count;
munmap(file_hdr, dlstat.st_size);
return symbol_entry ? symbol_entry->address : NULL;
#elif defined PLATFORM_APPLE
uintptr_t dlbase, linkedit_addr;
uint32_t image_count;
struct mach_header *file_hdr;
struct load_command *loadcmds;
struct segment_command *linkedit_hdr;
struct symtab_command *symtab_hdr;
struct nlist *symtab;
const char *strtab;
uint32_t loadcmd_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlbase = 0;
image_count = m_ImageList->infoArrayCount;
linkedit_hdr = NULL;
symtab_hdr = NULL;
table = NULL;
/* Loop through mach-o images in process.
* We can skip index 0 since that is just the executable.
*/
for (uint32_t i = 1; i < image_count; i++)
{
const struct dyld_image_info &info = m_ImageList->infoArray[i];
/* "Load" each one until we get a matching handle */
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
if (h == handle)
{
dlbase = (uintptr_t)info.imageLoadAddress;
dlclose(h);
break;
}
dlclose(h);
}
if (!dlbase)
{
/* Uh oh, we couldn't find a matching handle */
return NULL;
}
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlbase)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlbase;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have to locate it in memory */
file_hdr = (struct mach_header *)dlbase;
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
loadcmd_count = file_hdr->ncmds;
/* Loop through load commands until we find the ones for the symbol table */
for (uint32_t i = 0; i < loadcmd_count; i++)
{
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
{
struct segment_command *seg = (struct segment_command *)loadcmds;
if (strcmp(seg->segname, "__LINKEDIT") == 0)
{
linkedit_hdr = seg;
if (symtab_hdr)
{
break;
}
}
}
else if (loadcmds->cmd == LC_SYMTAB)
{
symtab_hdr = (struct symtab_command *)loadcmds;
if (linkedit_hdr)
{
break;
}
}
/* Load commands are not of a fixed size which is why we add the size */
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
}
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
{
/* Uh oh, no symbol table */
return NULL;
}
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
symbol_count = symtab_hdr->nsyms;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
struct nlist &sym = symtab[i];
/* Ignore the prepended underscore on all symbols, so +1 here */
const char *sym_name = strtab + sym.n_un.n_strx + 1;
Symbol *cur_sym;
/* Skip symbols that are undefined */
if (sym.n_sect == NO_SECT)
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
return symbol_entry ? symbol_entry->address : NULL;
#endif
}
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
{
uintptr_t baseAddr;
if (libPtr == NULL)
{
return false;
}
#ifdef PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION info;
IMAGE_DOS_HEADER *dos;
IMAGE_NT_HEADERS *pe;
IMAGE_FILE_HEADER *file;
IMAGE_OPTIONAL_HEADER *opt;
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
{
return false;
}
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
/* All this is for our insane sanity checks :o */
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
file = &pe->FileHeader;
opt = &pe->OptionalHeader;
/* Check PE magic and signature */
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
return false;
}
/* Check architecture, which is 32-bit/x86 right now
* Should change this for 64-bit if Valve gets their act together
*/
if (file->Machine != IMAGE_FILE_MACHINE_I386)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
{
return false;
}
/* Finally, we can do this */
lib.memorySize = opt->SizeOfImage;
#elif defined PLATFORM_LINUX
Dl_info info;
Elf32_Ehdr *file;
Elf32_Phdr *phdr;
uint16_t phdrCount;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
/* Check ELF magic */
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
{
return false;
}
/* Check ELF version */
if (file->e_ident[EI_VERSION] != EV_CURRENT)
{
return false;
}
/* Check ELF architecture, which is 32-bit/x86 right now
* Should change this for 64-bit if Valve gets their act together
*/
if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
{
return false;
}
/* For our purposes, this must be a dynamic library/shared object */
if (file->e_type != ET_DYN)
{
return false;
}
phdrCount = file->e_phnum;
phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
for (uint16_t i = 0; i < phdrCount; i++)
{
Elf32_Phdr &hdr = phdr[i];
/* We only really care about the segment with executable code */
if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
{
/* From glibc, elf/dl-load.c:
* c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
* & ~(GLRO(dl_pagesize) - 1));
*
* In glibc, the segment file size is aligned up to the nearest page size and
* added to the virtual address of the segment. We just want the size here.
*/
lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
break;
}
}
#elif defined PLATFORM_APPLE
Dl_info info;
struct mach_header *file;
struct segment_command *seg;
uint32_t cmd_count;
if (!dladdr(libPtr, &info))
{
return false;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
}
/* This is for our insane sanity checks :o */
baseAddr = (uintptr_t)info.dli_fbase;
file = (struct mach_header *)baseAddr;
/* Check Mach-O magic */
if (file->magic != MH_MAGIC)
{
return false;
}
/* Check architecture (32-bit/x86) */
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
{
return false;
}
/* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB)
{
return false;
}
cmd_count = file->ncmds;
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
/* Add up memory sizes of mapped segments */
for (uint32_t i = 0; i < cmd_count; i++)
{
if (seg->cmd == LC_SEGMENT)
{
lib.memorySize += seg->vmsize;
}
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
}
#endif
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
}
const char* MemoryUtils::ResolveAddr(void *handle, void* addr)
{
struct link_map *dlmap;
dlmap = (struct link_map *)handle;
LibSymbolTable *libtable;
AddrTable *table2;
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlmap->l_addr)
{
table2 = &libtable->table2;
break;
}
}
if (table2 == NULL) return NULL;
Symbol *sym = table2->FindAddr(addr);
return sym ? sym->buffer() : NULL;
}

View File

@ -0,0 +1,82 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#include <IMemoryUtils.h>
#include <string.h>
#include <vector>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#include "sm_symtable.h"
#include <unistd.h>
#endif
using namespace SourceMod;
using std::vector;
struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
};
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
struct LibSymbolTable
{
SymbolTable table;
AddrTable table2;
uintptr_t lib_base;
uint32_t last_pos;
};
#endif
class MemoryUtils
{
public:
MemoryUtils();
~MemoryUtils();
public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
void *ResolveSymbol(void *handle, const char *symbol);
const char *ResolveAddr(void *handle, void *addr);
public:
void *FindPatternInFile(int fd, const char *pattern, size_t len);
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
private:
vector<LibSymbolTable *> m_SymTables;
#ifdef PLATFORM_APPLE
struct dyld_all_image_infos *m_ImageList;
#endif
#endif
};
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#include <ITextParsers.h>
#include "gdc.h"
using namespace SourceMod;
/**
* @param void * IN: Stream pointer
* @param char * IN/OUT: Stream buffer
* @param size_t IN: Maximum size of buffer
* @param unsigned int * OUT: Number of bytes read (0 = end of stream)
* @return True on success, false on failure
*/
typedef bool (*STREAMREADER)(void *, char *, size_t, unsigned int *);
class TextParsers :
public ITextParsers
{
public:
TextParsers();
public:
bool ParseFile_INI(const char *file,
ITextListener_INI *ini_listener,
unsigned int *line,
unsigned int *col);
SMCError ParseFile_SMC(const char *file,
ITextListener_SMC *smc_listener,
SMCStates *states);
SMCError ParseSMCFile(const char *file,
ITextListener_SMC *smc_listener,
SMCStates *states,
char *buffer,
size_t maxsize);
SMCError ParseSMCStream(const char *stream,
size_t length,
ITextListener_SMC *smc_listener,
SMCStates *states,
char *buffer,
size_t maxsize);
unsigned int GetUTF8CharBytes(const char *stream);
const char *GetSMCErrorString(SMCError err);
bool IsWhitespace(const char *stream);
private:
SMCError ParseStream_SMC(void *stream,
STREAMREADER srdr,
ITextListener_SMC *smc,
SMCStates *states);
};
extern TextParsers g_TextParser;
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_

448
tools/gdc-psyfork/gdc.cpp Normal file
View File

@ -0,0 +1,448 @@
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <math.h>
#include "gdc.h"
#include "GameConfigs.h"
#include "MemoryUtils.h"
MemoryUtils mu;
char *game = NULL;
char *engine = NULL;
char *game_binary = NULL;
char *engine_binary = NULL;
char *wgame_binary = NULL;
char *wengine_binary = NULL;
int main(int argc, char **argv)
{
char *gamedata = NULL;
bool debug = false;
opterr = 0;
int opt;
while ((opt = getopt(argc, argv, "b:de:f:g:x:w:y:")) != -1)
switch (opt)
{
case 'd':
debug = true;
break;
case 'g':
game = optarg;
break;
case 'e':
engine = optarg;
break;
case 'f':
gamedata = optarg;
break;
case 'b':
game_binary = optarg;
break;
case 'x':
engine_binary = optarg;
break;
case 'w':
wgame_binary = optarg;
break;
case 'y':
wengine_binary = optarg;
break;
case '?':
printf("Usage: ./gdc -g <game> -e <engine name> -f <gamedata file> -b <game binary> -x <engine binary> -w <win game binary> -y <win engine binary>\n");
return 0;
default:
printf("WHAT\n");
return 0;
}
if (!game || !engine || !gamedata || !game_binary || !engine_binary || !wgame_binary || !wengine_binary)
{
printf("Usage: ./gdc -g <game> -e <engine name> -f <gamedata file> -b <game binary> -x <engine binary> -w <win game binary> -y <win engine binary>\n");
return 0;
}
printf("Game: %s\n", game);
if (debug)
{
printf("Engine: %s\nGame binary: %s\nEngine binary: %s\nWin game binary: %s\nWin engine binary: %s\n",
engine, game_binary, engine_binary, wgame_binary, wengine_binary
);
}
printf("Gamedata: %s\n\n", gamedata);
void *ghandle;
ghandle = dlopen(game_binary, RTLD_LAZY);
if (!ghandle)
{
printf("Couldn't open %s (%s)\n", game_binary, dlerror());
return 0;
}
void *ehandle;
ehandle = dlopen(engine_binary, RTLD_LAZY);
if (!ehandle)
{
printf("Couldn't open %s (%s)\n", engine_binary, dlerror());
return 0;
}
int wgfile = open(wgame_binary, O_RDONLY);
if (wgfile == -1)
{
printf("Couldn't open %s\n", wgame_binary);
return 0;
}
int wefile = open(wengine_binary, O_RDONLY);
if (wefile == -1)
{
printf("Couldn't open %s\n", wengine_binary);
return 0;
}
CGameConfig gc;
char err[512];
if (!gc.EnterFile(gamedata, err, sizeof(err)))
{
printf("%s: %s\n", gamedata, err);
return 0;
}
CGameConfig symbols;
if (!symbols.EnterFile("symbols.txt", err, sizeof(err)))
{
printf("symbols.txt: %s\n", err);
return 0;
}
const char *vtsym = symbols.GetKeyValue("vtsym");
if (!vtsym)
{
printf("Couldn't find vtsym\n");
return 0;
}
void **vt = (void**) mu.ResolveSymbol(ghandle, vtsym);
if (!vt)
{
printf("Couldn't find vtable %s\n", vtsym);
dlclose(ghandle);
dlclose(ehandle);
close(wgfile);
close(wefile);
return 0;
}
for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
{
if (debug)
{
printf("DEBUG %s - l: %d w: %d\n", it->name, it->lin, it->win);
}
const char *symbol = symbols.GetKeyValue(it->name);
if (symbol)
{
int newOffset;
char symvt[128];
strcpy(symvt, it->name);
strcat(symvt, "_vt");
const char *newvtsym = symbols.GetKeyValue(symvt);
if (newvtsym && newvtsym[0])
{
void **newvt = (void**) mu.ResolveSymbol(ghandle, newvtsym);
if (!newvt)
{
printf("O: %-22s - can't find, skipping\n", symvt);
continue;
}
newOffset = findVFunc(ghandle, newvt, symbol);
}
else
{
newOffset = findVFunc(ghandle, vt, symbol);
}
if (newOffset == it->lin)
{
printf("O: %-22s - GOOD. current [ w: %3d, l: %3d ].\n", it->name, it->win, it->lin);
}
else
{
printf("O: %-22s - CHANGED. old [ w: %3d, l: %3d ]. new [ w: %3d, l: %3d ].\n",
it->name,
it->win, it->lin,
newOffset - (it->lin - it->win), newOffset
);
}
}
else // !symbol
{
printf("O: %-22s - no Linux symbol, skipping\n", it->name);
}
}
printf("\nWindows offsets are (semi-)wild guesses!\n\n");
for (list<Sig>::iterator it = gc.m_Sigs.begin(); it != gc.m_Sigs.end(); it++)
{
if (debug)
{
printf("DEBUG %s - %s - l: %s\n", it->name, it->lib == Server ? "server" : "engine", it->lin);
}
const char *linSymbol = it->lin;
const char *winSymbol = it->win;
bool hasLinux = (linSymbol && linSymbol[0]);
bool hasWindows = (winSymbol && winSymbol[0]);
if (!hasLinux && !hasWindows)
{
printf("S: %-22s - hasn't linux nor windows data, skipping\n", it->name);
continue;
}
int winFile;
void *linHandle;
if (it->lib == Server)
{
winFile = wgfile;
linHandle = ghandle;
}
else if (it->lib == Engine)
{
winFile = wefile;
linHandle = ehandle;
}
else
{
printf("S: %-22s - isn't from server nor engine, skipping\n", it->name);
continue;
}
bool foundLinux = (!hasLinux || checkSigStringL(linHandle, linSymbol));
bool foundWindows = (!hasWindows || checkSigStringW(winFile, winSymbol));
// Prepare for ternery ABUSE
if (foundLinux && foundWindows)
{
// too much clutter to print current data if it matches anyway, unlike with offsets
/*
printf("%-22s (%s) - GOOD. current:\n\t[w:%s]\n\t[l:%s]\n",
it->name,
(it->lib == Server) ? "server" : "engine",
winSymbol ? winSymbol : "",
linSymbol ? linSymbol : ""
);
*/
printf("S: %-22s (%s) - GOOD.\n",
it->name,
(it->lib == Server) ? "server" : "engine"
);
}
else
{
// extra \n at end is intentional to add buffer after possibly long sigs
printf("S: %-22s (%s) - w: %s - l: %s\n%s%s%s%s%s%s%s%s\n",
it->name,
(it->lib == Server) ? "server" : "engine",
hasWindows ? (foundWindows ? "GOOD" : "CHANGED") : "UNKNOWN",
hasLinux ? (foundLinux ? "GOOD" : "CHANGED") : "UNKNOWN",
hasWindows ? "\tcurrent - w: " : "",
(hasWindows && foundWindows) ? " (found) \"" : (hasWindows ? "(NOT found) \"" : ""),
(hasWindows && winSymbol) ? winSymbol : "",
hasWindows ? "\"\n" : "",
hasLinux ? "\tcurrent - l: " : "",
(hasLinux && foundLinux) ? " (found) \"" : (hasLinux ? "(NOT found) \"" : ""),
(hasLinux && linSymbol) ? linSymbol : "",
hasLinux ? "\"\n" : ""
);
}
// j/k, no way that anyone could have been prepared for that
}
return 0;
}
bool checkSigStringW(int file, const char* symbol)
{
void *addr = NULL;
bool isAt = (symbol[0] == '@');
// we can't support this on windows from here
if (isAt)
return false;
unsigned char real_sig[511];
size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
if (real_bytes >= 1)
{
addr = mu.FindPatternInFile(file, (char*)real_sig, real_bytes);
}
if (addr)
return true;
return false;
}
bool checkSigStringL(void *handle, const char* symbol)
{
void *addr = NULL;
bool isAt = (symbol[0] == '@');
if (isAt)
{
addr = mu.ResolveSymbol(handle, symbol + 1);
}
else
{
unsigned char real_sig[511];
size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
if (real_bytes >= 1)
{
addr = mu.FindPattern(handle, (char*)real_sig, real_bytes);
}
}
if (addr)
return true;
return false;
}
/*
takes a mangled member function symbol and returns the position where the function name and parameters start
01234567890123456789012345678
_ZN9CTFPlayer12ForceRespawnEv
^13 ^28
*/
void findFuncPos(const char *sym, int &func, int &params)
{
int i = 0;
while ((sym[i] < '0') || (sym[i] > '9')) i++;
int classLen = atoi(sym + i);
func = i + (int)ceil(log10(classLen)) + classLen;
int funcLen = atoi(sym + func);
params = func + (int)ceil(log10(funcLen)) + funcLen;
}
int findVFunc(void *handle, void **vt, const char *symbol)
{
int offset = 1;
int funcPos, paramPos;
findFuncPos(symbol, funcPos, paramPos);
for (int i = 0; i < 1000; i++)
{
void *pFunc = vt[i];
const char *s;
if (!(s = mu.ResolveAddr(handle, pFunc)))
continue;
if ((i > 1) && (strncmp(s, "_ZTI", 4) == 0))
break;
int tempFuncPos, tempParamPos;
findFuncPos(s, tempFuncPos, tempParamPos);
if (strcmp(s + tempFuncPos, symbol + funcPos) == 0)
{
offset = i;
break;
}
}
return offset - 2;
}
unsigned int strncopy(char *dest, const char *src, size_t count)
{
if (!count)
{
return 0;
}
char *start = dest;
while ((*src) && (--count))
{
*dest++ = *src++;
}
*dest = '\0';
return (dest - start);
}
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
va_end(ap);
if (len >= maxlength)
{
buffer[maxlength - 1] = '\0';
return (maxlength - 1);
}
else
{
return len;
}
}
size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
{
size_t written = 0;
size_t length = strlen(hexstr);
for (size_t i = 0; i < length; i++)
{
if (written >= maxlength)
break;
buffer[written++] = hexstr[i];
if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
{
if (i + 3 >= length)
continue;
/* Get the hex part. */
char s_byte[3];
int r_byte;
s_byte[0] = hexstr[i + 2];
s_byte[1] = hexstr[i + 3];
s_byte[2] = '\0';
/* Read it as an integer */
sscanf(s_byte, "%x", &r_byte);
/* Save the value */
buffer[written - 1] = r_byte;
/* Adjust index */
i += 3;
}
}
return written;
}

22
tools/gdc-psyfork/gdc.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _INCLUDE_GDC_MAIN_H_
#define _INCLUDE_GDC_MAIN_H_
#include <stdarg.h>
#if 0
#include "TextParsers.h"
#include "GameConfigs.h"
using namespace SourceMod;
#endif
int findFuncPos(const char* sym);
int findVFunc(void *handle, void **vt, const char *symbol);
bool checkSigStringW(int file, const char* symbol);
bool checkSigStringL(void* handle, const char* symbol);
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);
unsigned int strncopy(char *dest, const char *src, size_t count);
#endif // _INCLUDE_GDC_MAIN_H_

View File

@ -0,0 +1,356 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define KESTRING_TABLE_START_SIZE 65536
struct Symbol
{
size_t length;
uint32_t hash;
void *address;
Symbol *tbl_next;
inline char *buffer()
{
return reinterpret_cast<char *>(this + 1);
}
};
class SymbolTable
{
public:
~SymbolTable()
{
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
free(sym);
sym = next;
}
}
free(buckets);
}
bool Initialize()
{
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
if (buckets == NULL)
{
return false;
}
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
nbuckets = KESTRING_TABLE_START_SIZE;
nused = 0;
bucketmask = KESTRING_TABLE_START_SIZE - 1;
return true;
}
static inline uint32_t HashString(const char *data, size_t len)
{
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL)
{
return 0;
}
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof (uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
#undef get16bits
}
Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
{
uint32_t bucket = hash & bucketmask;
Symbol **pkvs = &buckets[bucket];
Symbol *kvs = *pkvs;
while (kvs != NULL)
{
if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
{
return pkvs;
}
pkvs = &kvs->tbl_next;
kvs = *pkvs;
}
return pkvs;
}
void ResizeSymbolTable()
{
uint32_t xnbuckets = nbuckets * 2;
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
if (xbuckets == NULL)
{
return;
}
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
uint32_t xbucketmask = xnbuckets - 1;
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
uint32_t bucket = sym->hash & xbucketmask;
sym->tbl_next = xbuckets[bucket];
xbuckets[bucket] = sym;
sym = next;
}
}
free(buckets);
buckets = xbuckets;
nbuckets = xnbuckets;
bucketmask = xbucketmask;
}
Symbol *FindSymbol(const char *str, size_t len)
{
uint32_t hash = HashString(str, len);
Symbol **pkvs = FindSymbolBucket(str, len, hash);
return *pkvs;
}
Symbol *InternSymbol(const char* str, size_t len, void *address)
{
uint32_t hash = HashString(str, len);
Symbol **pkvs = FindSymbolBucket(str, len, hash);
if (*pkvs != NULL)
{
return *pkvs;
}
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
kvs->length = len;
kvs->hash = hash;
kvs->address = address;
kvs->tbl_next = NULL;
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
*pkvs = kvs;
nused++;
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
{
ResizeSymbolTable();
}
return kvs;
}
private:
uint32_t nbuckets;
uint32_t nused;
uint32_t bucketmask;
Symbol **buckets;
};
class AddrTable
{
public:
~AddrTable()
{
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
free(sym);
sym = next;
}
}
free(buckets);
}
bool Initialize()
{
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
if (buckets == NULL)
{
return false;
}
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
nbuckets = KESTRING_TABLE_START_SIZE;
nused = 0;
bucketmask = KESTRING_TABLE_START_SIZE - 1;
return true;
}
//Knuth's quick 32-bit integer hash, might not be appropriate but I don't think I care much!
static inline uint32_t HashAddr(void *addr)
{
return (uint32_t)addr * (uint32_t)2654435761u;
}
Symbol **FindSymbolBucket(void *addr, uint32_t hash)
{
uint32_t bucket = hash & bucketmask;
Symbol **pkvs = &buckets[bucket];
Symbol *kvs = *pkvs;
while (kvs != NULL)
{
if (kvs->address == addr)
{
return pkvs;
}
pkvs = &kvs->tbl_next;
kvs = *pkvs;
}
return pkvs;
}
void ResizeSymbolTable()
{
uint32_t xnbuckets = nbuckets * 2;
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
if (xbuckets == NULL)
{
return;
}
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
uint32_t xbucketmask = xnbuckets - 1;
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
uint32_t bucket = sym->hash & xbucketmask;
sym->tbl_next = xbuckets[bucket];
xbuckets[bucket] = sym;
sym = next;
}
}
free(buckets);
buckets = xbuckets;
nbuckets = xnbuckets;
bucketmask = xbucketmask;
}
Symbol *FindAddr(void *addr)
{
uint32_t hash = HashAddr(addr);
Symbol **pkvs = FindSymbolBucket(addr, hash);
return *pkvs;
}
Symbol *InternSymbol(const char* str, size_t len, void *address)
{
uint32_t hash = HashAddr(address);
Symbol **pkvs = FindSymbolBucket(address, hash);
if (*pkvs != NULL)
{
return *pkvs;
}
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
kvs->length = len;
kvs->hash = hash;
kvs->address = address;
kvs->tbl_next = NULL;
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
*pkvs = kvs;
nused++;
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
{
ResizeSymbolTable();
}
return kvs;
}
private:
uint32_t nbuckets;
uint32_t nused;
uint32_t bucketmask;
Symbol **buckets;
};
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_

View File

@ -0,0 +1,129 @@
"Games"
{
"#default"
{
"Keys"
{
"vtsym" "_ZTV11CBaseEntity"
"GiveNamedItem" "_ZN11CBasePlayer13GiveNamedItemEPKci"
"GiveNamedItem_vt" "_ZTV11CBasePlayer"
"RemovePlayerItem" "_ZN11CBasePlayer16RemovePlayerItemEP17CBaseCombatWeapon"
"RemovePlayerItem_vt" "_ZTV11CBasePlayer"
"Weapon_GetSlot" "_ZNK20CBaseCombatCharacter14Weapon_GetSlotEi"
"Weapon_GetSlot_vt" "_ZTV20CBaseCombatCharacter"
"Ignite" "_ZN14CBaseAnimating6IgniteEfbfb"
"Ignite_vt" "_ZTV14CBaseAnimating"
"Extinguish" "_ZN14CBaseAnimating10ExtinguishEv"
"Extinguish_vt" "_ZTV14CBaseAnimating"
"Teleport" "_ZN11CBaseEntity8TeleportEPK6VectorPK6QAngleS2_"
"CommitSuicide" "_ZN11CBasePlayer13CommitSuicideEbb"
"CommitSuicide_vt" "_ZTV11CBasePlayer"
"GetVelocity" "_ZN11CBaseEntity11GetVelocityEP6VectorS1_"
"EyeAngles" "_ZN11CBasePlayer9EyeAnglesEv"
"DispatchKeyValue" "_ZN11CBaseEntity8KeyValueEPKcS1_"
"DispatchKeyValueFloat" "_ZN11CBaseEntity8KeyValueEPKcf"
"DispatchKeyValueVector" "_ZN11CBaseEntity8KeyValueEPKcRK6Vector"
"SetEntityModel" "_ZN11CBaseEntity8SetModelEPKc"
"AcceptInput" "_ZN11CBaseEntity11AcceptInputEPKcPS_S2_9variant_ti"
"WeaponEquip" "_ZN11CBasePlayer12Weapon_EquipEP17CBaseCombatWeapon"
"WeaponEquip_vt" "_ZTV20CBaseCombatCharacter"
"Activate" "_ZN11CBaseEntity8ActivateEv"
"PlayerRunCmd" "_ZN11CBasePlayer16PlayerRunCommandEP8CUserCmdP11IMoveHelper"
"PlayerRunCmd_vt" "_ZTV11CBasePlayer"
// SDKHooks
"EndTouch" "_ZN11CBaseEntity8EndTouchEPS_"
"FireBullets" "_ZN11CBaseEntity11FireBulletsERK17FireBulletsInfo_t"
"GroundEntChanged" "_ZN11CBaseEntity35NetworkStateChanged_m_hGroundEntityEv"
"OnTakeDamage" "_ZN11CBaseEntity12OnTakeDamageERK15CTakeDamageInfo"
"PreThink" "_ZN11CBasePlayer8PreThinkEv"
"PreThink_vt" "_ZTV11CBasePlayer"
"PostThink" "_ZN11CBasePlayer9PostThinkEv"
"PostThink_vt" "_ZTV11CBasePlayer"
"Reload" "_ZN17CBaseCombatWeapon6ReloadEv"
"Reload_vt" "_ZTV17CBaseCombatWeapon"
"SetTransmit" "_ZN11CBaseEntity11SetTransmitEP18CCheckTransmitInfob"
"ShouldCollide" "_ZNK11CBaseEntity13ShouldCollideEii"
"Spawn" "_ZN11CBaseEntity5SpawnEv"
"StartTouch" "_ZN11CBaseEntity10StartTouchEPS_"
"Think" "_ZN11CBaseEntity5ThinkEv"
"Touch" "_ZN11CBaseEntity5TouchEPS_"
"TraceAttack" "_ZN11CBaseEntity11TraceAttackERK15CTakeDamageInfoRK6VectorP10CGameTrace"
"UpdateOnRemove" "_ZN11CBaseEntity14UpdateOnRemoveEv"
"Use" "_ZN11CBaseEntity3UseEPS_S0_8USE_TYPEf"
"VPhysicsUpdate" "_ZN11CBaseEntity14VPhysicsUpdateEP14IPhysicsObject"
"Weapon_CanSwitchTo" "_ZN20CBaseCombatCharacter18Weapon_CanSwitchToEP17CBaseCombatWeapon"
"Weapon_CanSwitchTo_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_CanUse" "_ZN20CBaseCombatCharacter13Weapon_CanUseEP17CBaseCombatWeapon"
"Weapon_CanUse_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Drop" "_ZN20CBaseCombatCharacter11Weapon_DropEP17CBaseCombatWeaponPK6VectorS4_"
"Weapon_Drop_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Equip" "_ZN11CBasePlayer12Weapon_EquipEP17CBaseCombatWeapon"
"Weapon_Equip_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Switch" "_ZN20CBaseCombatCharacter13Weapon_SwitchEP17CBaseCombatWeaponi"
"Weapon_Switch_vt" "_ZTV20CBaseCombatCharacter"
}
}
"#default"
{
"#supported"
{
"engine" "orangebox_valve"
"engine" "left4dead2"
"engine" "alienswarm"
}
"Keys"
{
"GetMaxHealth" "_ZNK11CBaseEntity12GetMaxHealthEv"
}
}
"#default"
{
"#supported"
{
"game" "tf"
}
"Keys"
{
"ForceRespawn" "_ZN9CTFPlayer12ForceRespawnEv"
"ForceRespawn_vt" "_ZTV9CTFPlayer"
"GiveNamedItemTF" "_ZN9CTFPlayer13GiveNamedItemEPKciP13CEconItemViewb"
"GiveNamedItemTF_vt" "_ZTV9CTFPlayer"
"EquipWearable" "_ZN11CBasePlayer13EquipWearableEP13CEconWearable"
"EquipWearable_vt" "_ZTV11CBasePlayer"
"RemoveWearable" "_ZN11CBasePlayer14RemoveWearableEP13CEconWearable"
"RemoveWearable_vt" "_ZTV11CBasePlayer"
"GrenadeDetonate" "_ZN12CBaseGrenade8DetonateEv"
"GrenadeDetonate_vt" "_ZTV12CBaseGrenade"
}
}
"#default"
{
"#supported"
{
"engine" "left4dead"
"engine" "left4dead2"
}
"Keys"
{
"GiveNamedItem" "_ZN9CCSPlayer13GiveNamedItemEPKci"
"GiveNamedItem_vt" "_ZTV9CCSPlayer"
}
}
}