Merge branch 'master' into dhooks-update

This commit is contained in:
A1mDev 2024-11-11 11:44:01 +07:00
commit a2626537b1
75 changed files with 38735 additions and 27618 deletions

View File

@ -14,14 +14,12 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
os_short: linux os_short: linux
- os: windows-latest - os: windows-latest
os_short: win os_short: win
- os: macos-latest
os_short: mac
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
@ -41,10 +39,6 @@ jobs:
python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade pip setuptools wheel
pip install git+https://github.com/alliedmodders/ambuild pip install git+https://github.com/alliedmodders/ambuild
- name: Build universal x64/arm64 on macOS
if: startsWith(runner.os, 'macOS')
run: echo "ARCH=x86_64,arm64" >> $GITHUB_ENV
- name: Install Linux dependencies - name: Install Linux dependencies
if: startsWith(runner.os, 'Linux') if: startsWith(runner.os, 'Linux')
run: | run: |
@ -56,7 +50,7 @@ jobs:
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }} linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
- name: Select clang compiler - name: Select clang compiler
if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS') if: startsWith(runner.os, 'Linux')
run: | run: |
echo "CC=clang" >> $GITHUB_ENV echo "CC=clang" >> $GITHUB_ENV
echo "CXX=clang++" >> $GITHUB_ENV echo "CXX=clang++" >> $GITHUB_ENV

View File

@ -129,6 +129,8 @@ class SMConfig(object):
self.mms_root = builder.options.mms_path self.mms_root = builder.options.mms_path
else: else:
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12') self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source')
if not self.mms_root: if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source') self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root: if not self.mms_root:

View File

@ -38,7 +38,7 @@
#include <am-inlinelist.h> #include <am-inlinelist.h>
#include <am-refcounting.h> #include <am-refcounting.h>
#include <am-utility.h> #include <am-utility.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include "sm_globals.h" #include "sm_globals.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"

View File

@ -43,7 +43,7 @@
#include <compat_wrappers.h> #include <compat_wrappers.h>
#include "concmd_cleaner.h" #include "concmd_cleaner.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
using namespace SourceHook; using namespace SourceHook;

View File

@ -34,7 +34,7 @@
#include "sm_globals.h" #include "sm_globals.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <IForwardSys.h> #include <IForwardSys.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
namespace SourceMod { namespace SourceMod {
class ICommandArgs; class ICommandArgs;

View File

@ -36,7 +36,7 @@
#include <ITextParsers.h> #include <ITextParsers.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <am-string.h> #include <am-string.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
using namespace SourceMod; using namespace SourceMod;

View File

@ -38,7 +38,7 @@
#include <am-utility.h> #include <am-utility.h>
#include <am-hashset.h> #include <am-hashset.h>
#include <am-hashmap.h> #include <am-hashmap.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sm_namehashset.h> #include <sm_namehashset.h>
#include "sm_globals.h" #include "sm_globals.h"
#include "sm_queue.h" #include "sm_queue.h"

View File

@ -34,7 +34,7 @@
#include <IUserMessages.h> #include <IUserMessages.h>
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "CellRecipientFilter.h" #include "CellRecipientFilter.h"
#include "sm_globals.h" #include "sm_globals.h"

View File

@ -34,7 +34,7 @@
#include <IADTFactory.h> #include <IADTFactory.h>
#include "common_logic.h" #include "common_logic.h"
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
using namespace SourceMod; using namespace SourceMod;

View File

@ -39,7 +39,7 @@
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#include <IForwardSys.h> #include <IForwardSys.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sm_namehashset.h> #include <sm_namehashset.h>
using namespace SourceHook; using namespace SourceHook;

View File

@ -36,7 +36,7 @@
#include <IGameConfigs.h> #include <IGameConfigs.h>
#include <ITextParsers.h> #include <ITextParsers.h>
#include <am-refcounting.h> #include <am-refcounting.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sm_namehashset.h> #include <sm_namehashset.h>
#include <unordered_set> #include <unordered_set>

View File

@ -36,7 +36,7 @@
#include <am-string.h> #include <am-string.h>
#include <am-utility.h> #include <am-utility.h>
#include <am-refcounting.h> #include <am-refcounting.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include "common_logic.h" #include "common_logic.h"
class CNativeOwner; class CNativeOwner;

View File

@ -47,7 +47,7 @@
#include <sh_string.h> #include <sh_string.h>
#include "common_logic.h" #include "common_logic.h"
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sm_namehashset.h> #include <sm_namehashset.h>
#include "ITranslator.h" #include "ITranslator.h"
#include "IGameConfigs.h" #include "IGameConfigs.h"

View File

@ -38,7 +38,7 @@
#include <am-utility.h> #include <am-utility.h>
#include <am-refcounting.h> #include <am-refcounting.h>
#include <sh_list.h> #include <sh_list.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sm_namehashset.h> #include <sm_namehashset.h>
#include "common_logic.h" #include "common_logic.h"
#include "Native.h" #include "Native.h"

View File

@ -33,7 +33,7 @@
#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_ #define _INCLUDE_SOURCEMOD_TRANSLATOR_H_
#include "common_logic.h" #include "common_logic.h"
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include <sh_string.h> #include <sh_string.h>
#include <sh_vector.h> #include <sh_vector.h>
#include "sm_memtable.h" #include "sm_memtable.h"

View File

@ -35,12 +35,14 @@
#include "common_logic.h" #include "common_logic.h"
#include <am-refcounting.h> #include <am-refcounting.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#include "sm_memtable.h" #include "sm_memtable.h"
#include <IHandleSys.h> #include <IHandleSys.h>
HandleType_t htCellTrie; HandleType_t htCellTrie;
HandleType_t htSnapshot; HandleType_t htSnapshot;
HandleType_t htIntCellTrie;
HandleType_t htIntSnapshot;
enum EntryType enum EntryType
{ {
@ -171,6 +173,11 @@ struct CellTrie
StringHashMap<Entry> map; StringHashMap<Entry> map;
}; };
struct IntCellTrie
{
IntHashMap<Entry> map;
};
struct TrieSnapshot struct TrieSnapshot
{ {
TrieSnapshot() TrieSnapshot()
@ -187,6 +194,19 @@ struct TrieSnapshot
BaseStringTable strings; BaseStringTable strings;
}; };
struct IntTrieSnapshot
{
IntTrieSnapshot() {}
size_t mem_usage()
{
return length * sizeof(int);
}
size_t length;
std::unique_ptr<int[]> keys;
};
class TrieHelpers : class TrieHelpers :
public SMGlobalClass, public SMGlobalClass,
public IHandleTypeDispatch public IHandleTypeDispatch
@ -196,11 +216,15 @@ public: //SMGlobalClass
{ {
htCellTrie = handlesys->CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL); htCellTrie = handlesys->CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
htSnapshot = handlesys->CreateType("TrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL); htSnapshot = handlesys->CreateType("TrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL);
htIntCellTrie = handlesys->CreateType("IntTrie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
htIntSnapshot = handlesys->CreateType("IntTrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL);
} }
void OnSourceModShutdown() void OnSourceModShutdown()
{ {
handlesys->RemoveType(htSnapshot, g_pCoreIdent); handlesys->RemoveType(htSnapshot, g_pCoreIdent);
handlesys->RemoveType(htCellTrie, g_pCoreIdent); handlesys->RemoveType(htCellTrie, g_pCoreIdent);
handlesys->RemoveType(htIntSnapshot, g_pCoreIdent);
handlesys->RemoveType(htIntCellTrie, g_pCoreIdent);
} }
public: //IHandleTypeDispatch public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object) void OnHandleDestroy(HandleType_t type, void *object)
@ -208,10 +232,21 @@ public: //IHandleTypeDispatch
if (type == htCellTrie) if (type == htCellTrie)
{ {
delete (CellTrie *)object; delete (CellTrie *)object;
} else { }
else if (type == htSnapshot)
{
TrieSnapshot *snapshot = (TrieSnapshot *)object; TrieSnapshot *snapshot = (TrieSnapshot *)object;
delete snapshot; delete snapshot;
} }
else if (type == htIntCellTrie)
{
delete (IntCellTrie *)object;
}
else if (type == htIntSnapshot)
{
IntTrieSnapshot *snapshot = (IntTrieSnapshot *)object;
delete snapshot;
}
} }
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
{ {
@ -219,12 +254,29 @@ public: //IHandleTypeDispatch
{ {
CellTrie *pArray = (CellTrie *)object; CellTrie *pArray = (CellTrie *)object;
*pSize = sizeof(CellTrie) + pArray->map.mem_usage(); *pSize = sizeof(CellTrie) + pArray->map.mem_usage();
} else { return true;
}
else if (type == htSnapshot)
{
TrieSnapshot *snapshot = (TrieSnapshot *)object; TrieSnapshot *snapshot = (TrieSnapshot *)object;
*pSize = sizeof(TrieSnapshot) + snapshot->mem_usage(); *pSize = sizeof(TrieSnapshot) + snapshot->mem_usage();
}
return true; return true;
} }
else if (type == htIntCellTrie)
{
IntCellTrie *pArray = (IntCellTrie *)object;
*pSize = sizeof(IntCellTrie) + pArray->map.mem_usage();
return true;
}
else if (type == htIntSnapshot)
{
IntTrieSnapshot *snapshot = (IntTrieSnapshot *)object;
*pSize = sizeof(IntTrieSnapshot) + snapshot->mem_usage();
return true;
}
return false;
}
} s_CellTrieHelpers; } s_CellTrieHelpers;
static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params) static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
@ -242,6 +294,21 @@ static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
return hndl; return hndl;
} }
static cell_t CreateIntTrie(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie = new IntCellTrie;
Handle_t hndl;
if ((hndl = handlesys->CreateHandle(htIntCellTrie, pTrie, pContext->GetIdentity(), g_pCoreIdent, NULL))
== BAD_HANDLE)
{
delete pTrie;
return BAD_HANDLE;
}
return hndl;
}
static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params) static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
{ {
CellTrie *pTrie; CellTrie *pTrie;
@ -275,6 +342,38 @@ static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t SetIntTrieValue(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
int32_t key = params[2];
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
if (!i.found())
{
if (!pTrie->map.add(i, key))
return 0;
i->value.setCell(params[3]);
return 1;
}
if (!params[4])
return 0;
i->value.setCell(params[3]);
return 1;
}
static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params) static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
{ {
CellTrie *pTrie; CellTrie *pTrie;
@ -316,6 +415,46 @@ static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t SetIntTrieArray(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
if (params[4] < 0)
{
return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
}
int32_t key = params[2];
cell_t *array;
pContext->LocalToPhysAddr(params[3], &array);
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
if (!i.found())
{
if (!pTrie->map.add(i, key))
return 0;
i->key = key;
i->value.setArray(array, params[4]);
return 1;
}
if (!params[5])
return 0;
i->value.setArray(array, params[4]);
return 1;
}
static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params) static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
{ {
CellTrie *pTrie; CellTrie *pTrie;
@ -350,6 +489,40 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t SetIntTrieString(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
int32_t key = params[2];
char *val;
pContext->LocalToString(params[3], &val);
IntHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
if (!i.found())
{
if (!pTrie->map.add(i, key))
return 0;
i->value.setString(val);
return 1;
}
if (!params[4])
return 0;
i->value.setString(val);
return 1;
}
static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params) static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
{ {
CellTrie *pTrie; CellTrie *pTrie;
@ -371,6 +544,26 @@ static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
return r.found() ? 1 : 0; return r.found() ? 1 : 0;
} }
static cell_t ContainsKeyInIntTrie(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie)) != HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
int32_t key = params[2];
IntHashMap<Entry>::Result r = pTrie->map.find(key);
return r.found() ? 1 : 0;
}
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params) static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
{ {
CellTrie *pTrie; CellTrie *pTrie;
@ -396,6 +589,30 @@ static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t RemoveFromIntTrie(IPluginContext *pContext, const cell_t *params)
{
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
int32_t key = params[2];
IntHashMap<Entry>::Result r = pTrie->map.find(key);
if (!r.found())
return 0;
pTrie->map.remove(r);
return 1;
}
static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params) static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl; Handle_t hndl;
@ -415,6 +632,25 @@ static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t ClearIntTrie(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl;
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
pTrie->map.clear();
return 1;
}
static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params) static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl; Handle_t hndl;
@ -457,6 +693,47 @@ static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
static cell_t GetIntTrieValue(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl;
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
int32_t key = params[2];
cell_t *pValue;
pContext->LocalToPhysAddr(params[3], &pValue);
IntHashMap<Entry>::Result r = pTrie->map.find(key);
if (!r.found())
return 0;
if (r->value.isCell())
{
*pValue = r->value.cell();
return 1;
}
// Maintain compatibility with an old bug. If an array was set with one
// cell, it was stored internally as a single cell. We now store as an
// actual array, but we make GetTrieValue() still work for this case.
if (r->value.isArray() && r->value.arrayLength() == 1)
{
*pValue = r->value.array()[0];
return 1;
}
return 0;
}
static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params) static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl; Handle_t hndl;
@ -509,6 +786,56 @@ static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t GetIntTrieArray(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl;
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
if (params[4] < 0)
{
return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
}
int32_t key = params[2];
cell_t *pValue, *pSize;
pContext->LocalToPhysAddr(params[3], &pValue);
pContext->LocalToPhysAddr(params[5], &pSize);
IntHashMap<Entry>::Result r = pTrie->map.find(key);
if (!r.found() || !r->value.isArray())
return 0;
if (!r->value.array())
{
*pSize = 0;
return 1;
}
if (!params[4])
return 1;
size_t length = r->value.arrayLength();
cell_t *base = r->value.array();
if (length > size_t(params[4]))
*pSize = params[4];
else
*pSize = length;
memcpy(pValue, base, sizeof(cell_t) * pSize[0]);
return 1;
}
static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params) static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl; Handle_t hndl;
@ -545,6 +872,41 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t GetIntTrieString(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl;
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
if (params[4] < 0)
{
return pContext->ThrowNativeError("Invalid buffer size: %d", params[4]);
}
int32_t key = params[2];
cell_t *pSize;
pContext->LocalToPhysAddr(params[5], &pSize);
IntHashMap<Entry>::Result r = pTrie->map.find(key);
if (!r.found() || !r->value.isString())
return 0;
size_t written;
pContext->StringToLocalUTF8(params[3], params[4], r->value.c_str(), &written);
*pSize = (cell_t)written;
return 1;
}
static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params) static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl; Handle_t hndl;
@ -563,6 +925,24 @@ static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
return pTrie->map.elements(); return pTrie->map.elements();
} }
static cell_t GetIntTrieSize(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl;
IntCellTrie *pTrie;
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
hndl = params[1];
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
return pTrie->map.elements();
}
static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params) static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
{ {
HandleError err; HandleError err;
@ -595,6 +975,38 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
return hndl; return hndl;
} }
static cell_t CreateIntTrieSnapshot(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
IntCellTrie *pTrie;
if ((err = handlesys->ReadHandle(hndl, htIntCellTrie, &sec, (void **)&pTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
IntTrieSnapshot *snapshot = new IntTrieSnapshot;
snapshot->length = pTrie->map.elements();
snapshot->keys = std::make_unique<int[]>(snapshot->length);
size_t i = 0;
for (IntHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
snapshot->keys[i] = iter->key;
assert(i == snapshot->length);
if ((hndl = handlesys->CreateHandle(htIntSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
== BAD_HANDLE)
{
delete snapshot;
return BAD_HANDLE;
}
return hndl;
}
static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params) static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
{ {
HandleError err; HandleError err;
@ -612,6 +1024,23 @@ static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
return snapshot->length; return snapshot->length;
} }
static cell_t IntTrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
IntTrieSnapshot *snapshot;
if ((err = handlesys->ReadHandle(hndl, htIntSnapshot, &sec, (void **)&snapshot))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
return snapshot->length;
}
static cell_t TrieSnapshotKeyBufferSize(IPluginContext *pContext, const cell_t *params) static cell_t TrieSnapshotKeyBufferSize(IPluginContext *pContext, const cell_t *params)
{ {
HandleError err; HandleError err;
@ -657,6 +1086,27 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
return written; return written;
} }
static cell_t GetIntTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
Handle_t hndl = params[1];
IntTrieSnapshot *snapshot;
if ((err = handlesys->ReadHandle(hndl, htIntSnapshot, &sec, (void **)&snapshot))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
}
unsigned index = params[2];
if (index >= snapshot->length)
return pContext->ThrowNativeError("Invalid index %d", index);
return snapshot->keys[index];
}
static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params) static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
{ {
HandleError err; HandleError err;
@ -707,6 +1157,56 @@ static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
return hndl; return hndl;
} }
static cell_t CloneIntTrie(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
IntCellTrie *pOldTrie;
if ((err = handlesys->ReadHandle(params[1], htIntCellTrie, &sec, (void **)&pOldTrie))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
}
IntCellTrie *pNewTrie = new IntCellTrie;
Handle_t hndl = handlesys->CreateHandle(htIntCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (!hndl)
{
delete pNewTrie;
return hndl;
}
for (IntHashMap<Entry>::iterator it = pOldTrie->map.iter(); !it.empty(); it.next())
{
int32_t key = it->key;
IntHashMap<Entry>::Insert insert = pNewTrie->map.findForAdd(key);
if (pNewTrie->map.add(insert, key))
{
IntHashMap<Entry>::Result result = pOldTrie->map.find(key);
if (result->value.isCell())
{
insert->value.setCell(result->value.cell());
}
else if (result->value.isString())
{
insert->value.setString(result->value.c_str());
}
else if (result->value.isArray())
{
insert->value.setArray(result->value.array(), result->value.arrayLength());
}
else
{
handlesys->FreeHandle(hndl, NULL);
return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852");
}
}
}
return hndl;
}
REGISTER_NATIVES(trieNatives) REGISTER_NATIVES(trieNatives)
{ {
{"ClearTrie", ClearTrie}, {"ClearTrie", ClearTrie},
@ -740,9 +1240,26 @@ REGISTER_NATIVES(trieNatives)
{"StringMap.Snapshot", CreateTrieSnapshot}, {"StringMap.Snapshot", CreateTrieSnapshot},
{"StringMap.Clone", CloneTrie}, {"StringMap.Clone", CloneTrie},
{"IntMap.IntMap", CreateIntTrie},
{"IntMap.Clear", ClearIntTrie},
{"IntMap.GetArray", GetIntTrieArray},
{"IntMap.GetString", GetIntTrieString},
{"IntMap.GetValue", GetIntTrieValue},
{"IntMap.ContainsKey", ContainsKeyInIntTrie},
{"IntMap.Remove", RemoveFromIntTrie},
{"IntMap.SetArray", SetIntTrieArray},
{"IntMap.SetString", SetIntTrieString},
{"IntMap.SetValue", SetIntTrieValue},
{"IntMap.Size.get", GetIntTrieSize},
{"IntMap.Snapshot", CreateIntTrieSnapshot},
{"IntMap.Clone", CloneIntTrie},
{"StringMapSnapshot.Length.get", TrieSnapshotLength}, {"StringMapSnapshot.Length.get", TrieSnapshotLength},
{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize}, {"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize},
{"StringMapSnapshot.GetKey", GetTrieSnapshotKey}, {"StringMapSnapshot.GetKey", GetTrieSnapshotKey},
{"IntMapSnapshot.Length.get", IntTrieSnapshotLength},
{"IntMapSnapshot.GetKey", GetIntTrieSnapshotKey},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -119,6 +119,7 @@ REGISTER_NATIVES(handles)
{"CloseHandle", sm_CloseHandle}, {"CloseHandle", sm_CloseHandle},
{"CloneHandle", sm_CloneHandle}, {"CloneHandle", sm_CloneHandle},
{"GetMyHandle", sm_GetMyHandle}, {"GetMyHandle", sm_GetMyHandle},
{"Handle.Clone", sm_CloneHandle},
{"Handle.Close", sm_CloseHandle}, {"Handle.Close", sm_CloseHandle},
{"Handle.~Handle", sm_CloseHandle}, {"Handle.~Handle", sm_CloseHandle},
{NULL, NULL}, {NULL, NULL},

View File

@ -42,27 +42,22 @@ for cxx in builder.targets:
'util.cpp', 'util.cpp',
'dynhooks_sourcepawn.cpp', 'dynhooks_sourcepawn.cpp',
'../../public/smsdk_ext.cpp', '../../public/smsdk_ext.cpp',
'asm/asm.c',
'libudis86/decode.c',
'libudis86/itab.c',
'libudis86/syn-att.c',
'libudis86/syn-intel.c',
'libudis86/syn.c',
'libudis86/udis86.c',
# Dynamic Hooks # Dynamic Hooks
os.path.join('DynamicHooks', 'registers.cpp') os.path.join('DynamicHooks', 'registers.cpp'),
os.path.join('DynamicHooks', 'hook.cpp'),
os.path.join('DynamicHooks', 'manager.cpp')
] ]
SM.AddCDetour(binary)
if binary.compiler.target.arch == 'x86': if binary.compiler.target.arch == 'x86':
binary.sources += ['../../sourcepawn/vm/x86/assembler-x86.cpp'] binary.sources += ['../../sourcepawn/vm/x86/assembler-x86.cpp']
binary.compiler.cxxincludes += [ binary.compiler.cxxincludes += [
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'), os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86') os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86')
] ]
# DynamicHooks # DynamicHooks
binary.sources += [ binary.sources += [
os.path.join('DynamicHooks', 'hook.cpp'),
os.path.join('DynamicHooks', 'manager.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'),
@ -77,6 +72,16 @@ for cxx in builder.targets:
binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR'] binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR']
elif binary.compiler.target.arch == 'x86_64': elif binary.compiler.target.arch == 'x86_64':
binary.compiler.defines += ['PLATFORM_X64'] binary.compiler.defines += ['DYNAMICHOOKS_x86_64', 'DHOOKS_DYNAMIC_DETOUR']
if binary.compiler.target.platform == 'windows':
binary.sources += [
os.path.join('DynamicHooks', 'conventions', 'x86_64MicrosoftDefault.cpp')
]
# Linux follows System V definition
elif binary.compiler.target.platform == 'linux':
binary.sources += [
os.path.join('DynamicHooks', 'conventions', 'x86_64SystemVDefault.cpp')
]
SM.extensions += [builder.Add(binary)] SM.extensions += [builder.Add(binary)]

View File

@ -0,0 +1,281 @@
/**
* =============================================================================
* DynamicHooks-x86_64
* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved.
* Copyright (C) 2024 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
// ============================================================================
// >> INCLUDES
// ============================================================================
#include "x86_64MicrosoftDefault.h"
#include <smsdk_ext.h>
// ============================================================================
// >> CLASSES
// ============================================================================
x86_64MicrosoftDefault::x86_64MicrosoftDefault(std::vector<DataTypeSized_t> &vecArgTypes, DataTypeSized_t returnType, int iAlignment) :
ICallingConvention(vecArgTypes, returnType, iAlignment),
m_stackArgs(0)
{
const Register_t params_reg[] = { RCX, RDX, R8, R9 };
const Register_t params_floatreg[] = { XMM0, XMM1, XMM2, XMM3 };
//const char* regNames[] = { "RCX or XMM0", "RDX or XMM1", "R8 or XMM2", "R9 or XMM3"};
const std::uint8_t num_reg = sizeof(params_reg) / sizeof(Register_t);
bool used_reg[] = { false, false, false, false };
// Figure out if any register has been used
auto retreg = m_returnType.custom_register;
used_reg[0] = (retreg == RCX || retreg == XMM0);
used_reg[1] = (retreg == RDX || retreg == XMM1);
used_reg[2] = (retreg == R8 || retreg == XMM2);
used_reg[3] = (retreg == R9 || retreg == XMM3);
for (const auto& arg : m_vecArgTypes) {
int reg_index = -1;
if (arg.custom_register == RCX || arg.custom_register == XMM0) {
reg_index = 0;
} else if (arg.custom_register == RDX || arg.custom_register == XMM1) {
reg_index = 1;
} else if (arg.custom_register == R8 || arg.custom_register == XMM2) {
reg_index = 2;
} else if (arg.custom_register == R9 || arg.custom_register == XMM3) {
reg_index = 3;
}
if (reg_index != -1) {
if (used_reg[reg_index]) {
puts("Argument register is used twice, or shared with return");
return;
}
used_reg[reg_index] = true;
}
}
// Special return type
if (m_returnType.custom_register == None && m_returnType.type == DATA_TYPE_OBJECT &&
// If size unknown, or doesn't fit on 1, 2, 4 or 8 bytes
// special place must have been allocated for it
(m_returnType.size == 0
|| m_returnType.size == 3
|| m_returnType.size == 5
|| m_returnType.size == 6
|| m_returnType.size == 7
|| m_returnType.size > 8)) {
for (std::uint8_t i = 0; i < num_reg && m_returnType.custom_register == None; i++) {
if (!used_reg[i]) {
m_returnType.custom_register = params_reg[i];
used_reg[i] = true;
}
// Couldn't find a free register, this is a big problem
if (m_returnType.custom_register == None) {
puts("Missing free register for return pointer");
return;
}
}
}
for (auto& arg : m_vecArgTypes) {
if (arg.custom_register == None) {
for (std::uint8_t i = 0; i < num_reg && arg.custom_register == None; i++) {
// Register is unused assign it
if (!used_reg[i]) {
arg.custom_register = (arg.type == DATA_TYPE_FLOAT || arg.type == DATA_TYPE_DOUBLE) ? params_floatreg[i] : params_reg[i];
used_reg[i] = true;
}
}
// Couldn't find a free register, it's therefore a stack parameter
if (arg.custom_register == None) {
m_stackArgs++;
}
}
}
}
std::vector<Register_t> x86_64MicrosoftDefault::GetRegisters()
{
std::vector<Register_t> registers;
registers.push_back(RSP);
if (m_returnType.custom_register != None)
{
registers.push_back(m_returnType.custom_register);
}
else if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE)
{
registers.push_back(XMM0);
}
else
{
registers.push_back(RAX);
}
for (size_t i = 0; i < m_vecArgTypes.size(); i++)
{
auto reg = m_vecArgTypes[i].custom_register;
if (reg == None)
{
continue;
}
registers.push_back(m_vecArgTypes[i].custom_register);
}
return registers;
}
int x86_64MicrosoftDefault::GetPopSize()
{
// Clean-up is caller handled
return 0;
}
int x86_64MicrosoftDefault::GetArgStackSize()
{
// Shadow space (32 bytes) + 8 bytes * amount of stack arguments
return 32 + 8 * m_stackArgs;
}
void** x86_64MicrosoftDefault::GetStackArgumentPtr(CRegisters* registers)
{
// Skip shadow space + return address
return (void **)(registers->m_rsp->GetValue<uintptr_t>() + 8 + 32);
}
int x86_64MicrosoftDefault::GetArgRegisterSize()
{
int argRegisterSize = 0;
for (size_t i = 0; i < m_vecArgTypes.size(); i++)
{
if (m_vecArgTypes[i].custom_register != None)
{
// It doesn't matter, it's always 8 bytes or less
argRegisterSize += 8;
}
}
return argRegisterSize;
}
void* x86_64MicrosoftDefault::GetArgumentPtr(unsigned int index, CRegisters* registers)
{
//g_pSM->LogMessage(myself, "Retrieving argument %d (max args %d) registers %p", index, m_vecArgTypes.size(), registers);
if (index >= m_vecArgTypes.size())
{
//g_pSM->LogMessage(myself, "Not enough arguments");
return nullptr;
}
// Check if this argument was passed in a register.
if (m_vecArgTypes[index].custom_register != None)
{
CRegister* reg = registers->GetRegister(m_vecArgTypes[index].custom_register);
if (!reg)
{
//g_pSM->LogMessage(myself, "Register does not exit");
return nullptr;
}
//g_pSM->LogMessage(myself, "Register arg %d", m_vecArgTypes[index].custom_register);
return reg->m_pAddress;
}
// Return address + shadow space
size_t offset = 8 + 32;
for (unsigned int i = 0; i < index; i++)
{
if (m_vecArgTypes[i].custom_register == None)
{
// No matter what, the stack is allocated in slices of 8 bytes
offset += 8;
}
}
return (void *) (registers->m_rsp->GetValue<uintptr_t>() + offset);
}
void x86_64MicrosoftDefault::ArgumentPtrChanged(unsigned int index, CRegisters* registers, void* argumentPtr)
{
}
void* x86_64MicrosoftDefault::GetReturnPtr(CRegisters* registers)
{
// Custom return value register
if (m_returnType.custom_register != None)
{
return registers->GetRegister(m_returnType.custom_register)->m_pAddress;
}
if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE)
{
// Floating point register
return registers->m_xmm0->m_pAddress;
}
return registers->m_rax->m_pAddress;
}
void x86_64MicrosoftDefault::ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr)
{
}
void x86_64MicrosoftDefault::SaveReturnValue(CRegisters* registers)
{
// It doesn't matter what the return value is, it will always be fitting on 8 bytes (or less)
std::unique_ptr<uint8_t[]> savedReturn = std::make_unique<uint8_t[]>(8);
memcpy(savedReturn.get(), GetReturnPtr(registers), 8);
m_pSavedReturnBuffers.push_back(std::move(savedReturn));
}
void x86_64MicrosoftDefault::RestoreReturnValue(CRegisters* registers)
{
// Like stated in SaveReturnValue, it will always fit within 8 bytes
// the actual underlining type does not matter
uint8_t* savedReturn = m_pSavedReturnBuffers.back().get();
memcpy(GetReturnPtr(registers), savedReturn, 8);
ReturnPtrChanged(registers, savedReturn);
m_pSavedReturnBuffers.pop_back();
}
void x86_64MicrosoftDefault::SaveCallArguments(CRegisters* registers)
{
int size = GetArgStackSize() + GetArgRegisterSize();
std::unique_ptr<uint8_t[]> savedCallArguments = std::make_unique<uint8_t[]>(size);
size_t offset = 0;
for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) {
// Doesn't matter the type, it will always be within 8 bytes
memcpy((void *)((uintptr_t)savedCallArguments.get() + offset), GetArgumentPtr(i, registers), 8);
offset += 8;
}
m_pSavedCallArguments.push_back(std::move(savedCallArguments));
}
void x86_64MicrosoftDefault::RestoreCallArguments(CRegisters* registers)
{
uint8_t *savedCallArguments = m_pSavedCallArguments.back().get();
size_t offset = 0;
for (size_t i = 0; i < m_vecArgTypes.size(); i++) {
// Doesn't matter the type, it will always be within 8 bytes
memcpy(GetArgumentPtr((unsigned int)i, registers), (void *)((uintptr_t)savedCallArguments + offset), 8);
offset += 8;
}
m_pSavedCallArguments.pop_back();
}

View File

@ -0,0 +1,68 @@
/**
* =============================================================================
* DynamicHooks-x86_64
* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved.
* Copyright (C) 2024 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _X86_64_MICROSOFT_DEFAULT_H
#define _X86_64_MICROSOFT_DEFAULT_H
// ============================================================================
// >> INCLUDES
// ============================================================================
#include "../convention.h"
// ============================================================================
// >> CLASSES
// ============================================================================
class x86_64MicrosoftDefault : public ICallingConvention
{
public:
x86_64MicrosoftDefault(std::vector<DataTypeSized_t>& vecArgTypes, DataTypeSized_t returnType, int iAlignment = 8);
virtual ~x86_64MicrosoftDefault() = default;
virtual std::vector<Register_t> GetRegisters() override;
virtual int GetPopSize() override;
virtual int GetArgStackSize() override;
virtual void** GetStackArgumentPtr(CRegisters* registers) override;
virtual int GetArgRegisterSize() override;
virtual void* GetArgumentPtr(unsigned int index, CRegisters* registers) override;
virtual void ArgumentPtrChanged(unsigned int index, CRegisters* registers, void* argumentPtr) override;
virtual void* GetReturnPtr(CRegisters* registers) override;
virtual void ReturnPtrChanged(CRegisters* registers, void* returnPtr) override;
virtual void SaveReturnValue(CRegisters* registers) override;
virtual void RestoreReturnValue(CRegisters* registers) override;
virtual void SaveCallArguments(CRegisters* pRegisters) override;
virtual void RestoreCallArguments(CRegisters* pRegisters) override;
protected:
std::uint32_t m_stackArgs;
};
#endif // _X86_64_MICROSOFT_DEFAULT_H

View File

@ -0,0 +1,25 @@
/**
* =============================================================================
* DynamicHooks-x86_64
* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved.
* Copyright (C) 2024 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

View File

@ -0,0 +1,25 @@
/**
* =============================================================================
* DynamicHooks-x86_64
* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved.
* Copyright (C) 2024 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

View File

@ -35,13 +35,16 @@
// >> INCLUDES // >> INCLUDES
// ============================================================================ // ============================================================================
#include "hook.h" #include "hook.h"
#include <asm/asm.h>
#include <macro-assembler-x86.h>
#include "extension.h" #include "extension.h"
#ifdef DYNAMICHOOKS_x86_64
#else
#include <macro-assembler-x86.h>
#include <jit/jit_helpers.h> #include <jit/jit_helpers.h>
#include <CDetour/detourhelpers.h> #include <CDetour/detourhelpers.h>
using namespace sp; using namespace sp;
#endif
// ============================================================================ // ============================================================================
// >> DEFINITIONS // >> DEFINITIONS
@ -64,45 +67,31 @@ CHook::CHook(void* pFunc, ICallingConvention* pConvention)
if (!m_RetAddr.init()) if (!m_RetAddr.init())
return; return;
unsigned char* pTarget = (unsigned char *) pFunc; CreateBridge();
if (!m_pBridge)
return;
// Determine the number of bytes we need to copy auto result = safetyhook::InlineHook::create(pFunc, m_pBridge, safetyhook::InlineHook::Flags::StartDisabled);
int iBytesToCopy = copy_bytes(pTarget, NULL, JMP_SIZE); if (!result) {
return;
}
// Create a buffer for the bytes to copy + a jump to the rest of the m_Hook = std::move(result.value());
// function. m_pTrampoline = m_Hook.original<void*>();
unsigned char* pCopiedBytes = (unsigned char *) smutils->GetScriptingEngine()->AllocatePageMemory(iBytesToCopy + JMP_SIZE);
// Fill the array with NOP instructions m_Hook.enable();
memset(pCopiedBytes, 0x90, iBytesToCopy + JMP_SIZE);
// Copy the required bytes to our array
copy_bytes(pTarget, pCopiedBytes, JMP_SIZE);
// Write a jump after the copied bytes to the function/bridge + number of bytes to copy
DoGatePatch(pCopiedBytes + iBytesToCopy, pTarget + iBytesToCopy);
// Save the trampoline
m_pTrampoline = (void *) pCopiedBytes;
// Create the bridge function
m_pBridge = CreateBridge();
// Write a jump to the bridge
DoGatePatch((unsigned char *) pFunc, m_pBridge);
} }
CHook::~CHook() CHook::~CHook()
{ {
// Copy back the previously copied bytes if (m_Hook.enabled()) {
copy_bytes((unsigned char *) m_pTrampoline, (unsigned char *) m_pFunc, JMP_SIZE); m_Hook.disable();
}
// Free the trampoline buffer if (m_pBridge) {
smutils->GetScriptingEngine()->FreePageMemory(m_pTrampoline);
// Free the asm bridge and new return address
smutils->GetScriptingEngine()->FreePageMemory(m_pBridge); smutils->GetScriptingEngine()->FreePageMemory(m_pBridge);
smutils->GetScriptingEngine()->FreePageMemory(m_pNewRetAddr); smutils->GetScriptingEngine()->FreePageMemory(m_pNewRetAddr);
}
delete m_pRegisters; delete m_pRegisters;
delete m_pCallingConvention; delete m_pCallingConvention;
@ -229,7 +218,392 @@ void __cdecl CHook::SetReturnAddress(void* pRetAddr, void* pESP)
i->value.push_back(pRetAddr); i->value.push_back(pRetAddr);
} }
void* CHook::CreateBridge() #ifdef DYNAMICHOOKS_x86_64
using namespace SourceHook::Asm;
SourceHook::CPageAlloc SourceHook::Asm::GenBuffer::ms_Allocator(16);
void PrintFunc(const char* message) {
g_pSM->LogMessage(myself, message);
}
void PrintDebug(x64JitWriter& jit, const char* message) {
// LogMessage has variadic parameters, this shouldn't be problem on x86_64
// but paranoia calls for safety
/*
union {
void (*PrintFunc)(const char* message);
std::uint64_t address;
} func;
func.PrintFunc = &PrintFunc;
// Shadow space
MSVC_ONLY(jit.sub(rsp, 40));
MSVC_ONLY(jit.mov(rcx, reinterpret_cast<std::uint64_t>(message)));
GCC_ONLY(jit.mov(rdi, reinterpret_cast<std::uint64_t>(message)));
jit.mov(rax, func.address);
jit.call(rax);
// Free shadow space
MSVC_ONLY(jit.add(rsp, 40));*/
}
void _PrintRegs(std::uint64_t* rsp, int numregs) {
g_pSM->LogMessage(myself, "RSP - %p", rsp);
for (int i = 0; i < numregs; i++) {
g_pSM->LogMessage(myself, "RSP[%d] - %llu", i, rsp[i]);
}
}
void PrintRegisters(x64JitWriter& jit) {
/*
union {
void (*PrintRegs)(std::uint64_t* rsp, int numregs);
std::uint64_t address;
} func;
func.PrintRegs = &_PrintRegs;
// Rax is pushed twice to keep the stack aligned
jit.push(rax);
jit.push(rax);
jit.push(rcx);
jit.push(rdx);
jit.push(r8);
jit.push(r9);
jit.mov(rcx, rsp);
jit.mov(rdx, 5);
jit.sub(rsp, 40);
jit.mov(rax, func.address);
jit.call(rax);
jit.add(rsp, 40);
jit.pop(r9);
jit.pop(r8);
jit.pop(rdx);
jit.pop(rcx);
jit.pop(rax);
jit.pop(rax);*/
}
void CHook::CreateBridge()
{
auto& jit = m_bridge;
//jit.breakpoint();
PrintRegisters(jit);
// Save registers right away
Write_SaveRegisters(jit, HOOKTYPE_PRE);
PrintDebug(jit, "Hook Called");
Write_ModifyReturnAddress(jit);
// Call the pre-hook handler and jump to label_supercede if ReturnAction_Supercede was returned
Write_CallHandler(jit, HOOKTYPE_PRE);
jit.cmp(rax, ReturnAction_Supercede);
// Restore the previously saved registers, so any changes will be applied
Write_RestoreRegisters(jit, HOOKTYPE_PRE);
jit.je(0x0);
std::int32_t jumpOff = jit.get_outputpos();
// Dump regs
PrintRegisters(jit);
// Jump to the trampoline
jit.mov(rax, reinterpret_cast<std::uint64_t>(&m_pTrampoline));
jit.mov(rax, rax());
jit.jump(rax);
// This code will be executed if a pre-hook returns ReturnAction_Supercede
jit.rewrite<std::int32_t>(jumpOff - sizeof(std::int32_t), jit.get_outputpos() - jumpOff);
PrintDebug(jit, "Hook leave");
// Finally, return to the caller
// This will still call post hooks, but will skip the original function.
jit.retn();
// It's very important to only finalise the jit code creation here
// setting the memory to ReadExecute too early can create crashes
// as it changes the permissions of the whole memory page
m_pBridge = m_bridge.GetData();
m_pNewRetAddr = m_postCallback.GetData();
m_bridge.SetRE();
m_postCallback.SetRE();
}
void CHook::Write_ModifyReturnAddress(x64JitWriter& jit)
{
// Store the return address in rax
jit.mov(rax, rsp());
// Save the original return address by using the current esp as the key.
// This should be unique until we have returned to the original caller.
union
{
void (__cdecl CHook::*SetReturnAddress)(void*, void*);
std::uint64_t address;
} func;
func.SetReturnAddress = &CHook::SetReturnAddress;
// Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes
MSVC_ONLY(jit.sub(rsp, 40));
// 1st param (this)
GCC_ONLY(jit.mov(rdi, reinterpret_cast<std::uint64_t>(this)));
MSVC_ONLY(jit.mov(rcx, reinterpret_cast<std::uint64_t>(this)));
// 2nd parameter (return address)
GCC_ONLY(jit.mov(rsi, rax));
MSVC_ONLY(jit.mov(rdx, rax));
// 3rd parameter (rsp)
GCC_ONLY(jit.lea(rdx, rsp()));
MSVC_ONLY(jit.lea(r8, rsp(40)));
// Call SetReturnAddress
jit.mov(rax, func.address);
jit.call(rax);
// Free shadow space
MSVC_ONLY(jit.add(rsp, 40));
// Override the return address. This is a redirect to our post-hook code
CreatePostCallback();
jit.mov(rax, reinterpret_cast<std::uint64_t>(&m_pNewRetAddr));
jit.mov(rax, rax());
jit.mov(rsp(), rax);
}
void CHook::CreatePostCallback()
{
auto& jit = m_postCallback;
jit.sub(rsp, 8);
PrintRegisters(jit);
// Save registers right away
Write_SaveRegisters(jit, HOOKTYPE_POST);
PrintDebug(jit, "Hook post");
PrintRegisters(jit);
// Call the post-hook handler
Write_CallHandler(jit, HOOKTYPE_POST);
// Restore the previously saved registers, so any changes will be applied
Write_RestoreRegisters(jit, HOOKTYPE_POST);
// Get return address
union
{
void* (__cdecl CHook::*GetReturnAddress)(void*);
std::uint64_t address;
} func;
func.GetReturnAddress = &CHook::GetReturnAddress;
// Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes
MSVC_ONLY(jit.sub(rsp, 40));
// 1st param (this)
GCC_ONLY(jit.mov(rdi, reinterpret_cast<std::uint64_t>(this)));
MSVC_ONLY(jit.mov(rcx, reinterpret_cast<std::uint64_t>(this)));
// 2n parameter (rsp)
GCC_ONLY(jit.lea(rsi, rsp()));
MSVC_ONLY(jit.lea(rdx, rsp(40)));
// Call GetReturnAddress
jit.mov(rax, func.address);
jit.call(rax);
// Free shadow space
MSVC_ONLY(jit.add(rsp, 40));
// Jump to the original return address
jit.add(rsp, 8);
jit.jump(rax);
}
void CHook::Write_CallHandler(x64JitWriter& jit, HookType_t type)
{
union
{
ReturnAction_t (__cdecl CHook::*HookHandler)(HookType_t);
std::uint64_t address;
} func;
func.HookHandler = &CHook::HookHandler;
// Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes
MSVC_ONLY(jit.sub(rsp, 40));
// Call the global hook handler
// 1st param (this)
GCC_ONLY(jit.mov(rdi, reinterpret_cast<std::uint64_t>(this)));
MSVC_ONLY(jit.mov(rcx, reinterpret_cast<std::uint64_t>(this)));
// 2nd parameter (type)
GCC_ONLY(jit.mov(rsi, type));
MSVC_ONLY(jit.mov(rdx, type));
jit.mov(rax, func.address);
jit.call(rax);
// Free shadow space
MSVC_ONLY(jit.add(rsp, 40));
}
void CHook::Write_SaveRegisters(x64JitWriter& jit, HookType_t type)
{
// Save RAX
jit.push(rax);
bool saveRAX = false;
std::vector<Register_t> vecRegistersToSave = m_pCallingConvention->GetRegisters();
for(size_t i = 0; i < vecRegistersToSave.size(); i++)
{
switch(vecRegistersToSave[i])
{
// ========================================================================
// >> 64-bit General purpose registers
// ========================================================================
// RAX is saved by default (see above)
case Register_t::RAX: saveRAX = true; break;
case Register_t::RCX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rcx->m_pAddress)); jit.mov(rax(), rcx); break;
case Register_t::RDX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rdx->m_pAddress)); jit.mov(rax(), rdx); break;
case Register_t::RBX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rbx->m_pAddress)); jit.mov(rax(), rbx); break;
// BEWARE BECAUSE WE PUSHED TO STACK ABOVE, RSP NEEDS TO BE HANDLED DIFFERENTLY
case Register_t::RSP:
jit.push(r8);
// Add +push(rax) & +push(r8)
jit.lea(r8, rsp(16));
jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rsp->m_pAddress)); jit.mov(rax(), r8);
jit.pop(r8);
break;
case Register_t::RBP: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rbp->m_pAddress)); jit.mov(rax(), rbp); break;
case Register_t::RSI: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rsi->m_pAddress)); jit.mov(rax(), rsi); break;
case Register_t::RDI: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rdi->m_pAddress)); jit.mov(rax(), rdi); break;
case Register_t::R8: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r8->m_pAddress)); jit.mov(rax(), r8); break;
case Register_t::R9: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r9->m_pAddress)); jit.mov(rax(), r9); break;
case Register_t::R10: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r10->m_pAddress)); jit.mov(rax(), r10); break;
case Register_t::R11: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r11->m_pAddress)); jit.mov(rax(), r11); break;
case Register_t::R12: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r12->m_pAddress)); jit.mov(rax(), r12); break;
case Register_t::R13: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r13->m_pAddress)); jit.mov(rax(), r13); break;
case Register_t::R14: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r14->m_pAddress)); jit.mov(rax(), r14); break;
case Register_t::R15: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r15->m_pAddress)); jit.mov(rax(), r15); break;
// ========================================================================
// >> 128-bit XMM registers
// ========================================================================
case Register_t::XMM0: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm0->m_pAddress)); jit.movsd(rax(), xmm0); break;
case Register_t::XMM1: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm1->m_pAddress)); jit.movsd(rax(), xmm1); break;
case Register_t::XMM2: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm2->m_pAddress)); jit.movsd(rax(), xmm2); break;
case Register_t::XMM3: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm3->m_pAddress)); jit.movsd(rax(), xmm3); break;
case Register_t::XMM4: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm4->m_pAddress)); jit.movsd(rax(), xmm4); break;
case Register_t::XMM5: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm5->m_pAddress)); jit.movsd(rax(), xmm5); break;
case Register_t::XMM6: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm6->m_pAddress)); jit.movsd(rax(), xmm6); break;
case Register_t::XMM7: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm7->m_pAddress)); jit.movsd(rax(), xmm7); break;
case Register_t::XMM8: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm8->m_pAddress)); jit.movsd(rax(), xmm8); break;
case Register_t::XMM9: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm9->m_pAddress)); jit.movsd(rax(), xmm9); break;
case Register_t::XMM10: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm10->m_pAddress)); jit.movsd(rax(), xmm10); break;
case Register_t::XMM11: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm11->m_pAddress)); jit.movsd(rax(), xmm11); break;
case Register_t::XMM12: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm12->m_pAddress)); jit.movsd(rax(), xmm12); break;
case Register_t::XMM13: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm13->m_pAddress)); jit.movsd(rax(), xmm13); break;
case Register_t::XMM14: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm14->m_pAddress)); jit.movsd(rax(), xmm14); break;
case Register_t::XMM15: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm15->m_pAddress)); jit.movsd(rax(), xmm15); break;
default: puts("Unsupported register.");
}
}
jit.pop(rax);
if (saveRAX) {
jit.push(r8);
jit.mov(r8, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rax->m_pAddress)); jit.mov(r8(), rax);
jit.pop(r8);
}
}
void CHook::Write_RestoreRegisters(x64JitWriter& jit, HookType_t type)
{
// RAX & RSP will be restored last
bool restoreRAX = false, restoreRSP = false;
const auto& vecRegistersToRestore = m_pCallingConvention->GetRegisters();
for(size_t i = 0; i < vecRegistersToRestore.size(); i++)
{
switch(vecRegistersToRestore[i])
{
// ========================================================================
// >> 64-bit General purpose registers
// ========================================================================
// RAX is handled differently (see below)
case Register_t::RAX: restoreRAX = true; break;
case Register_t::RCX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rcx->m_pAddress)); jit.mov(rcx, rax()); break;
case Register_t::RDX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rdx->m_pAddress)); jit.mov(rdx, rax()); break;
case Register_t::RBX: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rbx->m_pAddress)); jit.mov(rbx, rax()); break;
// This could be very troublesome, but oh well...
case Register_t::RSP: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rsp->m_pAddress)); jit.mov(rsp, rax()); break;
case Register_t::RBP: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rbp->m_pAddress)); jit.mov(rbp, rax()); break;
case Register_t::RSI: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rsi->m_pAddress)); jit.mov(rsi, rax()); break;
case Register_t::RDI: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rdi->m_pAddress)); jit.mov(rdi, rax()); break;
case Register_t::R8: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r8->m_pAddress)); jit.mov(r8, rax()); break;
case Register_t::R9: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r9->m_pAddress)); jit.mov(r9, rax()); break;
case Register_t::R10: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r10->m_pAddress)); jit.mov(r10, rax()); break;
case Register_t::R11: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r11->m_pAddress)); jit.mov(r11, rax()); break;
case Register_t::R12: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r12->m_pAddress)); jit.mov(r12, rax()); break;
case Register_t::R13: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r13->m_pAddress)); jit.mov(r13, rax()); break;
case Register_t::R14: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r14->m_pAddress)); jit.mov(r14, rax()); break;
case Register_t::R15: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_r15->m_pAddress)); jit.mov(r15, rax()); break;
// ========================================================================
// >> 128-bit XMM registers
// ========================================================================
case Register_t::XMM0: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm0->m_pAddress)); jit.movsd(xmm0, rax()); break;
case Register_t::XMM1: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm1->m_pAddress)); jit.movsd(xmm1, rax()); break;
case Register_t::XMM2: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm2->m_pAddress)); jit.movsd(xmm2, rax()); break;
case Register_t::XMM3: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm3->m_pAddress)); jit.movsd(xmm3, rax()); break;
case Register_t::XMM4: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm4->m_pAddress)); jit.movsd(xmm4, rax()); break;
case Register_t::XMM5: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm5->m_pAddress)); jit.movsd(xmm5, rax()); break;
case Register_t::XMM6: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm6->m_pAddress)); jit.movsd(xmm6, rax()); break;
case Register_t::XMM7: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm7->m_pAddress)); jit.movsd(xmm7, rax()); break;
case Register_t::XMM8: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm8->m_pAddress)); jit.movsd(xmm8, rax()); break;
case Register_t::XMM9: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm9->m_pAddress)); jit.movsd(xmm9, rax()); break;
case Register_t::XMM10: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm10->m_pAddress)); jit.movsd(xmm10, rax()); break;
case Register_t::XMM11: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm11->m_pAddress)); jit.movsd(xmm11, rax()); break;
case Register_t::XMM12: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm12->m_pAddress)); jit.movsd(xmm12, rax()); break;
case Register_t::XMM13: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm13->m_pAddress)); jit.movsd(xmm13, rax()); break;
case Register_t::XMM14: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm14->m_pAddress)); jit.movsd(xmm14, rax()); break;
case Register_t::XMM15: jit.mov(rax, reinterpret_cast<std::uint64_t>(m_pRegisters->m_xmm15->m_pAddress)); jit.movsd(xmm15, rax()); break;
default: puts("Unsupported register.");
}
}
if (restoreRAX) {
jit.push(r8);
jit.mov(r8, reinterpret_cast<std::uint64_t>(m_pRegisters->m_rax->m_pAddress));
jit.mov(rax, r8());
jit.pop(r8);
}
}
#else
void CHook::CreateBridge()
{ {
sp::MacroAssembler masm; sp::MacroAssembler masm;
Label label_supercede; Label label_supercede;
@ -247,7 +621,8 @@ void* CHook::CreateBridge()
masm.j(equal, &label_supercede); masm.j(equal, &label_supercede);
// Jump to the trampoline // Jump to the trampoline
masm.jmp(ExternalAddress(m_pTrampoline)); masm.movl(eax, Operand(ExternalAddress(&m_pTrampoline)));
masm.jmp(eax);
// This code will be executed if a pre-hook returns ReturnAction_Supercede // This code will be executed if a pre-hook returns ReturnAction_Supercede
masm.bind(&label_supercede); masm.bind(&label_supercede);
@ -256,9 +631,9 @@ void* CHook::CreateBridge()
// This will still call post hooks, but will skip the original function. // This will still call post hooks, but will skip the original function.
masm.ret(m_pCallingConvention->GetPopSize()); masm.ret(m_pCallingConvention->GetPopSize());
void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base); masm.emitToExecutableMemory(base);
return base; m_pBridge = base;
} }
void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm) void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm)
@ -290,11 +665,11 @@ void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm)
masm.movl(edx, Operand(ExternalAddress(&pEDX))); masm.movl(edx, Operand(ExternalAddress(&pEDX)));
// Override the return address. This is a redirect to our post-hook code // Override the return address. This is a redirect to our post-hook code
m_pNewRetAddr = CreatePostCallback(); CreatePostCallback();
masm.movl(Operand(esp, 0), intptr_t(m_pNewRetAddr)); masm.movl(Operand(esp, 0), intptr_t(m_pNewRetAddr));
} }
void* CHook::CreatePostCallback() void CHook::CreatePostCallback()
{ {
sp::MacroAssembler masm; sp::MacroAssembler masm;
@ -342,9 +717,9 @@ void* CHook::CreatePostCallback()
masm.jmp(Operand(ExternalAddress(&pRetAddr))); masm.jmp(Operand(ExternalAddress(&pRetAddr)));
// Generate the code // Generate the code
void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
masm.emitToExecutableMemory(base); masm.emitToExecutableMemory(base);
return base; m_pNewRetAddr = base;
} }
void CHook::Write_CallHandler(sp::MacroAssembler& masm, HookType_t type) void CHook::Write_CallHandler(sp::MacroAssembler& masm, HookType_t type)
@ -502,3 +877,4 @@ void CHook::Write_RestoreRegisters(sp::MacroAssembler& masm, HookType_t type)
} }
} }
} }
#endif

