mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-06 18:08:36 +00:00
Compare commits
7 Commits
a65aef25ab
...
d4db62f199
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4db62f199 | ||
|
|
c4d5235217 | ||
|
|
6439769d50 | ||
|
|
0c900be7fc | ||
|
|
1f39fc3265 | ||
|
|
600bbbcb54 | ||
|
|
21fce47352 |
221
.github/workflows/build-release.yml
vendored
Normal file
221
.github/workflows/build-release.yml
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
name: Build master branch
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
env:
|
||||
ARCH: x86,x86_64
|
||||
# Used for caching
|
||||
# TODO: Handle this better so that we don't have to update this in lockstep with checkout-deps
|
||||
MYSQL_VERSION: '5.5'
|
||||
MMSOURCE_VERSION: '1.12'
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
# For release creation, at the end
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- platform: windows
|
||||
os: windows-latest
|
||||
os_short: win
|
||||
- platform: linux
|
||||
os: ubuntu-latest
|
||||
os_short: linux
|
||||
container_image: ghcr.io/alliedmodders/build-containers/debian11:latest
|
||||
fail-fast: false
|
||||
name: ${{ matrix.platform }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ matrix.container_image }}
|
||||
steps:
|
||||
- name: Checkout SourceMod
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: sourcemod
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Windows dependencies
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install -y gzip
|
||||
choco install -y 7zip
|
||||
|
||||
# Add DIA SDK bin directory to PATH for dump_syms
|
||||
Install-Module -Name VSSetup -Scope AllUsers -Force -AllowClobber
|
||||
$vsRoot = Get-VSSetupInstance |
|
||||
Sort-Object -Property InstallationVersion -Descending |
|
||||
Select-Object -First 1 |
|
||||
Select-Object -ExpandProperty InstallationPath
|
||||
$diaDir = (Join-Path -Path $vsRoot -ChildPath 'DIA SDK\bin')
|
||||
$diaDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
$toolsDir = New-Item -Path '_tools' -ItemType Directory -Force
|
||||
$toolsDir.FullName | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
Push-Location $toolsDir
|
||||
# TODO: Move this somewhere more official
|
||||
curl -sSL -o dump_syms.exe https://users.alliedmods.net/~psychonic/dump_syms.exe
|
||||
Unblock-File -Path dump_syms.exe
|
||||
Pop-Location
|
||||
|
||||
# Largely a workaround for issue where github.workspace doesn't match $GITHUB_WORKSPACE
|
||||
# in containerized jobs. See https://github.com/actions/runner/issues/2058
|
||||
- name: Resolve paths
|
||||
id: path_helper
|
||||
shell: bash
|
||||
run: |
|
||||
echo "dependencies=$GITHUB_WORKSPACE/dependencies" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate SDK list
|
||||
id: sdk_list
|
||||
shell: bash
|
||||
run: |
|
||||
sdk_list=()
|
||||
for file in sourcemod/hl2sdk-manifests/manifests/*.json; do
|
||||
sdk=$(basename "$file" .json)
|
||||
if [[ $sdk == "mock" ]]; then
|
||||
# We don't need to ship a build for the mock SDK
|
||||
continue
|
||||
fi
|
||||
|
||||
platform=$(jq -r '.platforms.${{ matrix.platform }}' "$file")
|
||||
if [[ -z $platform || $platform == "null" || ${#platform[@]} -eq 0 ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
source2=$(jq -r '.source2' "$file")
|
||||
if [[ $source2 == "null" || $source2 == "true" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
sdk_list+=("$sdk")
|
||||
done
|
||||
echo "sdk_list=$(printf '%s\n' "${sdk_list[@]}" | jq --raw-input . | jq --slurp --compact-output .)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: hl2sdk-mysql-mmsource
|
||||
with:
|
||||
path: ${{ steps.path_helper.outputs.dependencies }}
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ join(fromJson(steps.sdk_list.outputs.sdk_list), '') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p '${{ steps.path_helper.outputs.dependencies }}'
|
||||
cd '${{ steps.path_helper.outputs.dependencies }}'
|
||||
|
||||
# Satisfy checkout-deps requirement for a "sourcemod" folder.
|
||||
mkdir -p sourcemod
|
||||
../sourcemod/tools/checkout-deps.sh -s ${{ join(fromJson(steps.sdk_list.outputs.sdk_list), ',') }}
|
||||
|
||||
if [ ! -f GeoLite2-City_20191217/GeoLite2-City.mmdb ]; then
|
||||
geotar="GeoLite2-City_20191217.tar.gz"
|
||||
curl -sSL "https://sm.alliedmods.net/$geotar" -o $geotar
|
||||
tar -xzf "$geotar"
|
||||
rm "$geotar"
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
working-directory: sourcemod
|
||||
shell: bash
|
||||
env:
|
||||
BREAKPAD_SYMBOL_SERVER: ${{ vars.BREAKPAD_SYMBOL_SERVER }}
|
||||
BREAKPAD_SYMBOL_SERVER_TOKEN: ${{ secrets.BREAKPAD_SYMBOL_SERVER_TOKEN }}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
python3 ../configure.py \
|
||||
--enable-optimize \
|
||||
--breakpad-dump \
|
||||
--no-color \
|
||||
--symbol-files \
|
||||
--sdks=${{ join(fromJson(steps.sdk_list.outputs.sdk_list), ',') }} \
|
||||
--targets=${{ env.ARCH }} \
|
||||
'--mms-path=${{ steps.path_helper.outputs.dependencies }}/mmsource-${{ env.MMSOURCE_VERSION }}' \
|
||||
'--hl2sdk-root=${{ steps.path_helper.outputs.dependencies }}' \
|
||||
'--mysql-path=${{ steps.path_helper.outputs.dependencies }}/mysql-${{ env.MYSQL_VERSION }}' \
|
||||
'--mysql64-path=${{ steps.path_helper.outputs.dependencies }}/mysql-${{ env.MYSQL_VERSION }}-x86_64'
|
||||
ambuild
|
||||
|
||||
mkdir -p addons/sourcemod/configs/geoip
|
||||
cp '${{ steps.path_helper.outputs.dependencies }}/GeoLite2-City_20191217/GeoLite2-City.mmdb' addons/sourcemod/configs/geoip/GeoLite2-City.mmdb
|
||||
|
||||
- name: Package
|
||||
id: package
|
||||
working-directory: sourcemod/build/package
|
||||
shell: bash
|
||||
run: |
|
||||
version_base=$(cat ../../product.version)
|
||||
version_base=${version_base%-dev} # Ex. 1.12.0
|
||||
version_rev=$(git rev-list --count HEAD)
|
||||
version="${version_base}.${version_rev}"
|
||||
expanded_version="${version_base}-git-${version_rev}"
|
||||
|
||||
if [ "${{ matrix.platform}}" == "windows" ]; then
|
||||
filename="sourcemod-${expanded_version}-${{ matrix.platform }}.zip"
|
||||
7z a "$filename" addons cfg
|
||||
content_type="application/zip"
|
||||
else
|
||||
filename="sourcemod-${expanded_version}-${{ matrix.platform }}.tar.gz"
|
||||
tar zcvf "$filename" addons cfg
|
||||
content_type="application/gzip"
|
||||
fi
|
||||
echo "version=$version" >> $GITHUB_OUTPUT
|
||||
echo "expanded_version=$expanded_version" >> $GITHUB_OUTPUT
|
||||
echo "filename=$filename" >> $GITHUB_OUTPUT
|
||||
echo "content_type=$content_type" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
# Windows and Linux packages will need to upload to the same release
|
||||
allowUpdates: true
|
||||
replacesArtifacts: false
|
||||
omitBodyDuringUpdate: true
|
||||
omitDraftDuringUpdate: true
|
||||
omitNameDuringUpdate: true
|
||||
omitPrereleaseDuringUpdate: true
|
||||
|
||||
artifacts: sourcemod/build/package/${{ steps.package.outputs.filename }}
|
||||
artifactContentType: ${{ steps.package.outputs.content_type }}
|
||||
artifactErrorsFailBuild: true
|
||||
|
||||
tag: ${{ steps.package.outputs.version }}
|
||||
commit: ${{ github.sha }}
|
||||
generateReleaseNotes: true
|
||||
|
||||
draft: false
|
||||
prerelease: ${{ github.ref == 'refs/heads/master' }}
|
||||
makeLatest: ${{ github.ref != 'refs/heads/master' }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Output PDBs
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
shell: pwsh
|
||||
id: output_pdbs
|
||||
working-directory: sourcemod/build
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$paths = (Get-Content -Path "pdblog.txt" | ForEach-Object -Process {
|
||||
$fullRelPath = Join-Path -Path 'sourcemod/build' -ChildPath $_
|
||||
$fullRelPath -replace '\.pdb$', '.*'
|
||||
}) -join "`n"
|
||||
"PDB_PATHS<<EOF" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
$paths | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
"EOF" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: Upload PDBs
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pdbs
|
||||
path: ${{ env.PDB_PATHS }}
|
||||
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -2,7 +2,6 @@ name: Continuous Integration
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '[0-9]+.[0-9]+-dev'
|
||||
pull_request:
|
||||
branches:
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -12,3 +12,6 @@
|
||||
[submodule "public/safetyhook"]
|
||||
path = public/safetyhook
|
||||
url = https://github.com/alliedmodders/safetyhook
|
||||
[submodule "core/logic/libaddrz"]
|
||||
path = core/logic/libaddrz
|
||||
url = https://github.com/dvander/libaddrz.git
|
||||
|
||||
@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS sm_cookie_cache
|
||||
PRIMARY KEY (player, cookie_id)
|
||||
);
|
||||
|
||||
CREATE LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS
|
||||
$$
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
CREATE TABLE sm_admins (
|
||||
CREATE TABLE IF NOT EXISTS sm_admins (
|
||||
id serial,
|
||||
authtype varchar(6) NOT NULL,
|
||||
CHECK (authtype in ('steam', 'name', 'ip')),
|
||||
@ -10,7 +10,7 @@ CREATE TABLE sm_admins (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_groups (
|
||||
CREATE TABLE IF NOT EXISTS sm_groups (
|
||||
id serial,
|
||||
flags varchar(30) NOT NULL,
|
||||
name varchar(120) NOT NULL,
|
||||
@ -18,7 +18,7 @@ CREATE TABLE sm_groups (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_immunity (
|
||||
CREATE TABLE IF NOT EXISTS sm_group_immunity (
|
||||
group_id int NOT NULL,
|
||||
other_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
@ -26,7 +26,7 @@ CREATE TABLE sm_group_immunity (
|
||||
PRIMARY KEY (group_id, other_id)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_group_overrides (
|
||||
CREATE TABLE IF NOT EXISTS sm_group_overrides (
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE,
|
||||
type varchar(10) NOT NULL,
|
||||
@ -37,7 +37,7 @@ CREATE TABLE sm_group_overrides (
|
||||
PRIMARY KEY (group_id, type, name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_overrides (
|
||||
CREATE TABLE IF NOT EXISTS sm_overrides (
|
||||
type varchar(10) NOT NULL,
|
||||
CHECK (type in ('command', 'group')),
|
||||
name varchar(32) NOT NULL,
|
||||
@ -45,7 +45,7 @@ CREATE TABLE sm_overrides (
|
||||
PRIMARY KEY (type,name)
|
||||
);
|
||||
|
||||
CREATE TABLE sm_admins_groups (
|
||||
CREATE TABLE IF NOT EXISTS sm_admins_groups (
|
||||
admin_id int NOT NULL,
|
||||
group_id int NOT NULL,
|
||||
FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE,
|
||||
@ -56,10 +56,10 @@ CREATE TABLE sm_admins_groups (
|
||||
|
||||
-- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin
|
||||
-- to figure out if it exists.
|
||||
CREATE TABLE sm_config (
|
||||
CREATE TABLE IF NOT EXISTS sm_config (
|
||||
cfg_key varchar(32) NOT NULL,
|
||||
cfg_value varchar(255) NOT NULL,
|
||||
PRIMARY KEY (cfg_key)
|
||||
);
|
||||
|
||||
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');
|
||||
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON CONFLICT (cfg_key) DO UPDATE SET cfg_value = EXCLUDED.cfg_value;
|
||||
|
||||
@ -86,9 +86,15 @@ for cxx in builder.targets:
|
||||
'DatabaseConfBuilder.cpp',
|
||||
'LumpManager.cpp',
|
||||
'smn_entitylump.cpp',
|
||||
'libaddrz/addrz.cpp',
|
||||
'libaddrz/mapping.cpp',
|
||||
'libaddrz/platform.cpp',
|
||||
'libaddrz/proc_maps.cpp',
|
||||
'PseudoAddrManager.cpp',
|
||||
]
|
||||
|
||||
if binary.compiler.target.arch == 'x86_64':
|
||||
binary.sources += ['PseudoAddrManager.cpp']
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.sources += ['libaddrz/platform_linux.cpp']
|
||||
elif binary.compiler.target.platform == 'windows':
|
||||
binary.sources += ['libaddrz/platform_windows.cpp']
|
||||
|
||||
SM.binaries += [builder.Add(binary)]
|
||||
|
||||
@ -330,6 +330,13 @@ bool CPlugin::ReadInfo()
|
||||
else
|
||||
m_MaxClientsVar = nullptr;
|
||||
|
||||
if (base->FindPubvarByName("PointerSize", &idx) == SP_ERROR_NONE) {
|
||||
sp_pubvar_t* var = nullptr;
|
||||
if (base->GetPubvarByIndex(idx, &var) == SP_ERROR_NONE && var) {
|
||||
*var->offs = sizeof(void*);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#ifdef PLATFORM_APPLE
|
||||
#include <mach/mach.h>
|
||||
#include <mach/vm_region.h>
|
||||
@ -35,135 +36,88 @@
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
PseudoAddressManager::PseudoAddressManager() : m_NumEntries(0)
|
||||
PseudoAddressManager::PseudoAddressManager() : m_dictionary(am::IPlatform::GetDefault())
|
||||
{
|
||||
}
|
||||
|
||||
// A pseudo address consists of a table index in the upper 6 bits and an offset in the
|
||||
// lower 26 bits. The table consists of memory allocation base addresses.
|
||||
void PseudoAddressManager::Initialize() {
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
auto process = GetCurrentProcess();
|
||||
auto get_module_details = [process](const char* name, void*& baseAddress, size_t& moduleSize) {
|
||||
if (process == NULL) {
|
||||
return false;
|
||||
}
|
||||
auto hndl = GetModuleHandle(name);
|
||||
if (hndl == NULL) {
|
||||
return false;
|
||||
}
|
||||
MODULEINFO info;
|
||||
if (!GetModuleInformation(process, hndl, &info, sizeof(info))) {
|
||||
return false;
|
||||
}
|
||||
moduleSize = info.SizeOfImage;
|
||||
baseAddress = info.lpBaseOfDll;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
#ifdef PLATFORM_LINUX
|
||||
auto get_module_details = [](const char* name, void* baseAddress, size_t& moduleSize) {
|
||||
auto hndl = dlopen(name, RTLD_NOLOAD);
|
||||
if (hndl == NULL) {
|
||||
return false;
|
||||
}
|
||||
void* addr = dlsym(hndl, "CreateInterface");
|
||||
dlclose(hndl);
|
||||
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
baseAddress = info.dli_fbase;
|
||||
// It doesn't matter much if we figure out the module size
|
||||
// libaddrz coalesce maps on linux
|
||||
moduleSize = 0;
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Early map commonly used modules, it's okay if not all of them are here
|
||||
// Everything else will be caught by "ToPseudoAddress" but you risk running out of ranges by then
|
||||
const char* libs[] = { "engine", "server", "tier0", "vstdlib" };
|
||||
|
||||
char formattedName[64];
|
||||
for (int i = 0; i < sizeof(libs) / sizeof(const char*); i++) {
|
||||
bridge->FormatSourceBinaryName(libs[i], formattedName, sizeof(formattedName));
|
||||
void* base_addr = nullptr;
|
||||
size_t module_size = 0;
|
||||
if (get_module_details(formattedName, base_addr, module_size)) {
|
||||
// Create the mapping (hopefully)
|
||||
m_dictionary.Make32bitAddress(base_addr, module_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
uint8_t index = paddr >> PSEUDO_OFFSET_BITS;
|
||||
uint32_t offset = paddr & ((1 << PSEUDO_OFFSET_BITS) - 1);
|
||||
|
||||
if (index >= m_NumEntries)
|
||||
if (paddr == 0) {
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void *>(uintptr_t(m_AllocBases[index]) + offset);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
return m_dictionary.RecoverAddress(paddr).value_or(nullptr);
|
||||
}
|
||||
|
||||
uint32_t PseudoAddressManager::ToPseudoAddress(void *addr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
uint8_t index = 0;
|
||||
uint32_t offset = 0;
|
||||
bool hasEntry = false;
|
||||
void *base = GetAllocationBase(addr);
|
||||
|
||||
if (base) {
|
||||
for (int i = 0; i < m_NumEntries; i++) {
|
||||
if (m_AllocBases[i] == base) {
|
||||
index = i;
|
||||
hasEntry = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (addr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hasEntry) {
|
||||
index = m_NumEntries;
|
||||
if (m_NumEntries < SM_ARRAYSIZE(m_AllocBases))
|
||||
m_AllocBases[m_NumEntries++] = base;
|
||||
else
|
||||
return 0; // Table is full
|
||||
}
|
||||
|
||||
ptrdiff_t diff = uintptr_t(addr) - uintptr_t(base);
|
||||
|
||||
// Ensure difference fits in 26 bits
|
||||
if (diff > (UINT32_MAX >> PSEUDO_INDEX_BITS))
|
||||
return 0;
|
||||
|
||||
return (index << PSEUDO_OFFSET_BITS) | diff;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *PseudoAddressManager::GetAllocationBase(void *ptr)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
if (!VirtualQuery(ptr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
return nullptr;
|
||||
return info.AllocationBase;
|
||||
|
||||
#elif defined PLATFORM_APPLE
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
typedef vm_region_info_t mach_vm_region_info_t;
|
||||
typedef vm_region_basic_info_data_t mach_vm_region_basic_info_data_t;
|
||||
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO;
|
||||
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT;
|
||||
#define mach_vm_region vm_region
|
||||
#elif defined KE_ARCH_X64
|
||||
typedef vm_region_info_64_t mach_vm_region_info_t ;
|
||||
typedef vm_region_basic_info_data_64_t mach_vm_region_basic_info_data_t;
|
||||
const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO_64;
|
||||
const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT_64;
|
||||
#define mach_vm_region vm_region_64
|
||||
#endif
|
||||
vm_size_t size;
|
||||
vm_address_t vmaddr = reinterpret_cast<vm_address_t>(ptr);
|
||||
mach_vm_region_basic_info_data_t info;
|
||||
memory_object_name_t obj;
|
||||
vm_region_flavor_t flavor = MACH_VM_REGION_BASIC_INFO;
|
||||
mach_msg_type_number_t count = MACH_VM_REGION_BASIC_INFO_COUNT;
|
||||
|
||||
kern_return_t kr = mach_vm_region(mach_task_self(), &vmaddr, &size, flavor,
|
||||
reinterpret_cast<mach_vm_region_info_t>(&info),
|
||||
&count, &obj);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<void *>(vmaddr);
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
// Format:
|
||||
// lower upper prot stuff path
|
||||
// 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat
|
||||
FILE *fp = fopen("/proc/self/maps", "r");
|
||||
if (fp) {
|
||||
uintptr_t lower, upper;
|
||||
while (fscanf(fp, "%" PRIxPTR "-%" PRIxPTR, &lower, &upper) != EOF) {
|
||||
if (addr >= lower && addr <= upper) {
|
||||
fclose(fp);
|
||||
return reinterpret_cast<void *>(lower);
|
||||
}
|
||||
|
||||
// Read to end of line
|
||||
int c;
|
||||
while ((c = fgetc(fp)) != '\n') {
|
||||
if (c == EOF)
|
||||
break;
|
||||
}
|
||||
if (c == EOF)
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
return m_dictionary.Make32bitAddress(addr).value_or(0);
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#define _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_
|
||||
|
||||
#include "common_logic.h"
|
||||
#include "libaddrz/addrz.h"
|
||||
|
||||
class PseudoAddressManager
|
||||
{
|
||||
@ -39,13 +40,9 @@ public:
|
||||
public:
|
||||
void *FromPseudoAddress(uint32_t paddr);
|
||||
uint32_t ToPseudoAddress(void *addr);
|
||||
void Initialize();
|
||||
private:
|
||||
void *GetAllocationBase(void *ptr);
|
||||
private:
|
||||
static constexpr uint8_t PSEUDO_OFFSET_BITS = 26;
|
||||
static constexpr uint8_t PSEUDO_INDEX_BITS = sizeof(uint32_t) * 8 - PSEUDO_OFFSET_BITS;
|
||||
void *m_AllocBases[1 << PSEUDO_INDEX_BITS];
|
||||
uint8_t m_NumEntries;
|
||||
am::AddressDict m_dictionary;
|
||||
};
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
#include "RootConsoleMenu.h"
|
||||
#include "CellArray.h"
|
||||
#include "smn_entitylump.h"
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <bridge/include/BridgeAPI.h>
|
||||
#include <bridge/include/IProviderCallbacks.h>
|
||||
|
||||
@ -86,9 +87,7 @@ IScriptManager *scripts = &g_PluginSys;
|
||||
IExtensionSys *extsys = &g_Extensions;
|
||||
ILogger *logger = &g_Logger;
|
||||
CNativeOwner g_CoreNatives;
|
||||
#ifdef KE_ARCH_X64
|
||||
PseudoAddressManager pseudoAddr;
|
||||
#endif
|
||||
|
||||
EntityLumpParseResult lastParseResult;
|
||||
|
||||
@ -122,20 +121,12 @@ static void RegisterProfiler(IProfilingTool *tool)
|
||||
|
||||
static void *FromPseudoAddress(uint32_t paddr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
return pseudoAddr.FromPseudoAddress(paddr);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t ToPseudoAddress(void *addr)
|
||||
{
|
||||
#ifdef KE_ARCH_X64
|
||||
return pseudoAddr.ToPseudoAddress(addr);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetEntityLumpWritable(bool writable)
|
||||
@ -236,6 +227,7 @@ static void logic_init(CoreProvider* core, sm_logic_t* _logic)
|
||||
g_pSourcePawn2 = *core->spe2;
|
||||
SMGlobalClass::head = core->listeners;
|
||||
|
||||
pseudoAddr.Initialize();
|
||||
g_ShareSys.Initialize();
|
||||
g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
|
||||
|
||||
|
||||
1
core/logic/libaddrz
Submodule
1
core/logic/libaddrz
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 661cd316e6ff8e8560efa20db1794f3fa479647c
|
||||
@ -59,6 +59,7 @@
|
||||
#include <bridge/include/CoreProvider.h>
|
||||
#include <bridge/include/IScriptManager.h>
|
||||
#include <bridge/include/IExtensionBridge.h>
|
||||
#include "PseudoAddrManager.h"
|
||||
#include <sh_vector.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
@ -863,11 +864,10 @@ enum NumberType
|
||||
|
||||
static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -892,14 +892,12 @@ static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -950,6 +948,60 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t LoadAddressFromAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
void* data = *reinterpret_cast<void**>(addr);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(data);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
static cell_t StoreAddressToAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = pseudoAddr.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
|
||||
}
|
||||
|
||||
void *data = reinterpret_cast<void*>(params[2]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
data = pseudoAddr.FromPseudoAddress(params[2]);
|
||||
}
|
||||
|
||||
bool updateMemAccess = params[3];
|
||||
|
||||
if (updateMemAccess) {
|
||||
SourceHook::SetMemAccess(addr, sizeof(void*), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
|
||||
}
|
||||
*reinterpret_cast<void**>(addr) = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cell_t IsNullVector(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *pNullVec = pContext->GetNullRef(SP_NULL_VECTOR);
|
||||
@ -1157,6 +1209,8 @@ REGISTER_NATIVES(coreNatives)
|
||||
{"RequireFeature", RequireFeature},
|
||||
{"LoadFromAddress", LoadFromAddress},
|
||||
{"StoreToAddress", StoreToAddress},
|
||||
{"LoadAddressFromAddress", LoadAddressFromAddress},
|
||||
{"StoreAddressToAddress", StoreAddressToAddress},
|
||||
{"IsNullVector", IsNullVector},
|
||||
{"IsNullString", IsNullString},
|
||||
{"LogStackTrace", LogStackTrace},
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#include "common_logic.h"
|
||||
#include <IHandleSys.h>
|
||||
#include "GameConfigs.h"
|
||||
#include "PseudoAddrManager.h"
|
||||
|
||||
HandleType_t g_GameConfigsType;
|
||||
|
||||
@ -155,11 +156,10 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params)
|
||||
if (!gc->GetAddress(key, &val))
|
||||
return 0;
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return (cell_t)val;
|
||||
#else
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
#endif
|
||||
if (pCtx->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(val);
|
||||
}
|
||||
|
||||
static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
|
||||
@ -187,11 +187,10 @@ static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return (cell_t)val;
|
||||
#else
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
#endif
|
||||
if (pCtx->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pseudoAddr.ToPseudoAddress(val);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(val);
|
||||
}
|
||||
|
||||
static GameConfigsNatives s_GameConfigsNatives;
|
||||
|
||||
@ -724,11 +724,10 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -835,11 +834,10 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
void *addr = reinterpret_cast<void*>(params[1]);
|
||||
#else
|
||||
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_SourceMod.FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
if (addr == NULL)
|
||||
{
|
||||
@ -2772,11 +2770,10 @@ static cell_t GetEntityAddress(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
|
||||
}
|
||||
|
||||
#ifdef KE_ARCH_X86
|
||||
return reinterpret_cast<cell_t>(pEntity);
|
||||
#else
|
||||
return g_SourceMod.ToPseudoAddress(pEntity);
|
||||
#endif
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_SourceMod.ToPseudoAddress(pEntity);
|
||||
}
|
||||
return reinterpret_cast<uintptr_t>(pEntity);
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entityNatives)
|
||||
|
||||
@ -376,7 +376,7 @@ ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour)
|
||||
{
|
||||
// The this pointer is implicitly always the first argument.
|
||||
void *thisPtr = pDetour->GetArgument<void *>(0);
|
||||
cell_t thisAddr = GetThisPtr(thisPtr, pWrapper->thisType);
|
||||
cell_t thisAddr = GetThisPtr(pCallback->GetParentContext(), thisPtr, pWrapper->thisType);
|
||||
pCallback->PushCell(thisAddr);
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,12 @@ cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params)
|
||||
//native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention:callConv, ReturnType:returntype, ThisPointerType:thistype);
|
||||
cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], (void *)params[1]);
|
||||
void* addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], addr);
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL);
|
||||
|
||||
@ -641,7 +646,10 @@ cell_t HookRawImpl(IPluginContext *pContext, const cell_t *params, int callbackI
|
||||
if (removalcbIndex > 0)
|
||||
removalcb = pContext->GetFunctionById(params[removalcbIndex]);
|
||||
|
||||
void *iface = (void *)(params[3]);
|
||||
void* iface = reinterpret_cast<void*>(params[3]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
iface = g_pSM->FromPseudoAddress(params[3]);
|
||||
}
|
||||
|
||||
for(int i = g_pHooks.size() -1; i >= 0; i--)
|
||||
{
|
||||
@ -1482,6 +1490,10 @@ cell_t Native_GetParamAddress(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
|
||||
size_t offset = GetParamOffset(paramStruct, index);
|
||||
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_pSM->ToPseudoAddress(*(void**)((intptr_t)paramStruct->orgParams + offset));
|
||||
}
|
||||
return *(cell_t *)((intptr_t)paramStruct->orgParams + offset);
|
||||
}
|
||||
|
||||
|
||||
@ -465,19 +465,18 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg)
|
||||
return res;
|
||||
}
|
||||
|
||||
cell_t GetThisPtr(void *iface, ThisPointerType type)
|
||||
cell_t GetThisPtr(IPluginContext* pContext, void *iface, ThisPointerType type)
|
||||
{
|
||||
if(type == ThisPointer_CBaseEntity)
|
||||
if (type == ThisPointer_CBaseEntity)
|
||||
{
|
||||
if (!iface)
|
||||
return -1;
|
||||
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
|
||||
}
|
||||
#ifdef KE_ARCH_X64
|
||||
return g_pSM->ToPseudoAddress(iface);
|
||||
#else
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return g_pSM->ToPseudoAddress(iface);
|
||||
}
|
||||
return (cell_t)iface;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined( WIN32 ) && !defined( KE_ARCH_X64 )
|
||||
@ -500,7 +499,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
if(dg->returnType != ReturnType_Void)
|
||||
{
|
||||
@ -684,7 +683,7 @@ float Callback_float(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
@ -841,7 +840,7 @@ SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
@ -995,7 +994,7 @@ string_t *Callback_stringt(DHooksCallback *dg, void **argStack)
|
||||
|
||||
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
|
||||
{
|
||||
dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
dg->plugin_callback->PushCell(GetThisPtr(dg->plugin_callback->GetParentContext(), g_SHPtr->GetIfacePtr(), dg->thisType));
|
||||
}
|
||||
|
||||
returnStruct = GetReturnStruct(dg);
|
||||
|
||||
@ -339,7 +339,7 @@ public:
|
||||
};
|
||||
|
||||
size_t GetStackArgsSize(DHooksCallback *dg);
|
||||
cell_t GetThisPtr(void *iface, ThisPointerType type);
|
||||
cell_t GetThisPtr(IPluginContext* pContext, void *iface, ThisPointerType type);
|
||||
|
||||
extern IBinTools *g_pBinTools;
|
||||
extern HandleType_t g_HookParamsHandle;
|
||||
|
||||
@ -63,7 +63,8 @@ inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &ty
|
||||
type = PassType_Basic;
|
||||
if (vtype == Valve_POD
|
||||
|| vtype == Valve_Float
|
||||
|| vtype == Valve_Bool)
|
||||
|| vtype == Valve_Bool
|
||||
|| vtype == Valve_VirtualAddress)
|
||||
{
|
||||
flags = PASSFLAG_BYVAL | PASSFLAG_ASPOINTER;
|
||||
} else {
|
||||
@ -86,6 +87,13 @@ inline void DecodePassMethod(ValveType vtype, SDKPassMethod method, PassType &ty
|
||||
|
||||
static cell_t StartPrepSDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
auto call_type = (ValveCallType)params[1];
|
||||
if (call_type == ValveCall_Raw && pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
return pContext->ThrowNativeError("SDKCall_Raw is unavailable for plugins that have enabled virtual address.");
|
||||
}
|
||||
if (call_type == ValveCall_VirtualAddress && pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) != SP_ERROR_NONE) {
|
||||
return pContext->ThrowNativeError("SDKCall_VirtualAddress is unavailable for plugins that haven't enabled virtual address.");
|
||||
}
|
||||
s_numparams = 0;
|
||||
s_vtbl_index = -1;
|
||||
s_call_addr = NULL;
|
||||
@ -172,11 +180,10 @@ static cell_t PrepSDKCall_SetSignature(IPluginContext *pContext, const cell_t *p
|
||||
|
||||
static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#ifdef KE_ARCH_X86
|
||||
s_call_addr = reinterpret_cast<void *>(params[1]);
|
||||
#else
|
||||
s_call_addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
#endif
|
||||
s_call_addr = reinterpret_cast<void*>(params[1]);
|
||||
if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) == SP_ERROR_NONE) {
|
||||
s_call_addr = g_pSM->FromPseudoAddress(params[1]);
|
||||
}
|
||||
|
||||
return (s_call_addr != NULL) ? 1 : 0;
|
||||
}
|
||||
@ -413,6 +420,36 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
case ValveCall_VirtualAddress:
|
||||
{
|
||||
//params[startparam] is an address to a pointer to THIS
|
||||
//params following this are params to the method we will invoke later
|
||||
if (startparam > numparams)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Expected a ThisPtr address, it wasn't found");
|
||||
}
|
||||
|
||||
//note: varargs pawn args are passed by-ref
|
||||
cell_t *cell;
|
||||
pContext->LocalToPhysAddr(params[startparam], &cell);
|
||||
void* thisptr = reinterpret_cast<void*>(g_pSM->FromPseudoAddress(*cell));
|
||||
|
||||
if (thisptr == nullptr)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("ThisPtr address cannot be null");
|
||||
}
|
||||
else if (reinterpret_cast<uintptr_t>(thisptr) < VALID_MINIMUM_MEMORY_ADDRESS)
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
return pContext->ThrowNativeError("Invalid ThisPtr address %p is pointing to reserved memory.", thisptr);
|
||||
}
|
||||
|
||||
*(void **)ptr = thisptr;
|
||||
startparam++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
vc->stk_put(ptr);
|
||||
@ -536,6 +573,13 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params)
|
||||
addr = *(bool **)addr;
|
||||
}
|
||||
return *addr ? 1 : 0;
|
||||
} else if (vc->retinfo->vtype == Valve_VirtualAddress) {
|
||||
void *addr = *(void **)vc->retbuf;
|
||||
if (vc->retinfo->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
addr = *(void **)addr;
|
||||
}
|
||||
return g_pSM->ToPseudoAddress(addr);
|
||||
} else {
|
||||
cell_t *addr = (cell_t *)vc->retbuf;
|
||||
if (vc->retinfo->flags & PASSFLAG_ASPOINTER)
|
||||
|
||||
@ -164,6 +164,21 @@ size_t ValveParamToBinParam(ValveType type,
|
||||
return sizeof(float);
|
||||
}
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
info->flags = flags;
|
||||
if (flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
needs_extra = true;
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void**);
|
||||
return sizeof(void**) + sizeof(void*);
|
||||
} else {
|
||||
info->type = PassType_Basic;
|
||||
info->size = sizeof(void*);
|
||||
return sizeof(void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -276,6 +291,19 @@ DataStatus EncodeValveParam(IPluginContext *pContext,
|
||||
|
||||
*addr = *(bool *)buffer ? 1 : 0;
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
|
||||
if (data->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
buffer = *(void **)buffer;
|
||||
}
|
||||
*addr = g_pSM->ToPseudoAddress(*(void**)buffer);
|
||||
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
@ -585,6 +613,29 @@ DataStatus DecodeValveParam(IPluginContext *pContext,
|
||||
*(char **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
case Valve_VirtualAddress:
|
||||
{
|
||||
if (data->decflags & VDECODE_FLAG_BYREF)
|
||||
{
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(param, &addr);
|
||||
param = *addr;
|
||||
}
|
||||
if (data->flags & PASSFLAG_ASPOINTER)
|
||||
{
|
||||
*(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
|
||||
buffer = *(void **)buffer;
|
||||
}
|
||||
void* addr = g_pSM->FromPseudoAddress(param);
|
||||
if (addr == nullptr && (data->decflags & VDECODE_FLAG_ALLOWNULL) == 0)
|
||||
{
|
||||
pContext->ThrowNativeError("NULL Address not allowed");
|
||||
return Data_Fail;
|
||||
}
|
||||
|
||||
*(void **)buffer = addr;
|
||||
return Data_Okay;
|
||||
}
|
||||
}
|
||||
|
||||
return Data_Fail;
|
||||
|
||||
@ -53,6 +53,7 @@ enum ValveType
|
||||
Valve_Edict, /**< Edict */
|
||||
Valve_String, /**< String */
|
||||
Valve_Bool, /**< Boolean */
|
||||
Valve_VirtualAddress, /**< SM Virtual Address */
|
||||
Valve_Object, /**< Object, not matching one of the above types */
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ enum ValveCallType
|
||||
ValveCall_Raw, /**< Thiscall (address explicit first parameter) */
|
||||
ValveCall_Server, /**< Thiscall (CBaseServer implicit first parameter) */
|
||||
ValveCall_Engine, /**< Thiscall (CVEngineServer implicit first parameter) */
|
||||
ValveCall_VirtualAddress /**< Thiscall (address explicit first parameter) */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -121,6 +121,13 @@
|
||||
"linux" "259"
|
||||
"linux64" "259"
|
||||
}
|
||||
"GetAttachment"
|
||||
{
|
||||
"windows" "211"
|
||||
"windows64" "211"
|
||||
"linux" "212"
|
||||
"linux64" "212"
|
||||
}
|
||||
}
|
||||
|
||||
"Keys"
|
||||
|
||||
@ -60,9 +60,10 @@ enum SDKCallType
|
||||
SDKCall_Player, /**< CBasePlayer call */
|
||||
SDKCall_GameRules, /**< CGameRules call */
|
||||
SDKCall_EntityList, /**< CGlobalEntityList call */
|
||||
SDKCall_Raw, /**< |this| pointer with an arbitrary address */
|
||||
SDKCall_Raw, /**< |this| pointer with an arbitrary address. This is not available if SM's virtual addresses are enabled */
|
||||
SDKCall_Server, /**< CBaseServer call */
|
||||
SDKCall_Engine /**< CVEngineServer call */
|
||||
SDKCall_Engine, /**< CVEngineServer call */
|
||||
SDKCall_VirtualAddress /**< |this| pointer with an arbitrary SM virtual address */
|
||||
};
|
||||
|
||||
enum SDKLibrary
|
||||
@ -88,7 +89,8 @@ enum SDKType
|
||||
SDKType_Float, /**< Float (any) */
|
||||
SDKType_Edict, /**< edict_t (always as pointer) */
|
||||
SDKType_String, /**< NULL-terminated string (always as pointer) */
|
||||
SDKType_Bool /**< Boolean (any) */
|
||||
SDKType_Bool, /**< Boolean (any) */
|
||||
SDKType_VirtualAddress, /**< SM Virtual Address */
|
||||
};
|
||||
|
||||
enum SDKPassMethod
|
||||
|
||||
@ -754,6 +754,26 @@ native any LoadFromAddress(Address addr, NumberType size);
|
||||
*/
|
||||
native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true);
|
||||
|
||||
/**
|
||||
* Load sizeof(void*) from a memory address.
|
||||
*
|
||||
* @param addr Address to a memory location.
|
||||
* @return The address that is stored at that address.
|
||||
* @error Address is null or pointing to reserved memory.
|
||||
*/
|
||||
native Address LoadAddressFromAddress(Address addr);
|
||||
|
||||
/**
|
||||
* Store sizeof(void*) bytes to a memory address.
|
||||
*
|
||||
* @param addr Address to a memory location.
|
||||
* @param data Address to store at that location.
|
||||
* @param updateMemAccess If true, SourceMod will set read / write / exec permissions
|
||||
* on the memory page being written to.
|
||||
* @error Address is null or pointing to reserved memory.
|
||||
*/
|
||||
native void StoreAddressToAddress(Address addr, Address data, bool updateMemAccess = true);
|
||||
|
||||
methodmap FrameIterator < Handle {
|
||||
// Creates a stack frame iterator to build your own stack traces.
|
||||
// @return New handle to a FrameIterator.
|
||||
|
||||
39
plugins/include/virtual_address.inc
Normal file
39
plugins/include/virtual_address.inc
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2025 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _virtual_address_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _virtual_address_included
|
||||
|
||||
public const Address __Virtual_Address__ = view_as<Address>(0);
|
||||
public const Address PointerSize = view_as<Address>(0); /**< Size of a pointer in bytes (same as `sizeof(void*)`) */
|
||||
Loading…
Reference in New Issue
Block a user