Static gamedata checker (NPOTB)

This commit is contained in:
Fyren 2010-10-01 12:15:43 -07:00
parent 943777e5d0
commit 430c001d58
16 changed files with 3960 additions and 41 deletions

View File

@ -2,13 +2,12 @@
# Makefile written by David "BAILOPAN" Anderson
SMSDK = ..
SRCDS_BASE = ~/srcds
HL2SDK_ORIG = ../../hl2sdk
HL2SDK_OB = ../../hl2sdk-ob
HL2SDK_OB_VALVE = ../../hl2sdk-ob-valve
HL2SDK_L4D = ../../hl2sdk-l4d
HL2SDK_L4D2 = ../../hl2sdk-l4d2
MMSOURCE17 = ../../mmsource-central
MMSOURCE = ../../mmsource-central
#####################################
### EDIT BELOW FOR OTHER PROJECTS ###
@ -48,71 +47,80 @@ CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
CPP = gcc
override ENGSET = false
ifneq (,$(filter original orangebox orangeboxvalve left4dead left4dead2,$(ENGINE)))
override ENGSET = true
endif
ifeq "$(ENGINE)" "original"
HL2SDK = $(HL2SDK_ORIG)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/linux_sdk
CFLAGS += -DSOURCE_ENGINE=1
METAMOD = $(MMSOURCE17)/core-legacy
METAMOD = $(MMSOURCE)/core-legacy
INCLUDE += -I$(HL2SDK)/public/dlls
SRCDS = $(SRCDS_BASE)
BINARY = sourcemod.1.ep1.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "orangebox"
HL2SDK = $(HL2SDK_OB)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=3
METAMOD = $(MMSOURCE17)/core
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/orangebox
BINARY = sourcemod.2.ep2.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "orangeboxvalve"
HL2SDK = $(HL2SDK_OB_VALVE)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=4
METAMOD = $(MMSOURCE17)/core
INCLUDE += -I$(HL2SDK)/public/game/server -I$(HL2SDK)/common
SRCDS = $(SRCDS_BASE)/orangebox
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
#-I$(HL2SDK)/common
BINARY = sourcemod.2.ep2v.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "left4dead"
HL2SDK = $(HL2SDK_L4D)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=5
METAMOD = $(MMSOURCE17)/core
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/l4d
BINARY = sourcemod.2.l4d.so
override ENGSET = true
endif
ifeq "$(ENGINE)" "left4dead2"
HL2SDK = $(HL2SDK_L4D2)
HL2PUB = $(HL2SDK)/public
HL2LIB = $(HL2SDK)/lib/linux
CFLAGS += -DSOURCE_ENGINE=6
METAMOD = $(MMSOURCE17)/core
METAMOD = $(MMSOURCE)/core
INCLUDE += -I$(HL2SDK)/public/game/server
SRCDS = $(SRCDS_BASE)/left4dead2
BINARY = sourcemod.2.l4d2.so
override ENGSET = true
endif
HL2PUB = $(HL2SDK)/public
OS := $(shell uname -s)
ifeq "$(OS)" "Darwin"
LIB_EXT = dylib
HL2LIB = $(HL2SDK)/lib/mac
else
LIB_EXT = so
ifeq "$(ENGINE)" "original"
HL2LIB = $(HL2SDK)/linux_sdk
else
HL2LIB = $(HL2SDK)/lib/linux
endif
endif
ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
LIB_SUFFIX = _i486.$(LIB_EXT)
else
LIB_PREFIX = lib
LIB_SUFFIX = .$(LIB_EXT)
endif
CFLAGS += -DSE_EPISODEONE=1 -DSE_DARKMESSIAH=2 -DSE_ORANGEBOX=3 -DSE_ORANGEBOXVALVE=4 -DSE_LEFT4DEAD=5 -DSE_LEFT4DEAD2=6
ifeq "$(ENGINE)" "left4dead2"
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a libvstdlib.so \
libtier0.so -static-libgcc
else
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so \
tier0_i486.so -static-libgcc
endif
LINK += $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a $(LIB_PREFIX)vstdlib$(LIB_SUFFIX) \
$(LIB_PREFIX)tier0$(LIB_SUFFIX) -static-libgcc
INCLUDE += -I. -I.. -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/mathlib -I$(HL2PUB)/vstdlib \
-I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook \
@ -152,18 +160,14 @@ $(BIN_DIR)/%.o: %.c
all: check
mkdir -p $(BIN_DIR)
ifeq "$(ENGINE)" "left4dead2"
ln -sf $(SRCDS)/bin/libvstdlib.so libvstdlib.so;
ln -sf $(SRCDS)/bin/libtier0.so libtier0.so;
else
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
endif
ln -sf $(HL2LIB)/$(LIB_PREFIX)vstdlib$(LIB_SUFFIX)
ln -sf $(HL2LIB)/$(LIB_PREFIX)tier0$(LIB_SUFFIX)
$(MAKE) -f Makefile sourcemod
check:
if [ "$(ENGSET)" = "false" ]; then \
echo "You must supply ENGINE=left4dead or ENGINE=orangebox or ENGINE=original"; \
echo "You must supply one of the following values for ENGINE:"; \
echo "left4dead2, left4dead, orangeboxvalve, orangebox, or original"; \
exit 1; \
fi