View File

@ -41,6 +41,22 @@
#include "convention.h" #include "convention.h"
#include <am-hashmap.h> #include <am-hashmap.h>
#include <am-hashset.h> #include <am-hashset.h>
#include <safetyhook.hpp>
#ifdef DYNAMICHOOKS_x86_64
#include <sourcehook.h>
#include <sh_memory.h>
#include "sh_asm_x86_64.h"
#if SH_COMP == SH_COMP_MSVC
# define GCC_ONLY(x)
# define MSVC_ONLY(x) x
#elif SH_COMP == SH_COMP_GCC
# define GCC_ONLY(x) x
# define MSVC_ONLY(x)
#endif
#endif
// ============================================================================ // ============================================================================
// >> HookType_t // >> HookType_t
@ -173,14 +189,23 @@ public:
} }
private: private:
void* CreateBridge(); void CreateBridge();
void CreatePostCallback();
#ifdef DYNAMICHOOKS_x86_64
void Write_ModifyReturnAddress(SourceHook::Asm::x64JitWriter& jit);
void Write_CallHandler(SourceHook::Asm::x64JitWriter& jit, HookType_t type);
void Write_SaveRegisters(SourceHook::Asm::x64JitWriter& jit, HookType_t type);
void Write_RestoreRegisters(SourceHook::Asm::x64JitWriter& jit, HookType_t type);
SourceHook::Asm::x64JitWriter m_bridge;
SourceHook::Asm::x64JitWriter m_postCallback;
#else
void Write_ModifyReturnAddress(sp::MacroAssembler& masm); void Write_ModifyReturnAddress(sp::MacroAssembler& masm);
void Write_CallHandler(sp::MacroAssembler& masm, HookType_t type); void Write_CallHandler(sp::MacroAssembler& masm, HookType_t type);
void Write_SaveRegisters(sp::MacroAssembler& masm, HookType_t type); void Write_SaveRegisters(sp::MacroAssembler& masm, HookType_t type);
void Write_RestoreRegisters(sp::MacroAssembler& masm, HookType_t type); void Write_RestoreRegisters(sp::MacroAssembler& masm, HookType_t type);
#endif
void* CreatePostCallback();
ReturnAction_t __cdecl HookHandler(HookType_t type); ReturnAction_t __cdecl HookHandler(HookType_t type);
@ -196,6 +221,9 @@ public:
ICallingConvention* m_pCallingConvention; ICallingConvention* m_pCallingConvention;
// SafetyHook
SafetyHookInline m_Hook{};
// Address of the bridge // Address of the bridge
void* m_pBridge; void* m_pBridge;

View File

