mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-07 02:18:35 +00:00
Merge branch 'master' into dhooks-update
This commit is contained in:
commit
a2626537b1
10
.github/workflows/scripting.yml
vendored
10
.github/workflows/scripting.yml
vendored
@ -14,14 +14,12 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
os_short: linux
|
||||
- os: windows-latest
|
||||
os_short: win
|
||||
- os: macos-latest
|
||||
os_short: mac
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
@ -41,10 +39,6 @@ jobs:
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
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
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
@ -56,7 +50,7 @@ jobs:
|
||||
linux-libc-dev:i386 lib32z1-dev ${{ matrix.compiler_cc }}
|
||||
|
||||
- name: Select clang compiler
|
||||
if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS')
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
run: |
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "CXX=clang++" >> $GITHUB_ENV
|
||||
|
||||
@ -129,6 +129,8 @@ class SMConfig(object):
|
||||
self.mms_root = builder.options.mms_path
|
||||
else:
|
||||
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:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||
if not self.mms_root:
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include <am-inlinelist.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <am-utility.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
#include <compat_wrappers.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "PlayerManager.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
namespace SourceMod {
|
||||
class ICommandArgs;
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <ITextParsers.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <am-string.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include <am-utility.h>
|
||||
#include <am-hashset.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sm_queue.h"
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
#include <IUserMessages.h>
|
||||
#include "sourcemm_api.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "CellRecipientFilter.h"
|
||||
#include "sm_globals.h"
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
#include <IADTFactory.h>
|
||||
#include "common_logic.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <IGameConfigs.h>
|
||||
#include <ITextParsers.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <am-string.h>
|
||||
#include <am-utility.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "common_logic.h"
|
||||
|
||||
class CNativeOwner;
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
#include <sh_string.h>
|
||||
#include "common_logic.h"
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "ITranslator.h"
|
||||
#include "IGameConfigs.h"
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include <am-utility.h>
|
||||
#include <am-refcounting.h>
|
||||
#include <sh_list.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sm_namehashset.h>
|
||||
#include "common_logic.h"
|
||||
#include "Native.h"
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#define _INCLUDE_SOURCEMOD_TRANSLATOR_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_memtable.h"
|
||||
|
||||
@ -35,12 +35,14 @@
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <am-refcounting.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#include "sm_memtable.h"
|
||||
#include <IHandleSys.h>
|
||||
|
||||
HandleType_t htCellTrie;
|
||||
HandleType_t htSnapshot;
|
||||
HandleType_t htIntCellTrie;
|
||||
HandleType_t htIntSnapshot;
|
||||
|
||||
enum EntryType
|
||||
{
|
||||
@ -171,6 +173,11 @@ struct CellTrie
|
||||
StringHashMap<Entry> map;
|
||||
};
|
||||
|
||||
struct IntCellTrie
|
||||
{
|
||||
IntHashMap<Entry> map;
|
||||
};
|
||||
|
||||
struct TrieSnapshot
|
||||
{
|
||||
TrieSnapshot()
|
||||
@ -187,6 +194,19 @@ struct TrieSnapshot
|
||||
BaseStringTable strings;
|
||||
};
|
||||
|
||||
struct IntTrieSnapshot
|
||||
{
|
||||
IntTrieSnapshot() {}
|
||||
|
||||
size_t mem_usage()
|
||||
{
|
||||
return length * sizeof(int);
|
||||
}
|
||||
|
||||
size_t length;
|
||||
std::unique_ptr<int[]> keys;
|
||||
};
|
||||
|
||||
class TrieHelpers :
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
@ -196,11 +216,15 @@ public: //SMGlobalClass
|
||||
{
|
||||
htCellTrie = handlesys->CreateType("Trie", 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()
|
||||
{
|
||||
handlesys->RemoveType(htSnapshot, g_pCoreIdent);
|
||||
handlesys->RemoveType(htCellTrie, g_pCoreIdent);
|
||||
handlesys->RemoveType(htIntSnapshot, g_pCoreIdent);
|
||||
handlesys->RemoveType(htIntCellTrie, g_pCoreIdent);
|
||||
}
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object)
|
||||
@ -208,10 +232,21 @@ public: //IHandleTypeDispatch
|
||||
if (type == htCellTrie)
|
||||
{
|
||||
delete (CellTrie *)object;
|
||||
} else {
|
||||
}
|
||||
else if (type == htSnapshot)
|
||||
{
|
||||
TrieSnapshot *snapshot = (TrieSnapshot *)object;
|
||||
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)
|
||||
{
|
||||
@ -219,12 +254,29 @@ public: //IHandleTypeDispatch
|
||||
{
|
||||
CellTrie *pArray = (CellTrie *)object;
|
||||
*pSize = sizeof(CellTrie) + pArray->map.mem_usage();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else if (type == htSnapshot)
|
||||
{
|
||||
TrieSnapshot *snapshot = (TrieSnapshot *)object;
|
||||
*pSize = sizeof(TrieSnapshot) + snapshot->mem_usage();
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -275,6 +342,38 @@ static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -316,6 +415,46 @@ static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -350,6 +489,40 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -371,6 +544,26 @@ static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
CellTrie *pTrie;
|
||||
@ -396,6 +589,30 @@ static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -415,6 +632,25 @@ static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -457,6 +693,47 @@ static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -509,6 +786,56 @@ static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -545,6 +872,41 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
Handle_t hndl;
|
||||
@ -563,6 +925,24 @@ static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
HandleError err;
|
||||
@ -595,6 +975,38 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
HandleError err;
|
||||
@ -612,6 +1024,23 @@ static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
HandleError err;
|
||||
@ -657,6 +1086,27 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
HandleError err;
|
||||
@ -707,6 +1157,56 @@ static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params)
|
||||
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)
|
||||
{
|
||||
{"ClearTrie", ClearTrie},
|
||||
@ -740,9 +1240,26 @@ REGISTER_NATIVES(trieNatives)
|
||||
{"StringMap.Snapshot", CreateTrieSnapshot},
|
||||
{"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.KeyBufferSize", TrieSnapshotKeyBufferSize},
|
||||
{"StringMapSnapshot.GetKey", GetTrieSnapshotKey},
|
||||
|
||||
{"IntMapSnapshot.Length.get", IntTrieSnapshotLength},
|
||||
{"IntMapSnapshot.GetKey", GetIntTrieSnapshotKey},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
@ -119,6 +119,7 @@ REGISTER_NATIVES(handles)
|
||||
{"CloseHandle", sm_CloseHandle},
|
||||
{"CloneHandle", sm_CloneHandle},
|
||||
{"GetMyHandle", sm_GetMyHandle},
|
||||
{"Handle.Clone", sm_CloneHandle},
|
||||
{"Handle.Close", sm_CloseHandle},
|
||||
{"Handle.~Handle", sm_CloseHandle},
|
||||
{NULL, NULL},
|
||||
|
||||
@ -42,27 +42,22 @@ for cxx in builder.targets:
|
||||
'util.cpp',
|
||||
'dynhooks_sourcepawn.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
|
||||
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':
|
||||
binary.sources += ['../../sourcepawn/vm/x86/assembler-x86.cpp']
|
||||
|
||||
binary.compiler.cxxincludes += [
|
||||
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
|
||||
os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86')
|
||||
]
|
||||
# DynamicHooks
|
||||
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', 'x86MsStdcall.cpp'),
|
||||
os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'),
|
||||
@ -77,6 +72,16 @@ for cxx in builder.targets:
|
||||
binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR']
|
||||
|
||||
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)]
|
||||
|
||||
@ -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();
|
||||
}
|
||||
@ -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
|
||||
@ -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.
|
||||
*/
|
||||
@ -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.
|
||||
*/
|
||||
@ -35,13 +35,16 @@
|
||||
// >> INCLUDES
|
||||
// ============================================================================
|
||||
#include "hook.h"
|
||||
#include <asm/asm.h>
|
||||
#include <macro-assembler-x86.h>
|
||||
#include "extension.h"
|
||||
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
|
||||
#else
|
||||
#include <macro-assembler-x86.h>
|
||||
#include <jit/jit_helpers.h>
|
||||
#include <CDetour/detourhelpers.h>
|
||||
|
||||
using namespace sp;
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// >> DEFINITIONS
|
||||
@ -64,45 +67,31 @@ CHook::CHook(void* pFunc, ICallingConvention* pConvention)
|
||||
if (!m_RetAddr.init())
|
||||
return;
|
||||
|
||||
unsigned char* pTarget = (unsigned char *) pFunc;
|
||||
CreateBridge();
|
||||
if (!m_pBridge)
|
||||
return;
|
||||
|
||||
// Determine the number of bytes we need to copy
|
||||
int iBytesToCopy = copy_bytes(pTarget, NULL, JMP_SIZE);
|
||||
auto result = safetyhook::InlineHook::create(pFunc, m_pBridge, safetyhook::InlineHook::Flags::StartDisabled);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for the bytes to copy + a jump to the rest of the
|
||||
// function.
|
||||
unsigned char* pCopiedBytes = (unsigned char *) smutils->GetScriptingEngine()->AllocatePageMemory(iBytesToCopy + JMP_SIZE);
|
||||
m_Hook = std::move(result.value());
|
||||
m_pTrampoline = m_Hook.original<void*>();
|
||||
|
||||
// Fill the array with NOP instructions
|
||||
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);
|
||||
m_Hook.enable();
|
||||
}
|
||||
|
||||
CHook::~CHook()
|
||||
{
|
||||
// Copy back the previously copied bytes
|
||||
copy_bytes((unsigned char *) m_pTrampoline, (unsigned char *) m_pFunc, JMP_SIZE);
|
||||
if (m_Hook.enabled()) {
|
||||
m_Hook.disable();
|
||||
}
|
||||
|
||||
// Free the trampoline buffer
|
||||
smutils->GetScriptingEngine()->FreePageMemory(m_pTrampoline);
|
||||
|
||||
// Free the asm bridge and new return address
|
||||
if (m_pBridge) {
|
||||
smutils->GetScriptingEngine()->FreePageMemory(m_pBridge);
|
||||
smutils->GetScriptingEngine()->FreePageMemory(m_pNewRetAddr);
|
||||
}
|
||||
|
||||
delete m_pRegisters;
|
||||
delete m_pCallingConvention;
|
||||
@ -229,7 +218,392 @@ void __cdecl CHook::SetReturnAddress(void* pRetAddr, void* pESP)
|
||||
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;
|
||||
Label label_supercede;
|
||||
@ -247,7 +621,8 @@ void* CHook::CreateBridge()
|
||||
masm.j(equal, &label_supercede);
|
||||
|
||||
// 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
|
||||
masm.bind(&label_supercede);
|
||||
@ -256,9 +631,9 @@ void* CHook::CreateBridge()
|
||||
// This will still call post hooks, but will skip the original function.
|
||||
masm.ret(m_pCallingConvention->GetPopSize());
|
||||
|
||||
void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
|
||||
void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
|
||||
masm.emitToExecutableMemory(base);
|
||||
return base;
|
||||
m_pBridge = base;
|
||||
}
|
||||
|
||||
void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm)
|
||||
@ -290,11 +665,11 @@ void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm)
|
||||
masm.movl(edx, Operand(ExternalAddress(&pEDX)));
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
void* CHook::CreatePostCallback()
|
||||
void CHook::CreatePostCallback()
|
||||
{
|
||||
sp::MacroAssembler masm;
|
||||
|
||||
@ -342,9 +717,9 @@ void* CHook::CreatePostCallback()
|
||||
masm.jmp(Operand(ExternalAddress(&pRetAddr)));
|
||||
|
||||
// Generate the code
|
||||
void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
|
||||
void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length());
|
||||
masm.emitToExecutableMemory(base);
|
||||
return base;
|
||||
m_pNewRetAddr = base;
|
||||
}
|
||||
|
||||
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
|
||||
@ -41,6 +41,22 @@
|
||||
#include "convention.h"
|
||||
#include <am-hashmap.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
|
||||
@ -173,14 +189,23 @@ public:
|
||||
}
|
||||
|
||||
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_CallHandler(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* CreatePostCallback();
|
||||
#endif
|
||||
|
||||
ReturnAction_t __cdecl HookHandler(HookType_t type);
|
||||
|
||||
@ -196,6 +221,9 @@ public:
|
||||
|
||||
ICallingConvention* m_pCallingConvention;
|
||||
|
||||
// SafetyHook
|
||||
SafetyHookInline m_Hook{};
|
||||
|
||||
// Address of the bridge
|
||||
void* m_pBridge;
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
|
||||
// >> 64-bit General purpose registers
|
||||
// ========================================================================
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
m_rax = CreateRegister(registers, RAX, 8);
|
||||
m_rcx = CreateRegister(registers, RCX, 8);
|
||||
m_rdx = CreateRegister(registers, RDX, 8);
|
||||
@ -279,7 +279,7 @@ CRegisters::~CRegisters()
|
||||
// >> 64-bit General purpose registers
|
||||
// ========================================================================
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
DeleteRegister(m_rax);
|
||||
DeleteRegister(m_rcx);
|
||||
DeleteRegister(m_rdx);
|
||||
@ -325,7 +325,7 @@ CRegisters::~CRegisters()
|
||||
DeleteRegister(m_xmm7);
|
||||
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
DeleteRegister(m_xmm8);
|
||||
DeleteRegister(m_xmm9);
|
||||
DeleteRegister(m_xmm10);
|
||||
@ -434,6 +434,42 @@ CRegister* CRegisters::GetRegister(Register_t reg)
|
||||
case 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:
|
||||
return m_mm0;
|
||||
case MM1:
|
||||
@ -468,6 +504,25 @@ CRegister* CRegisters::GetRegister(Register_t reg)
|
||||
case 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:
|
||||
return m_cs;
|
||||
case SS:
|
||||
@ -499,6 +554,6 @@ CRegister* CRegisters::GetRegister(Register_t reg)
|
||||
return m_st7;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -132,7 +132,7 @@ enum Register_t
|
||||
// ========================================================================
|
||||
// >> 64-bit General purpose registers
|
||||
// ========================================================================
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
RAX,
|
||||
RCX,
|
||||
RDX,
|
||||
@ -177,7 +177,7 @@ enum Register_t
|
||||
XMM7,
|
||||
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
XMM8,
|
||||
XMM9,
|
||||
XMM10,
|
||||
@ -373,7 +373,7 @@ public:
|
||||
// >> 64-bit General purpose registers
|
||||
// ========================================================================
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
CRegister* m_rax;
|
||||
CRegister* m_rcx;
|
||||
CRegister* m_rdx;
|
||||
@ -418,7 +418,7 @@ public:
|
||||
CRegister* m_xmm7;
|
||||
|
||||
// 64-bit mode only
|
||||
#ifdef PLATFORM_X64
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
CRegister* m_xmm8;
|
||||
CRegister* m_xmm9;
|
||||
CRegister* m_xmm10;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -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
|
||||
@ -34,6 +34,10 @@
|
||||
#include <memory>
|
||||
|
||||
#ifdef KE_WINDOWS
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
#include "conventions/x86_64MicrosoftDefault.h"
|
||||
typedef x86_64MicrosoftDefault x86_64DetourCall;
|
||||
#else
|
||||
#include "conventions/x86MsCdecl.h"
|
||||
#include "conventions/x86MsThiscall.h"
|
||||
#include "conventions/x86MsStdcall.h"
|
||||
@ -42,7 +46,10 @@ typedef x86MsCdecl x86DetourCdecl;
|
||||
typedef x86MsThiscall x86DetourThisCall;
|
||||
typedef x86MsStdcall x86DetourStdCall;
|
||||
typedef x86MsFastcall x86DetourFastCall;
|
||||
#endif
|
||||
#elif defined KE_LINUX
|
||||
#ifdef DYNAMICHOOKS_x86_64
|
||||
#else
|
||||
#include "conventions/x86GccCdecl.h"
|
||||
#include "conventions/x86GccThiscall.h"
|
||||
#include "conventions/x86MsStdcall.h"
|
||||
@ -53,6 +60,7 @@ typedef x86GccThiscall x86DetourThisCall;
|
||||
typedef x86MsStdcall x86DetourStdCall;
|
||||
// Uhumm, fastcall on linux?
|
||||
typedef x86MsFastcall x86DetourFastCall;
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported platform."
|
||||
#endif
|
||||
@ -246,9 +254,29 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
|
||||
// TODO: Add support for a custom return register.
|
||||
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;
|
||||
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:
|
||||
pCallConv = new x86DetourCdecl(vecArgTypes, returnType);
|
||||
break;
|
||||
@ -261,6 +289,7 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
|
||||
case CallConv_FASTCALL:
|
||||
pCallConv = new x86DetourFastCall(vecArgTypes, returnType);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
smutils->LogError(myself, "Unknown calling convention %d.", setup->callConv);
|
||||
break;
|
||||
@ -624,7 +653,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct()
|
||||
|
||||
// Save the old parameters passed in a register.
|
||||
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.
|
||||
if (argTypes[i].custom_register == None)
|
||||
@ -633,7 +662,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct()
|
||||
size_t size = argTypes[i].size;
|
||||
// Register argument values are saved after all stack arguments in this buffer.
|
||||
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);
|
||||
offset += size;
|
||||
}
|
||||
@ -656,7 +685,6 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params)
|
||||
// TODO: Support custom register for this ptr.
|
||||
if (callConv == CallConv_THISCALL)
|
||||
firstArg = 1;
|
||||
|
||||
size_t stackOffset = 0;
|
||||
// Values of arguments stored in registers are saved after the stack arguments.
|
||||
size_t registerOffset = stackSize;
|
||||
@ -676,9 +704,15 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params)
|
||||
}
|
||||
|
||||
// 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;
|
||||
else
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
registerOffset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
*/
|
||||
@ -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
@ -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 */
|
||||
@ -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
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
@ -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_ */
|
||||
@ -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 */
|
||||
@ -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
|
||||
@ -73,12 +73,22 @@ SMCResult SignatureGameConfig::ReadSMC_NewSection(const SMCStates *states, const
|
||||
}
|
||||
|
||||
// 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 (!strcmp(name, "windows"))
|
||||
#elif defined _LINUX
|
||||
if (!strcmp(name, "linux"))
|
||||
#elif defined _OSX
|
||||
if (!strcmp(name, "mac"))
|
||||
#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.
|
||||
@ -99,13 +109,8 @@ SMCResult SignatureGameConfig::ReadSMC_NewSection(const SMCStates *states, const
|
||||
g_PlatformOnlyState = g_ParseState;
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
#if defined WIN32
|
||||
else if (!strcmp(name, "linux") || !strcmp(name, "mac"))
|
||||
#elif defined _LINUX
|
||||
else if (!strcmp(name, "windows") || !strcmp(name, "mac"))
|
||||
#elif defined _OSX
|
||||
else if (!strcmp(name, "windows") || !strcmp(name, "linux"))
|
||||
#endif
|
||||
else if (!strcmp(name, "windows") || !strcmp(name, "linux") || !strcmp(name, "mac")
|
||||
|| !strcmp(name, "windows64") || !strcmp(name, "linux64") || !strcmp(name, "mac64"))
|
||||
{
|
||||
if (g_PlatformOnlyState != PState_None)
|
||||
{
|
||||
@ -565,6 +570,42 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str)
|
||||
else if (!strcmp(str, "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"))
|
||||
return MM0;
|
||||
else if (!strcmp(str, "mm1"))
|
||||
@ -599,6 +640,25 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str)
|
||||
else if (!strcmp(str, "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"))
|
||||
return CS;
|
||||
else if (!strcmp(str, "ss"))
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include "util.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
|
||||
struct ArgumentInfo {
|
||||
ArgumentInfo() : name()
|
||||
|
||||
@ -53,34 +53,12 @@ using namespace sp;
|
||||
|
||||
#ifdef PLATFORM_X64
|
||||
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)
|
||||
{
|
||||
auto masm = new x64JitWriter();
|
||||
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
|
||||
masm->push(rbp);
|
||||
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
#include "data-pool.h"
|
||||
#include "maxminddb.h"
|
||||
|
||||
@ -5,8 +9,6 @@
|
||||
#include <stddef.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
|
||||
// MMDB_entry_data_list_s structs.
|
||||
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.
|
||||
//
|
||||
// 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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ typedef struct MMDB_data_pool_s {
|
||||
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
|
||||
} 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);
|
||||
void data_pool_destroy(MMDB_data_pool_s *const);
|
||||
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);
|
||||
|
||||
@ -42,9 +42,9 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
static void *
|
||||
static const void *
|
||||
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 *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);
|
||||
|
||||
/* 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)
|
||||
return cur;
|
||||
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "data-pool.h"
|
||||
#include "maxminddb-compat-util.h"
|
||||
#include "maxminddb.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -19,6 +23,10 @@
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <ws2ipdef.h>
|
||||
#ifndef SSIZE_MAX
|
||||
#define SSIZE_MAX INTPTR_MAX
|
||||
#endif
|
||||
typedef ADDRESS_FAMILY sa_family_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/mman.h>
|
||||
@ -152,7 +160,7 @@ static int populate_description_metadata(MMDB_s *mmdb,
|
||||
MMDB_entry_s *metadata_start);
|
||||
static int resolve_any_address(const char *ipstr, struct addrinfo **addresses);
|
||||
static int find_address_in_search_tree(const MMDB_s *const mmdb,
|
||||
uint8_t *address,
|
||||
uint8_t const *address,
|
||||
sa_family_t address_family,
|
||||
MMDB_lookup_result_s *result);
|
||||
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 data_section_offset_for_record(const MMDB_s *const mmdb,
|
||||
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,
|
||||
const MMDB_s *const mmdb,
|
||||
MMDB_entry_data_s *entry_data);
|
||||
@ -201,7 +209,7 @@ dump_entry_data_list(FILE *stream,
|
||||
int indent,
|
||||
int *status);
|
||||
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) \
|
||||
do { \
|
||||
@ -284,18 +292,29 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint32_t search_tree_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) {
|
||||
if (!can_multiply(SSIZE_MAX,
|
||||
mmdb->metadata.node_count,
|
||||
mmdb->full_record_byte_size)) {
|
||||
status = MMDB_INVALID_METADATA_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
mmdb->data_section_size = (uint32_t)mmdb->file_size - search_tree_size -
|
||||
MMDB_DATA_SECTION_SEPARATOR;
|
||||
ssize_t search_tree_size = (ssize_t)mmdb->metadata.node_count *
|
||||
(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
|
||||
// valid metadata, as parsed above, and a data_section_size less than 3,
|
||||
@ -406,28 +425,39 @@ cleanup:;
|
||||
#else // _WIN32
|
||||
|
||||
static int map_file(MMDB_s *const mmdb) {
|
||||
ssize_t size;
|
||||
int status = MMDB_SUCCESS;
|
||||
|
||||
int flags = O_RDONLY;
|
||||
int o_flags = O_RDONLY;
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
o_flags |= O_CLOEXEC;
|
||||
#endif
|
||||
int fd = open(mmdb->filename, flags);
|
||||
struct stat s;
|
||||
if (fd < 0 || fstat(fd, &s)) {
|
||||
int fd = open(mmdb->filename, o_flags);
|
||||
if (fd < 0) {
|
||||
status = MMDB_FILE_OPEN_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size = s.st_size;
|
||||
if (size < 0 || size != s.st_size) {
|
||||
#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
|
||||
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;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
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 (ENOMEM == errno) {
|
||||
status = MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -437,7 +467,7 @@ static int map_file(MMDB_s *const mmdb) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mmdb->file_size = size;
|
||||
mmdb->file_size = (ssize_t)size;
|
||||
mmdb->file_content = file_content;
|
||||
|
||||
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
|
||||
? METADATA_BLOCK_MAX_SIZE
|
||||
: file_size;
|
||||
if (max_size < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size));
|
||||
uint8_t *start = search_area;
|
||||
uint8_t *tmp;
|
||||
uint8_t const *search_area = (file_content + (file_size - max_size));
|
||||
uint8_t const *start = search_area;
|
||||
uint8_t const *tmp;
|
||||
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) {
|
||||
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));
|
||||
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) {
|
||||
return MMDB_OUT_OF_MEMORY_ERROR;
|
||||
}
|
||||
@ -719,9 +753,8 @@ static int populate_languages_metadata(MMDB_s *mmdb,
|
||||
return MMDB_INVALID_METADATA_ERROR;
|
||||
}
|
||||
|
||||
mmdb->metadata.languages.names[i] =
|
||||
mmdb_strndup((char *)member->entry_data.utf8_string,
|
||||
member->entry_data.data_size);
|
||||
mmdb->metadata.languages.names[i] = mmdb_strndup(
|
||||
member->entry_data.utf8_string, member->entry_data.data_size);
|
||||
|
||||
if (NULL == mmdb->metadata.languages.names[i]) {
|
||||
return MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -803,9 +836,8 @@ static int populate_description_metadata(MMDB_s *mmdb,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mmdb->metadata.description.descriptions[i]->language =
|
||||
mmdb_strndup((char *)member->entry_data.utf8_string,
|
||||
member->entry_data.data_size);
|
||||
mmdb->metadata.description.descriptions[i]->language = mmdb_strndup(
|
||||
member->entry_data.utf8_string, member->entry_data.data_size);
|
||||
|
||||
if (NULL == mmdb->metadata.description.descriptions[i]->language) {
|
||||
status = MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -819,9 +851,8 @@ static int populate_description_metadata(MMDB_s *mmdb,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mmdb->metadata.description.descriptions[i]->description =
|
||||
mmdb_strndup((char *)member->entry_data.utf8_string,
|
||||
member->entry_data.data_size);
|
||||
mmdb->metadata.description.descriptions[i]->description = mmdb_strndup(
|
||||
member->entry_data.utf8_string, member->entry_data.data_size);
|
||||
|
||||
if (NULL == mmdb->metadata.description.descriptions[i]->description) {
|
||||
status = MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -879,22 +910,24 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
|
||||
.netmask = 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 (sockaddr->sa_family == AF_INET6) {
|
||||
*mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR;
|
||||
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 {
|
||||
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;
|
||||
} else {
|
||||
address = mapped_address;
|
||||
memset(address, 0, 12);
|
||||
memcpy(address + 12,
|
||||
&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr,
|
||||
memset(mapped_address, 0, 12);
|
||||
memcpy(mapped_address + 12,
|
||||
&((struct sockaddr_in const *)sockaddr)->sin_addr.s_addr,
|
||||
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,
|
||||
uint8_t *address,
|
||||
uint8_t const *address,
|
||||
sa_family_t address_family,
|
||||
MMDB_lookup_result_s *result) {
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t value = 0;
|
||||
uint64_t value = 0;
|
||||
uint16_t current_bit = 0;
|
||||
if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) {
|
||||
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 =
|
||||
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];
|
||||
if (record_pointer + record_info.record_length > mmdb->data_section) {
|
||||
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.right_record_getter = &get_uint32;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -990,6 +1025,9 @@ static int find_ipv4_start_node(MMDB_s *const 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;
|
||||
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) {
|
||||
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) {
|
||||
@ -1052,7 +1090,7 @@ int MMDB_read_node(const MMDB_s *const mmdb,
|
||||
uint32_t node_number,
|
||||
MMDB_search_node_s *const node) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1104,13 +1142,13 @@ int MMDB_get_value(MMDB_entry_s *const start,
|
||||
int MMDB_vget_value(MMDB_entry_s *const start,
|
||||
MMDB_entry_data_s *const entry_data,
|
||||
va_list va_path) {
|
||||
int length = path_length(va_path);
|
||||
size_t length = path_length(va_path);
|
||||
const char *path_elem;
|
||||
int i = 0;
|
||||
|
||||
MAYBE_CHECK_SIZE_OVERFLOW(length,
|
||||
SIZE_MAX / sizeof(const char *) - 1,
|
||||
MMDB_INVALID_METADATA_ERROR);
|
||||
if (length == SIZE_MAX) {
|
||||
return MMDB_INVALID_METADATA_ERROR;
|
||||
}
|
||||
|
||||
const char **path = calloc(length + 1, sizeof(const char *));
|
||||
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);
|
||||
|
||||
free((char **)path);
|
||||
free(path);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int path_length(va_list va_path) {
|
||||
int i = 0;
|
||||
const char *ignore;
|
||||
static size_t path_length(va_list va_path) {
|
||||
size_t i = 0;
|
||||
va_list path_copy;
|
||||
va_copy(path_copy, va_path);
|
||||
|
||||
while (NULL != (ignore = va_arg(path_copy, char *))) {
|
||||
while (NULL != va_arg(path_copy, char *)) {
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -1209,7 +1246,7 @@ static int lookup_path_in_array(const char *path_elem,
|
||||
|
||||
int saved_errno = errno;
|
||||
errno = 0;
|
||||
int array_index = strtol(path_elem, &first_invalid, 10);
|
||||
long array_index = strtol(path_elem, &first_invalid, 10);
|
||||
if (ERANGE == errno) {
|
||||
errno = saved_errno;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* pointer we simply skip it and keep going */
|
||||
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));
|
||||
}
|
||||
|
||||
entry_data->type = type;
|
||||
entry_data->type = (uint32_t)type;
|
||||
|
||||
if (type == MMDB_DATA_TYPE_POINTER) {
|
||||
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]);
|
||||
offset += 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1485,28 +1523,28 @@ static int decode_one(const MMDB_s *const mmdb,
|
||||
DEBUG_MSGF("uint16 of size %d", size);
|
||||
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);
|
||||
} else if (type == MMDB_DATA_TYPE_UINT32) {
|
||||
if (size > 4) {
|
||||
DEBUG_MSGF("uint32 of size %d", size);
|
||||
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);
|
||||
} else if (type == MMDB_DATA_TYPE_INT32) {
|
||||
if (size > 4) {
|
||||
DEBUG_MSGF("int32 of size %d", size);
|
||||
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);
|
||||
} else if (type == MMDB_DATA_TYPE_UINT64) {
|
||||
if (size > 8) {
|
||||
DEBUG_MSGF("uint64 of size %d", size);
|
||||
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);
|
||||
} else if (type == MMDB_DATA_TYPE_UINT128) {
|
||||
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);
|
||||
}
|
||||
#else
|
||||
entry_data->uint128 = get_uint128(&mem[offset], size);
|
||||
entry_data->uint128 = get_uint128(&mem[offset], (int)size);
|
||||
#endif
|
||||
} else if (type == MMDB_DATA_TYPE_FLOAT) {
|
||||
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]);
|
||||
DEBUG_MSGF("double value: %f", entry_data->double_value);
|
||||
} 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;
|
||||
#ifdef MMDB_DEBUG
|
||||
char *string =
|
||||
@ -1566,13 +1604,15 @@ get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size) {
|
||||
uint32_t new_offset;
|
||||
switch (ptr_size) {
|
||||
case 1:
|
||||
new_offset = ((ctrl & 7) << 8) + ptr[0];
|
||||
new_offset = (uint32_t)((ctrl & 7) << 8) + ptr[0];
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
case 4:
|
||||
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) {
|
||||
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
|
||||
* little-endian. */
|
||||
#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) {
|
||||
volatile double d;
|
||||
uint8_t *q = (void *)&d;
|
||||
volatile uint8_t *q = (volatile void *)&d;
|
||||
#if MMDB_LITTLE_ENDIAN || _WIN32
|
||||
q[7] = p[0];
|
||||
q[6] = p[1];
|
||||
@ -1791,7 +1831,16 @@ static void free_mmdb_struct(MMDB_s *const mmdb) {
|
||||
}
|
||||
|
||||
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);
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
if (NULL != mmdb->file_content) {
|
||||
#ifdef _WIN32
|
||||
@ -1800,12 +1849,30 @@ static void free_mmdb_struct(MMDB_s *const mmdb) {
|
||||
* to cleanup then. */
|
||||
WSACleanup();
|
||||
#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
|
||||
}
|
||||
|
||||
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);
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
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++) {
|
||||
#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]);
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
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++) {
|
||||
if (NULL != mmdb->metadata.description.descriptions[i]) {
|
||||
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(
|
||||
mmdb->metadata.description.descriptions[i]->language);
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
if (NULL !=
|
||||
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(
|
||||
mmdb->metadata.description.descriptions[i]->description);
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]);
|
||||
}
|
||||
@ -1879,8 +1973,8 @@ dump_entry_data_list(FILE *stream,
|
||||
*status = MMDB_INVALID_DATA_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
char *key = mmdb_strndup(
|
||||
(char *)entry_data_list->entry_data.utf8_string,
|
||||
char *key =
|
||||
mmdb_strndup(entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == key) {
|
||||
*status = MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -1926,8 +2020,7 @@ dump_entry_data_list(FILE *stream,
|
||||
fprintf(stream, "]\n");
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
char *string =
|
||||
mmdb_strndup((char *)entry_data_list->entry_data.utf8_string,
|
||||
char *string = mmdb_strndup(entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == string) {
|
||||
*status = MMDB_OUT_OF_MEMORY_ERROR;
|
||||
@ -1940,7 +2033,7 @@ dump_entry_data_list(FILE *stream,
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
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);
|
||||
|
||||
if (NULL == hex_string) {
|
||||
@ -2032,12 +2125,12 @@ dump_entry_data_list(FILE *stream,
|
||||
static void print_indentation(FILE *stream, int i) {
|
||||
char buffer[1024];
|
||||
int size = i >= 1024 ? 1023 : i;
|
||||
memset(buffer, 32, size);
|
||||
memset(buffer, 32, (size_t)size);
|
||||
buffer[size] = '\0';
|
||||
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;
|
||||
MAYBE_CHECK_SIZE_OVERFLOW(size, SIZE_MAX / 2 - 1, NULL);
|
||||
|
||||
|
||||
@ -5,18 +5,6 @@ extern "C" {
|
||||
#ifndef 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 <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
@ -28,9 +16,6 @@ extern "C" {
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
/* libmaxminddb package version from configure */
|
||||
#define PACKAGE_VERSION "1.5.2"
|
||||
|
||||
typedef ADDRESS_FAMILY sa_family_t;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* MSVC doesn't define signed size_t, copy it from configure */
|
||||
|
||||
@ -11,6 +11,6 @@
|
||||
#define MMDB_UINT128_USING_MODE 0
|
||||
#define MMDB_UINT128_IS_BYTE_ARRAY 1
|
||||
|
||||
#define PACKAGE_VERSION "1.5.2"
|
||||
#define PACKAGE_VERSION "1.10.0"
|
||||
|
||||
#endif /* MAXMINDDB_CONFIG_H */
|
||||
|
||||
@ -16,7 +16,7 @@ if SM.mysql_root:
|
||||
|
||||
if binary.compiler.target.platform == 'linux' or binary.compiler.target.platform == 'mac':
|
||||
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',
|
||||
'-lpthread',
|
||||
'-lm',
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
#include <cdll_int.h>
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
#include <am-hashset.h>
|
||||
#include <sm_stringhashmap.h>
|
||||
#include <sm_hashmap.h>
|
||||
#endif
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
|
||||
|
||||
@ -575,7 +575,13 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
case Valve_String:
|
||||
{
|
||||
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;
|
||||
return Data_Okay;
|
||||
}
|
||||
|
||||
47001
extensions/sqlite/sqlite-source/sqlite3.c
vendored
47001
extensions/sqlite/sqlite-source/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
1212
extensions/sqlite/sqlite-source/sqlite3.h
vendored
1212
extensions/sqlite/sqlite-source/sqlite3.h
vendored
File diff suppressed because it is too large
Load Diff
@ -167,6 +167,125 @@ methodmap StringMapSnapshot < Handle
|
||||
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
|
||||
* "keys") to arbitrary values (cells, arrays, or strings). Keys in a hash map
|
||||
|
||||
@ -78,7 +78,34 @@ native Handle CloneHandle(Handle hndl, Handle plugin=INVALID_HANDLE);
|
||||
methodmap Handle __nullable__ {
|
||||
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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -42,8 +42,8 @@
|
||||
#define SOURCEMOD_V_REV 0
|
||||
#define SOURCEMOD_V_CSET "0"
|
||||
#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_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
|
||||
|
||||
@ -13,6 +13,7 @@ public Plugin:myinfo =
|
||||
public OnPluginStart()
|
||||
{
|
||||
RegServerCmd("test_maps", RunTests);
|
||||
RegServerCmd("test_int_maps", RunIntTests);
|
||||
}
|
||||
|
||||
public Action:RunTests(argc)
|
||||
@ -161,3 +162,189 @@ public Action:RunTests(argc)
|
||||
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;
|
||||
}
|
||||
@ -1 +1 @@
|
||||
1.12.0
|
||||
1.13.0
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 285b4f853c0003023838140113e3ec066bd800c6
|
||||
Subproject commit 2d3b1a3378a3728637f26660c9ffc2df3189cf62
|
||||
@ -1,47 +1,5 @@
|
||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os, sys
|
||||
|
||||
# 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'),
|
||||
}
|
||||
import os
|
||||
|
||||
def ResolveEnvPath(env, folder):
|
||||
if env in os.environ:
|
||||
@ -64,14 +22,70 @@ def ResolveEnvPath(env, folder):
|
||||
def Normalize(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):
|
||||
def __init__(self):
|
||||
self.sdk_manifests = []
|
||||
self.sdks = {}
|
||||
self.binaries = []
|
||||
self.sdk_targets = []
|
||||
self.extensions = []
|
||||
self.generated_headers = None
|
||||
self.mms_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
|
||||
def tag(self):
|
||||
@ -79,41 +93,26 @@ class ExtensionConfig(object):
|
||||
return 'Debug'
|
||||
return 'Release'
|
||||
|
||||
def detectSDKs(self):
|
||||
sdk_list = builder.options.sdks.split(',')
|
||||
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:
|
||||
def findSdkPath(self, sdk_name):
|
||||
dir_name = 'hl2sdk-{}'.format(sdk_name)
|
||||
if builder.options.hl2sdk_root:
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
||||
else:
|
||||
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
||||
if sdk_path is None or not os.path.isdir(sdk_path):
|
||||
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
|
||||
sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
|
||||
if os.path.exists(sdk_path):
|
||||
return sdk_path
|
||||
return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
|
||||
|
||||
if len(self.sdks) < 1:
|
||||
raise Exception('At least one SDK must be available.')
|
||||
def shouldIncludeSdk(self, sdk):
|
||||
return not sdk.get('source2', False)
|
||||
|
||||
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')
|
||||
def detectSDKs(self):
|
||||
sdk_list = [s for s in builder.options.sdks.split(',') if s]
|
||||
SdkHelpers.sdk_filter = self.shouldIncludeSdk
|
||||
SdkHelpers.find_sdk_path = self.findSdkPath
|
||||
SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
|
||||
|
||||
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)
|
||||
self.sdks = SdkHelpers.sdks
|
||||
self.sdk_manifests = SdkHelpers.sdk_manifests
|
||||
self.sdk_targets = SdkHelpers.sdk_targets
|
||||
|
||||
if 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')
|
||||
if not self.mms_root:
|
||||
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:
|
||||
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')
|
||||
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):
|
||||
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'):
|
||||
self.configure_gcc(cxx)
|
||||
elif cxx.vendor == 'msvc':
|
||||
elif cxx.family == 'msvc':
|
||||
self.configure_msvc(cxx)
|
||||
|
||||
# Optimization
|
||||
@ -145,18 +179,13 @@ class ExtensionConfig(object):
|
||||
cxx.defines += ['DEBUG', '_DEBUG']
|
||||
|
||||
# Platform-specifics
|
||||
if builder.target_platform == 'linux':
|
||||
if cxx.target.platform == 'linux':
|
||||
self.configure_linux(cxx)
|
||||
elif builder.target_platform == 'mac':
|
||||
elif cxx.target.platform == 'mac':
|
||||
self.configure_mac(cxx)
|
||||
elif builder.target_platform == 'windows':
|
||||
elif cxx.target.platform == 'windows':
|
||||
self.configure_windows(cxx)
|
||||
|
||||
# Finish up.
|
||||
cxx.includes += [
|
||||
os.path.join(self.sm_root, 'public'),
|
||||
]
|
||||
|
||||
def configure_gcc(self, cxx):
|
||||
cxx.defines += [
|
||||
'stricmp=strcasecmp',
|
||||
@ -174,46 +203,48 @@ class ExtensionConfig(object):
|
||||
'-Wno-unused',
|
||||
'-Wno-switch',
|
||||
'-Wno-array-bounds',
|
||||
'-msse',
|
||||
'-m32',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
|
||||
if cxx.target.arch in ['x86', 'x86_64']:
|
||||
cxx.cflags += ['-msse']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-std=c++14',
|
||||
'-fno-exceptions',
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-overloaded-virtual',
|
||||
'-Wno-register',
|
||||
'-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:
|
||||
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']
|
||||
else:
|
||||
cxx.cxxflags += ['-Wno-deprecated']
|
||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||
|
||||
# Work around SDK warnings.
|
||||
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||
cxx.cflags += [
|
||||
'-Wno-implicit-int-float-conversion',
|
||||
'-Wno-tautological-overlap-compare',
|
||||
]
|
||||
|
||||
if have_gcc:
|
||||
cxx.cflags += ['-mfpmath=sse']
|
||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||
|
||||
if builder.options.opt == '1':
|
||||
cxx.cflags += ['-O3']
|
||||
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['-fno-omit-frame-pointer']
|
||||
|
||||
def configure_msvc(self, cxx):
|
||||
|
||||
if builder.options.debug == '1':
|
||||
cxx.cflags += ['/MTd']
|
||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||
@ -232,9 +263,9 @@ class ExtensionConfig(object):
|
||||
'/EHsc',
|
||||
'/GR-',
|
||||
'/TP',
|
||||
'/std:c++17',
|
||||
]
|
||||
cxx.linkflags += [
|
||||
'/MACHINE:X86',
|
||||
'kernel32.lib',
|
||||
'user32.lib',
|
||||
'gdi32.lib',
|
||||
@ -261,27 +292,40 @@ class ExtensionConfig(object):
|
||||
cxx.cflags += ['/Oy-']
|
||||
|
||||
def configure_linux(self, cxx):
|
||||
cxx.defines += ['_LINUX', 'POSIX']
|
||||
cxx.linkflags += ['-Wl,--exclude-libs,ALL', '-lm']
|
||||
if cxx.vendor == 'gcc':
|
||||
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.linkflags += ['-lm']
|
||||
if cxx.family == 'gcc':
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
elif cxx.vendor == 'clang':
|
||||
elif cxx.family == 'clang':
|
||||
cxx.linkflags += ['-lgcc_eh']
|
||||
cxx.linkflags += ['-static-libstdc++']
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.5',
|
||||
'-arch', 'i386',
|
||||
'-lstdc++',
|
||||
'-stdlib=libstdc++',
|
||||
'-mmacosx-version-min=10.15',
|
||||
'-stdlib=libc++',
|
||||
'-lc++',
|
||||
]
|
||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||
cxx.cxxflags += ['-stdlib=libc++']
|
||||
|
||||
def configure_windows(self, cxx):
|
||||
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):
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(context.currentSourcePath),
|
||||
@ -294,156 +338,65 @@ class ExtensionConfig(object):
|
||||
]
|
||||
return compiler
|
||||
|
||||
def ConfigureForHL2(self, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
def ExtLibrary(self, context, compiler, name):
|
||||
binary = self.Library(context, compiler, name)
|
||||
SetArchFlags(compiler)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return binary
|
||||
|
||||
if sdk.name == 'episode1':
|
||||
mms_path = os.path.join(self.mms_root, 'core-legacy')
|
||||
else:
|
||||
mms_path = os.path.join(self.mms_root, 'core')
|
||||
def AddCxxCompat(self, binary):
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.sources += [
|
||||
os.path.join(self.sm_root, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
|
||||
]
|
||||
|
||||
def ConfigureForHL2(self, context, binary, sdk):
|
||||
compiler = binary.compiler
|
||||
SetArchFlags(compiler)
|
||||
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(mms_path),
|
||||
os.path.join(mms_path, 'sourcehook'),
|
||||
os.path.join(self.mms_root, 'core'),
|
||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||
]
|
||||
|
||||
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
||||
compiler.defines += defines
|
||||
for other_sdk in self.sdk_manifests:
|
||||
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
|
||||
|
||||
paths = [
|
||||
['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)]
|
||||
SdkHelpers.configureCxx(context, binary, sdk)
|
||||
|
||||
return binary
|
||||
|
||||
def HL2Library(self, context, name, sdk):
|
||||
binary = context.compiler.Library(name)
|
||||
def HL2Library(self, context, compiler, name, sdk):
|
||||
binary = self.Library(context, compiler, name)
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return self.ConfigureForHL2(binary, sdk)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2Project(self, context, name):
|
||||
project = context.compiler.LibraryProject(name)
|
||||
self.ConfigureForExtension(context, project.compiler)
|
||||
return project
|
||||
def HL2Config(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
|
||||
self.AddCxxCompat(binary)
|
||||
return self.ConfigureForHL2(context, binary, sdk)
|
||||
|
||||
def HL2Config(self, project, name, sdk):
|
||||
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
||||
return self.ConfigureForHL2(binary, sdk)
|
||||
def HL2ExtConfig(self, project, context, compiler, name, sdk):
|
||||
binary = project.Configure(compiler, name,
|
||||
'{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.detectSDKs()
|
||||
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 = [
|
||||
'AMBuilder',
|
||||
'PackageScript',
|
||||
]
|
||||
|
||||
if builder.backend == 'amb2':
|
||||
BuildScripts += [
|
||||
'PackageScript',
|
||||
]
|
||||
builder.Build(BuildScripts, { 'Extension': Extension })
|
||||
|
||||
builder.RunBuildScripts(BuildScripts, { 'Extension': Extension})
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# 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'
|
||||
|
||||
# smsdk_ext.cpp will be automatically added later
|
||||
@ -8,11 +9,7 @@ sourceFiles = [
|
||||
'extension.cpp',
|
||||
]
|
||||
|
||||
###############
|
||||
# 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')
|
||||
project = builder.LibraryProject(projectName)
|
||||
|
||||
if os.path.isfile(os.path.join(builder.currentSourcePath, 'sdk', 'smsdk_ext.cpp')):
|
||||
# Use the copy included in the project
|
||||
@ -25,7 +22,13 @@ project.sources += sourceFiles
|
||||
|
||||
for sdk_name in Extension.sdks:
|
||||
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)
|
||||
|
||||
@ -13,6 +13,11 @@ folder_list = [
|
||||
#'addons/sourcemod/configs',
|
||||
]
|
||||
|
||||
if 'x86_64' in Extension.target_archs:
|
||||
folder_list.extend([
|
||||
'addons/sourcemod/extensions/x64',
|
||||
])
|
||||
|
||||
# Create the distribution folder hierarchy.
|
||||
folder_map = {}
|
||||
for folder in folder_list:
|
||||
@ -49,4 +54,7 @@ def CopyFiles(src, dest, files):
|
||||
|
||||
# Copy binaries.
|
||||
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'])
|
||||
|
||||
@ -4,20 +4,24 @@ from ambuild2 import run
|
||||
|
||||
# Simple extensions do not need to modify this file.
|
||||
|
||||
builder = run.PrepareBuild(sourcePath = sys.path[0])
|
||||
|
||||
builder.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
|
||||
help='Root search folder for HL2SDKs')
|
||||
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,
|
||||
parser.options.add_argument('--hl2sdk-manifest-path', type=str, dest='hl2sdk_manifest', default=None,
|
||||
help='Path to HL2SDK Manifests')
|
||||
parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
|
||||
help='Path to SourceMod')
|
||||
builder.options.add_option('--enable-debug', action='store_const', const='1', dest='debug',
|
||||
help='Enable debugging symbols')
|
||||
builder.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
help='Enable optimization')
|
||||
builder.options.add_option('-s', '--sdks', default='all', dest='sdks',
|
||||
help='Build against specified SDKs; valid args are "all", "present", or '
|
||||
'comma-delimited list of engine names (default: %default)')
|
||||
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')
|
||||
parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt',
|
||||
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()
|
||||
|
||||
@ -24,6 +24,14 @@ def ResolveEnvPath(env, folder):
|
||||
def Normalize(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):
|
||||
def __init__(self):
|
||||
self.binaries = []
|
||||
@ -31,6 +39,28 @@ class ExtensionConfig(object):
|
||||
self.generated_headers = None
|
||||
self.mms_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
|
||||
def tag(self):
|
||||
@ -39,25 +69,14 @@ class ExtensionConfig(object):
|
||||
return 'Release'
|
||||
|
||||
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:
|
||||
self.mms_root = builder.options.mms_path
|
||||
else:
|
||||
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:
|
||||
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
||||
if not self.mms_root:
|
||||
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')
|
||||
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):
|
||||
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'):
|
||||
self.configure_gcc(cxx)
|
||||
elif cxx.vendor == 'msvc':
|
||||
elif cxx.family == 'msvc':
|
||||
self.configure_msvc(cxx)
|
||||
|
||||
# Optimization
|
||||
@ -82,18 +134,13 @@ class ExtensionConfig(object):
|
||||
cxx.defines += ['DEBUG', '_DEBUG']
|
||||
|
||||
# Platform-specifics
|
||||
if builder.target_platform == 'linux':
|
||||
if cxx.target.platform == 'linux':
|
||||
self.configure_linux(cxx)
|
||||
elif builder.target_platform == 'mac':
|
||||
elif cxx.target.platform == 'mac':
|
||||
self.configure_mac(cxx)
|
||||
elif builder.target_platform == 'windows':
|
||||
elif cxx.target.platform == 'windows':
|
||||
self.configure_windows(cxx)
|
||||
|
||||
# Finish up.
|
||||
cxx.includes += [
|
||||
os.path.join(self.sm_root, 'public'),
|
||||
]
|
||||
|
||||
def configure_gcc(self, cxx):
|
||||
cxx.defines += [
|
||||
'stricmp=strcasecmp',
|
||||
@ -111,46 +158,47 @@ class ExtensionConfig(object):
|
||||
'-Wno-unused',
|
||||
'-Wno-switch',
|
||||
'-Wno-array-bounds',
|
||||
'-msse',
|
||||
'-m32',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
|
||||
if cxx.target.arch in ['x86', 'x86_64']:
|
||||
cxx.cflags += ['-msse']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-std=c++14',
|
||||
'-fno-exceptions',
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
'-Wno-overloaded-virtual',
|
||||
'-Wno-register',
|
||||
'-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:
|
||||
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']
|
||||
else:
|
||||
cxx.cxxflags += ['-Wno-deprecated']
|
||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
||||
|
||||
# Work around SDK warnings.
|
||||
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
|
||||
cxx.cflags += [
|
||||
'-Wno-implicit-int-float-conversion',
|
||||
'-Wno-tautological-overlap-compare',
|
||||
]
|
||||
|
||||
if have_gcc:
|
||||
cxx.cflags += ['-mfpmath=sse']
|
||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||
|
||||
if builder.options.opt == '1':
|
||||
cxx.cflags += ['-O3']
|
||||
|
||||
# Don't omit the frame pointer.
|
||||
cxx.cflags += ['-fno-omit-frame-pointer']
|
||||
|
||||
def configure_msvc(self, cxx):
|
||||
|
||||
if builder.options.debug == '1':
|
||||
cxx.cflags += ['/MTd']
|
||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
||||
@ -169,9 +217,9 @@ class ExtensionConfig(object):
|
||||
'/EHsc',
|
||||
'/GR-',
|
||||
'/TP',
|
||||
'/std:c++17',
|
||||
]
|
||||
cxx.linkflags += [
|
||||
'/MACHINE:X86',
|
||||
'kernel32.lib',
|
||||
'user32.lib',
|
||||
'gdi32.lib',
|
||||
@ -198,23 +246,23 @@ class ExtensionConfig(object):
|
||||
cxx.cflags += ['/Oy-']
|
||||
|
||||
def configure_linux(self, cxx):
|
||||
cxx.defines += ['_LINUX', 'POSIX']
|
||||
cxx.linkflags += ['-Wl,--exclude-libs,ALL', '-lm']
|
||||
if cxx.vendor == 'gcc':
|
||||
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
||||
cxx.linkflags += ['-lm']
|
||||
if cxx.family == 'gcc':
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
elif cxx.vendor == 'clang':
|
||||
elif cxx.family == 'clang':
|
||||
cxx.linkflags += ['-lgcc_eh']
|
||||
cxx.linkflags += ['-static-libstdc++']
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.15']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.5',
|
||||
'-arch', 'i386',
|
||||
'-lstdc++',
|
||||
'-stdlib=libstdc++',
|
||||
'-mmacosx-version-min=10.15',
|
||||
'-stdlib=libc++',
|
||||
'-lc++',
|
||||
]
|
||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||
cxx.cxxflags += ['-stdlib=libc++']
|
||||
|
||||
def configure_windows(self, cxx):
|
||||
cxx.defines += ['WIN32', '_WINDOWS']
|
||||
@ -233,26 +281,14 @@ class ExtensionConfig(object):
|
||||
|
||||
def ConfigureForHL2(self, binary):
|
||||
compiler = binary.compiler
|
||||
|
||||
mms_path = os.path.join(self.mms_root, 'core')
|
||||
SetArchFlags(compiler)
|
||||
|
||||
compiler.cxxincludes += [
|
||||
os.path.join(mms_path),
|
||||
os.path.join(mms_path, 'sourcehook'),
|
||||
os.path.join(self.mms_root, 'core'),
|
||||
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
||||
]
|
||||
|
||||
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
|
||||
|
||||
def HL2Library(self, context, name):
|
||||
@ -261,26 +297,26 @@ class ExtensionConfig(object):
|
||||
return self.ConfigureForHL2(binary)
|
||||
|
||||
def HL2Project(self, context, name):
|
||||
project = context.compiler.LibraryProject(name)
|
||||
self.ConfigureForExtension(context, project.compiler)
|
||||
project = builder.LibraryProject(name)
|
||||
return project
|
||||
|
||||
def HL2Config(self, project, name):
|
||||
binary = project.Configure(name, '{0}'.format(self.tag))
|
||||
def HL2Config(self, context, project, name, compiler):
|
||||
binary = project.Configure(compiler, name, '{0} - {1}'.format(self.tag, compiler.target.arch))
|
||||
self.ConfigureForExtension(context, binary.compiler)
|
||||
return self.ConfigureForHL2(binary)
|
||||
|
||||
Extension = ExtensionConfig()
|
||||
Extension.detectSDKs()
|
||||
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
|
||||
BuildScripts = [
|
||||
'AMBuilder',
|
||||
'PackageScript',
|
||||
]
|
||||
|
||||
if builder.backend == 'amb2':
|
||||
BuildScripts += [
|
||||
'PackageScript',
|
||||
]
|
||||
|
||||
builder.RunBuildScripts(BuildScripts, { 'Extension': Extension})
|
||||
builder.Build(BuildScripts, { 'Extension': Extension })
|
||||
|
||||
@ -23,6 +23,9 @@ else:
|
||||
|
||||
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)
|
||||
|
||||
@ -13,6 +13,11 @@ folder_list = [
|
||||
#'addons/sourcemod/configs',
|
||||
]
|
||||
|
||||
if 'x86_64' in Extension.target_archs:
|
||||
folder_list.extend([
|
||||
'addons/sourcemod/extensions/x64',
|
||||
])
|
||||
|
||||
# Create the distribution folder hierarchy.
|
||||
folder_map = {}
|
||||
for folder in folder_list:
|
||||
@ -49,4 +54,8 @@ def CopyFiles(src, dest, files):
|
||||
|
||||
# Copy binaries.
|
||||
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'])
|
||||
|
||||
|
||||
@ -4,15 +4,15 @@ from ambuild2 import run
|
||||
|
||||
# Simple extensions do not need to modify this file.
|
||||
|
||||
builder = run.PrepareBuild(sourcePath = sys.path[0])
|
||||
|
||||
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,
|
||||
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
|
||||
parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None,
|
||||
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')
|
||||
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')
|
||||
|
||||
builder.Configure()
|
||||
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
|
||||
help="Override the target architecture (use commas to separate multiple targets).")
|
||||
parser.Configure()
|
||||
@ -98,16 +98,25 @@ namespace detail
|
||||
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>
|
||||
class StringHashMap
|
||||
template <typename T, typename KeyStoreType, typename Policy, typename ContainerType, typename KeyLookupType>
|
||||
class HashMap
|
||||
{
|
||||
typedef detail::CharsAndLength CharsAndLength;
|
||||
typedef ke::HashMap<std::string, T, detail::StringHashMapPolicy> Internal;
|
||||
typedef ke::HashMap<KeyStoreType, T, Policy> Internal;
|
||||
|
||||
public:
|
||||
StringHashMap()
|
||||
HashMap()
|
||||
: internal_(ke::SystemAllocatorPolicy()),
|
||||
memory_used_(0)
|
||||
{
|
||||
@ -120,9 +129,9 @@ public:
|
||||
typedef typename Internal::iterator iterator;
|
||||
|
||||
// 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);
|
||||
if (!r.found())
|
||||
return false;
|
||||
@ -131,9 +140,9 @@ public:
|
||||
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);
|
||||
if (!r.found())
|
||||
return false;
|
||||
@ -141,23 +150,23 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
Result find(const char *aKey)
|
||||
Result find(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
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);
|
||||
return r.found();
|
||||
}
|
||||
|
||||
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);
|
||||
if (!i.found())
|
||||
{
|
||||
@ -170,9 +179,9 @@ public:
|
||||
}
|
||||
|
||||
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);
|
||||
if (i.found())
|
||||
return false;
|
||||
@ -182,9 +191,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove(const char *aKey)
|
||||
bool remove(const KeyLookupType &aKey)
|
||||
{
|
||||
CharsAndLength key(aKey);
|
||||
ContainerType key(aKey);
|
||||
Result r = internal_.find(key);
|
||||
if (!r.found())
|
||||
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);
|
||||
}
|
||||
|
||||
@ -234,7 +243,7 @@ public:
|
||||
}
|
||||
|
||||
// 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))
|
||||
return false;
|
||||
@ -246,6 +255,12 @@ private:
|
||||
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_
|
||||
@ -41,7 +41,7 @@
|
||||
#include <am-allocator-policies.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <am-string.h>
|
||||
#include "sm_stringhashmap.h"
|
||||
#include "sm_hashmap.h"
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
|
||||
@ -50,7 +50,7 @@ a dead fish
|
||||
ten clams, ten of them
|
||||
🐌🐌🐌🐌🐌🐌
|
||||
rum ham
|
||||
scrambled eggs
|
||||
scrambled eggs with a lack of soop
|
||||
EXCEPTION
|
||||
erin make me touch this
|
||||
a newline embiggens the noblest of files
|
||||
@ -78,3 +78,4 @@ travis stole my shoe, once.
|
||||
I love my anime wife.
|
||||
Make the world your clam
|
||||
you guys ever have gay thoughts
|
||||
quick before sappho gets mad!
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit d59a51b5741823903ecbe8c014632ee1f8aad65d
|
||||
Subproject commit 91397a3ff3d6807808ff5e0c4772bdef357099f3
|
||||
12
tools/checkout-deps.sh
vendored
12
tools/checkout-deps.sh
vendored
@ -64,13 +64,13 @@ if [ $ismac -eq 1 ]; then
|
||||
mysqlver=mysql-5.5.28-osx10.5-x86
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
|
||||
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
|
||||
# The folder in the zip archive does not contain the substring "-noinstall", so strip it
|
||||
mysqlver=${mysqlver/-noinstall}
|
||||
else
|
||||
mysqlver=mysql-5.6.15-linux-glibc2.5-i686
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.6/$mysqlver.$archive_ext
|
||||
mysqlver=mysql-5.7.44-linux-glibc2.12-i686
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.7/$mysqlver.$archive_ext
|
||||
fi
|
||||
if [ $download_mysql -eq 1 ]; then
|
||||
getmysql
|
||||
@ -82,11 +82,11 @@ if [ $ismac -eq 1 ]; then
|
||||
mysqlver=mysql-5.5.28-osx10.5-x86_64
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.5/$mysqlver.$archive_ext
|
||||
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
|
||||
else
|
||||
mysqlver=mysql-5.6.15-linux-glibc2.5-x86_64
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.6/$mysqlver.$archive_ext
|
||||
mysqlver=mysql-5.7.44-linux-glibc2.12-x86_64
|
||||
mysqlurl=https://cdn.mysql.com/archives/mysql-5.7/$mysqlver.$archive_ext
|
||||
fi
|
||||
if [ $download_mysql -eq 1 ]; then
|
||||
getmysql
|
||||
|
||||
Loading…
Reference in New Issue
Block a user