View File

@ -2741,6 +2741,6 @@ void CPluginManager::ListPluginsToClient(CPlayer *player, const CCommand &args)
/* Do we actually have more plugins? */
if (iter != m_plugins.end())
{
ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id + 1);
ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id);
}
}

View File

@ -630,6 +630,179 @@ static cell_t EmitSound(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t EmitSound2(IPluginContext *pContext, const cell_t *params)
{
cell_t *addr, *cl_array;
CellRecipientFilter crf;
unsigned int numClients;
int client;
IGamePlayer *pPlayer = NULL;
pContext->LocalToPhysAddr(params[1], &cl_array);
numClients = params[2];
/* Client validation */
for (unsigned int i = 0; i < numClients; i++)
{
client = cl_array[i];
pPlayer = playerhelpers->GetGamePlayer(client);
if (!pPlayer)
{
return pContext->ThrowNativeError("Client index %d is invalid", client);
} else if (!pPlayer->IsInGame()) {
return pContext->ThrowNativeError("Client %d is not connected", client);
}
}
crf.Initialize(cl_array, numClients);
char *sample;
pContext->LocalToString(params[3], &sample);
int entity = SoundReferenceToIndex(params[4]);
int channel = params[5];
float level = sp_ctof(params[6]);
int flags = params[7];
float vol = sp_ctof(params[8]);
int pitch = params[9];
int speakerentity = params[10];
Vector *pOrigin = NULL, origin;
Vector *pDir = NULL, dir;
pContext->LocalToPhysAddr(params[11], &addr);
if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
{
pOrigin = &origin;
origin.x = sp_ctof(addr[0]);
origin.y = sp_ctof(addr[1]);
origin.z = sp_ctof(addr[2]);
}
pContext->LocalToPhysAddr(params[12], &addr);
if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
{
pDir = &dir;
dir.x = sp_ctof(addr[0]);
dir.y = sp_ctof(addr[1]);
dir.z = sp_ctof(addr[2]);
}
bool updatePos = params[13] ? true : false;
float soundtime = sp_ctof(params[14]);
CUtlVector<Vector> *pOrigVec = NULL;
CUtlVector<Vector> origvec;
if (params[0] > 14)
{
pOrigVec = &origvec;
for (cell_t i = 15; i <= params[0]; i++)
{
Vector vec;
pContext->LocalToPhysAddr(params[i], &addr);
vec.x = sp_ctof(addr[0]);
vec.y = sp_ctof(addr[1]);
vec.z = sp_ctof(addr[2]);
origvec.AddToTail(vec);
}
}
/* If we're going to a "local player" and this is a dedicated server,
* intelligently redirect each sound.
*/
if (entity == -2 && engine->IsDedicatedServer())
{
for (unsigned int i = 0; i < numClients; i++)
{
cell_t player[1];
player[0] = cl_array[i];
crf.Reset();
crf.Initialize(player, 1);
if (g_InSoundHook)
{
SH_CALL(enginesoundPatch,
static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float,
float, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
(&IEngineSound::EmitSound))
(crf,
player[0],
channel,
sample,
vol,
level,
flags,
pitch,
pOrigin,
pDir,
pOrigVec,
updatePos,
soundtime,
speakerentity);
}
else
{
engsound->EmitSound(crf,
player[0],
channel,
sample,
vol,
level,
flags,
pitch,
pOrigin,
pDir,
pOrigVec,
updatePos,
soundtime,
speakerentity);
}
}
} else {
if (g_InSoundHook)
{
SH_CALL(enginesoundPatch,
static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float,
float, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
(&IEngineSound::EmitSound))
(crf,
entity,
channel,
sample,
vol,
level,
flags,
pitch,
pOrigin,
pDir,
pOrigVec,
updatePos,
soundtime,
speakerentity);
}
else
{
engsound->EmitSound(crf,
entity,
channel,
sample,
vol,
level,
flags,
pitch,
pOrigin,
pDir,
pOrigVec,
updatePos,
soundtime,
speakerentity);
}
}
return 1;
}
static cell_t EmitSentence(IPluginContext *pContext, const cell_t *params)
{
cell_t *addr;
@ -786,6 +959,7 @@ sp_nativeinfo_t g_SoundNatives[] =
{
{"EmitAmbientSound", EmitAmbientSound},
{"EmitSentence", EmitSentence},
{"EmitSound2", EmitSound2},
{"EmitSound", EmitSound},
{"FadeClientVolume", FadeClientVolume},
{"GetSoundDuration", GetSoundDuration},

View File

@ -28,9 +28,9 @@ CPP = gcc
LINK = -lgcc -static-libgcc
INCLUDE = -I. -I$(SMSDK)/public/sourcepawn
INCLUDE = -I. -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn
CFLAGS += -DLINUX -DHAVE_STDINT_H -DAMX_ANSIONLY -DENABLE_BINRELOC -m32
CFLAGS += -DLINUX -DHAVE_STDINT_H -DAMX_ANSIONLY -DENABLE_BINRELOC -Dstricmp=strcasecmp -m32
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
################################################

15
tools/gdc/DOCS Normal file
View File

@ -0,0 +1,15 @@
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
This will verify the gamedata in engine.l4d2.txt against the L4D2 server.so.
The parameters taken (in any order) are:
-g <game name>
-e <engine name>
-f <gameconf file>
-b <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 game's player class' vtable. The symbols.txt itself is a gameconf file.

828
tools/gdc/GameConfigs.cpp Normal file
View File

@ -0,0 +1,828 @@
/**
* 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"
//#include "sm_stringutil.h"
//#include "sourcemod.h"
//#include "sourcemm_api.h"
//#include "HalfLife2.h"
//#include "Logger.h"
//#include "ShareSys.h"
//#include "MemoryUtils.h"
//#include "LibrarySys.h"
//#include "HandleSys.h"
//#include "sm_crc32.h"
//#if defined PLATFORM_LINUX
//#include <dlfcn.h>
//#endif
#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 /*CGameConfig::*/DoesGameMatch(const char *value)
{
if (strcmp(value, /*m_gdcG*/game) == 0)
{
return true;
}
return false;
}
bool /*CGameConfig::*/DoesEngineMatch(const char *value)
{
if (strcmp(value, /*m_gdcE*/engine) == 0)
{
return true;
}
return false;
}
CGameConfig::CGameConfig()//const char *file)//, const char *game, const char *engine)
{
// strncopy(m_File, file, sizeof(m_File));
// strncopy(m_gdcGame, game, sizeof(m_gdcGame));
// strncopy(m_gdcEngine, engine, sizeof(m_gdcEngine));
//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;
}
else if (strcmp(name, "CRC") == 0)
{
#if 0
m_ParseState = PSTATE_GAMEDEFS_CRC;
bShouldBeReadingDefault = false;
#endif
}
else
{
#if 0
ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name);
if (pListen != NULL)
{
m_CustomLevel = 0;
m_ParseState = PSTATE_GAMEDEFS_CUSTOM;
m_CustomHandler = *pListen;
m_CustomHandler->ReadSMC_ParseStart();
break;
}
#endif
}
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;
}
#if 0
case PSTATE_GAMEDEFS_CRC:
{
char error[255];
error[0] = '\0';
if (strcmp(name, "server") != 0)
{
UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name);
}
else if (!s_ServerBinCRC_Ok)
{
FILE *fp;
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
if ((fp = fopen(path, "rb")) == NULL)
{
UTIL_Format(error, sizeof(error), "Could not open binary: %s", path);
} else {
size_t size;
void *buffer;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = malloc(size);
fread(buffer, size, 1, fp);
s_ServerBinCRC = UTIL_CRC32(buffer, size);
free(buffer);
s_ServerBinCRC_Ok = true;
fclose(fp);
}
}
if (error[0] != '\0')
{
m_IgnoreLevel = 1;
g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile);
g_Logger.LogError("[SM] %s", error);
} else {
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
}
break;
}
case PSTATE_GAMEDEFS_CUSTOM:
{
m_CustomLevel++;
return m_CustomHandler->ReadSMC_NewSection(states, name);
break;
}
#endif
/* 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 /*if (strcmp(key, PLATFORM_NAME) == 0) */ {
int val = atoi(value);
// sm_trie_replace(m_pOffsets, m_offset, (void *)val);
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[key] = value;
// printf("Inserting %s - %s\n", key, value);
// int id = m_pStrings->AddString(value);
// sm_trie_replace(m_pKeys, key, (void *)id);
} 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:
{
m_Offsets.push_back(*tempOffset);
#if 0
/* Parse the offset... */
if (m_Class[0] != '\0'
&& m_Prop[0] != '\0')
{
SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop);
if (pProp)
{
int val = pProp->GetOffset();
sm_trie_replace(m_pOffsets, m_offset, (void *)val);
sm_trie_replace(m_pProps, m_offset, pProp);
} else {
/* Check if it's a non-default game and no offsets exist */
if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
{
g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
m_Class,
m_Prop,
m_CurFile,
m_Game);
}
}
}
#endif
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);
#if 0
if (s_TempSig.library[0] == '\0')
{
/* assume server */
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
}
void *addrInBase = NULL;
if (strcmp(s_TempSig.library, "server") == 0)
{
addrInBase = (void *)g_SMAPI->GetServerFactory(false);
} else if (strcmp(s_TempSig.library, "engine") == 0) {
addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
}
void *final_addr = NULL;
if (addrInBase == NULL)
{
g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_CurFile);
} else {
#if defined PLATFORM_LINUX
if (s_TempSig.sig[0] == '@')
{
Dl_info info;
/* GNU only: returns 0 on error, inconsistent! >:[ */
if (dladdr(addrInBase, &info) != 0)
{
void *handle = dlopen(info.dli_fname, RTLD_NOW);
if (handle)
{
final_addr = dlsym(handle, &s_TempSig.sig[1]);
dlclose(handle);
} else {
g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_File);
}
} else {
g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
s_TempSig.library,
m_File);
}
}
if (final_addr)
{
goto skip_find;
}
#endif
/* First, preprocess the signature */
char real_sig[511];
size_t real_bytes;
size_t length;
real_bytes = 0;
length = strlen(s_TempSig.sig);
for (size_t i=0; i<length; i++)
{
if (real_bytes >= sizeof(real_sig))
{
break;
}
real_sig[real_bytes++] = s_TempSig.sig[i];
if (s_TempSig.sig[i] == '\\'
&& s_TempSig.sig[i+1] == 'x')
{
if (i + 3 >= length)
{
continue;
}
/* Get the hex part */
char s_byte[3];
int r_byte;
s_byte[0] = s_TempSig.sig[i+2];
s_byte[1] = s_TempSig.sig[i+3];
s_byte[2] = '\0';
/* Read it as an integer */
sscanf(s_byte, "%x", &r_byte);
/* Save the value */
real_sig[real_bytes-1] = r_byte;
/* Adjust index */
i += 3;
}
}
if (real_bytes >= 1)
{
final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
}
}
#if defined PLATFORM_LINUX
skip_find:
#endif
sm_trie_replace(m_pSigs, m_offset, final_addr);
#endif
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 0
if ((!had_engine && !had_game) ||
(!had_engine && (had_game && matched_game)) ||
(!had_game && (had_engine && matched_engine)) ||
((had_game && had_engine) && (matched_game && matched_engine)))
#endif
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();
char path[PLATFORM_MAX_PATH];
/* See if we can use the extended gamedata format. */
//TODO pass in path to gamedata somehow
// g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/master.games.txt", m_File);
/* 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;
}
#if 0
bool CGameConfig::GetOffset(const char *key, int *value)
{
void *obj;
if (!sm_trie_retrieve(m_pOffsets, key, &obj))
{
return false;
}
*value = (int)obj;
return true;
}
const char *CGameConfig::GetKeyValue(const char *key)
{
void *obj;
if (!sm_trie_retrieve(m_pKeys, key, &obj))
{
return NULL;
}
return m_pStrings->GetString((int)obj);
}
SendProp *CGameConfig::GetSendProp(const char *key)
{
SendProp *pProp;
if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
{
return NULL;
}
return pProp;
}
bool CGameConfig::GetMemSig(const char *key, void **addr)
{
return sm_trie_retrieve(m_pSigs, key, addr);
}
void CGameConfig::IncRefCount()
{
m_RefCount++;
}
unsigned int CGameConfig::DecRefCount()
{
m_RefCount--;
return m_RefCount;
}
#endif
const char *CGameConfig::GetKeyValue(const char *key)
{
map<const char*,const char*,cmp_str>::iterator it = m_Keys.find(key);
if (it == m_Keys.end()) return NULL;
return it->second;
}
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
list<Sig> CGameConfig::GetSigs() { return m_Sigs; }

239
tools/gdc/GameConfigs.h Normal file
View File

@ -0,0 +1,239 @@
/**
* 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>
#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;
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_

72
tools/gdc/Makefile Normal file
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-4.1
BINARY = gdc
LINK += -L. -lstdc++ -ldl -lm
INCLUDE += -I. -I../../public -I../../public/sourcepawn
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)/

615
tools/gdc/MemoryUtils.cpp Normal file
View File

@ -0,0 +1,615 @@
/**
* 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 g_MemUtils;
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::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
}*/
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;
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;
}