@ -116,7 +116,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
m_rax = CreateRegister(registers, RAX, 8); m_rax = CreateRegister(registers, RAX, 8);
m_rcx = CreateRegister(registers, RCX, 8); m_rcx = CreateRegister(registers, RCX, 8);
m_rdx = CreateRegister(registers, RDX, 8); m_rdx = CreateRegister(registers, RDX, 8);
@ -279,7 +279,7 @@ CRegisters::~CRegisters()
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
DeleteRegister(m_rax); DeleteRegister(m_rax);
DeleteRegister(m_rcx); DeleteRegister(m_rcx);
DeleteRegister(m_rdx); DeleteRegister(m_rdx);
@ -325,7 +325,7 @@ CRegisters::~CRegisters()
DeleteRegister(m_xmm7); DeleteRegister(m_xmm7);
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
DeleteRegister(m_xmm8); DeleteRegister(m_xmm8);
DeleteRegister(m_xmm9); DeleteRegister(m_xmm9);
DeleteRegister(m_xmm10); DeleteRegister(m_xmm10);
@ -434,6 +434,42 @@ CRegister* CRegisters::GetRegister(Register_t reg)
case EDI: case EDI:
return m_edi; return m_edi;
#ifdef DYNAMICHOOKS_x86_64
case RAX:
return m_rax;
case RCX:
return m_rcx;
case RDX:
return m_rdx;
case RBX:
return m_rbx;
case RSP:
return m_rsp;
case RBP:
return m_rbp;
case RSI:
return m_rsi;
case RDI:
return m_rdi;
case R8:
return m_r8;
case R9:
return m_r9;
case R10:
return m_r10;
case R11:
return m_r11;
case R12:
return m_r12;
case R13:
return m_r13;
case R14:
return m_r14;
case R15:
return m_r15;
#endif
case MM0: case MM0:
return m_mm0; return m_mm0;
case MM1: case MM1:
@ -468,6 +504,25 @@ CRegister* CRegisters::GetRegister(Register_t reg)
case XMM7: case XMM7:
return m_xmm7; return m_xmm7;
#ifdef DYNAMICHOOKS_x86_64
case XMM8:
return m_xmm8;
case XMM9:
return m_xmm9;
case XMM10:
return m_xmm10;
case XMM11:
return m_xmm11;
case XMM12:
return m_xmm12;
case XMM13:
return m_xmm13;
case XMM14:
return m_xmm14;
case XMM15:
return m_xmm15;
#endif
case CS: case CS:
return m_cs; return m_cs;
case SS: case SS:
@ -499,6 +554,6 @@ CRegister* CRegisters::GetRegister(Register_t reg)
return m_st7; return m_st7;
default: default:
return NULL; return nullptr;
} }
} }

View File

@ -132,7 +132,7 @@ enum Register_t
// ======================================================================== // ========================================================================
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
RAX, RAX,
RCX, RCX,
RDX, RDX,
@ -177,7 +177,7 @@ enum Register_t
XMM7, XMM7,
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
XMM8, XMM8,
XMM9, XMM9,
XMM10, XMM10,
@ -373,7 +373,7 @@ public:
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
CRegister* m_rax; CRegister* m_rax;
CRegister* m_rcx; CRegister* m_rcx;
CRegister* m_rdx; CRegister* m_rdx;
@ -418,7 +418,7 @@ public:
CRegister* m_xmm7; CRegister* m_xmm7;
// 64-bit mode only // 64-bit mode only
#ifdef PLATFORM_X64 #ifdef DYNAMICHOOKS_x86_64
CRegister* m_xmm8; CRegister* m_xmm8;
CRegister* m_xmm9; CRegister* m_xmm9;
CRegister* m_xmm10; CRegister* m_xmm10;

View File

@ -1,478 +0,0 @@
#include "asm.h"
#include "libudis86/udis86.h"
#include <string.h>
#ifndef WIN32
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "libudis86/udis86.h"
#define REG_EAX 0
#define REG_ECX 1
#define REG_EDX 2
#define REG_EBX 3
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
#endif
/**
* Checks if a call to a fpic thunk has just been written into dest.
* If found replaces it with a direct mov that sets the required register to the value of pc.
*
* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
* @param pc The program counter value that needs to be set (usually the next address from the source).
*/
void check_thunks(unsigned char *dest, unsigned char *pc)
{
#if defined(_WIN32) || defined(__x86_64__)
return;
#else
/* Step write address back 4 to the start of the function address */
unsigned char *writeaddr = dest - 4;
unsigned char *calloffset = *(unsigned char **)writeaddr;
unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
/* Lookup name of function being called */
if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
{
//a thunk maybe?
char movByte = IA32_MOV_REG_IMM;
/* Calculate the correct mov opcode */
switch (*(calladdr+1))
{
case 0x04:
{
movByte += REG_EAX;
break;
}
case 0x1C:
{
movByte += REG_EBX;
break;
}
case 0x0C:
{
movByte += REG_ECX;
break;
}
case 0x14:
{
movByte += REG_EDX;
break;
}
default:
{
printf("Unknown thunk: %c\n", *(calladdr+1));
#ifndef NDEBUG
abort();
#endif
break;
}
}
/* Move our write address back one to where the call opcode was */
writeaddr--;
/* Write our mov */
*writeaddr = movByte;
writeaddr++;
/* Write the value - The provided program counter value */
*(void **)writeaddr = (void *)pc;
writeaddr += 4;
}
#endif
}
int copy_bytes(unsigned char *func, unsigned char *dest, unsigned int required_len)
{
ud_t ud_obj;
ud_init(&ud_obj);
#if defined(_WIN64) || defined(__x86_64__)
ud_set_mode(&ud_obj, 64);
#else
ud_set_mode(&ud_obj, 32);
#endif
ud_set_input_buffer(&ud_obj, func, 20);
unsigned int bytecount = 0;
while (bytecount < required_len && ud_disassemble(&ud_obj))
{
unsigned int insn_len = ud_insn_len(&ud_obj);
bytecount += insn_len;
if (dest)
{
const uint8_t *opcode = ud_insn_ptr(&ud_obj);
if ((opcode[0] & 0xFE) == 0xE8) // Fix CALL/JMP offset
{
dest[0] = func[0];
dest++; func++;
if (ud_insn_opr(&ud_obj, 0)->size == 32)
{
*(int32_t *)dest = func + *(int32_t *)func - dest;
check_thunks(dest+4, func+4);
dest += sizeof(int32_t);
}
else
{
*(int16_t *)dest = func + *(int16_t *)func - dest;
dest += sizeof(int16_t);
}
func--;
}
else
{
memcpy(dest, func, insn_len);
dest += insn_len;
}
}
func += insn_len;
}
return bytecount;
}
#if 0
//if dest is NULL, returns minimum number of bytes needed to be copied
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
//http://www.devmaster.net/forums/showthread.php?t=2311
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
int bytecount = 0;
while(bytecount < required_len && *func != 0xCC)
{
// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
int operandSize = 4;
int FPU = 0;
int twoByte = 0;
unsigned char opcode = 0x90;
unsigned char modRM = 0xFF;
while(*func == 0xF0 ||
*func == 0xF2 ||
*func == 0xF3 ||
(*func & 0xFC) == 0x64 ||
(*func & 0xF8) == 0xD8 ||
(*func & 0x7E) == 0x62)
{
if(*func == 0x66)
{
operandSize = 2;
}
else if((*func & 0xF8) == 0xD8)
{
FPU = *func;
if (dest)
*dest++ = *func++;
else
func++;
bytecount++;
break;
}
if (dest)
*dest++ = *func++;
else
func++;
bytecount++;
}
// two-byte opcode byte
if(*func == 0x0F)
{
twoByte = 1;
if (dest)
*dest++ = *func++;
else
func++;
bytecount++;
}
// opcode byte
opcode = *func++;
if (dest) *dest++ = opcode;
bytecount++;
// mod R/M byte
modRM = 0xFF;
if(FPU)
{
if((opcode & 0xC0) != 0xC0)
{
modRM = opcode;
}
}
else if(!twoByte)
{
if((opcode & 0xC4) == 0x00 ||
((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
(opcode & 0xF0) == 0x80 ||
((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
(opcode & 0xFC) == 0xD0 ||
(opcode & 0xF6) == 0xF6)
{
modRM = *func++;
if (dest) *dest++ = modRM;
bytecount++;
}
}
else
{
if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
(opcode & 0xF0) == 0x30 ||
opcode == 0x77 ||
(opcode & 0xF0) == 0x80 ||
((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
(opcode & 0xF8) == 0xC8)
{
// No mod R/M byte
}
else
{
modRM = *func++;
if (dest) *dest++ = modRM;
bytecount++;
}
}
// SIB
if((modRM & 0x07) == 0x04 &&
(modRM & 0xC0) != 0xC0)
{
if (dest)
*dest++ = *func++; //SIB
else
func++;
bytecount++;
}
// mod R/M displacement
// Dword displacement, no base
if((modRM & 0xC5) == 0x05) {
if (dest) {
*(unsigned int*)dest = *(unsigned int*)func;
dest += 4;
}
func += 4;
bytecount += 4;
}
// Byte displacement
if((modRM & 0xC0) == 0x40) {
if (dest)
*dest++ = *func++;
else
func++;
bytecount++;
}
// Dword displacement
if((modRM & 0xC0) == 0x80) {
if (dest) {
*(unsigned int*)dest = *(unsigned int*)func;
dest += 4;
}
func += 4;
bytecount += 4;
}
// immediate
if(FPU)
{
// Can't have immediate operand
}
else if(!twoByte)
{
if((opcode & 0xC7) == 0x04 ||
(opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
(opcode & 0xF0) == 0x70 || // Jcc
opcode == 0x80 ||
opcode == 0x83 ||
(opcode & 0xFD) == 0xA0 || // MOV
opcode == 0xA8 || // TEST
(opcode & 0xF8) == 0xB0 || // MOV
(opcode & 0xFE) == 0xC0 || // RCL
opcode == 0xC6 || // MOV
opcode == 0xCD || // INT
(opcode & 0xFE) == 0xD4 || // AAD/AAM
(opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
opcode == 0xEB ||
(opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
{
if (dest)
*dest++ = *func++;
else
func++;
bytecount++;
}
else if((opcode & 0xF7) == 0xC2) // RET
{
if (dest) {
*(unsigned short*)dest = *(unsigned short*)func;
dest += 2;
}
func += 2;
bytecount += 2;
}
else if((opcode & 0xFC) == 0x80 ||
(opcode & 0xC7) == 0x05 ||
(opcode & 0xF8) == 0xB8 ||
(opcode & 0xFE) == 0xE8 || // CALL/Jcc
(opcode & 0xFE) == 0x68 ||
(opcode & 0xFC) == 0xA0 ||
(opcode & 0xEE) == 0xA8 ||
opcode == 0xC7 ||
(opcode == 0xF7 && (modRM & 0x30) == 0x00))
{
if (dest) {
//Fix CALL/JMP offset
if ((opcode & 0xFE) == 0xE8) {
if (operandSize == 4)
{
*(long*)dest = ((func + *(long*)func) - dest);
//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
check_thunks(dest+4, func+4);
}
else
*(short*)dest = ((func + *(short*)func) - dest);
} else {
if (operandSize == 4)
*(unsigned long*)dest = *(unsigned long*)func;
else
*(unsigned short*)dest = *(unsigned short*)func;
}
dest += operandSize;
}
func += operandSize;
bytecount += operandSize;
}
}
else
{
if(opcode == 0xBA || // BT
opcode == 0x0F || // 3DNow!
(opcode & 0xFC) == 0x70 || // PSLLW
(opcode & 0xF7) == 0xA4 || // SHLD
opcode == 0xC2 ||
opcode == 0xC4 ||
opcode == 0xC5 ||
opcode == 0xC6)
{
if (dest)
*dest++ = *func++;
else
func++;
}
else if((opcode & 0xF0) == 0x80) // Jcc -i
{
if (dest) {
if (operandSize == 4)
*(unsigned long*)dest = *(unsigned long*)func;
else
*(unsigned short*)dest = *(unsigned short*)func;
dest += operandSize;
}
func += operandSize;
bytecount += operandSize;
}
}
}
return bytecount;
}
#endif
//insert a specific JMP instruction at the given location
void inject_jmp(void* src, void* dest) {
*(unsigned char*)src = OP_JMP;
*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
}
//fill a given block with NOPs
void fill_nop(void* src, unsigned int len) {
unsigned char* src2 = (unsigned char*)src;
while (len) {
*src2++ = OP_NOP;
--len;
}
}
void* eval_jump(void* src) {
unsigned char* addr = (unsigned char*)src;
if (!addr) return 0;
//import table jump
if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
addr += 2;
addr = *(unsigned char**)addr;
//TODO: if addr points into the IAT
return *(void**)addr;
}
//8bit offset
else if (addr[0] == OP_JMP_BYTE) {
addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
//mangled 32bit jump?
if (addr[0] == OP_JMP) {
addr = addr + *(int*)&addr[1];
}
return addr;
}
/*
//32bit offset
else if (addr[0] == OP_JMP) {
addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
}
*/
return addr;
}
/*
from ms detours package
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
__try {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return false;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
return false;
}
if (pbAddress >= ((PBYTE)pDosHeader +
pNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
pbAddress < ((PBYTE)pDosHeader +
pNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
pNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
return true;
}
return false;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
return false;
}
}
*/

View File

@ -1,38 +0,0 @@
#pragma once
#define OP_JMP 0xE9
#define OP_JMP_SIZE 5
#define X64_ABS_SIZE 14
#define OP_NOP 0x90
#define OP_NOP_SIZE 1
#define OP_PREFIX 0xFF
#define OP_JMP_SEG 0x25
#define OP_JMP_BYTE 0xEB
#define OP_JMP_BYTE_SIZE 2
#ifdef __cplusplus
extern "C" {
#endif
void check_thunks(unsigned char *dest, unsigned char *pc);
//if dest is NULL, returns minimum number of bytes needed to be copied
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
//http://www.devmaster.net/forums/showthread.php?t=2311
int copy_bytes(unsigned char *func, unsigned char* dest, unsigned int required_len);
//insert a specific JMP instruction at the given location
void inject_jmp(void* src, void* dest);
//fill a given block with NOPs
void fill_nop(void* src, unsigned int len);
//evaluate a JMP at the target
void* eval_jump(void* src);
#ifdef __cplusplus
}
#endif

View File

@ -34,6 +34,10 @@
#include <memory> #include <memory>
#ifdef KE_WINDOWS #ifdef KE_WINDOWS
#ifdef DYNAMICHOOKS_x86_64
#include "conventions/x86_64MicrosoftDefault.h"
typedef x86_64MicrosoftDefault x86_64DetourCall;
#else
#include "conventions/x86MsCdecl.h" #include "conventions/x86MsCdecl.h"
#include "conventions/x86MsThiscall.h" #include "conventions/x86MsThiscall.h"
#include "conventions/x86MsStdcall.h" #include "conventions/x86MsStdcall.h"
@ -42,7 +46,10 @@ typedef x86MsCdecl x86DetourCdecl;
typedef x86MsThiscall x86DetourThisCall; typedef x86MsThiscall x86DetourThisCall;
typedef x86MsStdcall x86DetourStdCall; typedef x86MsStdcall x86DetourStdCall;
typedef x86MsFastcall x86DetourFastCall; typedef x86MsFastcall x86DetourFastCall;
#endif
#elif defined KE_LINUX #elif defined KE_LINUX
#ifdef DYNAMICHOOKS_x86_64
#else
#include "conventions/x86GccCdecl.h" #include "conventions/x86GccCdecl.h"
#include "conventions/x86GccThiscall.h" #include "conventions/x86GccThiscall.h"
#include "conventions/x86MsStdcall.h" #include "conventions/x86MsStdcall.h"
@ -53,6 +60,7 @@ typedef x86GccThiscall x86DetourThisCall;
typedef x86MsStdcall x86DetourStdCall; typedef x86MsStdcall x86DetourStdCall;
// Uhumm, fastcall on linux? // Uhumm, fastcall on linux?
typedef x86MsFastcall x86DetourFastCall; typedef x86MsFastcall x86DetourFastCall;
#endif
#else #else
#error "Unsupported platform." #error "Unsupported platform."
#endif #endif
@ -246,9 +254,29 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
// TODO: Add support for a custom return register. // TODO: Add support for a custom return register.
returnType.custom_register = None; returnType.custom_register = None;
#ifdef DYNAMICHOOKS_x86_64
#ifdef WIN32
if (setup->callConv == CallConv_THISCALL) {
DataTypeSized_t type;
type.type = DATA_TYPE_POINTER;
type.size = GetDataTypeSize(type, sizeof(void*));
type.custom_register = RCX;
vecArgTypes.insert(vecArgTypes.begin(), type);
}
#endif
#endif
ICallingConvention *pCallConv = nullptr; ICallingConvention *pCallConv = nullptr;
switch (setup->callConv) switch (setup->callConv)
{ {
#ifdef DYNAMICHOOKS_x86_64
case CallConv_THISCALL:
case CallConv_CDECL:
case CallConv_STDCALL:
case CallConv_FASTCALL:
pCallConv = new x86_64DetourCall(vecArgTypes, returnType);
break;
#else
case CallConv_CDECL: case CallConv_CDECL:
pCallConv = new x86DetourCdecl(vecArgTypes, returnType); pCallConv = new x86DetourCdecl(vecArgTypes, returnType);
break; break;
@ -261,6 +289,7 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
case CallConv_FASTCALL: case CallConv_FASTCALL:
pCallConv = new x86DetourFastCall(vecArgTypes, returnType); pCallConv = new x86DetourFastCall(vecArgTypes, returnType);
break; break;
#endif
default: default:
smutils->LogError(myself, "Unknown calling convention %d.", setup->callConv); smutils->LogError(myself, "Unknown calling convention %d.", setup->callConv);
break; break;
@ -624,7 +653,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct()
// Save the old parameters passed in a register. // Save the old parameters passed in a register.
size_t offset = stackSize; size_t offset = stackSize;
for (size_t i = 0; i < numArgs; i++) for (size_t i = firstArg; i < numArgs; i++)
{ {
// We already saved the stack arguments. // We already saved the stack arguments.
if (argTypes[i].custom_register == None) if (argTypes[i].custom_register == None)
@ -633,7 +662,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct()
size_t size = argTypes[i].size; size_t size = argTypes[i].size;
// Register argument values are saved after all stack arguments in this buffer. // Register argument values are saved after all stack arguments in this buffer.
void *paramAddr = (void *)((intptr_t)params->orgParams + offset); void *paramAddr = (void *)((intptr_t)params->orgParams + offset);
void *regAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); void *regAddr = callingConvention->GetArgumentPtr(i, m_pDetour->m_pRegisters);
memcpy(paramAddr, regAddr, size); memcpy(paramAddr, regAddr, size);
offset += size; offset += size;
} }
@ -656,7 +685,6 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params)
// TODO: Support custom register for this ptr. // TODO: Support custom register for this ptr.
if (callConv == CallConv_THISCALL) if (callConv == CallConv_THISCALL)
firstArg = 1; firstArg = 1;
size_t stackOffset = 0; size_t stackOffset = 0;
// Values of arguments stored in registers are saved after the stack arguments. // Values of arguments stored in registers are saved after the stack arguments.
size_t registerOffset = stackSize; size_t registerOffset = stackSize;
@ -676,9 +704,15 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params)
} }
// Keep track of the seperate stack and register arguments. // Keep track of the seperate stack and register arguments.
if (argTypes[i].custom_register == None) if (argTypes[i].custom_register == None) {
#ifdef DYNAMICHOOKS_x86_64
stackOffset += 8;
#else
stackOffset += size; stackOffset += size;
else #endif
}
else {
registerOffset += size; registerOffset += size;
} }
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +0,0 @@
/* udis86 - libudis86/decode.h
*
* Copyright (c) 2002-2009 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UD_DECODE_H
#define UD_DECODE_H
#include "types.h"
#include "itab.h"
#define MAX_INSN_LENGTH 15
/* itab prefix bits */
#define P_none ( 0 )
#define P_cast ( 1 << 0 )
#define P_CAST(n) ( ( n >> 0 ) & 1 )
#define P_rexb ( 1 << 1 )
#define P_REXB(n) ( ( n >> 1 ) & 1 )
#define P_inv64 ( 1 << 4 )
#define P_INV64(n) ( ( n >> 4 ) & 1 )
#define P_rexw ( 1 << 5 )
#define P_REXW(n) ( ( n >> 5 ) & 1 )
#define P_def64 ( 1 << 7 )
#define P_DEF64(n) ( ( n >> 7 ) & 1 )
#define P_rexr ( 1 << 8 )
#define P_REXR(n) ( ( n >> 8 ) & 1 )
#define P_oso ( 1 << 9 )
#define P_OSO(n) ( ( n >> 9 ) & 1 )
#define P_aso ( 1 << 10 )
#define P_ASO(n) ( ( n >> 10 ) & 1 )
#define P_rexx ( 1 << 11 )
#define P_REXX(n) ( ( n >> 11 ) & 1 )
#define P_ImpAddr ( 1 << 12 )
#define P_IMPADDR(n) ( ( n >> 12 ) & 1 )
#define P_seg ( 1 << 13 )
#define P_SEG(n) ( ( n >> 13 ) & 1 )
#define P_str ( 1 << 14 )
#define P_STR(n) ( ( n >> 14 ) & 1 )
#define P_strz ( 1 << 15 )
#define P_STR_ZF(n) ( ( n >> 15 ) & 1 )
/* operand type constants -- order is important! */
enum ud_operand_code {
OP_NONE,
OP_A, OP_E, OP_M, OP_G,
OP_I, OP_F,
OP_R0, OP_R1, OP_R2, OP_R3,
OP_R4, OP_R5, OP_R6, OP_R7,
OP_AL, OP_CL, OP_DL,
OP_AX, OP_CX, OP_DX,
OP_eAX, OP_eCX, OP_eDX,
OP_rAX, OP_rCX, OP_rDX,
OP_ES, OP_CS, OP_SS, OP_DS,
OP_FS, OP_GS,
OP_ST0, OP_ST1, OP_ST2, OP_ST3,
OP_ST4, OP_ST5, OP_ST6, OP_ST7,
OP_J, OP_S, OP_O,
OP_I1, OP_I3, OP_sI,
OP_V, OP_W, OP_Q, OP_P,
OP_U, OP_N, OP_MU,
OP_R, OP_C, OP_D,
OP_MR
} UD_ATTR_PACKED;
/* operand size constants */
enum ud_operand_size {
SZ_NA = 0,
SZ_Z = 1,
SZ_V = 2,
SZ_RDQ = 7,
/* the following values are used as is,
* and thus hard-coded. changing them
* will break internals
*/
SZ_B = 8,
SZ_W = 16,
SZ_D = 32,
SZ_Q = 64,
SZ_T = 80,
SZ_O = 128,
SZ_Y = 17,
/*
* complex size types, that encode sizes for operands
* of type MR (memory or register), for internal use
* only. Id space 256 and above.
*/
SZ_BD = (SZ_B << 8) | SZ_D,
SZ_BV = (SZ_B << 8) | SZ_V,
SZ_WD = (SZ_W << 8) | SZ_D,
SZ_WV = (SZ_W << 8) | SZ_V,
SZ_WY = (SZ_W << 8) | SZ_Y,
SZ_DY = (SZ_D << 8) | SZ_Y,
SZ_WO = (SZ_W << 8) | SZ_O,
SZ_DO = (SZ_D << 8) | SZ_O,
SZ_QO = (SZ_Q << 8) | SZ_O,
} UD_ATTR_PACKED;
/* resolve complex size type.
*/
static inline enum ud_operand_size
Mx_mem_size(enum ud_operand_size size)
{
return (size >> 8) & 0xff;
}
static inline enum ud_operand_size
Mx_reg_size(enum ud_operand_size size)
{
return size & 0xff;
}
/* A single operand of an entry in the instruction table.
* (internal use only)
*/
struct ud_itab_entry_operand
{
enum ud_operand_code type;
enum ud_operand_size size;
};
/* A single entry in an instruction table.
*(internal use only)
*/
struct ud_itab_entry
{
enum ud_mnemonic_code mnemonic;
struct ud_itab_entry_operand operand1;
struct ud_itab_entry_operand operand2;
struct ud_itab_entry_operand operand3;
uint32_t prefix;
};
struct ud_lookup_table_list_entry {
const uint16_t *table;
enum ud_table_type type;
const char *meta;
};
static inline int
ud_opcode_field_sext(uint8_t primary_opcode)
{
return (primary_opcode & 0x02) != 0;
}
extern struct ud_itab_entry ud_itab[];
extern struct ud_lookup_table_list_entry ud_lookup_table_list[];
#endif /* UD_DECODE_H */
/* vim:cindent
* vim:expandtab
* vim:ts=4
* vim:sw=4
*/

View File

@ -1,105 +0,0 @@
/* udis86 - libudis86/extern.h
*
* Copyright (c) 2002-2009, 2013 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UD_EXTERN_H
#define UD_EXTERN_H
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
/* ============================= PUBLIC API ================================= */
extern void ud_init(struct ud*);
extern void ud_set_mode(struct ud*, uint8_t);
extern void ud_set_pc(struct ud*, uint64_t);
extern void ud_set_input_hook(struct ud*, int (*)(struct ud*));
extern void ud_set_input_buffer(struct ud*, const uint8_t*, size_t);
#ifndef __UD_STANDALONE__
extern void ud_set_input_file(struct ud*, FILE*);
#endif /* __UD_STANDALONE__ */
extern void ud_set_vendor(struct ud*, unsigned);
extern void ud_set_syntax(struct ud*, void (*)(struct ud*));
extern void ud_input_skip(struct ud*, size_t);
extern int ud_input_end(const struct ud*);
extern unsigned int ud_decode(struct ud*);
extern unsigned int ud_disassemble(struct ud*);
extern void ud_translate_intel(struct ud*);
extern void ud_translate_att(struct ud*);
extern const char* ud_insn_asm(const struct ud* u);
extern const uint8_t* ud_insn_ptr(const struct ud* u);
extern uint64_t ud_insn_off(const struct ud*);
extern const char* ud_insn_hex(struct ud*);
extern unsigned int ud_insn_len(const struct ud* u);
extern const struct ud_operand* ud_insn_opr(const struct ud *u, unsigned int n);
extern int ud_opr_is_sreg(const struct ud_operand *opr);
extern int ud_opr_is_gpr(const struct ud_operand *opr);
extern enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u);
extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c);
extern void ud_set_user_opaque_data(struct ud*, void*);
extern void* ud_get_user_opaque_data(const struct ud*);
extern uint64_t ud_insn_sext_imm(const struct ud*, const struct ud_operand*);
extern void ud_set_asm_buffer(struct ud *u, char *buf, size_t size);
extern void ud_set_sym_resolver(struct ud *u,
const char* (*resolver)(struct ud*,
uint64_t addr,
int64_t *offset));
/* ========================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* UD_EXTERN_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,678 +0,0 @@
#ifndef UD_ITAB_H
#define UD_ITAB_H
/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
/* ud_table_type -- lookup table types (see decode.c) */
enum ud_table_type {
UD_TAB__OPC_TABLE,
UD_TAB__OPC_X87,
UD_TAB__OPC_MOD,
UD_TAB__OPC_VEX_M,
UD_TAB__OPC_VEX_P,
UD_TAB__OPC_RM,
UD_TAB__OPC_VENDOR,
UD_TAB__OPC_OSIZE,
UD_TAB__OPC_MODE,
UD_TAB__OPC_3DNOW,
UD_TAB__OPC_REG,
UD_TAB__OPC_ASIZE,
UD_TAB__OPC_SSE
};
/* ud_mnemonic -- mnemonic constants */
enum ud_mnemonic_code {
UD_Iinvalid,
UD_I3dnow,
UD_Inone,
UD_Idb,
UD_Ipause,
UD_Iaaa,
UD_Iaad,
UD_Iaam,
UD_Iaas,
UD_Iadc,
UD_Iadd,
UD_Iaddpd,
UD_Iaddps,
UD_Iaddsd,
UD_Iaddss,
UD_Iand,
UD_Iandpd,
UD_Iandps,
UD_Iandnpd,
UD_Iandnps,
UD_Iarpl,
UD_Imovsxd,
UD_Ibound,
UD_Ibsf,
UD_Ibsr,
UD_Ibswap,
UD_Ibt,
UD_Ibtc,
UD_Ibtr,
UD_Ibts,
UD_Icall,
UD_Icbw,
UD_Icwde,
UD_Icdqe,
UD_Iclc,
UD_Icld,
UD_Iclflush,
UD_Iclgi,
UD_Icli,
UD_Iclts,
UD_Icmc,
UD_Icmovo,
UD_Icmovno,
UD_Icmovb,
UD_Icmovae,
UD_Icmovz,
UD_Icmovnz,
UD_Icmovbe,
UD_Icmova,
UD_Icmovs,
UD_Icmovns,
UD_Icmovp,
UD_Icmovnp,
UD_Icmovl,
UD_Icmovge,
UD_Icmovle,
UD_Icmovg,
UD_Icmp,
UD_Icmppd,
UD_Icmpps,
UD_Icmpsb,
UD_Icmpsw,
UD_Icmpsd,
UD_Icmpsq,
UD_Icmpss,
UD_Icmpxchg,
UD_Icmpxchg8b,
UD_Icmpxchg16b,
UD_Icomisd,
UD_Icomiss,
UD_Icpuid,
UD_Icvtdq2pd,
UD_Icvtdq2ps,
UD_Icvtpd2dq,
UD_Icvtpd2pi,
UD_Icvtpd2ps,
UD_Icvtpi2ps,
UD_Icvtpi2pd,
UD_Icvtps2dq,
UD_Icvtps2pi,
UD_Icvtps2pd,
UD_Icvtsd2si,
UD_Icvtsd2ss,
UD_Icvtsi2ss,
UD_Icvtss2si,
UD_Icvtss2sd,
UD_Icvttpd2pi,
UD_Icvttpd2dq,
UD_Icvttps2dq,
UD_Icvttps2pi,
UD_Icvttsd2si,
UD_Icvtsi2sd,
UD_Icvttss2si,
UD_Icwd,
UD_Icdq,
UD_Icqo,
UD_Idaa,
UD_Idas,
UD_Idec,
UD_Idiv,
UD_Idivpd,
UD_Idivps,
UD_Idivsd,
UD_Idivss,
UD_Iemms,
UD_Ienter,
UD_If2xm1,
UD_Ifabs,
UD_Ifadd,
UD_Ifaddp,
UD_Ifbld,
UD_Ifbstp,
UD_Ifchs,
UD_Ifclex,
UD_Ifcmovb,
UD_Ifcmove,
UD_Ifcmovbe,
UD_Ifcmovu,
UD_Ifcmovnb,
UD_Ifcmovne,
UD_Ifcmovnbe,
UD_Ifcmovnu,
UD_Ifucomi,
UD_Ifcom,
UD_Ifcom2,
UD_Ifcomp3,
UD_Ifcomi,
UD_Ifucomip,
UD_Ifcomip,
UD_Ifcomp,
UD_Ifcomp5,
UD_Ifcompp,
UD_Ifcos,
UD_Ifdecstp,
UD_Ifdiv,
UD_Ifdivp,
UD_Ifdivr,
UD_Ifdivrp,
UD_Ifemms,
UD_Iffree,
UD_Iffreep,
UD_Ificom,
UD_Ificomp,
UD_Ifild,
UD_Ifincstp,
UD_Ifninit,
UD_Ifiadd,
UD_Ifidivr,
UD_Ifidiv,
UD_Ifisub,
UD_Ifisubr,
UD_Ifist,
UD_Ifistp,
UD_Ifisttp,
UD_Ifld,
UD_Ifld1,
UD_Ifldl2t,
UD_Ifldl2e,
UD_Ifldpi,
UD_Ifldlg2,
UD_Ifldln2,
UD_Ifldz,
UD_Ifldcw,
UD_Ifldenv,
UD_Ifmul,
UD_Ifmulp,
UD_Ifimul,
UD_Ifnop,
UD_Ifpatan,
UD_Ifprem,
UD_Ifprem1,
UD_Ifptan,
UD_Ifrndint,
UD_Ifrstor,
UD_Ifnsave,
UD_Ifscale,
UD_Ifsin,
UD_Ifsincos,
UD_Ifsqrt,
UD_Ifstp,
UD_Ifstp1,
UD_Ifstp8,
UD_Ifstp9,
UD_Ifst,
UD_Ifnstcw,
UD_Ifnstenv,
UD_Ifnstsw,
UD_Ifsub,
UD_Ifsubp,
UD_Ifsubr,
UD_Ifsubrp,
UD_Iftst,
UD_Ifucom,
UD_Ifucomp,
UD_Ifucompp,
UD_Ifxam,
UD_Ifxch,
UD_Ifxch4,
UD_Ifxch7,
UD_Ifxrstor,
UD_Ifxsave,
UD_Ifxtract,
UD_Ifyl2x,
UD_Ifyl2xp1,
UD_Ihlt,
UD_Iidiv,
UD_Iin,
UD_Iimul,
UD_Iinc,
UD_Iinsb,
UD_Iinsw,
UD_Iinsd,
UD_Iint1,
UD_Iint3,
UD_Iint,
UD_Iinto,
UD_Iinvd,
UD_Iinvept,
UD_Iinvlpg,
UD_Iinvlpga,
UD_Iinvvpid,
UD_Iiretw,
UD_Iiretd,
UD_Iiretq,
UD_Ijo,
UD_Ijno,
UD_Ijb,
UD_Ijae,
UD_Ijz,
UD_Ijnz,
UD_Ijbe,
UD_Ija,
UD_Ijs,
UD_Ijns,
UD_Ijp,
UD_Ijnp,
UD_Ijl,
UD_Ijge,
UD_Ijle,
UD_Ijg,
UD_Ijcxz,
UD_Ijecxz,
UD_Ijrcxz,
UD_Ijmp,
UD_Ilahf,
UD_Ilar,
UD_Ilddqu,
UD_Ildmxcsr,
UD_Ilds,
UD_Ilea,
UD_Iles,
UD_Ilfs,
UD_Ilgs,
UD_Ilidt,
UD_Ilss,
UD_Ileave,
UD_Ilfence,
UD_Ilgdt,
UD_Illdt,
UD_Ilmsw,
UD_Ilock,
UD_Ilodsb,
UD_Ilodsw,
UD_Ilodsd,
UD_Ilodsq,
UD_Iloopne,
UD_Iloope,
UD_Iloop,
UD_Ilsl,
UD_Iltr,
UD_Imaskmovq,
UD_Imaxpd,
UD_Imaxps,
UD_Imaxsd,
UD_Imaxss,
UD_Imfence,
UD_Iminpd,
UD_Iminps,
UD_Iminsd,
UD_Iminss,
UD_Imonitor,
UD_Imontmul,
UD_Imov,
UD_Imovapd,
UD_Imovaps,
UD_Imovd,
UD_Imovhpd,
UD_Imovhps,
UD_Imovlhps,
UD_Imovlpd,
UD_Imovlps,
UD_Imovhlps,
UD_Imovmskpd,
UD_Imovmskps,
UD_Imovntdq,
UD_Imovnti,
UD_Imovntpd,
UD_Imovntps,
UD_Imovntq,
UD_Imovq,
UD_Imovsb,
UD_Imovsw,
UD_Imovsd,
UD_Imovsq,
UD_Imovss,
UD_Imovsx,
UD_Imovupd,
UD_Imovups,
UD_Imovzx,
UD_Imul,
UD_Imulpd,
UD_Imulps,
UD_Imulsd,
UD_Imulss,
UD_Imwait,
UD_Ineg,
UD_Inop,
UD_Inot,
UD_Ior,
UD_Iorpd,
UD_Iorps,
UD_Iout,
UD_Ioutsb,
UD_Ioutsw,
UD_Ioutsd,
UD_Ipacksswb,
UD_Ipackssdw,
UD_Ipackuswb,
UD_Ipaddb,
UD_Ipaddw,
UD_Ipaddd,
UD_Ipaddsb,
UD_Ipaddsw,
UD_Ipaddusb,
UD_Ipaddusw,
UD_Ipand,
UD_Ipandn,
UD_Ipavgb,
UD_Ipavgw,
UD_Ipcmpeqb,
UD_Ipcmpeqw,
UD_Ipcmpeqd,
UD_Ipcmpgtb,
UD_Ipcmpgtw,
UD_Ipcmpgtd,
UD_Ipextrb,
UD_Ipextrd,
UD_Ipextrq,
UD_Ipextrw,
UD_Ipinsrb,
UD_Ipinsrw,
UD_Ipinsrd,
UD_Ipinsrq,
UD_Ipmaddwd,
UD_Ipmaxsw,
UD_Ipmaxub,
UD_Ipminsw,
UD_Ipminub,
UD_Ipmovmskb,
UD_Ipmulhuw,
UD_Ipmulhw,
UD_Ipmullw,
UD_Ipop,
UD_Ipopa,
UD_Ipopad,
UD_Ipopfw,
UD_Ipopfd,
UD_Ipopfq,
UD_Ipor,
UD_Iprefetch,
UD_Iprefetchnta,
UD_Iprefetcht0,
UD_Iprefetcht1,
UD_Iprefetcht2,
UD_Ipsadbw,
UD_Ipshufw,
UD_Ipsllw,
UD_Ipslld,
UD_Ipsllq,
UD_Ipsraw,
UD_Ipsrad,
UD_Ipsrlw,
UD_Ipsrld,
UD_Ipsrlq,
UD_Ipsubb,
UD_Ipsubw,
UD_Ipsubd,
UD_Ipsubsb,
UD_Ipsubsw,
UD_Ipsubusb,
UD_Ipsubusw,
UD_Ipunpckhbw,
UD_Ipunpckhwd,
UD_Ipunpckhdq,
UD_Ipunpcklbw,
UD_Ipunpcklwd,
UD_Ipunpckldq,
UD_Ipi2fw,
UD_Ipi2fd,
UD_Ipf2iw,
UD_Ipf2id,
UD_Ipfnacc,
UD_Ipfpnacc,
UD_Ipfcmpge,
UD_Ipfmin,
UD_Ipfrcp,
UD_Ipfrsqrt,
UD_Ipfsub,
UD_Ipfadd,
UD_Ipfcmpgt,
UD_Ipfmax,
UD_Ipfrcpit1,
UD_Ipfrsqit1,
UD_Ipfsubr,
UD_Ipfacc,
UD_Ipfcmpeq,
UD_Ipfmul,
UD_Ipfrcpit2,
UD_Ipmulhrw,
UD_Ipswapd,
UD_Ipavgusb,
UD_Ipush,
UD_Ipusha,
UD_Ipushad,
UD_Ipushfw,
UD_Ipushfd,
UD_Ipushfq,
UD_Ipxor,
UD_Ircl,
UD_Ircr,
UD_Irol,
UD_Iror,
UD_Ircpps,
UD_Ircpss,
UD_Irdmsr,
UD_Irdpmc,
UD_Irdtsc,
UD_Irdtscp,
UD_Irepne,
UD_Irep,
UD_Iret,
UD_Iretf,
UD_Irsm,
UD_Irsqrtps,
UD_Irsqrtss,
UD_Isahf,
UD_Isalc,
UD_Isar,
UD_Ishl,
UD_Ishr,
UD_Isbb,
UD_Iscasb,
UD_Iscasw,
UD_Iscasd,
UD_Iscasq,
UD_Iseto,
UD_Isetno,
UD_Isetb,
UD_Isetae,
UD_Isetz,
UD_Isetnz,
UD_Isetbe,
UD_Iseta,
UD_Isets,
UD_Isetns,
UD_Isetp,
UD_Isetnp,
UD_Isetl,
UD_Isetge,
UD_Isetle,
UD_Isetg,
UD_Isfence,
UD_Isgdt,
UD_Ishld,
UD_Ishrd,
UD_Ishufpd,
UD_Ishufps,
UD_Isidt,
UD_Isldt,
UD_Ismsw,
UD_Isqrtps,
UD_Isqrtpd,
UD_Isqrtsd,
UD_Isqrtss,
UD_Istc,
UD_Istd,
UD_Istgi,
UD_Isti,
UD_Iskinit,
UD_Istmxcsr,
UD_Istosb,
UD_Istosw,
UD_Istosd,
UD_Istosq,
UD_Istr,
UD_Isub,
UD_Isubpd,
UD_Isubps,
UD_Isubsd,
UD_Isubss,
UD_Iswapgs,
UD_Isyscall,
UD_Isysenter,
UD_Isysexit,
UD_Isysret,
UD_Itest,
UD_Iucomisd,
UD_Iucomiss,
UD_Iud2,
UD_Iunpckhpd,
UD_Iunpckhps,
UD_Iunpcklps,
UD_Iunpcklpd,
UD_Iverr,
UD_Iverw,
UD_Ivmcall,
UD_Ivmclear,
UD_Ivmxon,
UD_Ivmptrld,
UD_Ivmptrst,
UD_Ivmlaunch,
UD_Ivmresume,
UD_Ivmxoff,
UD_Ivmread,
UD_Ivmwrite,
UD_Ivmrun,
UD_Ivmmcall,
UD_Ivmload,
UD_Ivmsave,
UD_Iwait,
UD_Iwbinvd,
UD_Iwrmsr,
UD_Ixadd,
UD_Ixchg,
UD_Ixgetbv,
UD_Ixlatb,
UD_Ixor,
UD_Ixorpd,
UD_Ixorps,
UD_Ixcryptecb,
UD_Ixcryptcbc,
UD_Ixcryptctr,
UD_Ixcryptcfb,
UD_Ixcryptofb,
UD_Ixrstor,
UD_Ixsave,
UD_Ixsetbv,
UD_Ixsha1,
UD_Ixsha256,
UD_Ixstore,
UD_Iaesdec,
UD_Iaesdeclast,
UD_Iaesenc,
UD_Iaesenclast,
UD_Iaesimc,
UD_Iaeskeygenassist,
UD_Ipclmulqdq,
UD_Igetsec,
UD_Imovdqa,
UD_Imaskmovdqu,
UD_Imovdq2q,
UD_Imovdqu,
UD_Imovq2dq,
UD_Ipaddq,
UD_Ipsubq,
UD_Ipmuludq,
UD_Ipshufhw,
UD_Ipshuflw,
UD_Ipshufd,
UD_Ipslldq,
UD_Ipsrldq,
UD_Ipunpckhqdq,
UD_Ipunpcklqdq,
UD_Iaddsubpd,
UD_Iaddsubps,
UD_Ihaddpd,
UD_Ihaddps,
UD_Ihsubpd,
UD_Ihsubps,
UD_Imovddup,
UD_Imovshdup,
UD_Imovsldup,
UD_Ipabsb,
UD_Ipabsw,
UD_Ipabsd,
UD_Ipshufb,
UD_Iphaddw,
UD_Iphaddd,
UD_Iphaddsw,
UD_Ipmaddubsw,
UD_Iphsubw,
UD_Iphsubd,
UD_Iphsubsw,
UD_Ipsignb,
UD_Ipsignd,
UD_Ipsignw,
UD_Ipmulhrsw,
UD_Ipalignr,
UD_Ipblendvb,
UD_Ipmuldq,
UD_Ipminsb,
UD_Ipminsd,
UD_Ipminuw,
UD_Ipminud,
UD_Ipmaxsb,
UD_Ipmaxsd,
UD_Ipmaxud,
UD_Ipmaxuw,
UD_Ipmulld,
UD_Iphminposuw,
UD_Iroundps,
UD_Iroundpd,
UD_Iroundss,
UD_Iroundsd,
UD_Iblendpd,
UD_Ipblendw,
UD_Iblendps,
UD_Iblendvpd,
UD_Iblendvps,
UD_Idpps,
UD_Idppd,
UD_Impsadbw,
UD_Iextractps,
UD_Iinsertps,
UD_Imovntdqa,
UD_Ipackusdw,
UD_Ipmovsxbw,
UD_Ipmovsxbd,
UD_Ipmovsxbq,
UD_Ipmovsxwd,
UD_Ipmovsxwq,
UD_Ipmovsxdq,
UD_Ipmovzxbw,
UD_Ipmovzxbd,
UD_Ipmovzxbq,
UD_Ipmovzxwd,
UD_Ipmovzxwq,
UD_Ipmovzxdq,
UD_Ipcmpeqq,
UD_Ipopcnt,
UD_Iptest,
UD_Ipcmpestri,
UD_Ipcmpestrm,
UD_Ipcmpgtq,
UD_Ipcmpistri,
UD_Ipcmpistrm,
UD_Imovbe,
UD_Icrc32,
UD_MAX_MNEMONIC_CODE
} UD_ATTR_PACKED;
extern const char * ud_mnemonics_str[];
#endif /* UD_ITAB_H */

View File

@ -1,224 +0,0 @@
/* udis86 - libudis86/syn-att.c
*
* Copyright (c) 2002-2009 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "types.h"
#include "extern.h"
#include "decode.h"
#include "itab.h"
#include "syn.h"
#include "udint.h"
/* -----------------------------------------------------------------------------
* opr_cast() - Prints an operand cast.
* -----------------------------------------------------------------------------
*/
static void
opr_cast(struct ud* u, struct ud_operand* op)
{
switch(op->size) {
case 16 : case 32 :
ud_asmprintf(u, "*"); break;
default: break;
}
}
/* -----------------------------------------------------------------------------
* gen_operand() - Generates assembly output for each operand.
* -----------------------------------------------------------------------------
*/
static void
gen_operand(struct ud* u, struct ud_operand* op)
{
switch(op->type) {
case UD_OP_CONST:
ud_asmprintf(u, "$0x%x", op->lval.udword);
break;
case UD_OP_REG:
ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]);
break;
case UD_OP_MEM:
if (u->br_far) {
opr_cast(u, op);
}
if (u->pfx_seg) {
ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
}
if (op->offset != 0) {
ud_syn_print_mem_disp(u, op, 0);
}
if (op->base) {
ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]);
}
if (op->index) {
if (op->base) {
ud_asmprintf(u, ",");
} else {
ud_asmprintf(u, "(");
}
ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]);
}
if (op->scale) {
ud_asmprintf(u, ",%d", op->scale);
}
if (op->base || op->index) {
ud_asmprintf(u, ")");
}
break;
case UD_OP_IMM:
ud_asmprintf(u, "$");
ud_syn_print_imm(u, op);
break;
case UD_OP_JIMM:
ud_syn_print_addr(u, ud_syn_rel_target(u, op));
break;
case UD_OP_PTR:
switch (op->size) {
case 32:
ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
op->lval.ptr.off & 0xFFFF);
break;
case 48:
ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
op->lval.ptr.off);
break;
}
break;
default: return;
}
}
/* =============================================================================
* translates to AT&T syntax
* =============================================================================
*/
extern void
ud_translate_att(struct ud *u)
{
int size = 0;
int star = 0;
/* check if P_OSO prefix is used */
if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
switch (u->dis_mode) {
case 16:
ud_asmprintf(u, "o32 ");
break;
case 32:
case 64:
ud_asmprintf(u, "o16 ");
break;
}
}
/* check if P_ASO prefix was used */
if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
switch (u->dis_mode) {
case 16:
ud_asmprintf(u, "a32 ");
break;
case 32:
ud_asmprintf(u, "a16 ");
break;
case 64:
ud_asmprintf(u, "a32 ");
break;
}
}
if (u->pfx_lock)
ud_asmprintf(u, "lock ");
if (u->pfx_rep) {
ud_asmprintf(u, "rep ");
} else if (u->pfx_rep) {
ud_asmprintf(u, "repe ");
} else if (u->pfx_repne) {
ud_asmprintf(u, "repne ");
}
/* special instructions */
switch (u->mnemonic) {
case UD_Iretf:
ud_asmprintf(u, "lret ");
break;
case UD_Idb:
ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte);
return;
case UD_Ijmp:
case UD_Icall:
if (u->br_far) ud_asmprintf(u, "l");
if (u->operand[0].type == UD_OP_REG) {
star = 1;
}
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
break;
case UD_Ibound:
case UD_Ienter:
if (u->operand[0].type != UD_NONE)
gen_operand(u, &u->operand[0]);
if (u->operand[1].type != UD_NONE) {
ud_asmprintf(u, ",");
gen_operand(u, &u->operand[1]);
}
return;
default:
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
}
if (size == 8)
ud_asmprintf(u, "b");
else if (size == 16)
ud_asmprintf(u, "w");
else if (size == 64)
ud_asmprintf(u, "q");
if (star) {
ud_asmprintf(u, " *");
} else {
ud_asmprintf(u, " ");
}
if (u->operand[2].type != UD_NONE) {
gen_operand(u, &u->operand[2]);
ud_asmprintf(u, ", ");
}
if (u->operand[1].type != UD_NONE) {
gen_operand(u, &u->operand[1]);
ud_asmprintf(u, ", ");
}
if (u->operand[0].type != UD_NONE)
gen_operand(u, &u->operand[0]);
}
/*
vim: set ts=2 sw=2 expandtab
*/

