core/MemoryUtils.cpp
author Scott Ehlert <ds@alliedmods.net>
Fri Apr 20 18:50:52 2007 +0000 (2007-04-20)
changeset 701 85c77b23ae47
parent 700 2b715374ce25
child 702 ff520b71249c
permissions -rw-r--r--
Made libPtr param const. Doesn't get modified so why not.
Also removed some unneccessary code (for now)
     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 "sm_platform.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::FindPattern(const void *libPtr, const char *pattern, size_t len)
    43 {
    44 	DynLibInfo lib;
    45 	bool found;
    46 	char *ptr, *end;
    47 
    48 	memset(&lib, 0, sizeof(DynLibInfo));
    49 
    50 	if (!GetLibraryInfo(libPtr, lib))
    51 	{
    52 		return NULL;
    53 	}
    54 
    55 	ptr = reinterpret_cast<char *>(lib.baseAddress);
    56 	end = ptr + lib.memorySize;
    57 
    58 	while (ptr < end)
    59 	{
    60 		found = true;
    61 		for (register size_t i = 0; i < len; i++)
    62 		{
    63 			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
    64 			{
    65 				found = false;
    66 				break;
    67 			}
    68 		}
    69 
    70 		if (found)
    71 			return ptr;
    72 
    73 		ptr++;
    74 	}
    75 
    76 	return NULL;
    77 }
    78 
    79 bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
    80 {
    81 	unsigned long baseAddr;
    82 
    83 	if (libPtr == NULL)
    84 	{
    85 		return false;
    86 	}
    87 
    88 #ifdef PLATFORM_WINDOWS
    89 
    90 	MEMORY_BASIC_INFORMATION info;
    91 	IMAGE_DOS_HEADER *dos;
    92 	IMAGE_NT_HEADERS *pe;
    93 	IMAGE_FILE_HEADER *file;
    94 	IMAGE_OPTIONAL_HEADER *opt;
    95 
    96 	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
    97 	{
    98 		return false;
    99 	}
   100 
   101 	baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
   102 
   103 	/* All this is for our insane sanity checks :o */
   104 	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
   105 	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
   106 	file = &pe->FileHeader;
   107 	opt = &pe->OptionalHeader;
   108 
   109 	/* Check PE magic and signature */
   110 	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
   111 	{
   112 		return false;
   113 	}
   114 
   115 	/* Check architecture, which is 32-bit/x86 right now
   116 	 * Should change this for 64-bit if Valve gets their act together
   117 	 */
   118 	if (file->Machine != IMAGE_FILE_MACHINE_I386)
   119 	{
   120 		return false;
   121 	}
   122 
   123 	/* For our purposes, this must be a dynamic library */
   124 	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
   125 	{
   126 		return false;
   127 	}
   128 
   129 	/* Finally, we can do this */
   130 	lib.memorySize = opt->SizeOfImage;
   131 
   132 #elif defined PLATFORM_LINUX
   133 
   134 	Dl_info info;
   135 	Elf32_Ehdr *file;
   136 	Elf32_Phdr *phdr;
   137 	uint16_t phdrCount;
   138 
   139 	if (!dladdr(libPtr, &info))
   140 	{
   141 		return false;
   142 	}
   143 
   144 	if (!info.dli_fbase || !info.dli_fname)
   145 	{
   146 		return false;
   147 	}
   148 
   149 	/* This is for our insane sanity checks :o */
   150 	baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
   151 	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
   152 
   153 	/* Check ELF magic */
   154 	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
   155 	{
   156 		return false;
   157 	}
   158 
   159 	/* Check ELF version */
   160 	if (file->e_ident[EI_VERSION] != EV_CURRENT)
   161 	{
   162 		return false;
   163 	}
   164 
   165 	/* Check ELF architecture, which is 32-bit/x86 right now
   166 	 * Should change this for 64-bit if Valve gets their act together
   167 	 */
   168 	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
   169 	{
   170 		return false;
   171 	}
   172 
   173 	/* For our purposes, this must be a dynamic library/shared object */
   174 	if (file->e_type != ET_DYN)
   175 	{
   176 		return false;
   177 	}
   178 
   179 	phdrCount = file->e_phnum;
   180 	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
   181 	
   182 	/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
   183 	for (uint16_t i = 0; i < phdrCount; i++)
   184 	{
   185 		Elf32_Phdr &hdr = phdr[i];
   186 
   187 		if (hdr.p_type == PT_LOAD)
   188 		{
   189 			lib.memorySize += hdr.p_memsz;
   190 		}
   191 	}
   192 
   193 #endif
   194 
   195 	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
   196 
   197 	return true;
   198 }