core/MemoryUtils.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 03 20:46:17 2007 +0000 (2007-07-03)
changeset 1036 2a073d5b3454
parent 702 ff520b71249c
child 1231 17badaf66ce4
permissions -rw-r--r--
added amb505
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "MemoryUtils.h"
    16 #include "ShareSys.h"
    17 #ifdef PLATFORM_LINUX
    18 #include <string.h>
    19 #include <elf.h>
    20 #endif
    21 
    22 MemoryUtils g_MemUtils;
    23 
    24 #if 0
    25 MemoryUtils::MemoryUtils()
    26 {
    27 #ifdef PLATFORM_WINDOWS
    28 
    29 	SYSTEM_INFO info;
    30 	GetSystemInfo(&info);
    31 
    32 	m_PageSize = info.dwPageSize;
    33 
    34 #elif defined PLATFORM_POSIX
    35 
    36 	m_PageSize = sysconf(_SC_PAGE_SIZE);
    37 
    38 #endif
    39 }
    40 #endif
    41 
    42 void MemoryUtils::OnSourceModAllInitialized()
    43 {
    44 	g_ShareSys.AddInterface(NULL, this);
    45 }
    46 
    47 void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
    48 {
    49 	DynLibInfo lib;
    50 	bool found;
    51 	char *ptr, *end;
    52 
    53 	memset(&lib, 0, sizeof(DynLibInfo));
    54 
    55 	if (!GetLibraryInfo(libPtr, lib))
    56 	{
    57 		return NULL;
    58 	}
    59 
    60 	ptr = reinterpret_cast<char *>(lib.baseAddress);
    61 	end = ptr + lib.memorySize;
    62 
    63 	while (ptr < end)
    64 	{
    65 		found = true;
    66 		for (register size_t i = 0; i < len; i++)
    67 		{
    68 			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
    69 			{
    70 				found = false;
    71 				break;
    72 			}
    73 		}
    74 
    75 		if (found)
    76 			return ptr;
    77 
    78 		ptr++;
    79 	}
    80 
    81 	return NULL;
    82 }
    83 
    84 bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
    85 {
    86 	unsigned long baseAddr;
    87 
    88 	if (libPtr == NULL)
    89 	{
    90 		return false;
    91 	}
    92 
    93 #ifdef PLATFORM_WINDOWS
    94 
    95 	MEMORY_BASIC_INFORMATION info;
    96 	IMAGE_DOS_HEADER *dos;
    97 	IMAGE_NT_HEADERS *pe;
    98 	IMAGE_FILE_HEADER *file;
    99 	IMAGE_OPTIONAL_HEADER *opt;
   100 
   101 	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
   102 	{
   103 		return false;
   104 	}
   105 
   106 	baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
   107 
   108 	/* All this is for our insane sanity checks :o */
   109 	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
   110 	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
   111 	file = &pe->FileHeader;
   112 	opt = &pe->OptionalHeader;
   113 
   114 	/* Check PE magic and signature */
   115 	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
   116 	{
   117 		return false;
   118 	}
   119 
   120 	/* Check architecture, which is 32-bit/x86 right now
   121 	 * Should change this for 64-bit if Valve gets their act together
   122 	 */
   123 	if (file->Machine != IMAGE_FILE_MACHINE_I386)
   124 	{
   125 		return false;
   126 	}
   127 
   128 	/* For our purposes, this must be a dynamic library */
   129 	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
   130 	{
   131 		return false;
   132 	}
   133 
   134 	/* Finally, we can do this */
   135 	lib.memorySize = opt->SizeOfImage;
   136 
   137 #elif defined PLATFORM_LINUX
   138 
   139 	Dl_info info;
   140 	Elf32_Ehdr *file;
   141 	Elf32_Phdr *phdr;
   142 	uint16_t phdrCount;
   143 
   144 	if (!dladdr(libPtr, &info))
   145 	{
   146 		return false;
   147 	}
   148 
   149 	if (!info.dli_fbase || !info.dli_fname)
   150 	{
   151 		return false;
   152 	}
   153 
   154 	/* This is for our insane sanity checks :o */
   155 	baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
   156 	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
   157 
   158 	/* Check ELF magic */
   159 	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
   160 	{
   161 		return false;
   162 	}
   163 
   164 	/* Check ELF version */
   165 	if (file->e_ident[EI_VERSION] != EV_CURRENT)
   166 	{
   167 		return false;
   168 	}
   169 
   170 	/* Check ELF architecture, which is 32-bit/x86 right now
   171 	 * Should change this for 64-bit if Valve gets their act together
   172 	 */
   173 	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
   174 	{
   175 		return false;
   176 	}
   177 
   178 	/* For our purposes, this must be a dynamic library/shared object */
   179 	if (file->e_type != ET_DYN)
   180 	{
   181 		return false;
   182 	}
   183 
   184 	phdrCount = file->e_phnum;
   185 	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
   186 	
   187 	/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
   188 	for (uint16_t i = 0; i < phdrCount; i++)
   189 	{
   190 		Elf32_Phdr &hdr = phdr[i];
   191 
   192 		if (hdr.p_type == PT_LOAD)
   193 		{
   194 			lib.memorySize += hdr.p_memsz;
   195 		}
   196 	}
   197 
   198 #endif
   199 
   200 	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
   201 
   202 	return true;
   203 }