View File

@ -1,213 +0,0 @@
/* udis86 - libudis86/syn-intel.c
*
* Copyright (c) 2002-2013 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "types.h"
#include "extern.h"
#include "decode.h"
#include "itab.h"
#include "syn.h"
#include "udint.h"
/* -----------------------------------------------------------------------------
* opr_cast() - Prints an operand cast.
* -----------------------------------------------------------------------------
*/
static void
opr_cast(struct ud* u, struct ud_operand* op)
{
if (u->br_far) {
ud_asmprintf(u, "far ");
}
switch(op->size) {
case 8: ud_asmprintf(u, "byte " ); break;
case 16: ud_asmprintf(u, "word " ); break;
case 32: ud_asmprintf(u, "dword "); break;
case 64: ud_asmprintf(u, "qword "); break;
case 80: ud_asmprintf(u, "tword "); break;
default: break;
}
}
/* -----------------------------------------------------------------------------
* gen_operand() - Generates assembly output for each operand.
* -----------------------------------------------------------------------------
*/
static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
{
switch(op->type) {
case UD_OP_REG:
ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
break;
case UD_OP_MEM:
if (syn_cast) {
opr_cast(u, op);
}
ud_asmprintf(u, "[");
if (u->pfx_seg) {
ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
}
if (op->base) {
ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
}
if (op->index) {
ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "",
ud_reg_tab[op->index - UD_R_AL]);
if (op->scale) {
ud_asmprintf(u, "*%d", op->scale);
}
}
if (op->offset != 0) {
ud_syn_print_mem_disp(u, op, (op->base != UD_NONE ||
op->index != UD_NONE) ? 1 : 0);
}
ud_asmprintf(u, "]");
break;
case UD_OP_IMM:
ud_syn_print_imm(u, op);
break;
case UD_OP_JIMM:
ud_syn_print_addr(u, ud_syn_rel_target(u, op));
break;
case UD_OP_PTR:
switch (op->size) {
case 32:
ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg,
op->lval.ptr.off & 0xFFFF);
break;
case 48:
ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg,
op->lval.ptr.off);
break;
}
break;
case UD_OP_CONST:
if (syn_cast) opr_cast(u, op);
ud_asmprintf(u, "%d", op->lval.udword);
break;
default: return;
}
}
/* =============================================================================
* translates to intel syntax
* =============================================================================
*/
extern void
ud_translate_intel(struct ud* u)
{
/* check if P_OSO prefix is used */
if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
switch (u->dis_mode) {
case 16: ud_asmprintf(u, "o32 "); break;
case 32:
case 64: ud_asmprintf(u, "o16 "); break;
}
}
/* check if P_ASO prefix was used */
if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
switch (u->dis_mode) {
case 16: ud_asmprintf(u, "a32 "); break;
case 32: ud_asmprintf(u, "a16 "); break;
case 64: ud_asmprintf(u, "a32 "); break;
}
}
if (u->pfx_seg &&
u->operand[0].type != UD_OP_MEM &&
u->operand[1].type != UD_OP_MEM ) {
ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]);
}
if (u->pfx_lock) {
ud_asmprintf(u, "lock ");
}
if (u->pfx_rep) {
ud_asmprintf(u, "rep ");
} else if (u->pfx_repe) {
ud_asmprintf(u, "repe ");
} else if (u->pfx_repne) {
ud_asmprintf(u, "repne ");
}
/* print the instruction mnemonic */
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
if (u->operand[0].type != UD_NONE) {
int cast = 0;
ud_asmprintf(u, " ");
if (u->operand[0].type == UD_OP_MEM) {
if (u->operand[1].type == UD_OP_IMM ||
u->operand[1].type == UD_OP_CONST ||
u->operand[1].type == UD_NONE ||
(u->operand[0].size != u->operand[1].size &&
u->operand[1].type != UD_OP_REG)) {
cast = 1;
} else if (u->operand[1].type == UD_OP_REG &&
u->operand[1].base == UD_R_CL) {
switch (u->mnemonic) {
case UD_Ircl:
case UD_Irol:
case UD_Iror:
case UD_Ircr:
case UD_Ishl:
case UD_Ishr:
case UD_Isar:
cast = 1;
break;
default: break;
}
}
}
gen_operand(u, &u->operand[0], cast);
}
if (u->operand[1].type != UD_NONE) {
int cast = 0;
ud_asmprintf(u, ", ");
if (u->operand[1].type == UD_OP_MEM &&
u->operand[0].size != u->operand[1].size &&
!ud_opr_is_sreg(&u->operand[0])) {
cast = 1;
}
gen_operand(u, &u->operand[1], cast);
}
if (u->operand[2].type != UD_NONE) {
ud_asmprintf(u, ", ");
gen_operand(u, &u->operand[2], 0);
}
}
/*
vim: set ts=2 sw=2 expandtab
*/

View File

@ -1,207 +0,0 @@
/* udis86 - libudis86/syn.c
*
* Copyright (c) 2002-2013 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "types.h"
#include "decode.h"
#include "syn.h"
#include "udint.h"
/* -----------------------------------------------------------------------------
* Intel Register Table - Order Matters (types.h)!
* -----------------------------------------------------------------------------
*/
const char* ud_reg_tab[] =
{
"al", "cl", "dl", "bl",
"ah", "ch", "dh", "bh",
"spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b",
"r12b", "r13b", "r14b", "r15b",
"ax", "cx", "dx", "bx",
"sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w",
"r12w", "r13w" , "r14w", "r15w",
"eax", "ecx", "edx", "ebx",
"esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d",
"r12d", "r13d", "r14d", "r15d",
"rax", "rcx", "rdx", "rbx",
"rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15",
"es", "cs", "ss", "ds",
"fs", "gs",
"cr0", "cr1", "cr2", "cr3",
"cr4", "cr5", "cr6", "cr7",
"cr8", "cr9", "cr10", "cr11",
"cr12", "cr13", "cr14", "cr15",
"dr0", "dr1", "dr2", "dr3",
"dr4", "dr5", "dr6", "dr7",
"dr8", "dr9", "dr10", "dr11",
"dr12", "dr13", "dr14", "dr15",
"mm0", "mm1", "mm2", "mm3",
"mm4", "mm5", "mm6", "mm7",
"st0", "st1", "st2", "st3",
"st4", "st5", "st6", "st7",
"xmm0", "xmm1", "xmm2", "xmm3",
"xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10", "xmm11",
"xmm12", "xmm13", "xmm14", "xmm15",
"rip"
};
uint64_t
ud_syn_rel_target(struct ud *u, struct ud_operand *opr)
{
const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode);
switch (opr->size) {
case 8 : return (u->pc + opr->lval.sbyte) & trunc_mask;
case 16: return (u->pc + opr->lval.sword) & trunc_mask;
case 32: return (u->pc + opr->lval.sdword) & trunc_mask;
default: UD_ASSERT(!"invalid relative offset size.");
return 0ull;
}
}
/*
* asmprintf
* Printf style function for printing translated assembly
* output. Returns the number of characters written and
* moves the buffer pointer forward. On an overflow,
* returns a negative number and truncates the output.
*/
int
ud_asmprintf(struct ud *u, const char *fmt, ...)
{
int ret;
int avail;
va_list ap;
va_start(ap, fmt);
avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */;
ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap);
if (ret < 0 || ret > avail) {
u->asm_buf_fill = u->asm_buf_size - 1;
} else {
u->asm_buf_fill += ret;
}
va_end(ap);
return ret;
}
void
ud_syn_print_addr(struct ud *u, uint64_t addr)
{
const char *name = NULL;
if (u->sym_resolver) {
int64_t offset = 0;
name = u->sym_resolver(u, addr, &offset);
if (name) {
if (offset) {
ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
} else {
ud_asmprintf(u, "%s", name);
}
return;
}
}
ud_asmprintf(u, "0x%" FMT64 "x", addr);
}
void
ud_syn_print_imm(struct ud* u, const struct ud_operand *op)
{
uint64_t v;
if (op->_oprcode == OP_sI && op->size != u->opr_mode) {
if (op->size == 8) {
v = (int64_t)op->lval.sbyte;
} else {
UD_ASSERT(op->size == 32);
v = (int64_t)op->lval.sdword;
}
if (u->opr_mode < 64) {
v = v & ((1ull << u->opr_mode) - 1ull);
}
} else {
switch (op->size) {
case 8 : v = op->lval.ubyte; break;
case 16: v = op->lval.uword; break;
case 32: v = op->lval.udword; break;
case 64: v = op->lval.uqword; break;
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
}
}
ud_asmprintf(u, "0x%" FMT64 "x", v);
}
void
ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign)
{
UD_ASSERT(op->offset != 0);
if (op->base == UD_NONE && op->index == UD_NONE) {
uint64_t v;
UD_ASSERT(op->scale == UD_NONE && op->offset != 8);
/* unsigned mem-offset */
switch (op->offset) {
case 16: v = op->lval.uword; break;
case 32: v = op->lval.udword; break;
case 64: v = op->lval.uqword; break;
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
}
ud_asmprintf(u, "0x%" FMT64 "x", v);
} else {
int64_t v;
UD_ASSERT(op->offset != 64);
switch (op->offset) {
case 8 : v = op->lval.sbyte; break;
case 16: v = op->lval.sword; break;
case 32: v = op->lval.sdword; break;
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
}
if (v < 0) {
ud_asmprintf(u, "-0x%" FMT64 "x", -v);
} else if (v > 0) {
ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v);
}
}
}
/*
vim: set ts=2 sw=2 expandtab
*/