89
tools/gdc/MemoryUtils.h Normal file
View File

@ -0,0 +1,89 @@
/**
* 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 "common_logic.h"
#include <IMemoryUtils.h>
#include <string.h>
#include <vector>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
//#include <sh_vector.h>
#include "sm_symtable.h"
//using namespace SourceHook;
#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 IMemoryUtils,
// public SMGlobalClass
{
public:
MemoryUtils();
~MemoryUtils();
public: // SMGlobalClass
// void OnSourceModAllInitialized();
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:
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
};
//extern MemoryUtils g_MemUtils;
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_

1094
tools/gdc/TextParsers.cpp Normal file

File diff suppressed because it is too large Load Diff

92
tools/gdc/TextParsers.h Normal file
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_

266
tools/gdc/gdc.cpp Normal file
View File

@ -0,0 +1,266 @@
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <math.h>
#include "gdc.h"
#include "GameConfigs.h"
#include "MemoryUtils.h"
MemoryUtils mu;
char *game = NULL;
char *engine = NULL;
char *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:")) != -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':
binary = optarg;
break;
case '?':
printf("Usage: ./gdc -g <game> -e <engine> -f <gamedata file> -b <binary>\n");
return 0;
default:
printf("WHAT\n");
return 0;
}
if (!game || !engine || !gamedata || !binary)
{
printf("Usage: ./gdc -g <game> -e <engine> -f <gamedata file> -b <binary>\n");
return 0;
}
printf("Game: %s\nEngine: %s\nGamedata: %s\nBinary: %s\n", game, engine, gamedata, binary);
void *handle = dlopen(binary, RTLD_LAZY);
if (!handle)
{
printf("Couldn't open %s (%s)\n", binary, dlerror());
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;
}
if (debug)
for (map<const char*, const char*, cmp_str>::iterator it = symbols.m_Keys.begin(); it != symbols.m_Keys.end(); it++)
printf("%s - %s\n", it->first, it->second);
const char *vtsym = symbols.GetKeyValue("vtsym");
if (!vtsym)
{
printf("Couldn't find vtsym\n");
return 0;
}
#if 0
void *lolwhat = (void*)1;
void *handle = lolwhat;
handle = dlopen(binary, RTLD_LAZY);
if (!handle)
{
printf("Couldn't open %s\n", binary);
return 0;
}
#endif
void **vt = (void**) mu.ResolveSymbol(handle, vtsym);
if (!vt)
{
printf("Couldn't find vtable %s\n", vtsym);
dlclose(handle);
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);
// else
{
const char *symbol = symbols.GetKeyValue(it->name);
if (symbol)
{
int offset = findVFunc(handle, vt, symbol);
if (offset == it->lin) printf("%s - good\n", it->name);
else printf("%s - l: %d w: %d\n", it->name, offset, offset + it->lin - it->win);
}
else printf("%s - no Linux symbol, skipping\n", it->name);
}
}
printf("\nWindows offsets are 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);
// else
{
if (it->lib != Server)
{
printf("%s - isn't server, skipping\n", it->name);
continue;
}
const char *symbol = it->lin;
if (!symbol)
{
printf("%s - no Linux symbol, skipping\n", it->name);
continue;
}
if (symbol[0] != '@')
{
printf("%s - didn't start with '@', skipping\n", it->name);
continue;
}
void *addr = mu.ResolveSymbol(handle, symbol + 1);
if (addr) printf("%s - good\n", it->name);
else printf("%s - %s not found\n", it->name, it->lin);
}
}
return 0;
}
/*
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 overloads = 0;
int funcPos, paramPos;
findFuncPos(symbol, funcPos, paramPos);
for (int i = 0; i < 1000; i++)
{
void *pFunc = vt[i];
const char *s;
// Dl_info info;
// if (!mu.ResolveAddr(pFunc, &info)) continue;
if (!(s = mu.ResolveAddr(handle, pFunc))) continue;
// if ((i > 1) && (strncmp(info.dli_sname, "_ZTI", 4) == 0)) break;
if ((i > 1) && (strncmp(s, "_ZTI", 4) == 0)) break;
int tempFuncPos, tempParamPos;
// findFuncPos(info.dli_sname, tempFuncPos, tempParamPos);
findFuncPos(s, tempFuncPos, tempParamPos);
#if 0
if (strncmp(info.dli_sname[tempFuncPos], symbol[funcPos], paramPos - funcPos) == 0)
{
overloads++;
if (firstOverload == -1) firstOverload = i - 1;
if (strncmp(info.dli_sname[tempParamPos], symbol[paramPos], strlen(symbol) - paramPos) == 0)
{
offset = i;
matchingOverload = overloads;
}
}
#else
// if (strcmp(info.dli_sname + tempFuncPos, symbol + funcPos) == 0)
if (strcmp(s + tempFuncPos, symbol + funcPos) == 0)
{
offset = i;
break;
}
#endif
}
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;
}
}

18
tools/gdc/gdc.h Normal file
View File

@ -0,0 +1,18 @@
#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);
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
unsigned int strncopy(char *dest, const char *src, size_t count);
#endif // _INCLUDE_GDC_MAIN_H_

356
tools/gdc/sm_symtable.h Normal file
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_

57
tools/gdc/symbols.txt Normal file
View File

@ -0,0 +1,57 @@
"Games"
{
"#default"
{
"Keys"
{
"GiveNamedItem" "_ZN11CBasePlayer13GiveNamedItemEPKci"
"RemovePlayerItem" "_ZN11CBasePlayer16RemovePlayerItemEP17CBaseCombatWeapon"
"Weapon_GetSlot" "_ZNK20CBaseCombatCharacter14Weapon_GetSlotEi"
"Ignite" "_ZN14CBaseAnimating6IgniteEfbfb"
"Extinguish" "_ZN14CBaseAnimating10ExtinguishEv"
"Teleport" "_ZN11CBaseEntity8TeleportEPK6VectorPK6QAngleS2_"
"CommitSuicide" "_ZN11CBasePlayer13CommitSuicideEv"
"GetVelocity" "_ZN11CBaseEntity11GetVelocityEP6VectorS1_"
"EyeAngles" "_ZN11CBasePlayer9EyeAnglesEv"
"DispatchKeyValue" "_ZN11CBaseEntity8KeyValueEPKcS1_"
"DispatchKeyValueFloat" "_ZN11CBaseEntity8KeyValueEPKcf"
"DispatchKeyValueVector" "_ZN11CBaseEntity8KeyValueEPKcRK6Vector"
"SetEntityModel" "_ZN11CBaseEntity8SetModelEPKc"
"AcceptInput" "_ZN11CBaseEntity11AcceptInputEPKcPS_S2_9variant_ti"
"WeaponEquip" "_ZN11CBasePlayer12Weapon_EquipEP17CBaseCombatWeapon"
"Activate" "_ZN11CBaseEntity8ActivateEv"
"PlayerRunCmd" "_ZN11CBasePlayer16PlayerRunCommandEP8CUserCmdP11IMoveHelper"
}
}
"#default"
{
"#supported"
{
"game" "tf"
}
"Keys"
{
"vtsym" "_ZTV9CTFPlayer"
"CommitSuicide" "_ZN9CTFPlayer13CommitSuicideEbb"
"ForceRespawn" "_ZN9CTFPlayer12ForceRespawnEv"
}
}
"#default"
{
"#supported"
{
"game" "left4dead"
"game" "left4dead2"
}
"Keys"
{
"vtsym" "_ZTV13CTerrorPlayer"
"CommitSuicide" "_ZN11CBasePlayer13CommitSuicideEbb"
}
}
}