core/MemoryUtils.cpp
author Michael McKoy <ferret99gt@gmail.com>
Wed Aug 08 23:26:42 2007 +0000 (2007-08-08)
changeset 1280 13c62962a9ef
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
Corrected filename in header of basefuncommands.sp
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     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.
    11  * 
    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.
    16  *
    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/>.
    19  *
    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>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include "MemoryUtils.h"
    34 #include "ShareSys.h"
    35 #ifdef PLATFORM_LINUX
    36 #include <string.h>
    37 #include <elf.h>
    38 #endif
    39 
    40 MemoryUtils g_MemUtils;
    41 
    42 #if 0
    43 MemoryUtils::MemoryUtils()
    44 {
    45 #ifdef PLATFORM_WINDOWS
    46 
    47 	SYSTEM_INFO info;
    48 	GetSystemInfo(&info);
    49 
    50 	m_PageSize = info.dwPageSize;
    51 
    52 #elif defined PLATFORM_POSIX
    53 
    54 	m_PageSize = sysconf(_SC_PAGE_SIZE);
    55 
    56 #endif
    57 }
    58 #endif
    59 
    60 void MemoryUtils::OnSourceModAllInitialized()
    61 {
    62 	g_ShareSys.AddInterface(NULL, this);
    63 }
    64 
    65 void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
    66 {
    67 	DynLibInfo lib;
    68 	bool found;
    69 	char *ptr, *end;
    70 
    71 	memset(&lib, 0, sizeof(DynLibInfo));
    72 
    73 	if (!GetLibraryInfo(libPtr, lib))
    74 	{
    75 		return NULL;
    76 	}
    77 
    78 	ptr = reinterpret_cast<char *>(lib.baseAddress);
    79 	end = ptr + lib.memorySize;
    80 
    81 	while (ptr < end)
    82 	{
    83 		found = true;
    84 		for (register size_t i = 0; i < len; i++)
    85 		{
    86 			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
    87 			{
    88 				found = false;
    89 				break;
    90 			}
    91 		}
    92 
    93 		if (found)
    94 			return ptr;
    95 
    96 		ptr++;
    97 	}
    98 
    99 	return NULL;
   100 }
   101 
   102 bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
   103 {
   104 	unsigned long baseAddr;
   105 
   106 	if (libPtr == NULL)
   107 	{
   108 		return false;
   109 	}
   110 
   111 #ifdef PLATFORM_WINDOWS
   112 
   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;
   118 
   119 	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
   120 	{
   121 		return false;
   122 	}
   123 
   124 	baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
   125 
   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;
   131 
   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)
   134 	{
   135 		return false;
   136 	}
   137 
   138 	/* Check architecture, which is 32-bit/x86 right now
   139 	 * Should change this for 64-bit if Valve gets their act together
   140 	 */
   141 	if (file->Machine != IMAGE_FILE_MACHINE_I386)
   142 	{
   143 		return false;
   144 	}
   145 
   146 	/* For our purposes, this must be a dynamic library */
   147 	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
   148 	{
   149 		return false;
   150 	}
   151 
   152 	/* Finally, we can do this */
   153 	lib.memorySize = opt->SizeOfImage;
   154 
   155 #elif defined PLATFORM_LINUX
   156 
   157 	Dl_info info;
   158 	Elf32_Ehdr *file;
   159 	Elf32_Phdr *phdr;
   160 	uint16_t phdrCount;
   161 
   162 	if (!dladdr(libPtr, &info))
   163 	{
   164 		return false;
   165 	}
   166 
   167 	if (!info.dli_fbase || !info.dli_fname)
   168 	{
   169 		return false;
   170 	}
   171 
   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);
   175 
   176 	/* Check ELF magic */
   177 	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
   178 	{
   179 		return false;
   180 	}
   181 
   182 	/* Check ELF version */
   183 	if (file->e_ident[EI_VERSION] != EV_CURRENT)
   184 	{
   185 		return false;
   186 	}
   187 
   188 	/* Check ELF architecture, which is 32-bit/x86 right now
   189 	 * Should change this for 64-bit if Valve gets their act together
   190 	 */
   191 	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
   192 	{
   193 		return false;
   194 	}
   195 
   196 	/* For our purposes, this must be a dynamic library/shared object */
   197 	if (file->e_type != ET_DYN)
   198 	{
   199 		return false;
   200 	}
   201 
   202 	phdrCount = file->e_phnum;
   203 	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
   204 	
   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++)
   207 	{
   208 		Elf32_Phdr &hdr = phdr[i];
   209 
   210 		if (hdr.p_type == PT_LOAD)
   211 		{
   212 			lib.memorySize += hdr.p_memsz;
   213 		}
   214 	}
   215 
   216 #endif
   217 
   218 	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
   219 
   220 	return true;
   221 }