View File

@ -1,53 +0,0 @@
/* udis86 - libudis86/syn.h
*
* Copyright (c) 2002-2009
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UD_SYN_H
#define UD_SYN_H
#include "types.h"
#ifndef __UD_STANDALONE__
# include <stdarg.h>
#endif /* __UD_STANDALONE__ */
extern const char* ud_reg_tab[];
uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*);
#ifdef __GNUC__
int ud_asmprintf(struct ud *u, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
#else
int ud_asmprintf(struct ud *u, const char *fmt, ...);
#endif
void ud_syn_print_addr(struct ud *u, uint64_t addr);
void ud_syn_print_imm(struct ud* u, const struct ud_operand *op);
void ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *, int sign);
#endif /* UD_SYN_H */
/*
vim: set ts=2 sw=2 expandtab
*/

View File

@ -1,250 +0,0 @@
/* udis86 - libudis86/types.h
*
* Copyright (c) 2002-2013 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UD_TYPES_H
#define UD_TYPES_H
#ifdef __KERNEL__
/* -D__KERNEL__ is automatically passed on the command line when
building something as part of the Linux kernel */
# include <linux/kernel.h>
# include <linux/string.h>
# ifndef __UD_STANDALONE__
# define __UD_STANDALONE__ 1
#endif
#endif /* __KERNEL__ */
#if defined(_MSC_VER) || defined(__BORLANDC__)
# include <stdint.h>
# include <stdio.h>
# define inline __inline /* MS Visual Studio requires __inline
instead of inline for C code */
#elif !defined(__UD_STANDALONE__)
# include <stdio.h>
# include <inttypes.h>
#endif /* !__UD_STANDALONE__ */
/* gcc specific extensions */
#ifdef __GNUC__
# define UD_ATTR_PACKED __attribute__((packed))
#else
# define UD_ATTR_PACKED
#endif /* UD_ATTR_PACKED */
/* -----------------------------------------------------------------------------
* All possible "types" of objects in udis86. Order is Important!
* -----------------------------------------------------------------------------
*/
enum ud_type
{
UD_NONE,
/* 8 bit GPRs */
UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL,
UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH,
UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL,
UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B,
UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B,
/* 16 bit GPRs */
UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX,
UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI,
UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W,
UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W,
/* 32 bit GPRs */
UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX,
UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI,
UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D,
UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D,
/* 64 bit GPRs */
UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX,
UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI,
UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11,
UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15,
/* segment registers */
UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS,
UD_R_FS, UD_R_GS,
/* control registers*/
UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3,
UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7,
UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11,
UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15,
/* debug registers */
UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3,
UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7,
UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11,
UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15,
/* mmx registers */
UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3,
UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7,
/* x87 registers */
UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3,
UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7,
/* extended multimedia registers */
UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3,
UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7,
UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11,
UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15,
UD_R_RIP,
/* Operand Types */
UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM,
UD_OP_JIMM, UD_OP_CONST
};
#include "itab.h"
union ud_lval {
int8_t sbyte;
uint8_t ubyte;
int16_t sword;
uint16_t uword;
int32_t sdword;
uint32_t udword;
int64_t sqword;
uint64_t uqword;
struct {
uint16_t seg;
uint32_t off;
} ptr;
};
/* -----------------------------------------------------------------------------
* struct ud_operand - Disassembled instruction Operand.
* -----------------------------------------------------------------------------
*/
struct ud_operand {
enum ud_type type;
uint8_t size;
enum ud_type base;
enum ud_type index;
uint8_t scale;
uint8_t offset;
union ud_lval lval;
/*
* internal use only
*/
uint64_t _legacy; /* this will be removed in 1.8 */
uint8_t _oprcode;
};
/* -----------------------------------------------------------------------------
* struct ud - The udis86 object.
* -----------------------------------------------------------------------------
*/
struct ud
{
/*
* input buffering
*/
int (*inp_hook) (struct ud*);
#ifndef __UD_STANDALONE__
FILE* inp_file;
#endif
const uint8_t* inp_buf;
size_t inp_buf_size;
size_t inp_buf_index;
uint8_t inp_curr;
size_t inp_ctr;
uint8_t inp_sess[64];
int inp_end;
void (*translator)(struct ud*);
uint64_t insn_offset;
char insn_hexcode[64];
/*
* Assembly output buffer
*/
char *asm_buf;
size_t asm_buf_size;
size_t asm_buf_fill;
char asm_buf_int[128];
/*
* Symbol resolver for use in the translation phase.
*/
const char* (*sym_resolver)(struct ud*, uint64_t addr, int64_t *offset);
uint8_t dis_mode;
uint64_t pc;
uint8_t vendor;
enum ud_mnemonic_code mnemonic;
struct ud_operand operand[3];
uint8_t error;
uint8_t pfx_rex;
uint8_t pfx_seg;
uint8_t pfx_opr;
uint8_t pfx_adr;
uint8_t pfx_lock;
uint8_t pfx_str;
uint8_t pfx_rep;
uint8_t pfx_repe;
uint8_t pfx_repne;
uint8_t opr_mode;
uint8_t adr_mode;
uint8_t br_far;
uint8_t br_near;
uint8_t have_modrm;
uint8_t modrm;
uint8_t primary_opcode;
void * user_opaque_data;
struct ud_itab_entry * itab_entry;
struct ud_lookup_table_list_entry *le;
};
/* -----------------------------------------------------------------------------
* Type-definitions
* -----------------------------------------------------------------------------
*/
typedef enum ud_type ud_type_t;
typedef enum ud_mnemonic_code ud_mnemonic_code_t;
typedef struct ud ud_t;
typedef struct ud_operand ud_operand_t;
#define UD_SYN_INTEL ud_translate_intel
#define UD_SYN_ATT ud_translate_att
#define UD_EOI (-1)
#define UD_INP_CACHE_SZ 32
#define UD_VENDOR_AMD 0
#define UD_VENDOR_INTEL 1
#define UD_VENDOR_ANY 2
#endif
/*
vim: set ts=2 sw=2 expandtab
*/

View File

@ -1,89 +0,0 @@
/* udis86 - libudis86/udint.h -- definitions for internal use only
*
* Copyright (c) 2002-2009 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _UDINT_H_
#define _UDINT_H_
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#if defined(UD_DEBUG) && HAVE_ASSERT_H
# include <assert.h>
# define UD_ASSERT(_x) assert(_x)
#else
# define UD_ASSERT(_x)
#endif /* !HAVE_ASSERT_H */
#if defined(UD_DEBUG)
#define UDERR(u, msg) \
do { \
(u)->error = 1; \
fprintf(stderr, "decode-error: %s:%d: %s", \
__FILE__, __LINE__, (msg)); \
} while (0)
#else
#define UDERR(u, m) \
do { \
(u)->error = 1; \
} while (0)
#endif /* !LOGERR */
#define UD_RETURN_ON_ERROR(u) \
do { \
if ((u)->error != 0) { \
return (u)->error; \
} \
} while (0)
#define UD_RETURN_WITH_ERROR(u, m) \
do { \
UDERR(u, m); \
return (u)->error; \
} while (0)
#ifndef __UD_STANDALONE__
# define UD_NON_STANDALONE(x) x
#else
# define UD_NON_STANDALONE(x)
#endif
/* printf formatting int64 specifier */
#ifdef FMT64
# undef FMT64
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
# define FMT64 "I64"
#else
# if defined(__APPLE__)
# define FMT64 "ll"
# elif defined(__amd64__) || defined(__x86_64__)
# define FMT64 "l"
# else
# define FMT64 "ll"
# endif /* !x64 */
#endif
#endif /* _UDINT_H_ */

View File

@ -1,457 +0,0 @@
/* udis86 - libudis86/udis86.c
*
* Copyright (c) 2002-2013 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "udint.h"
#include "extern.h"
#include "decode.h"
#if !defined(__UD_STANDALONE__)
# if HAVE_STRING_H
# include <string.h>
# endif
#endif /* !__UD_STANDALONE__ */
static void ud_inp_init(struct ud *u);
/* =============================================================================
* ud_init
* Initializes ud_t object.
* =============================================================================
*/
extern void
ud_init(struct ud* u)
{
memset((void*)u, 0, sizeof(struct ud));
ud_set_mode(u, 16);
u->mnemonic = UD_Iinvalid;
ud_set_pc(u, 0);
#ifndef __UD_STANDALONE__
ud_set_input_file(u, stdin);
#endif /* __UD_STANDALONE__ */
ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
}
/* =============================================================================
* ud_disassemble
* Disassembles one instruction and returns the number of
* bytes disassembled. A zero means end of disassembly.
* =============================================================================
*/
extern unsigned int
ud_disassemble(struct ud* u)
{
int len;
if (u->inp_end) {
return 0;
}
if ((len = ud_decode(u)) > 0) {
if (u->translator != NULL) {
u->asm_buf[0] = '\0';
u->translator(u);
}
}
return len;
}
/* =============================================================================
* ud_set_mode() - Set Disassemly Mode.
* =============================================================================
*/
extern void
ud_set_mode(struct ud* u, uint8_t m)
{
switch(m) {
case 16:
case 32:
case 64: u->dis_mode = m ; return;
default: u->dis_mode = 16; return;
}
}
/* =============================================================================
* ud_set_vendor() - Set vendor.
* =============================================================================
*/
extern void
ud_set_vendor(struct ud* u, unsigned v)
{
switch(v) {
case UD_VENDOR_INTEL:
u->vendor = v;
break;
case UD_VENDOR_ANY:
u->vendor = v;
break;
default:
u->vendor = UD_VENDOR_AMD;
}
}
/* =============================================================================
* ud_set_pc() - Sets code origin.
* =============================================================================
*/
extern void
ud_set_pc(struct ud* u, uint64_t o)
{
u->pc = o;
}
/* =============================================================================
* ud_set_syntax() - Sets the output syntax.
* =============================================================================
*/
extern void
ud_set_syntax(struct ud* u, void (*t)(struct ud*))
{
u->translator = t;
}
/* =============================================================================
* ud_insn() - returns the disassembled instruction
* =============================================================================
*/
const char*
ud_insn_asm(const struct ud* u)
{
return u->asm_buf;
}
/* =============================================================================
* ud_insn_offset() - Returns the offset.
* =============================================================================
*/
uint64_t
ud_insn_off(const struct ud* u)
{
return u->insn_offset;
}
/* =============================================================================
* ud_insn_hex() - Returns hex form of disassembled instruction.
* =============================================================================
*/
const char*
ud_insn_hex(struct ud* u)
{
u->insn_hexcode[0] = 0;
if (!u->error) {
unsigned int i;
const unsigned char *src_ptr = ud_insn_ptr(u);
char* src_hex;
src_hex = (char*) u->insn_hexcode;
/* for each byte used to decode instruction */
for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2;
++i, ++src_ptr) {
sprintf(src_hex, "%02x", *src_ptr & 0xFF);
src_hex += 2;
}
}
return u->insn_hexcode;
}
/* =============================================================================
* ud_insn_ptr
* Returns a pointer to buffer containing the bytes that were
* disassembled.
* =============================================================================
*/
extern const uint8_t*
ud_insn_ptr(const struct ud* u)
{
return (u->inp_buf == NULL) ?
u->inp_sess : u->inp_buf + (u->inp_buf_index - u->inp_ctr);
}
/* =============================================================================
* ud_insn_len
* Returns the count of bytes disassembled.
* =============================================================================
*/
extern unsigned int
ud_insn_len(const struct ud* u)
{
return u->inp_ctr;
}
/* =============================================================================
* ud_insn_get_opr
* Return the operand struct representing the nth operand of
* the currently disassembled instruction. Returns NULL if
* there's no such operand.
* =============================================================================
*/
const struct ud_operand*
ud_insn_opr(const struct ud *u, unsigned int n)
{
if (n > 2 || u->operand[n].type == UD_NONE) {
return NULL;
} else {
return &u->operand[n];
}
}
/* =============================================================================
* ud_opr_is_sreg
* Returns non-zero if the given operand is of a segment register type.
* =============================================================================
*/
int
ud_opr_is_sreg(const struct ud_operand *opr)
{
return opr->type == UD_OP_REG &&
opr->base >= UD_R_ES &&
opr->base <= UD_R_GS;
}
/* =============================================================================
* ud_opr_is_sreg
* Returns non-zero if the given operand is of a general purpose
* register type.
* =============================================================================
*/
int
ud_opr_is_gpr(const struct ud_operand *opr)
{
return opr->type == UD_OP_REG &&
opr->base >= UD_R_AL &&
opr->base <= UD_R_R15;
}
/* =============================================================================
* ud_set_user_opaque_data
* ud_get_user_opaque_data
* Get/set user opaqute data pointer
* =============================================================================
*/
void
ud_set_user_opaque_data(struct ud * u, void* opaque)
{
u->user_opaque_data = opaque;
}
void*
ud_get_user_opaque_data(const struct ud *u)
{
return u->user_opaque_data;
}
/* =============================================================================
* ud_set_asm_buffer
* Allow the user to set an assembler output buffer. If `buf` is NULL,
* we switch back to the internal buffer.
* =============================================================================
*/
void
ud_set_asm_buffer(struct ud *u, char *buf, size_t size)
{
if (buf == NULL) {
ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
} else {
u->asm_buf = buf;
u->asm_buf_size = size;
}
}
/* =============================================================================
* ud_set_sym_resolver
* Set symbol resolver for relative targets used in the translation
* phase.
*
* The resolver is a function that takes a uint64_t address and returns a
* symbolic name for the that address. The function also takes a second
* argument pointing to an integer that the client can optionally set to a
* non-zero value for offsetted targets. (symbol+offset) The function may
* also return NULL, in which case the translator only prints the target
* address.
*
* The function pointer maybe NULL which resets symbol resolution.
* =============================================================================
*/
void
ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*,
uint64_t addr,
int64_t *offset))
{
u->sym_resolver = resolver;
}
/* =============================================================================
* ud_insn_mnemonic
* Return the current instruction mnemonic.
* =============================================================================
*/
enum ud_mnemonic_code
ud_insn_mnemonic(const struct ud *u)
{
return u->mnemonic;
}
/* =============================================================================
* ud_lookup_mnemonic
* Looks up mnemonic code in the mnemonic string table.
* Returns NULL if the mnemonic code is invalid.
* =============================================================================
*/
const char*
ud_lookup_mnemonic(enum ud_mnemonic_code c)
{
if (c < UD_MAX_MNEMONIC_CODE) {
return ud_mnemonics_str[c];
} else {
return NULL;
}
}
/*
* ud_inp_init
* Initializes the input system.
*/
static void
ud_inp_init(struct ud *u)
{
u->inp_hook = NULL;
u->inp_buf = NULL;
u->inp_buf_size = 0;
u->inp_buf_index = 0;
u->inp_curr = 0;
u->inp_ctr = 0;
u->inp_end = 0;
UD_NON_STANDALONE(u->inp_file = NULL);
}
/* =============================================================================
* ud_inp_set_hook
* Sets input hook.
* =============================================================================
*/
void
ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*))
{
ud_inp_init(u);
u->inp_hook = hook;
}
/* =============================================================================
* ud_inp_set_buffer
* Set buffer as input.
* =============================================================================
*/
void
ud_set_input_buffer(register struct ud* u, const uint8_t* buf, size_t len)
{
ud_inp_init(u);
u->inp_buf = buf;
u->inp_buf_size = len;
u->inp_buf_index = 0;
}
#ifndef __UD_STANDALONE__
/* =============================================================================
* ud_input_set_file
* Set FILE as input.
* =============================================================================
*/
static int
inp_file_hook(struct ud* u)
{
return fgetc(u->inp_file);
}
void
ud_set_input_file(register struct ud* u, FILE* f)
{
ud_inp_init(u);
u->inp_hook = inp_file_hook;
u->inp_file = f;
}
#endif /* __UD_STANDALONE__ */
/* =============================================================================
* ud_input_skip
* Skip n input bytes.
* ============================================================================
*/
void
ud_input_skip(struct ud* u, size_t n)
{
if (u->inp_end) {
return;
}
if (u->inp_buf == NULL) {
while (n--) {
int c = u->inp_hook(u);
if (c == UD_EOI) {
goto eoi;
}
}
return;
} else {
if (n > u->inp_buf_size ||
u->inp_buf_index > u->inp_buf_size - n) {
u->inp_buf_index = u->inp_buf_size;
goto eoi;
}
u->inp_buf_index += n;
return;
}
eoi:
u->inp_end = 1;
UDERR(u, "cannot skip, eoi received\b");
return;
}
/* =============================================================================
* ud_input_end
* Returns non-zero on end-of-input.
* =============================================================================
*/
int
ud_input_end(const struct ud *u)
{
return u->inp_end;
}
/* vim:set ts=2 sw=2 expandtab */

View File

@ -1,33 +0,0 @@
/* udis86 - udis86.h
*
* Copyright (c) 2002-2009 Vivek Thampi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UDIS86_H
#define UDIS86_H
#include "libudis86/types.h"
#include "libudis86/extern.h"
#include "libudis86/itab.h"
#endif

View File

@ -73,12 +73,22 @@ SMCResult SignatureGameConfig::ReadSMC_NewSection(const SMCStates *states, const
} }
// Handle platform specific sections first. // Handle platform specific sections first.
#ifdef DYNAMICHOOKS_x86_64
#if defined WIN32
if (!strcmp(name, "windows64"))
#elif defined _LINUX
if (!strcmp(name, "linux64"))
#elif defined _OSX
if (!strcmp(name, "mac64"))
#endif
#else
#if defined WIN32 #if defined WIN32
if (!strcmp(name, "windows")) if (!strcmp(name, "windows"))
#elif defined _LINUX #elif defined _LINUX
if (!strcmp(name, "linux")) if (!strcmp(name, "linux"))
#elif defined _OSX #elif defined _OSX
if (!strcmp(name, "mac")) if (!strcmp(name, "mac"))
#endif
#endif #endif
{ {
// We're already in a section for a different OS that we're ignoring. Can't have a section for our OS in here. // We're already in a section for a different OS that we're ignoring. Can't have a section for our OS in here.
@ -99,13 +109,8 @@ SMCResult SignatureGameConfig::ReadSMC_NewSection(const SMCStates *states, const
g_PlatformOnlyState = g_ParseState; g_PlatformOnlyState = g_ParseState;
return SMCResult_Continue; return SMCResult_Continue;
} }
#if defined WIN32 else if (!strcmp(name, "windows") || !strcmp(name, "linux") || !strcmp(name, "mac")
else if (!strcmp(name, "linux") || !strcmp(name, "mac")) || !strcmp(name, "windows64") || !strcmp(name, "linux64") || !strcmp(name, "mac64"))
#elif defined _LINUX
else if (!strcmp(name, "windows") || !strcmp(name, "mac"))
#elif defined _OSX
else if (!strcmp(name, "windows") || !strcmp(name, "linux"))
#endif
{ {
if (g_PlatformOnlyState != PState_None) if (g_PlatformOnlyState != PState_None)
{ {
@ -565,6 +570,42 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str)
else if (!strcmp(str, "edi")) else if (!strcmp(str, "edi"))
return EDI; return EDI;
#ifdef DYNAMICHOOKS_x86_64
else if (!strcmp(str, "rax"))
return RAX;
else if (!strcmp(str, "rcx"))
return RCX;
else if (!strcmp(str, "rdx"))
return RDX;
else if (!strcmp(str, "rbx"))
return RBX;
else if (!strcmp(str, "rsp"))
return RSP;
else if (!strcmp(str, "rbp"))
return RBP;
else if (!strcmp(str, "rsi"))
return RSI;
else if (!strcmp(str, "rdi"))
return RDI;
else if (!strcmp(str, "r8"))
return R8;
else if (!strcmp(str, "r9"))
return R9;
else if (!strcmp(str, "r10"))
return R10;
else if (!strcmp(str, "r11"))
return R11;
else if (!strcmp(str, "r12"))
return R12;
else if (!strcmp(str, "r13"))
return R13;
else if (!strcmp(str, "r14"))
return R14;
else if (!strcmp(str, "r15"))
return R15;
#endif
else if (!strcmp(str, "mm0")) else if (!strcmp(str, "mm0"))
return MM0; return MM0;
else if (!strcmp(str, "mm1")) else if (!strcmp(str, "mm1"))
@ -599,6 +640,25 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str)
else if (!strcmp(str, "xmm7")) else if (!strcmp(str, "xmm7"))
return XMM7; return XMM7;
#ifdef DYNAMICHOOKS_x86_64
else if (!strcmp(str, "xmm8"))
return XMM8;
else if (!strcmp(str, "xmm9"))
return XMM9;
else if (!strcmp(str, "xmm10"))
return XMM10;
else if (!strcmp(str, "xmm11"))
return XMM11;
else if (!strcmp(str, "xmm12"))
return XMM12;
else if (!strcmp(str, "xmm13"))
return XMM13;
else if (!strcmp(str, "xmm14"))
return XMM14;
else if (!strcmp(str, "xmm15"))
return XMM15;
#endif
else if (!strcmp(str, "cs")) else if (!strcmp(str, "cs"))
return CS; return CS;
else if (!strcmp(str, "ss")) else if (!strcmp(str, "ss"))

View File

@ -36,7 +36,7 @@
#include "util.h" #include "util.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
struct ArgumentInfo { struct ArgumentInfo {
ArgumentInfo() : name() ArgumentInfo() : name()

View File

@ -53,34 +53,12 @@ using namespace sp;
#ifdef PLATFORM_X64 #ifdef PLATFORM_X64
using namespace SourceHook::Asm; using namespace SourceHook::Asm;
SourceHook::CPageAlloc GenBuffer::ms_Allocator(16);
void test_func(void* rcx, void* rdx, SDKVector* r8, bool r9)
{
//g_pSM->LogMessage(myself, "rcx(%p) - rdx(%p) - r8(%p) - r9(%p)", rcx, rdx, r8, r9);
}
SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* hook) SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* hook)
{ {
auto masm = new x64JitWriter(); auto masm = new x64JitWriter();
auto type = hook->returnType; auto type = hook->returnType;
/*if (type == ReturnType_Vector)
{
masm->push(rcx);
masm->push(rdx);
masm->push(r8);
masm->push(r9);
masm->sub(rsp, 40);
masm->mov(rax, (uintptr_t)test_func);
masm->call(rax);
masm->add(rsp, 40);
masm->pop(r9);
masm->pop(r8);
masm->pop(rdx);
masm->pop(rcx);
}*/
// We're going to transform rbp into our stack // We're going to transform rbp into our stack
masm->push(rbp); masm->push(rbp);

View File

