3 * ================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * ================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License,
10 * version 3.0, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to
21 * link the code of this program (as well as its derivative works) to
22 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any
23 * Game MODs that run on software by the Valve Corporation. You must
24 * obey the GNU General Public License in all respects for all other
25 * code used. Additionally, AlliedModders LLC grants this exception
26 * to all derivative works. AlliedModders LLC defines further
27 * exceptions, found in LICENSE.txt (as of this writing, version
28 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
33 #include "MemoryUtils.h"
40 MemoryUtils g_MemUtils;
43 MemoryUtils::MemoryUtils()
45 #ifdef PLATFORM_WINDOWS
50 m_PageSize = info.dwPageSize;
52 #elif defined PLATFORM_POSIX
54 m_PageSize = sysconf(_SC_PAGE_SIZE);
60 void MemoryUtils::OnSourceModAllInitialized()
62 g_ShareSys.AddInterface(NULL, this);
65 void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
71 memset(&lib, 0, sizeof(DynLibInfo));
73 if (!GetLibraryInfo(libPtr, lib))
78 ptr = reinterpret_cast<char *>(lib.baseAddress);
79 end = ptr + lib.memorySize;
84 for (register size_t i = 0; i < len; i++)
86 if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
102 bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
104 unsigned long baseAddr;
111 #ifdef PLATFORM_WINDOWS
113 MEMORY_BASIC_INFORMATION info;
114 IMAGE_DOS_HEADER *dos;
115 IMAGE_NT_HEADERS *pe;
116 IMAGE_FILE_HEADER *file;
117 IMAGE_OPTIONAL_HEADER *opt;
119 if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
124 baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
126 /* All this is for our insane sanity checks :o */
127 dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
128 pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
129 file = &pe->FileHeader;
130 opt = &pe->OptionalHeader;
132 /* Check PE magic and signature */
133 if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
138 /* Check architecture, which is 32-bit/x86 right now
139 * Should change this for 64-bit if Valve gets their act together
141 if (file->Machine != IMAGE_FILE_MACHINE_I386)
146 /* For our purposes, this must be a dynamic library */
147 if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
152 /* Finally, we can do this */
153 lib.memorySize = opt->SizeOfImage;
155 #elif defined PLATFORM_LINUX
162 if (!dladdr(libPtr, &info))
167 if (!info.dli_fbase || !info.dli_fname)
172 /* This is for our insane sanity checks :o */
173 baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
174 file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
176 /* Check ELF magic */
177 if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
182 /* Check ELF version */
183 if (file->e_ident[EI_VERSION] != EV_CURRENT)
188 /* Check ELF architecture, which is 32-bit/x86 right now
189 * Should change this for 64-bit if Valve gets their act together
191 if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
196 /* For our purposes, this must be a dynamic library/shared object */
197 if (file->e_type != ET_DYN)
202 phdrCount = file->e_phnum;
203 phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
205 /* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
206 for (uint16_t i = 0; i < phdrCount; i++)
208 Elf32_Phdr &hdr = phdr[i];
210 if (hdr.p_type == PT_LOAD)
212 lib.memorySize += hdr.p_memsz;
218 lib.baseAddress = reinterpret_cast<void *>(baseAddr);