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