@ -1,3 +1,7 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include "data-pool.h" #include "data-pool.h"
#include "maxminddb.h" #include "maxminddb.h"
@ -5,8 +9,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
static bool can_multiply(size_t const, size_t const, size_t const);
// Allocate an MMDB_data_pool_s. It initially has space for size // Allocate an MMDB_data_pool_s. It initially has space for size
// MMDB_entry_data_list_s structs. // MMDB_entry_data_list_s structs.
MMDB_data_pool_s *data_pool_new(size_t const size) { MMDB_data_pool_s *data_pool_new(size_t const size) {
@ -39,7 +41,7 @@ MMDB_data_pool_s *data_pool_new(size_t const size) {
// the given max. max will typically be SIZE_MAX. // the given max. max will typically be SIZE_MAX.
// //
// We want to know if we'll wrap around. // We want to know if we'll wrap around.
static bool can_multiply(size_t const max, size_t const m, size_t const n) { bool can_multiply(size_t const max, size_t const m, size_t const n) {
if (m == 0) { if (m == 0) {
return false; return false;
} }

View File

@ -44,6 +44,7 @@ typedef struct MMDB_data_pool_s {
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS]; MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
} MMDB_data_pool_s; } MMDB_data_pool_s;
bool can_multiply(size_t const, size_t const, size_t const);
MMDB_data_pool_s *data_pool_new(size_t const); MMDB_data_pool_s *data_pool_new(size_t const);
void data_pool_destroy(MMDB_data_pool_s *const); void data_pool_destroy(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const); MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);

View File

@ -42,9 +42,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
static void * static const void *
mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) { mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) {
register char *cur, *last; const char *cur, *last;
const char *cl = (const char *)l; const char *cl = (const char *)l;
const char *cs = (const char *)s; const char *cs = (const char *)s;
@ -61,9 +61,9 @@ mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) {
return memchr(l, (int)*cs, l_len); return memchr(l, (int)*cs, l_len);
/* the last position where its possible to find "s" in "l" */ /* the last position where its possible to find "s" in "l" */
last = (char *)cl + l_len - s_len; last = cl + l_len - s_len;
for (cur = (char *)cl; cur <= last; cur++) for (cur = cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur; return cur;

View File

@ -1,13 +1,17 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include "data-pool.h" #include "data-pool.h"
#include "maxminddb-compat-util.h" #include "maxminddb-compat-util.h"
#include "maxminddb.h" #include "maxminddb.h"
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -19,6 +23,10 @@
#endif #endif
#include <windows.h> #include <windows.h>
#include <ws2ipdef.h> #include <ws2ipdef.h>
#ifndef SSIZE_MAX
#define SSIZE_MAX INTPTR_MAX
#endif
typedef ADDRESS_FAMILY sa_family_t;
#else #else
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -152,7 +160,7 @@ static int populate_description_metadata(MMDB_s *mmdb,
MMDB_entry_s *metadata_start); MMDB_entry_s *metadata_start);
static int resolve_any_address(const char *ipstr, struct addrinfo **addresses); static int resolve_any_address(const char *ipstr, struct addrinfo **addresses);
static int find_address_in_search_tree(const MMDB_s *const mmdb, static int find_address_in_search_tree(const MMDB_s *const mmdb,
uint8_t *address, uint8_t const *address,
sa_family_t address_family, sa_family_t address_family,
MMDB_lookup_result_s *result); MMDB_lookup_result_s *result);
static record_info_s record_info_for_database(const MMDB_s *const mmdb); static record_info_s record_info_for_database(const MMDB_s *const mmdb);
@ -162,7 +170,7 @@ static uint32_t get_left_28_bit_record(const uint8_t *record);
static uint32_t get_right_28_bit_record(const uint8_t *record); static uint32_t get_right_28_bit_record(const uint8_t *record);
static uint32_t data_section_offset_for_record(const MMDB_s *const mmdb, static uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
uint64_t record); uint64_t record);
static int path_length(va_list va_path); static size_t path_length(va_list va_path);
static int lookup_path_in_array(const char *path_elem, static int lookup_path_in_array(const char *path_elem,
const MMDB_s *const mmdb, const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data); MMDB_entry_data_s *entry_data);
@ -201,7 +209,7 @@ dump_entry_data_list(FILE *stream,
int indent, int indent,
int *status); int *status);
static void print_indentation(FILE *stream, int i); static void print_indentation(FILE *stream, int i);
static char *bytes_to_hex(uint8_t *bytes, uint32_t size); static char *bytes_to_hex(uint8_t const *bytes, uint32_t size);
#define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \ #define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \
do { \ do { \
@ -284,18 +292,29 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) {
goto cleanup; goto cleanup;
} }
uint32_t search_tree_size = if (!can_multiply(SSIZE_MAX,
mmdb->metadata.node_count * mmdb->full_record_byte_size; mmdb->metadata.node_count,
mmdb->full_record_byte_size)) {
mmdb->data_section =
mmdb->file_content + search_tree_size + MMDB_DATA_SECTION_SEPARATOR;
if (search_tree_size + MMDB_DATA_SECTION_SEPARATOR >
(uint32_t)mmdb->file_size) {
status = MMDB_INVALID_METADATA_ERROR; status = MMDB_INVALID_METADATA_ERROR;
goto cleanup; goto cleanup;
} }
mmdb->data_section_size = (uint32_t)mmdb->file_size - search_tree_size - ssize_t search_tree_size = (ssize_t)mmdb->metadata.node_count *
MMDB_DATA_SECTION_SEPARATOR; (ssize_t)mmdb->full_record_byte_size;
mmdb->data_section =
mmdb->file_content + search_tree_size + MMDB_DATA_SECTION_SEPARATOR;
if (mmdb->file_size < MMDB_DATA_SECTION_SEPARATOR ||
search_tree_size > mmdb->file_size - MMDB_DATA_SECTION_SEPARATOR) {
status = MMDB_INVALID_METADATA_ERROR;
goto cleanup;
}
ssize_t data_section_size =
mmdb->file_size - search_tree_size - MMDB_DATA_SECTION_SEPARATOR;
if (data_section_size > UINT32_MAX || data_section_size <= 0) {
status = MMDB_INVALID_METADATA_ERROR;
goto cleanup;
}
mmdb->data_section_size = (uint32_t)data_section_size;
// Although it is likely not possible to construct a database with valid // Although it is likely not possible to construct a database with valid
// valid metadata, as parsed above, and a data_section_size less than 3, // valid metadata, as parsed above, and a data_section_size less than 3,
@ -406,28 +425,39 @@ cleanup:;
#else // _WIN32 #else // _WIN32
static int map_file(MMDB_s *const mmdb) { static int map_file(MMDB_s *const mmdb) {
ssize_t size;
int status = MMDB_SUCCESS; int status = MMDB_SUCCESS;
int flags = O_RDONLY; int o_flags = O_RDONLY;
#ifdef O_CLOEXEC #ifdef O_CLOEXEC
flags |= O_CLOEXEC; o_flags |= O_CLOEXEC;
#endif #endif
int fd = open(mmdb->filename, flags); int fd = open(mmdb->filename, o_flags);
struct stat s; if (fd < 0) {
if (fd < 0 || fstat(fd, &s)) {
status = MMDB_FILE_OPEN_ERROR; status = MMDB_FILE_OPEN_ERROR;
goto cleanup; goto cleanup;
} }
size = s.st_size; #if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
if (size < 0 || size != s.st_size) { int fd_flags = fcntl(fd, F_GETFD);
if (fd_flags >= 0) {
fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC);
}
#endif
struct stat s;
if (fstat(fd, &s)) {
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
}
off_t size = s.st_size;
if (size < 0 || size > SSIZE_MAX) {
status = MMDB_OUT_OF_MEMORY_ERROR; status = MMDB_OUT_OF_MEMORY_ERROR;
goto cleanup; goto cleanup;
} }
uint8_t *file_content = uint8_t *file_content =
(uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); (uint8_t *)mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, fd, 0);
if (MAP_FAILED == file_content) { if (MAP_FAILED == file_content) {
if (ENOMEM == errno) { if (ENOMEM == errno) {
status = MMDB_OUT_OF_MEMORY_ERROR; status = MMDB_OUT_OF_MEMORY_ERROR;
@ -437,7 +467,7 @@ static int map_file(MMDB_s *const mmdb) {
goto cleanup; goto cleanup;
} }
mmdb->file_size = size; mmdb->file_size = (ssize_t)size;
mmdb->file_content = file_content; mmdb->file_content = file_content;
cleanup:; cleanup:;
@ -459,12 +489,16 @@ static const uint8_t *find_metadata(const uint8_t *file_content,
ssize_t max_size = file_size > METADATA_BLOCK_MAX_SIZE ssize_t max_size = file_size > METADATA_BLOCK_MAX_SIZE
? METADATA_BLOCK_MAX_SIZE ? METADATA_BLOCK_MAX_SIZE
: file_size; : file_size;
if (max_size < 0) {
return NULL;
}
uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size)); uint8_t const *search_area = (file_content + (file_size - max_size));
uint8_t *start = search_area; uint8_t const *start = search_area;
uint8_t *tmp; uint8_t const *tmp;
do { do {
tmp = mmdb_memmem(search_area, max_size, METADATA_MARKER, marker_len); tmp = mmdb_memmem(
search_area, (size_t)max_size, METADATA_MARKER, marker_len);
if (NULL != tmp) { if (NULL != tmp) {
max_size -= tmp - search_area; max_size -= tmp - search_area;
@ -671,7 +705,7 @@ value_for_key_as_string(MMDB_entry_s *start, char *key, char const **value) {
type_num_to_name(entry_data.type)); type_num_to_name(entry_data.type));
return MMDB_INVALID_METADATA_ERROR; return MMDB_INVALID_METADATA_ERROR;
} }
*value = mmdb_strndup((char *)entry_data.utf8_string, entry_data.data_size); *value = mmdb_strndup(entry_data.utf8_string, entry_data.data_size);
if (NULL == *value) { if (NULL == *value) {
return MMDB_OUT_OF_MEMORY_ERROR; return MMDB_OUT_OF_MEMORY_ERROR;
} }
@ -719,9 +753,8 @@ static int populate_languages_metadata(MMDB_s *mmdb,
return MMDB_INVALID_METADATA_ERROR; return MMDB_INVALID_METADATA_ERROR;
} }
mmdb->metadata.languages.names[i] = mmdb->metadata.languages.names[i] = mmdb_strndup(
mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.utf8_string, member->entry_data.data_size);
member->entry_data.data_size);
if (NULL == mmdb->metadata.languages.names[i]) { if (NULL == mmdb->metadata.languages.names[i]) {
return MMDB_OUT_OF_MEMORY_ERROR; return MMDB_OUT_OF_MEMORY_ERROR;
@ -803,9 +836,8 @@ static int populate_description_metadata(MMDB_s *mmdb,
goto cleanup; goto cleanup;
} }
mmdb->metadata.description.descriptions[i]->language = mmdb->metadata.description.descriptions[i]->language = mmdb_strndup(
mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.utf8_string, member->entry_data.data_size);
member->entry_data.data_size);
if (NULL == mmdb->metadata.description.descriptions[i]->language) { if (NULL == mmdb->metadata.description.descriptions[i]->language) {
status = MMDB_OUT_OF_MEMORY_ERROR; status = MMDB_OUT_OF_MEMORY_ERROR;
@ -819,9 +851,8 @@ static int populate_description_metadata(MMDB_s *mmdb,
goto cleanup; goto cleanup;
} }
mmdb->metadata.description.descriptions[i]->description = mmdb->metadata.description.descriptions[i]->description = mmdb_strndup(
mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.utf8_string, member->entry_data.data_size);
member->entry_data.data_size);
if (NULL == mmdb->metadata.description.descriptions[i]->description) { if (NULL == mmdb->metadata.description.descriptions[i]->description) {
status = MMDB_OUT_OF_MEMORY_ERROR; status = MMDB_OUT_OF_MEMORY_ERROR;
@ -879,22 +910,24 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
.netmask = 0, .netmask = 0,
.entry = {.mmdb = mmdb, .offset = 0}}; .entry = {.mmdb = mmdb, .offset = 0}};
uint8_t mapped_address[16], *address; uint8_t mapped_address[16];
uint8_t const *address;
if (mmdb->metadata.ip_version == 4) { if (mmdb->metadata.ip_version == 4) {
if (sockaddr->sa_family == AF_INET6) { if (sockaddr->sa_family == AF_INET6) {
*mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR; *mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR;
return result; return result;
} }
address = (uint8_t *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr; address = (uint8_t const *)&((struct sockaddr_in const *)sockaddr)
->sin_addr.s_addr;
} else { } else {
if (sockaddr->sa_family == AF_INET6) { if (sockaddr->sa_family == AF_INET6) {
address = (uint8_t *)&((struct sockaddr_in6 *)sockaddr) address = (uint8_t const *)&((struct sockaddr_in6 const *)sockaddr)
->sin6_addr.s6_addr; ->sin6_addr.s6_addr;
} else { } else {
address = mapped_address; address = mapped_address;
memset(address, 0, 12); memset(mapped_address, 0, 12);
memcpy(address + 12, memcpy(mapped_address + 12,
&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr, &((struct sockaddr_in const *)sockaddr)->sin_addr.s_addr,
4); 4);
} }
} }
@ -906,15 +939,15 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
} }
static int find_address_in_search_tree(const MMDB_s *const mmdb, static int find_address_in_search_tree(const MMDB_s *const mmdb,
uint8_t *address, uint8_t const *address,
sa_family_t address_family, sa_family_t address_family,
MMDB_lookup_result_s *result) { MMDB_lookup_result_s *result) {
record_info_s record_info = record_info_for_database(mmdb); record_info_s record_info = record_info_for_database(mmdb);
if (0 == record_info.right_record_offset) { if (record_info.right_record_offset == 0) {
return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
} }
uint32_t value = 0; uint64_t value = 0;
uint16_t current_bit = 0; uint16_t current_bit = 0;
if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) { if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) {
value = mmdb->ipv4_start_node.node_value; value = mmdb->ipv4_start_node.node_value;
@ -928,6 +961,7 @@ static int find_address_in_search_tree(const MMDB_s *const mmdb,
uint8_t bit = uint8_t bit =
1U & (address[current_bit >> 3] >> (7 - (current_bit % 8))); 1U & (address[current_bit >> 3] >> (7 - (current_bit % 8)));
// Note that value*record_info.record_length can be larger than 2**32
record_pointer = &search_tree[value * record_info.record_length]; record_pointer = &search_tree[value * record_info.record_length];
if (record_pointer + record_info.record_length > mmdb->data_section) { if (record_pointer + record_info.record_length > mmdb->data_section) {
return MMDB_CORRUPT_SEARCH_TREE_ERROR; return MMDB_CORRUPT_SEARCH_TREE_ERROR;
@ -974,10 +1008,11 @@ static record_info_s record_info_for_database(const MMDB_s *const mmdb) {
record_info.left_record_getter = &get_uint32; record_info.left_record_getter = &get_uint32;
record_info.right_record_getter = &get_uint32; record_info.right_record_getter = &get_uint32;
record_info.right_record_offset = 4; record_info.right_record_offset = 4;
} else {
assert(false);
} }
// Callers must check that right_record_offset is non-zero in case none of
// the above conditions matched.
return record_info; return record_info;
} }
@ -990,6 +1025,9 @@ static int find_ipv4_start_node(MMDB_s *const mmdb) {
} }
record_info_s record_info = record_info_for_database(mmdb); record_info_s record_info = record_info_for_database(mmdb);
if (record_info.right_record_offset == 0) {
return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
}
const uint8_t *search_tree = mmdb->file_content; const uint8_t *search_tree = mmdb->file_content;
uint32_t node_value = 0; uint32_t node_value = 0;
@ -1040,7 +1078,7 @@ static uint8_t record_type(const MMDB_s *const mmdb, uint64_t record) {
static uint32_t get_left_28_bit_record(const uint8_t *record) { static uint32_t get_left_28_bit_record(const uint8_t *record) {
return record[0] * 65536 + record[1] * 256 + record[2] + return record[0] * 65536 + record[1] * 256 + record[2] +
((record[3] & 0xf0) << 20); (uint32_t)((record[3] & 0xf0) << 20);
} }
static uint32_t get_right_28_bit_record(const uint8_t *record) { static uint32_t get_right_28_bit_record(const uint8_t *record) {
@ -1052,7 +1090,7 @@ int MMDB_read_node(const MMDB_s *const mmdb,
uint32_t node_number, uint32_t node_number,
MMDB_search_node_s *const node) { MMDB_search_node_s *const node) {
record_info_s record_info = record_info_for_database(mmdb); record_info_s record_info = record_info_for_database(mmdb);
if (0 == record_info.right_record_offset) { if (record_info.right_record_offset == 0) {
return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
} }
@ -1104,13 +1142,13 @@ int MMDB_get_value(MMDB_entry_s *const start,
int MMDB_vget_value(MMDB_entry_s *const start, int MMDB_vget_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data, MMDB_entry_data_s *const entry_data,
va_list va_path) { va_list va_path) {
int length = path_length(va_path); size_t length = path_length(va_path);
const char *path_elem; const char *path_elem;
int i = 0; int i = 0;
MAYBE_CHECK_SIZE_OVERFLOW(length, if (length == SIZE_MAX) {
SIZE_MAX / sizeof(const char *) - 1, return MMDB_INVALID_METADATA_ERROR;
MMDB_INVALID_METADATA_ERROR); }
const char **path = calloc(length + 1, sizeof(const char *)); const char **path = calloc(length + 1, sizeof(const char *));
if (NULL == path) { if (NULL == path) {
@ -1125,18 +1163,17 @@ int MMDB_vget_value(MMDB_entry_s *const start,
int status = MMDB_aget_value(start, entry_data, path); int status = MMDB_aget_value(start, entry_data, path);
free((char **)path); free(path);
return status; return status;
} }
static int path_length(va_list va_path) { static size_t path_length(va_list va_path) {
int i = 0; size_t i = 0;
const char *ignore;
va_list path_copy; va_list path_copy;
va_copy(path_copy, va_path); va_copy(path_copy, va_path);
while (NULL != (ignore = va_arg(path_copy, char *))) { while (NULL != va_arg(path_copy, char *)) {
i++; i++;
} }
@ -1209,7 +1246,7 @@ static int lookup_path_in_array(const char *path_elem,
int saved_errno = errno; int saved_errno = errno;
errno = 0; errno = 0;
int array_index = strtol(path_elem, &first_invalid, 10); long array_index = strtol(path_elem, &first_invalid, 10);
if (ERANGE == errno) { if (ERANGE == errno) {
errno = saved_errno; errno = saved_errno;
return MMDB_INVALID_LOOKUP_PATH_ERROR; return MMDB_INVALID_LOOKUP_PATH_ERROR;
@ -1224,11 +1261,11 @@ static int lookup_path_in_array(const char *path_elem,
} }
} }
if (*first_invalid || (uint32_t)array_index >= size) { if (*first_invalid || (unsigned long)array_index >= size) {
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
} }
for (int i = 0; i < array_index; i++) { for (long i = 0; i < array_index; i++) {
/* We don't want to follow a pointer here. If the next element is a /* We don't want to follow a pointer here. If the next element is a
* pointer we simply skip it and keep going */ * pointer we simply skip it and keep going */
CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data);
@ -1394,7 +1431,7 @@ static int decode_one(const MMDB_s *const mmdb,
DEBUG_MSGF("Extended type: %i (%s)", type, type_num_to_name(type)); DEBUG_MSGF("Extended type: %i (%s)", type, type_num_to_name(type));
} }
entry_data->type = type; entry_data->type = (uint32_t)type;
if (type == MMDB_DATA_TYPE_POINTER) { if (type == MMDB_DATA_TYPE_POINTER) {
uint8_t psize = ((ctrl >> 3) & 3) + 1; uint8_t psize = ((ctrl >> 3) & 3) + 1;
@ -1450,6 +1487,7 @@ static int decode_one(const MMDB_s *const mmdb,
} }
size = 65821 + get_uint24(&mem[offset]); size = 65821 + get_uint24(&mem[offset]);
offset += 3; offset += 3;
break;
default: default:
break; break;
} }
@ -1485,28 +1523,28 @@ static int decode_one(const MMDB_s *const mmdb,
DEBUG_MSGF("uint16 of size %d", size); DEBUG_MSGF("uint16 of size %d", size);
return MMDB_INVALID_DATA_ERROR; return MMDB_INVALID_DATA_ERROR;
} }
entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], size); entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], (int)size);
DEBUG_MSGF("uint16 value: %u", entry_data->uint16); DEBUG_MSGF("uint16 value: %u", entry_data->uint16);
} else if (type == MMDB_DATA_TYPE_UINT32) { } else if (type == MMDB_DATA_TYPE_UINT32) {
if (size > 4) { if (size > 4) {
DEBUG_MSGF("uint32 of size %d", size); DEBUG_MSGF("uint32 of size %d", size);
return MMDB_INVALID_DATA_ERROR; return MMDB_INVALID_DATA_ERROR;
} }
entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], size); entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], (int)size);
DEBUG_MSGF("uint32 value: %u", entry_data->uint32); DEBUG_MSGF("uint32 value: %u", entry_data->uint32);
} else if (type == MMDB_DATA_TYPE_INT32) { } else if (type == MMDB_DATA_TYPE_INT32) {
if (size > 4) { if (size > 4) {
DEBUG_MSGF("int32 of size %d", size); DEBUG_MSGF("int32 of size %d", size);
return MMDB_INVALID_DATA_ERROR; return MMDB_INVALID_DATA_ERROR;
} }
entry_data->int32 = get_sintX(&mem[offset], size); entry_data->int32 = get_sintX(&mem[offset], (int)size);
DEBUG_MSGF("int32 value: %i", entry_data->int32); DEBUG_MSGF("int32 value: %i", entry_data->int32);
} else if (type == MMDB_DATA_TYPE_UINT64) { } else if (type == MMDB_DATA_TYPE_UINT64) {
if (size > 8) { if (size > 8) {
DEBUG_MSGF("uint64 of size %d", size); DEBUG_MSGF("uint64 of size %d", size);
return MMDB_INVALID_DATA_ERROR; return MMDB_INVALID_DATA_ERROR;
} }
entry_data->uint64 = get_uintX(&mem[offset], size); entry_data->uint64 = get_uintX(&mem[offset], (int)size);
DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64); DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64);
} else if (type == MMDB_DATA_TYPE_UINT128) { } else if (type == MMDB_DATA_TYPE_UINT128) {
if (size > 16) { if (size > 16) {
@ -1519,7 +1557,7 @@ static int decode_one(const MMDB_s *const mmdb,
memcpy(entry_data->uint128 + 16 - size, &mem[offset], size); memcpy(entry_data->uint128 + 16 - size, &mem[offset], size);
} }
#else #else
entry_data->uint128 = get_uint128(&mem[offset], size); entry_data->uint128 = get_uint128(&mem[offset], (int)size);
#endif #endif
} else if (type == MMDB_DATA_TYPE_FLOAT) { } else if (type == MMDB_DATA_TYPE_FLOAT) {
if (size != 4) { if (size != 4) {
@ -1538,7 +1576,7 @@ static int decode_one(const MMDB_s *const mmdb,
entry_data->double_value = get_ieee754_double(&mem[offset]); entry_data->double_value = get_ieee754_double(&mem[offset]);
DEBUG_MSGF("double value: %f", entry_data->double_value); DEBUG_MSGF("double value: %f", entry_data->double_value);
} else if (type == MMDB_DATA_TYPE_UTF8_STRING) { } else if (type == MMDB_DATA_TYPE_UTF8_STRING) {
entry_data->utf8_string = size == 0 ? "" : (char *)&mem[offset]; entry_data->utf8_string = size == 0 ? "" : (char const *)&mem[offset];
entry_data->data_size = size; entry_data->data_size = size;
#ifdef MMDB_DEBUG #ifdef MMDB_DEBUG
char *string = char *string =
@ -1566,13 +1604,15 @@ get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size) {
uint32_t new_offset; uint32_t new_offset;
switch (ptr_size) { switch (ptr_size) {
case 1: case 1:
new_offset = ((ctrl & 7) << 8) + ptr[0]; new_offset = (uint32_t)((ctrl & 7) << 8) + ptr[0];
break; break;
case 2: case 2:
new_offset = 2048 + ((ctrl & 7) << 16) + (ptr[0] << 8) + ptr[1]; new_offset = 2048 + (uint32_t)((ctrl & 7) << 16) +
(uint32_t)(ptr[0] << 8) + ptr[1];
break; break;
case 3: case 3:
new_offset = 2048 + 524288 + ((ctrl & 7) << 24) + get_uint24(ptr); new_offset =
2048 + 524288 + (uint32_t)((ctrl & 7) << 24) + get_uint24(ptr);
break; break;
case 4: case 4:
default: default:
@ -1720,7 +1760,7 @@ static int get_entry_data_list(const MMDB_s *const mmdb,
static float get_ieee754_float(const uint8_t *restrict p) { static float get_ieee754_float(const uint8_t *restrict p) {
volatile float f; volatile float f;
uint8_t *q = (void *)&f; volatile uint8_t *q = (volatile void *)&f;
/* Windows builds don't use autoconf but we can assume they're all /* Windows builds don't use autoconf but we can assume they're all
* little-endian. */ * little-endian. */
#if MMDB_LITTLE_ENDIAN || _WIN32 #if MMDB_LITTLE_ENDIAN || _WIN32
@ -1736,7 +1776,7 @@ static float get_ieee754_float(const uint8_t *restrict p) {
static double get_ieee754_double(const uint8_t *restrict p) { static double get_ieee754_double(const uint8_t *restrict p) {
volatile double d; volatile double d;
uint8_t *q = (void *)&d; volatile uint8_t *q = (volatile void *)&d;
#if MMDB_LITTLE_ENDIAN || _WIN32 #if MMDB_LITTLE_ENDIAN || _WIN32
q[7] = p[0]; q[7] = p[0];
q[6] = p[1]; q[6] = p[1];
@ -1791,7 +1831,16 @@ static void free_mmdb_struct(MMDB_s *const mmdb) {
} }
if (NULL != mmdb->filename) { if (NULL != mmdb->filename) {
#if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
FREE_AND_SET_NULL(mmdb->filename); FREE_AND_SET_NULL(mmdb->filename);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
if (NULL != mmdb->file_content) { if (NULL != mmdb->file_content) {
#ifdef _WIN32 #ifdef _WIN32
@ -1800,12 +1849,30 @@ static void free_mmdb_struct(MMDB_s *const mmdb) {
* to cleanup then. */ * to cleanup then. */
WSACleanup(); WSACleanup();
#else #else
munmap((void *)mmdb->file_content, mmdb->file_size); #if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
munmap((void *)mmdb->file_content, (size_t)mmdb->file_size);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif #endif
} }
if (NULL != mmdb->metadata.database_type) { if (NULL != mmdb->metadata.database_type) {
#if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
FREE_AND_SET_NULL(mmdb->metadata.database_type); FREE_AND_SET_NULL(mmdb->metadata.database_type);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
free_languages_metadata(mmdb); free_languages_metadata(mmdb);
@ -1818,7 +1885,16 @@ static void free_languages_metadata(MMDB_s *mmdb) {
} }
for (size_t i = 0; i < mmdb->metadata.languages.count; i++) { for (size_t i = 0; i < mmdb->metadata.languages.count; i++) {
#if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]); FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
FREE_AND_SET_NULL(mmdb->metadata.languages.names); FREE_AND_SET_NULL(mmdb->metadata.languages.names);
} }
@ -1831,14 +1907,32 @@ static void free_descriptions_metadata(MMDB_s *mmdb) {
for (size_t i = 0; i < mmdb->metadata.description.count; i++) { for (size_t i = 0; i < mmdb->metadata.description.count; i++) {
if (NULL != mmdb->metadata.description.descriptions[i]) { if (NULL != mmdb->metadata.description.descriptions[i]) {
if (NULL != mmdb->metadata.description.descriptions[i]->language) { if (NULL != mmdb->metadata.description.descriptions[i]->language) {
#if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
FREE_AND_SET_NULL( FREE_AND_SET_NULL(
mmdb->metadata.description.descriptions[i]->language); mmdb->metadata.description.descriptions[i]->language);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
if (NULL != if (NULL !=
mmdb->metadata.description.descriptions[i]->description) { mmdb->metadata.description.descriptions[i]->description) {
#if defined(__clang__)
// This is a const char * that we need to free, which isn't valid. However it
// would mean changing the public API to fix this.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
FREE_AND_SET_NULL( FREE_AND_SET_NULL(
mmdb->metadata.description.descriptions[i]->description); mmdb->metadata.description.descriptions[i]->description);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} }
FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]); FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]);
} }
@ -1879,8 +1973,8 @@ dump_entry_data_list(FILE *stream,
*status = MMDB_INVALID_DATA_ERROR; *status = MMDB_INVALID_DATA_ERROR;
return NULL; return NULL;
} }
char *key = mmdb_strndup( char *key =
(char *)entry_data_list->entry_data.utf8_string, mmdb_strndup(entry_data_list->entry_data.utf8_string,
entry_data_list->entry_data.data_size); entry_data_list->entry_data.data_size);
if (NULL == key) { if (NULL == key) {
*status = MMDB_OUT_OF_MEMORY_ERROR; *status = MMDB_OUT_OF_MEMORY_ERROR;
@ -1926,8 +2020,7 @@ dump_entry_data_list(FILE *stream,
fprintf(stream, "]\n"); fprintf(stream, "]\n");
} break; } break;
case MMDB_DATA_TYPE_UTF8_STRING: { case MMDB_DATA_TYPE_UTF8_STRING: {
char *string = char *string = mmdb_strndup(entry_data_list->entry_data.utf8_string,
mmdb_strndup((char *)entry_data_list->entry_data.utf8_string,
entry_data_list->entry_data.data_size); entry_data_list->entry_data.data_size);
if (NULL == string) { if (NULL == string) {
*status = MMDB_OUT_OF_MEMORY_ERROR; *status = MMDB_OUT_OF_MEMORY_ERROR;
@ -1940,7 +2033,7 @@ dump_entry_data_list(FILE *stream,
} break; } break;
case MMDB_DATA_TYPE_BYTES: { case MMDB_DATA_TYPE_BYTES: {
char *hex_string = char *hex_string =
bytes_to_hex((uint8_t *)entry_data_list->entry_data.bytes, bytes_to_hex(entry_data_list->entry_data.bytes,
entry_data_list->entry_data.data_size); entry_data_list->entry_data.data_size);
if (NULL == hex_string) { if (NULL == hex_string) {
@ -2032,12 +2125,12 @@ dump_entry_data_list(FILE *stream,
static void print_indentation(FILE *stream, int i) { static void print_indentation(FILE *stream, int i) {
char buffer[1024]; char buffer[1024];
int size = i >= 1024 ? 1023 : i; int size = i >= 1024 ? 1023 : i;
memset(buffer, 32, size); memset(buffer, 32, (size_t)size);
buffer[size] = '\0'; buffer[size] = '\0';
fputs(buffer, stream); fputs(buffer, stream);
} }
static char *bytes_to_hex(uint8_t *bytes, uint32_t size) { static char *bytes_to_hex(uint8_t const *bytes, uint32_t size) {
char *hex_string; char *hex_string;
MAYBE_CHECK_SIZE_OVERFLOW(size, SIZE_MAX / 2 - 1, NULL); MAYBE_CHECK_SIZE_OVERFLOW(size, SIZE_MAX / 2 - 1, NULL);

View File

@ -5,18 +5,6 @@ extern "C" {
#ifndef MAXMINDDB_H #ifndef MAXMINDDB_H
#define MAXMINDDB_H #define MAXMINDDB_H
/* Request POSIX.1-2008. However, we want to remain compatible with
* POSIX.1-2001 (since we have been historically and see no reason to drop
* compatibility). By requesting POSIX.1-2008, we can conditionally use
* features provided by that standard if the implementation provides it. We can
* check for what the implementation provides by checking the _POSIX_VERSION
* macro after including unistd.h. If a feature is in POSIX.1-2008 but not
* POSIX.1-2001, check that macro before using the feature (or check for the
* feature directly if possible). */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include "maxminddb_config.h" #include "maxminddb_config.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
@ -28,9 +16,6 @@ extern "C" {
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
/* libmaxminddb package version from configure */ /* libmaxminddb package version from configure */
#define PACKAGE_VERSION "1.5.2"
typedef ADDRESS_FAMILY sa_family_t;
#if defined(_MSC_VER) #if defined(_MSC_VER)
/* MSVC doesn't define signed size_t, copy it from configure */ /* MSVC doesn't define signed size_t, copy it from configure */

View File

@ -11,6 +11,6 @@
#define MMDB_UINT128_USING_MODE 0 #define MMDB_UINT128_USING_MODE 0
#define MMDB_UINT128_IS_BYTE_ARRAY 1 #define MMDB_UINT128_IS_BYTE_ARRAY 1
#define PACKAGE_VERSION "1.5.2" #define PACKAGE_VERSION "1.10.0"
#endif /* MAXMINDDB_CONFIG_H */ #endif /* MAXMINDDB_CONFIG_H */

View File

@ -16,7 +16,7 @@ if SM.mysql_root:
if binary.compiler.target.platform == 'linux' or binary.compiler.target.platform == 'mac': if binary.compiler.target.platform == 'linux' or binary.compiler.target.platform == 'mac':
binary.compiler.postlink += [ binary.compiler.postlink += [
os.path.join(SM.mysql_root[arch], 'lib', 'libmysqlclient_r.a'), os.path.join(SM.mysql_root[arch], 'lib', 'libmysqlclient.a'),
'-lz', '-lz',
'-lpthread', '-lpthread',
'-lm', '-lm',

View File

@ -53,7 +53,7 @@
#include <cdll_int.h> #include <cdll_int.h>
#if SOURCE_ENGINE == SE_CSGO #if SOURCE_ENGINE == SE_CSGO
#include <am-hashset.h> #include <am-hashset.h>
#include <sm_stringhashmap.h> #include <sm_hashmap.h>
#endif #endif
#include "SoundEmitterSystem/isoundemittersystembase.h" #include "SoundEmitterSystem/isoundemittersystembase.h"

View File

@ -575,7 +575,13 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
case Valve_String: case Valve_String:
{ {
char *addr; char *addr;
pContext->LocalToString(param, &addr); pContext->LocalToStringNULL(param, &addr);
if (addr == NULL && (data->decflags & VDECODE_FLAG_ALLOWNULL) == 0)
{
pContext->ThrowNativeError("NULL not allowed");
return Data_Fail;
}
*(char **)buffer = addr; *(char **)buffer = addr;
return Data_Okay; return Data_Okay;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -167,6 +167,125 @@ methodmap StringMapSnapshot < Handle
public native int GetKey(int index, char[] buffer, int maxlength); public native int GetKey(int index, char[] buffer, int maxlength);
}; };
methodmap IntMap < Handle
{
// Creates a hash map. A hash map is a container that can map integers (called
// "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map
// are unique. That is, there is at most one entry in the map for a given key.
//
// Insertion, deletion, and lookup in a hash map are all considered to be fast
// operations, amortized to O(1), or constant time.
//
// The word "Trie" in this API is historical. As of SourceMod 1.6, tries have
// been internally replaced with hash tables, which have O(1) insertion time
// instead of O(n).
//
// The IntMap must be freed via delete or CloseHandle().
public native IntMap();
// Clones a hash map, returning a new handle with the same size and data.
// This should NOT be confused with CloneHandle. This is a completely new
// handle with the same data but no relation to the original. It should be
// closed when no longer needed with delete or CloseHandle().
//
// @return New handle to the cloned hash map
public native IntMap Clone();
// Sets a value in a hash map, either inserting a new entry or replacing an old one.
//
// @param key Key integer.
// @param value Value to store at this key.
// @param replace If false, operation will fail if the key is already set.
// @return True on success, false on failure.
public native bool SetValue(const int key, any value, bool replace=true);
// Sets an array value in a Map, either inserting a new entry or replacing an old one.
//
// @param key Key integer.
// @param array Array to store.
// @param num_items Number of items in the array.
// @param replace If false, operation will fail if the key is already set.
// @return True on success, false on failure.
public native bool SetArray(const int key, const any[] array, int num_items, bool replace=true);
// Sets a string value in a Map, either inserting a new entry or replacing an old one.
//
// @param key Key integer.
// @param value String to store.
// @param replace If false, operation will fail if the key is already set.
// @return True on success, false on failure.
public native bool SetString(const int key, const char[] value, bool replace=true);
// Retrieves a value in a Map.
//
// @param key Key integer.
// @param value Variable to store value.
// @return True on success. False if the key is not set, or the key is set
// as an array or string (not a value).
public native bool GetValue(const int key, any &value);
// Retrieves an array in a Map.
//
// @param key Key integer.
// @param array Buffer to store array.
// @param max_size Maximum size of array buffer.
// @param size Optional parameter to store the number of elements written to the buffer.
// @return True on success. False if the key is not set, or the key is set
// as a value or string (not an array).
public native bool GetArray(const int key, any[] array, int max_size, int &size=0);
// Retrieves a string in a Map.
//
// @param key Key integer.
// @param value Buffer to store value.
// @param max_size Maximum size of string buffer.
// @param size Optional parameter to store the number of bytes written to the buffer.
// @return True on success. False if the key is not set, or the key is set
// as a value or array (not a string).
public native bool GetString(const int key, char[] value, int max_size, int &size=0);
// Checks whether a key is present in a Map.
//
// @param key Key integer.
// @return True if the key has been found, else false.
public native bool ContainsKey(const int key);
// Removes a key entry from a Map.
//
// @param key Key integer.
// @return True on success, false if the value was never set.
public native bool Remove(const int key);
// Clears all entries from a Map.
public native void Clear();
// Create a snapshot of the map's keys. See IntMapSnapshot.
public native IntMapSnapshot Snapshot();
// Retrieves the number of elements in a map.
property int Size {
public native get();
}
};
// A IntMapSnapshot is created via IntMap.Snapshot(). It captures the
// keys on a map so they can be read. Snapshots must be freed with delete or
// CloseHandle().
methodmap IntMapSnapshot < Handle
{
// Returns the number of keys in the map snapshot.
property int Length {
public native get();
}
// Retrieves the key integer of a given key in a map snapshot.
//
// @param index Key index (starting from 0).
// @return The key integer
// @error Index out of range.
public native int GetKey(int index);
};
/** /**
* Creates a hash map. A hash map is a container that can map strings (called * Creates a hash map. A hash map is a container that can map strings (called
* "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map * "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map

View File

@ -78,7 +78,34 @@ native Handle CloneHandle(Handle hndl, Handle plugin=INVALID_HANDLE);
methodmap Handle __nullable__ { methodmap Handle __nullable__ {
public native ~Handle(); public native ~Handle();
/**
* Closes a Handle. If the handle has multiple copies open,
* it is not destroyed unless all copies are closed.
*
* @note Closing a Handle has a different meaning for each Handle type. Make
* sure you read the documentation on whatever provided the Handle.
*
* @error Invalid handles will cause a run time error.
*/
public native void Close(); public native void Close();
/**
* Clones a Handle. When passing handles in between plugins, caching handles
* can result in accidental invalidation when one plugin releases the Handle, or is its owner
* is unloaded from memory. To prevent this, the Handle may be "cloned" with a new owner.
*
* @note Usually, you will be cloning Handles for other plugins. This means that if you clone
* the Handle without specifying the new owner, it will assume the identity of your original
* calling plugin, which is not very useful. You should either specify that the receiving
* plugin should clone the handle on its own, or you should explicitly clone the Handle
* using the receiving plugin's identity Handle.
*
* @param plugin Optional Handle to another plugin to mark as the new owner.
* If no owner is passed, the owner becomes the calling plugin.
* @return Handle on success, INVALID_HANDLE if not cloneable.
* @error Invalid handles will cause a run time error.
*/
public native Handle Clone(Handle plugin=INVALID_HANDLE);
}; };
/** /**

View File

@ -42,8 +42,8 @@
#define SOURCEMOD_V_REV 0 #define SOURCEMOD_V_REV 0
#define SOURCEMOD_V_CSET "0" #define SOURCEMOD_V_CSET "0"
#define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */ #define SOURCEMOD_V_MAJOR 1 /**< SourceMod Major version */
#define SOURCEMOD_V_MINOR 12 /**< SourceMod Minor version */ #define SOURCEMOD_V_MINOR 13 /**< SourceMod Minor version */
#define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */ #define SOURCEMOD_V_RELEASE 0 /**< SourceMod Release version */
#define SOURCEMOD_VERSION "1.12.0-manual" /**< SourceMod version string (major.minor.release-tag) */ #define SOURCEMOD_VERSION "1.13.0-manual" /**< SourceMod version string (major.minor.release-tag) */
#endif #endif

View File

@ -13,6 +13,7 @@ public Plugin:myinfo =
public OnPluginStart() public OnPluginStart()
{ {
RegServerCmd("test_maps", RunTests); RegServerCmd("test_maps", RunTests);
RegServerCmd("test_int_maps", RunIntTests);
} }
public Action:RunTests(argc) public Action:RunTests(argc)
@ -161,3 +162,189 @@ public Action:RunTests(argc)
return Plugin_Handled; return Plugin_Handled;
} }
public Action:RunIntTests(argc)
{
IntMap map = new IntMap();
for (new i = 0; i < 64; i++) {
if (!map.SetValue(i, i))
ThrowError("set map to %d failed", i);
if (!map.ContainsKey(i))
ThrowError("map contains %d failed", i)
new value;
if (!map.GetValue(i, value))
ThrowError("get map %d", i);
if (value != i)
ThrowError("get map %d == %d", i, i);
}
// Setting 17 without replace should fail.
new value;
if (map.SetValue(17, 999, false))
ThrowError("set map 17 should fail");
if (!map.GetValue(17, value) || value != 17)
ThrowError("value at 17 not correct");
if (!map.SetValue(17, 999))
ThrowError("set map 17 = 999 should succeed");
if (!map.GetValue(17, value) || value != 999)
ThrowError("value at 17 not correct");
// Check size is 64.
if (map.Size != 64)
ThrowError("map size not 64");
// Check 100 is not found.
int array[64];
char string[64];
if (map.ContainsKey(100) ||
map.GetValue(100, value) ||
map.GetArray(100, array, sizeof(array)) ||
map.GetString(100, string, sizeof(string)))
{
ThrowError("map should not have 100");
}
// Check that 17 is not a string or array.
if (map.GetArray(17, array, sizeof(array)) ||
map.GetString(17, string, sizeof(string)))
{
ThrowError("entry 17 should not be an array or string");
}
// Strings.
if (!map.SetString(17, "hellokitty"))
ThrowError("17 should be string");
if (!map.GetString(17, string, sizeof(string)) ||
strcmp(string, "hellokitty") != 0)
{
ThrowError("17 should be hellokitty");
}
if (map.GetValue(17, value) ||
map.GetArray(17, array, sizeof(array)))
{
ThrowError("entry 17 should not be an array or string");
}
// Arrays.
new data[5] = { 93, 1, 2, 3, 4 };
if (!map.SetArray(17, data, 5))
ThrowError("couldn't set 17 to 5-entry array");
if (!map.GetArray(17, array, sizeof(array)))
ThrowError("couldn't fetch 5-entry array");
for (new i = 0; i < 5; i++) {
if (data[i] != array[i])
ThrowError("17 slot %d should be %d, got %d", i, data[i], array[i]);
}
if (map.GetValue(17, value) ||
map.GetString(17, string, sizeof(string)))
{
ThrowError("entry 17 should not be a value or string");
}
if (!map.SetArray(17, data, 1))
ThrowError("couldn't set 17 to 1-entry array");
// Check that we fixed an old bug where 1-entry arrays where cells
if (!map.GetArray(17, array, sizeof(array), value))
ThrowError("couldn't fetch 1-entry array");
if (value != 1)
ThrowError("array size mismatch (%d, expected %d)", value, 1);
// Check that we maintained backward compatibility.
if (!map.GetValue(17, value))
ThrowError("backwards compatibility failed");
if (value != data[0])
ThrowError("wrong value (%d, expected %d)", value, data[0]);
// Remove "17".
if (!map.Remove(17))
ThrowError("17 should have been removed");
if (map.Remove(17))
ThrowError("17 should not exist");
if (map.ContainsKey(17) ||
map.GetValue(17, value) ||
map.GetArray(17, array, sizeof(array)) ||
map.GetString(17, string, sizeof(string)))
{
ThrowError("map should not have a 17");
}
map.Clear();
if (map.Size)
ThrowError("size should be 0");
map.SetString(42, "time!");
map.SetString(84, "bees");
map.SetString(126, "egg");
IntMapSnapshot keys = map.Snapshot();
{
if (keys.Length != 3)
ThrowError("map snapshot length should be 3");
bool found[3];
for (new i = 0; i < keys.Length; i++) {
decl key = keys.GetKey(i);
if (key == 42)
found[0] = true;
else if (key == 84)
found[1] = true;
else if (key == 126)
found[2] = true;
else
ThrowError("unexpected key: %d", key);
}
if (!found[0] || !found[1] || !found[2])
ThrowError("did not find all keys");
}
delete keys;
map.SetValue(10240, 6744);
map.SetValue(8, 13);
new cloneData[5] = { 12, 23, 55, 1, 2 };
new cloneArr[5];
map.SetArray(9102, cloneData, 5);
IntMap clone = map.Clone();
if (clone.Size != map.Size)
ThrowError("cloned map size mismatch (%d, expected %d)", clone.Size, map.Size);
if (!clone.GetString(42, string, sizeof(string)))
ThrowError("cloned map entry 42 should be a string");
if (strcmp(string, "time!") != 0)
ThrowError("cloned map entry 42 should be \"time!\"");
if (!clone.GetString(84, string, sizeof(string)))
ThrowError("cloned map entry 84 should be a string");
if (strcmp(string, "bees") != 0)
ThrowError("cloned map entry 84 should be \"bees\"");
if (!clone.GetString(126, string, sizeof(string)))
ThrowError("cloned map entry 126 should be a string");
if (strcmp(string, "egg") != 0)
ThrowError("cloned map entry 126 should be \"egg\"");
if (!clone.GetValue(10240, value))
ThrowError("cloned map entry 10240 should be a value");
if (value != 6744)
ThrowError("cloned map entry 10240 should be 6744")
if (!clone.GetValue(8, value))
ThrowError("cloned map entry 8 should be a value");
if (value != 13)
ThrowError("cloned map entry 8 should be 13")
if (!clone.GetArray(9102, cloneArr, 5))
ThrowError("cloned map entry 9102 should be an array");
for (new i = 0; i < 5; i++) {
if (cloneData[i] != cloneArr[i])
ThrowError("cloned map entry 9102 slot %d should be %d, got %d", i, cloneData[i], cloneArr[i]);
}
delete clone;
PrintToServer("All tests passed!");
delete map;
return Plugin_Handled;
}

View File

@ -1 +1 @@
1.12.0 1.13.0

@ -1 +1 @@
Subproject commit 285b4f853c0003023838140113e3ec066bd800c6 Subproject commit 2d3b1a3378a3728637f26660c9ffc2df3189cf62

View File

@ -1,47 +1,5 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os, sys import os
# Simple extensions do not need to modify this file.
class SDK(object):
def __init__(self, sdk, ext, aDef, name, platform, dir):
self.folder = 'hl2sdk-' + dir
self.envvar = sdk
self.ext = ext
self.code = aDef
self.define = name
self.platform = platform
self.name = dir
self.path = None # Actual path
WinOnly = ['windows']
WinLinux = ['windows', 'linux']
WinLinuxMac = ['windows', 'linux', 'mac']
PossibleSDKs = {
'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
'tf2': SDK('HL2SDKTF2', '2.tf2', '12', 'TF2', WinLinuxMac, 'tf2'),
'l4d': SDK('HL2SDKL4D', '2.l4d', '13', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
'nucleardawn': SDK('HL2SDKND', '2.nd', '14', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '16', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '17', 'ALIENSWARM', WinOnly, 'swarm'),
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
'csgo': SDK('HL2SDKCSGO', '2.csgo', '22', 'CSGO', WinLinuxMac, 'csgo'),
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '18', 'PORTAL2', [], 'portal2'),
'blade': SDK('HL2SDKBLADE', '2.blade', '19', 'BLADE', WinLinux, 'blade'),
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '20', 'INSURGENCY', WinLinuxMac, 'insurgency'),
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '15', 'CONTAGION', WinOnly, 'contagion'),
'bms': SDK('HL2SDKBMS', '2.bms', '11', 'BMS', WinLinux, 'bms'),
'doi': SDK('HL2SDKDOI', '2.doi', '21', 'DOI', WinLinuxMac, 'doi'),
'pvkii': SDK('HL2SDKPVKII', '2.pvkii', '10', 'PVKII', WinLinux, 'pvkii'),
}
def ResolveEnvPath(env, folder): def ResolveEnvPath(env, folder):
if env in os.environ: if env in os.environ:
@ -64,14 +22,70 @@ def ResolveEnvPath(env, folder):
def Normalize(path): def Normalize(path):
return os.path.abspath(os.path.normpath(path)) return os.path.abspath(os.path.normpath(path))
def SetArchFlags(compiler):
if compiler.behavior == 'gcc':
if compiler.target.arch == 'x86_64':
compiler.cflags += ['-fPIC']
elif compiler.like('msvc'):
if compiler.target.arch == 'x86_64':
compiler.defines += ['WIN64']
hl2sdk_manifests_path = None
# First we check if the manifest exists in the current path
hl2sdk_manifests_path = os.path.join(builder.sourcePath, 'hl2sdk-manifests/SdkHelpers.ambuild')
if not os.path.exists(hl2sdk_manifests_path):
# manifests does not exists in the project file, use the path from --hl2sdk-manifest-path
if not builder.options.hl2sdk_manifest:
raise Exception('HL2SDK Manifest root path not set! (--hl2sdk-manifest-path)')
else:
hl2sdk_manifests_path = os.path.join(builder.options.hl2sdk_manifest, 'SdkHelpers.ambuild')
if not os.path.exists(hl2sdk_manifests_path):
raise Exception('Could not find SdkHelpers.ambuild in the given HL2SDK Manifest path!')
SdkHelpers = builder.Eval(hl2sdk_manifests_path, {
'Project': 'sm-extension'
})
class ExtensionConfig(object): class ExtensionConfig(object):
def __init__(self): def __init__(self):
self.sdk_manifests = []
self.sdks = {} self.sdks = {}
self.binaries = [] self.sdk_targets = []
self.extensions = [] self.extensions = []
self.generated_headers = None self.generated_headers = None
self.mms_root = None self.mms_root = None
self.sm_root = None self.sm_root = None
self.all_targets = []
self.target_archs = set()
if builder.options.targets:
target_archs = builder.options.targets.split(',')
else:
target_archs = ['x86', 'x86_64']
for arch in target_archs:
try:
cxx = builder.DetectCxx(target_arch = arch)
self.target_archs.add(cxx.target.arch)
except Exception as e:
# Error if archs were manually overridden.
if builder.options.targets:
raise
print('Skipping target {}: {}'.format(arch, e))
continue
self.all_targets.append(cxx)
if not self.all_targets:
raise Exception('No suitable C/C++ compiler was found.')
def use_auto_versioning(self):
if builder.backend != 'amb2':
return False
return not getattr(builder.options, 'disable_auto_versioning', False)
@property @property
def tag(self): def tag(self):
@ -79,41 +93,26 @@ class ExtensionConfig(object):
return 'Debug' return 'Debug'
return 'Release' return 'Release'
def detectSDKs(self): def findSdkPath(self, sdk_name):
sdk_list = builder.options.sdks.split(',') dir_name = 'hl2sdk-{}'.format(sdk_name)
use_all = sdk_list[0] == 'all'
use_present = sdk_list[0] == 'present'
for sdk_name in PossibleSDKs:
sdk = PossibleSDKs[sdk_name]
if builder.target_platform in sdk.platform:
if builder.options.hl2sdk_root: if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder) sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
else: if os.path.exists(sdk_path):
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder) return sdk_path
if sdk_path is None or not os.path.isdir(sdk_path): return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
if use_all or sdk_name in sdk_list:
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
continue
if use_all or use_present or sdk_name in sdk_list:
sdk.path = Normalize(sdk_path)
self.sdks[sdk_name] = sdk
if len(self.sdks) < 1: def shouldIncludeSdk(self, sdk):
raise Exception('At least one SDK must be available.') return not sdk.get('source2', False)
if builder.options.sm_path: def detectSDKs(self):
self.sm_root = builder.options.sm_path sdk_list = [s for s in builder.options.sdks.split(',') if s]
else: SdkHelpers.sdk_filter = self.shouldIncludeSdk
self.sm_root = ResolveEnvPath('SOURCEMOD18', 'sourcemod-1.8') SdkHelpers.find_sdk_path = self.findSdkPath
if not self.sm_root: SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central')
if not self.sm_root or not os.path.isdir(self.sm_root): self.sdks = SdkHelpers.sdks
raise Exception('Could not find a source copy of SourceMod') self.sdk_manifests = SdkHelpers.sdk_manifests
self.sm_root = Normalize(self.sm_root) self.sdk_targets = SdkHelpers.sdk_targets
if builder.options.mms_path: if builder.options.mms_path:
self.mms_root = builder.options.mms_path self.mms_root = builder.options.mms_path
@ -121,6 +120,8 @@ class ExtensionConfig(object):
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12') self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
if not self.mms_root: if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root: if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
@ -128,12 +129,45 @@ class ExtensionConfig(object):
raise Exception('Could not find a source copy of Metamod:Source') raise Exception('Could not find a source copy of Metamod:Source')
self.mms_root = Normalize(self.mms_root) self.mms_root = Normalize(self.mms_root)
if builder.options.sm_path:
self.sm_root = builder.options.sm_path
else:
self.sm_root = ResolveEnvPath('SOURCEMOD112', 'sourcemod-1.12')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central')
if not self.sm_root or not os.path.isdir(self.sm_root):
raise Exception('Could not find a source copy of SourceMod')
self.sm_root = Normalize(self.sm_root)
def configure(self): def configure(self):
cxx = builder.DetectCompilers()
allowed_archs = ['x86','x86_64']
if not set(self.target_archs).issubset(allowed_archs):
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
for cxx in self.all_targets:
self.configure_cxx(cxx)
def configure_cxx(self, cxx):
if cxx.family == 'msvc':
if cxx.version < 1914 and builder.options.generator != 'vs':
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
elif cxx.family == 'gcc':
if cxx.version < 'gcc-8':
raise Exception('Only GCC versions 8 or later are supported, full C++17 support is required.')
elif cxx.family == 'clang':
if cxx.version < 'clang-5':
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
if cxx.like('gcc'): if cxx.like('gcc'):
self.configure_gcc(cxx) self.configure_gcc(cxx)
elif cxx.vendor == 'msvc': elif cxx.family == 'msvc':
self.configure_msvc(cxx) self.configure_msvc(cxx)
# Optimization # Optimization
@ -145,18 +179,13 @@ class ExtensionConfig(object):
cxx.defines += ['DEBUG', '_DEBUG'] cxx.defines += ['DEBUG', '_DEBUG']
# Platform-specifics # Platform-specifics
if builder.target_platform == 'linux': if cxx.target.platform == 'linux':
self.configure_linux(cxx) self.configure_linux(cxx)
elif builder.target_platform == 'mac': elif cxx.target.platform == 'mac':
self.configure_mac(cxx) self.configure_mac(cxx)
elif builder.target_platform == 'windows': elif cxx.target.platform == 'windows':
self.configure_windows(cxx) self.configure_windows(cxx)
# Finish up.
cxx.includes += [
os.path.join(self.sm_root, 'public'),
]
def configure_gcc(self, cxx): def configure_gcc(self, cxx):
cxx.defines += [ cxx.defines += [
'stricmp=strcasecmp', 'stricmp=strcasecmp',
@ -174,46 +203,48 @@ class ExtensionConfig(object):
'-Wno-unused', '-Wno-unused',
'-Wno-switch', '-Wno-switch',
'-Wno-array-bounds', '-Wno-array-bounds',
'-msse',
'-m32',
'-fvisibility=hidden', '-fvisibility=hidden',
] ]
if cxx.target.arch in ['x86', 'x86_64']:
cxx.cflags += ['-msse']
cxx.cxxflags += [ cxx.cxxflags += [
'-std=c++14',
'-fno-exceptions',
'-fno-threadsafe-statics', '-fno-threadsafe-statics',
'-Wno-non-virtual-dtor', '-Wno-non-virtual-dtor',
'-Wno-overloaded-virtual', '-Wno-overloaded-virtual',
'-Wno-register',
'-fvisibility-inlines-hidden', '-fvisibility-inlines-hidden',
'-std=c++17',
] ]
cxx.linkflags += ['-m32']
have_gcc = cxx.vendor == 'gcc'
have_clang = cxx.vendor == 'clang'
if cxx.version >= 'clang-3.6':
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
if have_clang or (cxx.version >= 'gcc-4.6'):
cxx.cflags += ['-Wno-narrowing']
if have_clang or (cxx.version >= 'gcc-4.7'):
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
if cxx.version >= 'gcc-4.8':
cxx.cflags += ['-Wno-unused-result']
have_gcc = cxx.family == 'gcc'
have_clang = cxx.family == 'clang'
# Work around errors from smsdk_ext.cpp
if have_clang: if have_clang:
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
cxx.cxxflags += ['-Wno-deprecated-register'] # Work around SDK warnings.
else: if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
cxx.cxxflags += ['-Wno-deprecated'] cxx.cflags += [
cxx.cflags += ['-Wno-sometimes-uninitialized'] '-Wno-implicit-int-float-conversion',
'-Wno-tautological-overlap-compare',
]
if have_gcc: if have_gcc:
cxx.cflags += ['-mfpmath=sse'] cxx.cflags += ['-mfpmath=sse']
cxx.cflags += ['-Wno-maybe-uninitialized']
if builder.options.opt == '1': if builder.options.opt == '1':
cxx.cflags += ['-O3'] cxx.cflags += ['-O3']
# Don't omit the frame pointer.
cxx.cflags += ['-fno-omit-frame-pointer']
def configure_msvc(self, cxx): def configure_msvc(self, cxx):
if builder.options.debug == '1': if builder.options.debug == '1':
cxx.cflags += ['/MTd'] cxx.cflags += ['/MTd']
cxx.linkflags += ['/NODEFAULTLIB:libcmt'] cxx.linkflags += ['/NODEFAULTLIB:libcmt']
@ -232,9 +263,9 @@ class ExtensionConfig(object):
'/EHsc', '/EHsc',
'/GR-', '/GR-',
'/TP', '/TP',
'/std:c++17',
] ]
cxx.linkflags += [ cxx.linkflags += [
'/MACHINE:X86',
'kernel32.lib', 'kernel32.lib',
'user32.lib', 'user32.lib',
'gdi32.lib', 'gdi32.lib',
@ -261,27 +292,40 @@ class ExtensionConfig(object):
cxx.cflags += ['/Oy-'] cxx.cflags += ['/Oy-']
def configure_linux(self, cxx): def configure_linux(self, cxx):
cxx.defines += ['_LINUX', 'POSIX'] cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.linkflags += ['-Wl,--exclude-libs,ALL', '-lm'] cxx.linkflags += ['-lm']
if cxx.vendor == 'gcc': if cxx.family == 'gcc':
cxx.linkflags += ['-static-libgcc'] cxx.linkflags += ['-static-libgcc']
elif cxx.vendor == 'clang': elif cxx.family == 'clang':
cxx.linkflags += ['-lgcc_eh'] cxx.linkflags += ['-lgcc_eh']
cxx.linkflags += ['-static-libstdc++']
def configure_mac(self, cxx): def configure_mac(self, cxx):
cxx.defines += ['OSX', '_OSX', 'POSIX'] cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
cxx.cflags += ['-mmacosx-version-min=10.5'] cxx.cflags += ['-mmacosx-version-min=10.15']
cxx.linkflags += [ cxx.linkflags += [
'-mmacosx-version-min=10.5', '-mmacosx-version-min=10.15',
'-arch', 'i386', '-stdlib=libc++',
'-lstdc++', '-lc++',
'-stdlib=libstdc++',
] ]
cxx.cxxflags += ['-stdlib=libstdc++'] cxx.cxxflags += ['-stdlib=libc++']
def configure_windows(self, cxx): def configure_windows(self, cxx):
cxx.defines += ['WIN32', '_WINDOWS'] cxx.defines += ['WIN32', '_WINDOWS']
def LibraryBuilder(self, compiler, name):
binary = compiler.Library(name)
self.AddVersioning(binary)
if binary.compiler.like('msvc'):
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
self.AddCxxCompat(binary)
return binary
def Library(self, context, compiler, name):
compiler = compiler.clone()
SetArchFlags(compiler)
return self.LibraryBuilder(compiler, name)
def ConfigureForExtension(self, context, compiler): def ConfigureForExtension(self, context, compiler):
compiler.cxxincludes += [ compiler.cxxincludes += [
os.path.join(context.currentSourcePath), os.path.join(context.currentSourcePath),
@ -294,156 +338,65 @@ class ExtensionConfig(object):
] ]
return compiler return compiler
def ConfigureForHL2(self, binary, sdk): def ExtLibrary(self, context, compiler, name):
compiler = binary.compiler binary = self.Library(context, compiler, name)
SetArchFlags(compiler)
self.ConfigureForExtension(context, binary.compiler)
return binary
if sdk.name == 'episode1': def AddCxxCompat(self, binary):
mms_path = os.path.join(self.mms_root, 'core-legacy') if binary.compiler.target.platform == 'linux':
else: binary.sources += [
mms_path = os.path.join(self.mms_root, 'core') os.path.join(self.sm_root, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
]
def ConfigureForHL2(self, context, binary, sdk):
compiler = binary.compiler
SetArchFlags(compiler)
compiler.cxxincludes += [ compiler.cxxincludes += [
os.path.join(mms_path), os.path.join(self.mms_root, 'core'),
os.path.join(mms_path, 'sourcehook'), os.path.join(self.mms_root, 'core', 'sourcehook'),
] ]
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs] for other_sdk in self.sdk_manifests:
compiler.defines += defines compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
paths = [ SdkHelpers.configureCxx(context, binary, sdk)
['public'],
['public', 'engine'],
['public', 'mathlib'],
['public', 'vstdlib'],
['public', 'tier0'],
['public', 'tier1']
]
if sdk.name == 'episode1' or sdk.name == 'darkm':
paths.append(['public', 'dlls'])
paths.append(['game_shared'])
else:
paths.append(['public', 'game', 'server'])
paths.append(['public', 'toolframework'])
paths.append(['game', 'shared'])
paths.append(['common'])
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
if sdk.name in ['sdk2013', 'bms', 'pvkii'] and compiler.like('gcc'):
# The 2013 SDK already has these in public/tier0/basetypes.h
compiler.defines.remove('stricmp=strcasecmp')
compiler.defines.remove('_stricmp=strcasecmp')
compiler.defines.remove('_snprintf=snprintf')
compiler.defines.remove('_vsnprintf=vsnprintf')
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
else:
compiler.defines += ['COMPILER_GCC']
# For everything after Swarm, this needs to be defined for entity networking
# to work properly with sendprop value changes.
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
compiler.defines += ['NETWORK_VARS_ENABLED']
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2', 'pvkii']:
if builder.target_platform in ['linux', 'mac']:
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
if sdk.name == 'csgo' and builder.target_platform == 'linux':
compiler.linkflags += ['-lstdc++']
for path in paths:
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
if builder.target_platform == 'linux':
if sdk.name == 'episode1':
lib_folder = os.path.join(sdk.path, 'linux_sdk')
elif sdk.name in ['sdk2013', 'bms', 'pvkii']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
elif builder.target_platform == 'mac':
if sdk.name in ['sdk2013', 'bms']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
if builder.target_platform in ['linux', 'mac']:
if sdk.name in ['sdk2013', 'bms', 'pvkii']:
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
]
else:
compiler.postlink += [
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
]
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
dynamic_libs = []
if builder.target_platform == 'linux':
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo', 'pvkii']:
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
else:
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
elif builder.target_platform == 'mac':
compiler.linkflags.append('-liconv')
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
elif builder.target_platform == 'windows':
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
libs.append('interfaces')
for lib in libs:
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
compiler.linkflags.append(compiler.Dep(lib_path))
for library in dynamic_libs:
source_path = os.path.join(lib_folder, library)
output_path = os.path.join(binary.localFolder, library)
def make_linker(source_path, output_path):
def link(context, binary):
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
return output
return link
linker = make_linker(source_path, output_path)
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
return binary return binary
def HL2Library(self, context, name, sdk): def HL2Library(self, context, compiler, name, sdk):
binary = context.compiler.Library(name) binary = self.Library(context, compiler, name)
self.ConfigureForExtension(context, binary.compiler) self.ConfigureForExtension(context, binary.compiler)
return self.ConfigureForHL2(binary, sdk) return self.ConfigureForHL2(context, binary, sdk)
def HL2Project(self, context, name): def HL2Config(self, project, context, compiler, name, sdk):
project = context.compiler.LibraryProject(name) binary = project.Configure(compiler, name,
self.ConfigureForExtension(context, project.compiler) '{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
return project self.AddCxxCompat(binary)
return self.ConfigureForHL2(context, binary, sdk)
def HL2Config(self, project, name, sdk): def HL2ExtConfig(self, project, context, compiler, name, sdk):
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name)) binary = project.Configure(compiler, name,
return self.ConfigureForHL2(binary, sdk) '{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
self.AddCxxCompat(binary)
self.ConfigureForHL2(context, binary, sdk)
self.ConfigureForExtension(context, binary.compiler)
return binary
Extension = ExtensionConfig() Extension = ExtensionConfig()
Extension.detectSDKs() Extension.detectSDKs()
Extension.configure() Extension.configure()
# Add additional buildscripts here # This will clone the list and each cxx object as we recurse, preventing child
# scripts from messing up global state.
builder.targets = builder.CloneableList(Extension.all_targets)
BuildScripts = [ BuildScripts = [
'AMBuilder', 'AMBuilder',
'PackageScript',
] ]
if builder.backend == 'amb2': builder.Build(BuildScripts, { 'Extension': Extension })
BuildScripts += [
'PackageScript',
]
builder.RunBuildScripts(BuildScripts, { 'Extension': Extension})

View File

@ -1,6 +1,7 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os, sys import os
# Name of your extesion, this will also be it's file name.
projectName = 'sample' projectName = 'sample'
# smsdk_ext.cpp will be automatically added later # smsdk_ext.cpp will be automatically added later
@ -8,11 +9,7 @@ sourceFiles = [
'extension.cpp', 'extension.cpp',
] ]
############### project = builder.LibraryProject(projectName)
# Make sure to edit PackageScript, which copies your files to their appropriate locations
# Simple extensions do not need to modify past this point.
project = Extension.HL2Project(builder, projectName + '.ext')
if os.path.isfile(os.path.join(builder.currentSourcePath, 'sdk', 'smsdk_ext.cpp')): if os.path.isfile(os.path.join(builder.currentSourcePath, 'sdk', 'smsdk_ext.cpp')):
# Use the copy included in the project # Use the copy included in the project
@ -25,7 +22,13 @@ project.sources += sourceFiles
for sdk_name in Extension.sdks: for sdk_name in Extension.sdks:
sdk = Extension.sdks[sdk_name] sdk = Extension.sdks[sdk_name]
if sdk['name'] in ['mock']:
continue
binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk) for cxx in builder.targets:
if not cxx.target.arch in sdk['platforms'][cxx.target.platform]:
continue
Extension.extensions = builder.Add(project) binary = Extension.HL2ExtConfig(project, builder, cxx, projectName + '.ext.' + sdk['extension'], sdk)
Extension.extensions += builder.Add(project)

View File

@ -13,6 +13,11 @@ folder_list = [
#'addons/sourcemod/configs', #'addons/sourcemod/configs',
] ]
if 'x86_64' in Extension.target_archs:
folder_list.extend([
'addons/sourcemod/extensions/x64',
])
# Create the distribution folder hierarchy. # Create the distribution folder hierarchy.
folder_map = {} folder_map = {}
for folder in folder_list: for folder in folder_list:
@ -49,4 +54,7 @@ def CopyFiles(src, dest, files):
# Copy binaries. # Copy binaries.
for cxx_task in Extension.extensions: for cxx_task in Extension.extensions:
if cxx_task.target.arch == 'x86_64':
builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions/x64'])
else:
builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions']) builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions'])

View File

@ -4,20 +4,24 @@ from ambuild2 import run
# Simple extensions do not need to modify this file. # Simple extensions do not need to modify this file.
builder = run.PrepareBuild(sourcePath = sys.path[0]) parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
builder.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
help='Root search folder for HL2SDKs') help='Root search folder for HL2SDKs')
builder.options.add_option('--mms-path', type=str, dest='mms_path', default=None, parser.options.add_argument('--hl2sdk-manifest-path', type=str, dest='hl2sdk_manifest', default=None,
help='Path to Metamod:Source') help='Path to HL2SDK Manifests')
builder.options.add_option('--sm-path', type=str, dest='sm_path', default=None, parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
help='Path to SourceMod') help='Path to SourceMod')
builder.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
help='Enable debugging symbols') help='Path to Metamod:Source')
builder.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
help='Enable optimization') parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
builder.options.add_option('-s', '--sdks', default='all', dest='sdks', help='Enable debugging symbols')
help='Build against specified SDKs; valid args are "all", "present", or ' parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
'comma-delimited list of engine names (default: %default)') help='Enable optimization')
parser.options.add_argument('-s', '--sdks', default='present', dest='sdks',
help='Build against specified SDKs; valid args are "none", "all", "present",'
' or comma-delimited list of engine names')
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
help="Override the target architecture (use commas to separate multiple targets).")
parser.Configure()
builder.Configure()

View File

@ -24,6 +24,14 @@ def ResolveEnvPath(env, folder):
def Normalize(path): def Normalize(path):
return os.path.abspath(os.path.normpath(path)) return os.path.abspath(os.path.normpath(path))
def SetArchFlags(compiler):
if compiler.behavior == 'gcc':
if compiler.target.arch == 'x86_64':
compiler.cflags += ['-fPIC']
elif compiler.like('msvc'):
if compiler.target.arch == 'x86_64':
compiler.defines += ['WIN64']
class ExtensionConfig(object): class ExtensionConfig(object):
def __init__(self): def __init__(self):
self.binaries = [] self.binaries = []
@ -31,6 +39,28 @@ class ExtensionConfig(object):
self.generated_headers = None self.generated_headers = None
self.mms_root = None self.mms_root = None
self.sm_root = None self.sm_root = None
self.all_targets = []
self.target_archs = set()
if builder.options.targets:
target_archs = builder.options.targets.split(',')
else:
target_archs = ['x86', 'x86_64']
for arch in target_archs:
try:
cxx = builder.DetectCxx(target_arch = arch)
self.target_archs.add(cxx.target.arch)
except Exception as e:
# Error if archs were manually overridden.
if builder.options.targets:
raise
print('Skipping target {}: {}'.format(arch, e))
continue
self.all_targets.append(cxx)
if not self.all_targets:
raise Exception('No suitable C/C++ compiler was found.')
@property @property
def tag(self): def tag(self):
@ -39,25 +69,14 @@ class ExtensionConfig(object):
return 'Release' return 'Release'
def detectSDKs(self): def detectSDKs(self):
if builder.options.sm_path:
self.sm_root = builder.options.sm_path
else:
self.sm_root = ResolveEnvPath('SOURCEMOD18', 'sourcemod-1.8')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central')
if not self.sm_root or not os.path.isdir(self.sm_root):
raise Exception('Could not find a source copy of SourceMod')
self.sm_root = Normalize(self.sm_root)
if builder.options.mms_path: if builder.options.mms_path:
self.mms_root = builder.options.mms_path self.mms_root = builder.options.mms_path
else: else:
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12') self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
if not self.mms_root: if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root: if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
@ -65,12 +84,45 @@ class ExtensionConfig(object):
raise Exception('Could not find a source copy of Metamod:Source') raise Exception('Could not find a source copy of Metamod:Source')
self.mms_root = Normalize(self.mms_root) self.mms_root = Normalize(self.mms_root)
if builder.options.sm_path:
self.sm_root = builder.options.sm_path
else:
self.sm_root = ResolveEnvPath('SOURCEMOD112', 'sourcemod-1.12')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod')
if not self.sm_root:
self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central')
if not self.sm_root or not os.path.isdir(self.sm_root):
raise Exception('Could not find a source copy of SourceMod')
self.sm_root = Normalize(self.sm_root)
def configure(self): def configure(self):
cxx = builder.DetectCompilers()
allowed_archs = ['x86','x86_64']
if not set(self.target_archs).issubset(allowed_archs):
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
for cxx in self.all_targets:
self.configure_cxx(cxx)
def configure_cxx(self, cxx):
if cxx.family == 'msvc':
if cxx.version < 1914 and builder.options.generator != 'vs':
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
elif cxx.family == 'gcc':
if cxx.version < 'gcc-8':
raise Exception('Only GCC versions 8 or later are supported, full C++17 support is required.')
elif cxx.family == 'clang':
if cxx.version < 'clang-5':
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
if cxx.like('gcc'): if cxx.like('gcc'):
self.configure_gcc(cxx) self.configure_gcc(cxx)
elif cxx.vendor == 'msvc': elif cxx.family == 'msvc':
self.configure_msvc(cxx) self.configure_msvc(cxx)
# Optimization # Optimization
@ -82,18 +134,13 @@ class ExtensionConfig(object):
cxx.defines += ['DEBUG', '_DEBUG'] cxx.defines += ['DEBUG', '_DEBUG']
# Platform-specifics # Platform-specifics
if builder.target_platform == 'linux': if cxx.target.platform == 'linux':
self.configure_linux(cxx) self.configure_linux(cxx)
elif builder.target_platform == 'mac': elif cxx.target.platform == 'mac':
self.configure_mac(cxx) self.configure_mac(cxx)
elif builder.target_platform == 'windows': elif cxx.target.platform == 'windows':
self.configure_windows(cxx) self.configure_windows(cxx)
# Finish up.
cxx.includes += [
os.path.join(self.sm_root, 'public'),
]
def configure_gcc(self, cxx): def configure_gcc(self, cxx):
cxx.defines += [ cxx.defines += [
'stricmp=strcasecmp', 'stricmp=strcasecmp',
@ -111,46 +158,47 @@ class ExtensionConfig(object):
'-Wno-unused', '-Wno-unused',
'-Wno-switch', '-Wno-switch',
'-Wno-array-bounds', '-Wno-array-bounds',
'-msse',
'-m32',
'-fvisibility=hidden', '-fvisibility=hidden',
] ]
if cxx.target.arch in ['x86', 'x86_64']:
cxx.cflags += ['-msse']
cxx.cxxflags += [ cxx.cxxflags += [
'-std=c++14',
'-fno-exceptions',
'-fno-threadsafe-statics', '-fno-threadsafe-statics',
'-Wno-non-virtual-dtor', '-Wno-non-virtual-dtor',
'-Wno-overloaded-virtual', '-Wno-overloaded-virtual',
'-Wno-register',
'-fvisibility-inlines-hidden', '-fvisibility-inlines-hidden',
'-std=c++17',
] ]
cxx.linkflags += ['-m32']
have_gcc = cxx.vendor == 'gcc' have_gcc = cxx.family == 'gcc'
have_clang = cxx.vendor == 'clang' have_clang = cxx.family == 'clang'
if cxx.version >= 'clang-3.6':
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
if have_clang or (cxx.version >= 'gcc-4.6'):
cxx.cflags += ['-Wno-narrowing']
if have_clang or (cxx.version >= 'gcc-4.7'):
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
if cxx.version >= 'gcc-4.8':
cxx.cflags += ['-Wno-unused-result']
# Work around errors from smsdk_ext.cpp
if have_clang: if have_clang:
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
cxx.cxxflags += ['-Wno-deprecated-register'] # Work around SDK warnings.
else: if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
cxx.cxxflags += ['-Wno-deprecated'] cxx.cflags += [
cxx.cflags += ['-Wno-sometimes-uninitialized'] '-Wno-implicit-int-float-conversion',
'-Wno-tautological-overlap-compare',
]
if have_gcc: if have_gcc:
cxx.cflags += ['-mfpmath=sse'] cxx.cflags += ['-mfpmath=sse']
cxx.cflags += ['-Wno-maybe-uninitialized']
if builder.options.opt == '1': if builder.options.opt == '1':
cxx.cflags += ['-O3'] cxx.cflags += ['-O3']
# Don't omit the frame pointer.
cxx.cflags += ['-fno-omit-frame-pointer']
def configure_msvc(self, cxx): def configure_msvc(self, cxx):
if builder.options.debug == '1': if builder.options.debug == '1':
cxx.cflags += ['/MTd'] cxx.cflags += ['/MTd']
cxx.linkflags += ['/NODEFAULTLIB:libcmt'] cxx.linkflags += ['/NODEFAULTLIB:libcmt']
@ -169,9 +217,9 @@ class ExtensionConfig(object):
'/EHsc', '/EHsc',
'/GR-', '/GR-',
'/TP', '/TP',
'/std:c++17',
] ]
cxx.linkflags += [ cxx.linkflags += [
'/MACHINE:X86',
'kernel32.lib', 'kernel32.lib',
'user32.lib', 'user32.lib',
'gdi32.lib', 'gdi32.lib',
@ -198,23 +246,23 @@ class ExtensionConfig(object):
cxx.cflags += ['/Oy-'] cxx.cflags += ['/Oy-']
def configure_linux(self, cxx): def configure_linux(self, cxx):
cxx.defines += ['_LINUX', 'POSIX'] cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.linkflags += ['-Wl,--exclude-libs,ALL', '-lm'] cxx.linkflags += ['-lm']
if cxx.vendor == 'gcc': if cxx.family == 'gcc':
cxx.linkflags += ['-static-libgcc'] cxx.linkflags += ['-static-libgcc']
elif cxx.vendor == 'clang': elif cxx.family == 'clang':
cxx.linkflags += ['-lgcc_eh'] cxx.linkflags += ['-lgcc_eh']
cxx.linkflags += ['-static-libstdc++']
def configure_mac(self, cxx): def configure_mac(self, cxx):
cxx.defines += ['OSX', '_OSX', 'POSIX'] cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
cxx.cflags += ['-mmacosx-version-min=10.5'] cxx.cflags += ['-mmacosx-version-min=10.15']
cxx.linkflags += [ cxx.linkflags += [
'-mmacosx-version-min=10.5', '-mmacosx-version-min=10.15',
'-arch', 'i386', '-stdlib=libc++',
'-lstdc++', '-lc++',
'-stdlib=libstdc++',
] ]
cxx.cxxflags += ['-stdlib=libstdc++'] cxx.cxxflags += ['-stdlib=libc++']
def configure_windows(self, cxx): def configure_windows(self, cxx):
cxx.defines += ['WIN32', '_WINDOWS'] cxx.defines += ['WIN32', '_WINDOWS']
@ -233,26 +281,14 @@ class ExtensionConfig(object):
def ConfigureForHL2(self, binary): def ConfigureForHL2(self, binary):
compiler = binary.compiler compiler = binary.compiler
SetArchFlags(compiler)
mms_path = os.path.join(self.mms_root, 'core')
compiler.cxxincludes += [ compiler.cxxincludes += [
os.path.join(mms_path), os.path.join(self.mms_root, 'core'),
os.path.join(mms_path, 'sourcehook'), os.path.join(self.mms_root, 'core', 'sourcehook'),
] ]
compiler.defines += ['META_NO_HL2SDK'] compiler.defines += ['META_NO_HL2SDK']
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
else:
compiler.defines += ['COMPILER_GCC']
if builder.target_platform == 'linux':
compiler.linkflags += ['-lstdc++']
elif builder.target_platform == 'mac':
compiler.linkflags.append('-liconv')
return binary return binary
def HL2Library(self, context, name): def HL2Library(self, context, name):
@ -261,26 +297,26 @@ class ExtensionConfig(object):
return self.ConfigureForHL2(binary) return self.ConfigureForHL2(binary)
def HL2Project(self, context, name): def HL2Project(self, context, name):
project = context.compiler.LibraryProject(name) project = builder.LibraryProject(name)
self.ConfigureForExtension(context, project.compiler)
return project return project
def HL2Config(self, project, name): def HL2Config(self, context, project, name, compiler):
binary = project.Configure(name, '{0}'.format(self.tag)) binary = project.Configure(compiler, name, '{0} - {1}'.format(self.tag, compiler.target.arch))
self.ConfigureForExtension(context, binary.compiler)
return self.ConfigureForHL2(binary) return self.ConfigureForHL2(binary)
Extension = ExtensionConfig() Extension = ExtensionConfig()
Extension.detectSDKs() Extension.detectSDKs()
Extension.configure() Extension.configure()
# This will clone the list and each cxx object as we recurse, preventing child
# scripts from messing up global state.
builder.targets = builder.CloneableList(Extension.all_targets)
# Add additional buildscripts here # Add additional buildscripts here
BuildScripts = [ BuildScripts = [
'AMBuilder', 'AMBuilder',
'PackageScript',
] ]
if builder.backend == 'amb2': builder.Build(BuildScripts, { 'Extension': Extension })
BuildScripts += [
'PackageScript',
]
builder.RunBuildScripts(BuildScripts, { 'Extension': Extension})

View File

@ -23,6 +23,9 @@ else:
project.sources += sourceFiles project.sources += sourceFiles
binary = Extension.HL2Config(project, projectName + '.ext') for cxx in builder.targets:
binary = Extension.HL2Config(builder, project, projectName + '.ext', cxx)
Extension.extensions = builder.Add(project) Extension.extensions = builder.Add(project)

View File

@ -13,6 +13,11 @@ folder_list = [
#'addons/sourcemod/configs', #'addons/sourcemod/configs',
] ]
if 'x86_64' in Extension.target_archs:
folder_list.extend([
'addons/sourcemod/extensions/x64',
])
# Create the distribution folder hierarchy. # Create the distribution folder hierarchy.
folder_map = {} folder_map = {}
for folder in folder_list: for folder in folder_list:
@ -49,4 +54,8 @@ def CopyFiles(src, dest, files):
# Copy binaries. # Copy binaries.
for cxx_task in Extension.extensions: for cxx_task in Extension.extensions:
if cxx_task.target.arch == 'x86_64':
builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions/x64'])
else:
builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions']) builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions'])

View File

@ -4,15 +4,15 @@ from ambuild2 import run
# Simple extensions do not need to modify this file. # Simple extensions do not need to modify this file.
builder = run.PrepareBuild(sourcePath = sys.path[0]) parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
builder.options.add_option('--mms-path', type=str, dest='mms_path', default=None,
help='Path to Metamod:Source')
builder.options.add_option('--sm-path', type=str, dest='sm_path', default=None,
help='Path to SourceMod') help='Path to SourceMod')
builder.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
help='Path to Metamod:Source')
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
help='Enable debugging symbols') help='Enable debugging symbols')
builder.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
help='Enable optimization') help='Enable optimization')
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
builder.Configure() help="Override the target architecture (use commas to separate multiple targets).")
parser.Configure()

