|
28 | 28 | */ |
29 | 29 |
|
30 | 30 | #include "PseudoAddrManager.h" |
| 31 | +#include <bridge/include/CoreProvider.h> |
31 | 32 | #ifdef PLATFORM_APPLE |
32 | 33 | #include <mach/mach.h> |
33 | 34 | #include <mach/vm_region.h> |
34 | 35 | #endif |
35 | 36 | #ifdef PLATFORM_LINUX |
36 | 37 | #include <inttypes.h> |
37 | 38 | #endif |
| 39 | +#ifdef PLATFORM_WINDOWS |
| 40 | +#include <Psapi.h> |
| 41 | +#endif |
38 | 42 |
|
39 | | -PseudoAddressManager::PseudoAddressManager() : m_NumEntries(0) |
| 43 | +PseudoAddressManager::PseudoAddressManager() : m_dictionary(am::IPlatform::GetDefault()) |
40 | 44 | { |
41 | 45 | } |
42 | 46 |
|
43 | | -// A pseudo address consists of a table index in the upper 6 bits and an offset in the |
44 | | -// lower 26 bits. The table consists of memory allocation base addresses. |
45 | | -void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr) |
46 | | -{ |
47 | | -#ifdef KE_ARCH_X64 |
48 | | - uint8_t index = paddr >> PSEUDO_OFFSET_BITS; |
49 | | - uint32_t offset = paddr & ((1 << PSEUDO_OFFSET_BITS) - 1); |
50 | | - |
51 | | - if (index >= m_NumEntries) |
52 | | - return nullptr; |
53 | | - |
54 | | - return reinterpret_cast<void *>(uintptr_t(m_AllocBases[index]) + offset); |
55 | | -#else |
56 | | - return nullptr; |
| 47 | +void PseudoAddressManager::Initialize() { |
| 48 | +#ifdef PLATFORM_WINDOWS |
| 49 | + auto process = GetCurrentProcess(); |
| 50 | + auto get_module_details = [process](const char* name, void*& baseAddress, size_t& moduleSize) { |
| 51 | + if (process == NULL) { |
| 52 | + return false; |
| 53 | + } |
| 54 | + auto hndl = GetModuleHandle(name); |
| 55 | + if (hndl == NULL) { |
| 56 | + return false; |
| 57 | + } |
| 58 | + MODULEINFO info; |
| 59 | + if (!GetModuleInformation(process, hndl, &info, sizeof(info))) { |
| 60 | + return false; |
| 61 | + } |
| 62 | + moduleSize = info.SizeOfImage; |
| 63 | + baseAddress = info.lpBaseOfDll; |
| 64 | + return true; |
| 65 | + }; |
57 | 66 | #endif |
58 | | -} |
59 | | - |
60 | | -uint32_t PseudoAddressManager::ToPseudoAddress(void *addr) |
61 | | -{ |
62 | | -#ifdef KE_ARCH_X64 |
63 | | - uint8_t index = 0; |
64 | | - uint32_t offset = 0; |
65 | | - bool hasEntry = false; |
66 | | - void *base = GetAllocationBase(addr); |
67 | | - |
68 | | - if (base) { |
69 | | - for (int i = 0; i < m_NumEntries; i++) { |
70 | | - if (m_AllocBases[i] == base) { |
71 | | - index = i; |
72 | | - hasEntry = true; |
73 | | - break; |
74 | | - } |
| 67 | +#ifdef PLATFORM_LINUX |
| 68 | + auto get_module_details = [](const char* name, void* baseAddress, size_t& moduleSize) { |
| 69 | + auto hndl = dlopen(name, RTLD_NOLOAD); |
| 70 | + if (hndl == NULL) { |
| 71 | + return false; |
75 | 72 | } |
76 | | - } else { |
77 | | - return 0; |
78 | | - } |
| 73 | + void* addr = dlsym(hndl, "CreateInterface"); |
| 74 | + dlclose(hndl); |
79 | 75 |
|
80 | | - if (!hasEntry) { |
81 | | - index = m_NumEntries; |
82 | | - if (m_NumEntries < SM_ARRAYSIZE(m_AllocBases)) |
83 | | - m_AllocBases[m_NumEntries++] = base; |
84 | | - else |
85 | | - return 0; // Table is full |
86 | | - } |
87 | | - |
88 | | - ptrdiff_t diff = uintptr_t(addr) - uintptr_t(base); |
| 76 | + if (!addr) { |
| 77 | + return false; |
| 78 | + } |
89 | 79 |
|
90 | | - // Ensure difference fits in 26 bits |
91 | | - if (diff > (UINT32_MAX >> PSEUDO_INDEX_BITS)) |
92 | | - return 0; |
| 80 | + Dl_info info; |
| 81 | + if (dladdr(addr, &info) == 0) { |
| 82 | + return false; |
| 83 | + } |
93 | 84 |
|
94 | | - return (index << PSEUDO_OFFSET_BITS) | diff; |
95 | | -#else |
96 | | - return 0; |
| 85 | + baseAddress = info.dli_fbase; |
| 86 | + // It doesn't matter much if we figure out the module size |
| 87 | + // libaddrz coalesce maps on linux |
| 88 | + moduleSize = 0; |
| 89 | + return true; |
| 90 | + }; |
97 | 91 | #endif |
| 92 | + |
| 93 | + // Early map commonly used modules, it's okay if not all of them are here |
| 94 | + // Everything else will be caught by "ToPseudoAddress" but you risk running out of ranges by then |
| 95 | + const char* libs[] = { "engine", "server", "tier0", "vstdlib" }; |
| 96 | + |
| 97 | + char formattedName[64]; |
| 98 | + for (int i = 0; i < sizeof(libs) / sizeof(const char*); i++) { |
| 99 | + bridge->FormatSourceBinaryName(libs[i], formattedName, sizeof(formattedName)); |
| 100 | + void* base_addr = nullptr; |
| 101 | + size_t module_size = 0; |
| 102 | + if (get_module_details(formattedName, base_addr, module_size)) { |
| 103 | + // Create the mapping (hopefully) |
| 104 | + m_dictionary.Make32bitAddress(base_addr, module_size); |
| 105 | + } |
| 106 | + } |
98 | 107 | } |
99 | 108 |
|
100 | | -void *PseudoAddressManager::GetAllocationBase(void *ptr) |
| 109 | +void *PseudoAddressManager::FromPseudoAddress(uint32_t paddr) |
101 | 110 | { |
102 | | -#if defined PLATFORM_WINDOWS |
103 | | - |
104 | | - MEMORY_BASIC_INFORMATION info; |
105 | | - if (!VirtualQuery(ptr, &info, sizeof(MEMORY_BASIC_INFORMATION))) |
| 111 | + if (paddr == 0) { |
106 | 112 | return nullptr; |
107 | | - return info.AllocationBase; |
108 | | - |
109 | | -#elif defined PLATFORM_APPLE |
110 | | - |
111 | | -#ifdef KE_ARCH_X86 |
112 | | - typedef vm_region_info_t mach_vm_region_info_t; |
113 | | - typedef vm_region_basic_info_data_t mach_vm_region_basic_info_data_t; |
114 | | - const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO; |
115 | | - const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT; |
116 | | - #define mach_vm_region vm_region |
117 | | -#elif defined KE_ARCH_X64 |
118 | | - typedef vm_region_info_64_t mach_vm_region_info_t ; |
119 | | - typedef vm_region_basic_info_data_64_t mach_vm_region_basic_info_data_t; |
120 | | - const vm_region_flavor_t MACH_VM_REGION_BASIC_INFO = VM_REGION_BASIC_INFO_64; |
121 | | - const mach_msg_type_number_t MACH_VM_REGION_BASIC_INFO_COUNT = VM_REGION_BASIC_INFO_COUNT_64; |
122 | | - #define mach_vm_region vm_region_64 |
123 | | -#endif |
124 | | - vm_size_t size; |
125 | | - vm_address_t vmaddr = reinterpret_cast<vm_address_t>(ptr); |
126 | | - mach_vm_region_basic_info_data_t info; |
127 | | - memory_object_name_t obj; |
128 | | - vm_region_flavor_t flavor = MACH_VM_REGION_BASIC_INFO; |
129 | | - mach_msg_type_number_t count = MACH_VM_REGION_BASIC_INFO_COUNT; |
130 | | - |
131 | | - kern_return_t kr = mach_vm_region(mach_task_self(), &vmaddr, &size, flavor, |
132 | | - reinterpret_cast<mach_vm_region_info_t>(&info), |
133 | | - &count, &obj); |
134 | | - |
135 | | - if (kr != KERN_SUCCESS) |
136 | | - return nullptr; |
137 | | - |
138 | | - return reinterpret_cast<void *>(vmaddr); |
139 | | - |
140 | | -#elif defined PLATFORM_LINUX |
141 | | - |
142 | | - uintptr_t addr = reinterpret_cast<uintptr_t>(ptr); |
143 | | - |
144 | | - // Format: |
145 | | - // lower upper prot stuff path |
146 | | - // 08048000-0804c000 r-xp 00000000 03:03 1010107 /bin/cat |
147 | | - FILE *fp = fopen("/proc/self/maps", "r"); |
148 | | - if (fp) { |
149 | | - uintptr_t lower, upper; |
150 | | - while (fscanf(fp, "%" PRIxPTR "-%" PRIxPTR, &lower, &upper) != EOF) { |
151 | | - if (addr >= lower && addr <= upper) { |
152 | | - fclose(fp); |
153 | | - return reinterpret_cast<void *>(lower); |
154 | | - } |
| 113 | + } |
| 114 | + return m_dictionary.RecoverAddress(paddr).value_or(nullptr); |
| 115 | +} |
155 | 116 |
|
156 | | - // Read to end of line |
157 | | - int c; |
158 | | - while ((c = fgetc(fp)) != '\n') { |
159 | | - if (c == EOF) |
160 | | - break; |
161 | | - } |
162 | | - if (c == EOF) |
163 | | - break; |
164 | | - } |
165 | | - fclose(fp); |
| 117 | +uint32_t PseudoAddressManager::ToPseudoAddress(void *addr) |
| 118 | +{ |
| 119 | + if (addr == nullptr) { |
| 120 | + return 0; |
166 | 121 | } |
167 | | - return nullptr; |
168 | | -#endif |
| 122 | + return m_dictionary.Make32bitAddress(addr).value_or(0); |
169 | 123 | } |
0 commit comments