diff --git a/.gitmodules b/.gitmodules index dce1debb8a..1a0be190b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/core/logic/AMBuilder b/core/logic/AMBuilder index 3af40f19d7..581f0c91a0 100644 --- a/core/logic/AMBuilder +++ b/core/logic/AMBuilder @@ -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)] diff --git a/core/logic/PseudoAddrManager.cpp b/core/logic/PseudoAddrManager.cpp index 2979b1ab09..a49d11e2ba 100644 --- a/core/logic/PseudoAddrManager.cpp +++ b/core/logic/PseudoAddrManager.cpp @@ -28,6 +28,7 @@ */ #include "PseudoAddrManager.h" +#include #ifdef PLATFORM_APPLE #include #include @@ -35,135 +36,88 @@ #ifdef PLATFORM_LINUX #include #endif +#ifdef PLATFORM_WINDOWS +#include +#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::FromPseudoAddress(uint32_t paddr) -{ -#ifdef PLATFORM_X64 - uint8_t index = paddr >> PSEUDO_OFFSET_BITS; - uint32_t offset = paddr & ((1 << PSEUDO_OFFSET_BITS) - 1); - - if (index >= m_NumEntries) - return nullptr; - - return reinterpret_cast(uintptr_t(m_AllocBases[index]) + offset); -#else - return nullptr; +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 -} - -uint32_t PseudoAddressManager::ToPseudoAddress(void *addr) -{ -#ifdef PLATFORM_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; - } +#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; } - } else { - return 0; - } + void* addr = dlsym(hndl, "CreateInterface"); + dlclose(hndl); - 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); + if (!addr) { + return false; + } - // Ensure difference fits in 26 bits - if (diff > (UINT32_MAX >> PSEUDO_INDEX_BITS)) - return 0; + Dl_info info; + if (dladdr(addr, &info) == 0) { + return false; + } - return (index << PSEUDO_OFFSET_BITS) | diff; -#else - return 0; + 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::GetAllocationBase(void *ptr) +void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr) { -#if defined PLATFORM_WINDOWS - - MEMORY_BASIC_INFORMATION info; - if (!VirtualQuery(ptr, &info, sizeof(MEMORY_BASIC_INFORMATION))) + if (paddr == 0) { return nullptr; - return info.AllocationBase; - -#elif defined PLATFORM_APPLE - -#ifdef PLATFORM_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 PLATFORM_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(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(&info), - &count, &obj); - - if (kr != KERN_SUCCESS) - return nullptr; - - return reinterpret_cast(vmaddr); - -#elif defined PLATFORM_LINUX - - uintptr_t addr = reinterpret_cast(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(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.RecoverAddress(paddr).value_or(nullptr); } + +uint32_t PseudoAddressManager::ToPseudoAddress(void *addr) +{ + if (addr == nullptr) { + return 0; + } + return m_dictionary.Make32bitAddress(addr).value_or(0); +} \ No newline at end of file diff --git a/core/logic/PseudoAddrManager.h b/core/logic/PseudoAddrManager.h index 5de802aa26..4c6ca59d78 100644 --- a/core/logic/PseudoAddrManager.h +++ b/core/logic/PseudoAddrManager.h @@ -31,6 +31,7 @@ #define _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_ #include "common_logic.h" +#include "libaddrz/addrz.h" class PseudoAddressManager { @@ -39,13 +40,9 @@ class PseudoAddressManager 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_ diff --git a/core/logic/common_logic.cpp b/core/logic/common_logic.cpp index 24e95092cf..cc9e1de6c7 100644 --- a/core/logic/common_logic.cpp +++ b/core/logic/common_logic.cpp @@ -57,6 +57,7 @@ #include "RootConsoleMenu.h" #include "CellArray.h" #include "smn_entitylump.h" +#include "PseudoAddrManager.h" #include #include @@ -86,9 +87,7 @@ IScriptManager *scripts = &g_PluginSys; IExtensionSys *extsys = &g_Extensions; ILogger *logger = &g_Logger; CNativeOwner g_CoreNatives; -#ifdef PLATFORM_X64 PseudoAddressManager pseudoAddr; -#endif EntityLumpParseResult lastParseResult; @@ -122,20 +121,12 @@ static void RegisterProfiler(IProfilingTool *tool) static void *FromPseudoAddress(uint32_t paddr) { -#ifdef PLATFORM_X64 return pseudoAddr.FromPseudoAddress(paddr); -#else - return nullptr; -#endif } static uint32_t ToPseudoAddress(void *addr) { -#ifdef PLATFORM_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(); diff --git a/core/logic/libaddrz b/core/logic/libaddrz new file mode 160000 index 0000000000..661cd316e6 --- /dev/null +++ b/core/logic/libaddrz @@ -0,0 +1 @@ +Subproject commit 661cd316e6ff8e8560efa20db1794f3fa479647c diff --git a/core/logic/smn_core.cpp b/core/logic/smn_core.cpp index 8e90d40310..b70049467e 100644 --- a/core/logic/smn_core.cpp +++ b/core/logic/smn_core.cpp @@ -59,6 +59,7 @@ #include #include #include +#include "PseudoAddrManager.h" #include using namespace SourceMod; @@ -863,11 +864,10 @@ enum NumberType static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) { -#ifdef PLATFORM_X86 void *addr = reinterpret_cast(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 PLATFORM_X86 void *addr = reinterpret_cast(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(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(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + + void* data = *reinterpret_cast(addr); + if (pContext->GetRuntime()->FindPubvarByName("__Virtual_Address__", nullptr) != SP_ERROR_NONE) { + return pseudoAddr.ToPseudoAddress(data); + } + return reinterpret_cast(data); +} + +static cell_t StoreAddressToAddress(IPluginContext *pContext, const cell_t *params) +{ + void *addr = reinterpret_cast(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(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + + void *data = reinterpret_cast(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(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}, diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 929b4a4a8f..3064a9a240 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -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 PLATFORM_X86 void *addr = reinterpret_cast(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) { diff --git a/extensions/dhooks/dynhooks_sourcepawn.cpp b/extensions/dhooks/dynhooks_sourcepawn.cpp index 927f3d66c8..f636786987 100644 --- a/extensions/dhooks/dynhooks_sourcepawn.cpp +++ b/extensions/dhooks/dynhooks_sourcepawn.cpp @@ -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(0); - cell_t thisAddr = GetThisPtr(thisPtr, pWrapper->thisType); + cell_t thisAddr = GetThisPtr(pCallback->GetParentContext(), thisPtr, pWrapper->thisType); pCallback->PushCell(thisAddr); } diff --git a/extensions/dhooks/natives.cpp b/extensions/dhooks/natives.cpp index f228fcf306..66f395f3c0 100644 --- a/extensions/dhooks/natives.cpp +++ b/extensions/dhooks/natives.cpp @@ -122,7 +122,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(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); @@ -589,7 +594,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(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--) { @@ -1510,6 +1518,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); } diff --git a/extensions/dhooks/vhook.cpp b/extensions/dhooks/vhook.cpp index d20eaf447d..a257d995ce 100644 --- a/extensions/dhooks/vhook.cpp +++ b/extensions/dhooks/vhook.cpp @@ -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 PLATFORM_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( PLATFORM_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); diff --git a/extensions/dhooks/vhook.h b/extensions/dhooks/vhook.h index b58f9c4ff1..def0161ebe 100644 --- a/extensions/dhooks/vhook.h +++ b/extensions/dhooks/vhook.h @@ -338,7 +338,7 @@ class DHooksManager }; 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; diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 3cabcc40ae..d940c2e8e2 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -172,11 +172,10 @@ static cell_t PrepSDKCall_SetSignature(IPluginContext *pContext, const cell_t *p static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *params) { -#ifdef PLATFORM_X86 - s_call_addr = reinterpret_cast(params[1]); -#else - s_call_addr = g_pSM->FromPseudoAddress(params[1]); -#endif + s_call_addr = reinterpret_cast(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; } diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index 3fb2618d5f..e3f092f9dd 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -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,16 @@ DataStatus EncodeValveParam(IPluginContext *pContext, *addr = *(bool *)buffer ? 1 : 0; + return Data_Okay; + } + case Valve_VirtualAddress: + { + if (data->flags & PASSFLAG_ASPOINTER) + { + buffer = *(void **)buffer; + } + param = g_pSM->ToPseudoAddress((void*)buffer); + return Data_Okay; } } @@ -585,6 +610,18 @@ DataStatus DecodeValveParam(IPluginContext *pContext, *(char **)buffer = addr; return Data_Okay; } + case Valve_VirtualAddress: + { + 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; diff --git a/extensions/sdktools/vdecoder.h b/extensions/sdktools/vdecoder.h index 16478cf101..c865b8e2e7 100644 --- a/extensions/sdktools/vdecoder.h +++ b/extensions/sdktools/vdecoder.h @@ -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 */ }; diff --git a/plugins/include/sdktools.inc b/plugins/include/sdktools.inc index 07fc55f82f..95663e8f2c 100644 --- a/plugins/include/sdktools.inc +++ b/plugins/include/sdktools.inc @@ -88,7 +88,10 @@ 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) */ +#if defined VIRTUAL_ADDRESS + SDKType_VirtualAddress, /**< SM Virtual Address */ +#endif }; enum SDKPassMethod diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 1927015680..3b8f958db7 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -730,6 +730,10 @@ enum Address Address_Null = 0 // a typical invalid result when an address lookup fails }; +#if defined VIRTUAL_ADDRESS +public const Address __Virtual_Address__ = 0; +#endif + /** * Load up to 4 bytes from a memory address. * @@ -754,6 +758,28 @@ 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. + * @param size How many bytes should be read. + * If loading a floating-point value, use NumberType_Int32. + * @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.