View File

@ -98,16 +98,25 @@ namespace detail
return key.hash(); return key.hash();
} }
}; };
struct IntHashMapPolicy
{
static inline bool matches(const int32_t lookup, const int32_t compare) {
return lookup == compare;
}
static inline uint32_t hash(const int32_t key) {
return ke::HashInt32(key);
}
};
} }
template <typename T> template <typename T, typename KeyStoreType, typename Policy, typename ContainerType, typename KeyLookupType>
class StringHashMap class HashMap
{ {
typedef detail::CharsAndLength CharsAndLength; typedef ke::HashMap<KeyStoreType, T, Policy> Internal;
typedef ke::HashMap<std::string, T, detail::StringHashMapPolicy> Internal;
public: public:
StringHashMap() HashMap()
: internal_(ke::SystemAllocatorPolicy()), : internal_(ke::SystemAllocatorPolicy()),
memory_used_(0) memory_used_(0)
{ {
@ -120,9 +129,9 @@ public:
typedef typename Internal::iterator iterator; typedef typename Internal::iterator iterator;
// Some KTrie-like helper functions. // Some KTrie-like helper functions.
bool retrieve(const char *aKey, T *aResult = NULL) bool retrieve(const KeyLookupType &aKey, T *aResult = NULL)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Result r = internal_.find(key); Result r = internal_.find(key);
if (!r.found()) if (!r.found())
return false; return false;
@ -131,9 +140,9 @@ public:
return true; return true;
} }
bool retrieve(const char *aKey, T **aResult) bool retrieve(const KeyLookupType &aKey, T **aResult)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Result r = internal_.find(key); Result r = internal_.find(key);
if (!r.found()) if (!r.found())
return false; return false;
@ -141,23 +150,23 @@ public:
return true; return true;
} }
Result find(const char *aKey) Result find(const KeyLookupType &aKey)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
return internal_.find(key); return internal_.find(key);
} }
bool contains(const char *aKey) bool contains(const KeyLookupType &aKey)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Result r = internal_.find(key); Result r = internal_.find(key);
return r.found(); return r.found();
} }
template <typename UV> template <typename UV>
bool replace(const char *aKey, UV &&value) bool replace(const KeyLookupType &aKey, UV &&value)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Insert i = internal_.findForAdd(key); Insert i = internal_.findForAdd(key);
if (!i.found()) if (!i.found())
{ {
@ -170,9 +179,9 @@ public:
} }
template <typename UV> template <typename UV>
bool insert(const char *aKey, UV &&value) bool insert(const KeyLookupType &aKey, UV &&value)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Insert i = internal_.findForAdd(key); Insert i = internal_.findForAdd(key);
if (i.found()) if (i.found())
return false; return false;
@ -182,9 +191,9 @@ public:
return true; return true;
} }
bool remove(const char *aKey) bool remove(const KeyLookupType &aKey)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
Result r = internal_.find(key); Result r = internal_.find(key);
if (!r.found()) if (!r.found())
return false; return false;
@ -219,9 +228,9 @@ public:
} }
Insert findForAdd(const char *aKey) Insert findForAdd(const KeyLookupType &aKey)
{ {
CharsAndLength key(aKey); ContainerType key(aKey);
return internal_.findForAdd(key); return internal_.findForAdd(key);
} }
@ -234,7 +243,7 @@ public:
} }
// Only value needs to be set after. // Only value needs to be set after.
bool add(Insert &i, const char *aKey) bool add(Insert &i, const KeyLookupType &aKey)
{ {
if (!internal_.add(i, aKey)) if (!internal_.add(i, aKey))
return false; return false;
@ -246,6 +255,12 @@ private:
size_t memory_used_; size_t memory_used_;
}; };
template <typename T>
using StringHashMap = HashMap<T, std::string, detail::StringHashMapPolicy, detail::CharsAndLength, const char *>;
template <typename T>
using IntHashMap = HashMap<T, int32_t, detail::IntHashMapPolicy, const int32_t, int32_t>;
} }
#endif // _include_sourcemod_hashtable_h_ #endif // _include_sourcemod_hashtable_h_

