Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul Address #2226

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 9 additions & 3 deletions core/logic/AMBuilder
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
186 changes: 70 additions & 116 deletions core/logic/PseudoAddrManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,142 +28,96 @@
*/

#include "PseudoAddrManager.h"
#include <bridge/include/CoreProvider.h>
#ifdef PLATFORM_APPLE
#include <mach/mach.h>
#include <mach/vm_region.h>
#endif
#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::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<void *>(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<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.RecoverAddress(paddr).value_or(nullptr);
}

uint32_t PseudoAddressManager::ToPseudoAddress(void *addr)
{
if (addr == nullptr) {
return 0;
}
return m_dictionary.Make32bitAddress(addr).value_or(0);
}
9 changes: 3 additions & 6 deletions core/logic/PseudoAddrManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define _INCLUDE_SOURCEMOD_PSEUDOADDRESSMANAGER_H_

#include "common_logic.h"
#include "libaddrz/addrz.h"

class PseudoAddressManager
{
Expand All @@ -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_
12 changes: 2 additions & 10 deletions core/logic/common_logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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();

Expand Down
1 change: 1 addition & 0 deletions core/logic/libaddrz
Submodule libaddrz added at 661cd3
Loading
Loading