View File

@ -41,7 +41,7 @@
#include <am-allocator-policies.h> #include <am-allocator-policies.h>
#include <am-hashmap.h> #include <am-hashmap.h>
#include <am-string.h> #include <am-string.h>
#include "sm_stringhashmap.h" #include "sm_hashmap.h"
namespace SourceMod namespace SourceMod
{ {

View File

@ -50,7 +50,7 @@ a dead fish
ten clams, ten of them ten clams, ten of them
🐌🐌🐌🐌🐌🐌 🐌🐌🐌🐌🐌🐌
rum ham rum ham
scrambled eggs scrambled eggs with a lack of soop
EXCEPTION EXCEPTION
erin make me touch this erin make me touch this
a newline embiggens the noblest of files a newline embiggens the noblest of files
@ -78,3 +78,4 @@ travis stole my shoe, once.
I love my anime wife. I love my anime wife.
Make the world your clam Make the world your clam
you guys ever have gay thoughts you guys ever have gay thoughts
quick before sappho gets mad!

@ -1 +1 @@
Subproject commit d59a51b5741823903ecbe8c014632ee1f8aad65d Subproject commit 91397a3ff3d6807808ff5e0c4772bdef357099f3

View File

@ -64,13 +64,13 @@ if [ $ismac -eq 1 ]; then
mysqlver=mysql-5.5.28-osx10.5-x86 mysqlver=mysql-5.5.28-osx10.5-x86
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
elif [ $iswin -eq 1 ]; then elif [ $iswin -eq 1 ]; then
mysqlver=mysql-5.5.54-win32 mysqlver=mysql-5.5.62-win32
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
# The folder in the zip archive does not contain the substring "-noinstall", so strip it # The folder in the zip archive does not contain the substring "-noinstall", so strip it
mysqlver=${mysqlver/-noinstall} mysqlver=${mysqlver/-noinstall}
else else
mysqlver=mysql-5.6.15-linux-glibc2.5-i686 mysqlver=mysql-5.7.44-linux-glibc2.12-i686
mysqlurl=https://cdn.mysql.com/archives/mysql-5.6/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.7/$mysqlver.$archive_ext
fi fi
if [ $download_mysql -eq 1 ]; then if [ $download_mysql -eq 1 ]; then
getmysql getmysql
@ -82,11 +82,11 @@ if [ $ismac -eq 1 ]; then
mysqlver=mysql-5.5.28-osx10.5-x86_64 mysqlver=mysql-5.5.28-osx10.5-x86_64
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
elif [ $iswin -eq 1 ]; then elif [ $iswin -eq 1 ]; then
mysqlver=mysql-5.5.54-winx64 mysqlver=mysql-5.5.62-winx64
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
else else
mysqlver=mysql-5.6.15-linux-glibc2.5-x86_64 mysqlver=mysql-5.7.44-linux-glibc2.12-x86_64
mysqlurl=https://cdn.mysql.com/archives/mysql-5.6/$mysqlver.$archive_ext mysqlurl=https://cdn.mysql.com/archives/mysql-5.7/$mysqlver.$archive_ext
fi fi
if [ $download_mysql -eq 1 ]; then if [ $download_mysql -eq 1 ]; then
getmysql getmysql