core/MemoryUtils.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 01 02:12:47 2007 +0000 (2007-08-01)
changeset 1231 17badaf66ce4
parent 702 ff520b71249c
child 1330 ab94316bb52b
permissions -rw-r--r--
updated more header files (mostly internal now)
ds@700
     1
/**
ds@700
     2
 * vim: set ts=4 :
dvander@1231
     3
 * ================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1231
     6
 * ================================================================
ds@700
     7
 *
dvander@1231
     8
 * This program is free software; you can redistribute it and/or 
dvander@1231
     9
 * modify it under the terms of the GNU General Public License, 
dvander@1231
    10
 * version 3.0, as published by the Free Software Foundation.
dvander@1231
    11
 * 
dvander@1231
    12
 * This program is distributed in the hope that it will be useful,
dvander@1231
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
dvander@1231
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dvander@1231
    15
 * GNU General Public License for more details.
dvander@1231
    16
 *
dvander@1231
    17
 * You should have received a copy of the GNU General Public License
dvander@1231
    18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
dvander@1231
    20
 * As a special exception, AlliedModders LLC gives you permission to 
dvander@1231
    21
 * link the code of this program (as well as its derivative works) to 
dvander@1231
    22
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
dvander@1231
    23
 * Game MODs that run on software by the Valve Corporation.  You must 
dvander@1231
    24
 * obey the GNU General Public License in all respects for all other 
dvander@1231
    25
 * code used. Additionally, AlliedModders LLC grants this exception 
dvander@1231
    26
 * to all derivative works. AlliedModders LLC defines further 
dvander@1231
    27
 * exceptions, found in LICENSE.txt (as of this writing, version 
dvander@1231
    28
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
ds@700
    29
 *
ds@700
    30
 * Version: $Id$
ds@700
    31
 */
ds@700
    32
ds@700
    33
#include "MemoryUtils.h"
ds@702
    34
#include "ShareSys.h"
ds@700
    35
#ifdef PLATFORM_LINUX
ds@700
    36
#include <string.h>
ds@700
    37
#include <elf.h>
ds@700
    38
#endif
ds@700
    39
ds@700
    40
MemoryUtils g_MemUtils;
ds@700
    41
ds@701
    42
#if 0
ds@700
    43
MemoryUtils::MemoryUtils()
ds@700
    44
{
ds@700
    45
#ifdef PLATFORM_WINDOWS
ds@700
    46
ds@700
    47
	SYSTEM_INFO info;
ds@700
    48
	GetSystemInfo(&info);
ds@700
    49
ds@700
    50
	m_PageSize = info.dwPageSize;
ds@700
    51
ds@700
    52
#elif defined PLATFORM_POSIX
ds@700
    53
ds@700
    54
	m_PageSize = sysconf(_SC_PAGE_SIZE);
ds@700
    55
ds@700
    56
#endif
ds@700
    57
}
ds@701
    58
#endif
ds@700
    59
ds@702
    60
void MemoryUtils::OnSourceModAllInitialized()
ds@702
    61
{
ds@702
    62
	g_ShareSys.AddInterface(NULL, this);
ds@702
    63
}
ds@702
    64
ds@701
    65
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
ds@700
    66
{
ds@700
    67
	DynLibInfo lib;
ds@700
    68
	bool found;
ds@700
    69
	char *ptr, *end;
ds@700
    70
ds@700
    71
	memset(&lib, 0, sizeof(DynLibInfo));
ds@700
    72
ds@700
    73
	if (!GetLibraryInfo(libPtr, lib))
ds@700
    74
	{
ds@700
    75
		return NULL;
ds@700
    76
	}
ds@700
    77
ds@700
    78
	ptr = reinterpret_cast<char *>(lib.baseAddress);
ds@700
    79
	end = ptr + lib.memorySize;
ds@700
    80
ds@700
    81
	while (ptr < end)
ds@700
    82
	{
ds@700
    83
		found = true;
ds@700
    84
		for (register size_t i = 0; i < len; i++)
ds@700
    85
		{
ds@700
    86
			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
ds@700
    87
			{
ds@700
    88
				found = false;
ds@700
    89
				break;
ds@700
    90
			}
ds@700
    91
		}
ds@700
    92
ds@700
    93
		if (found)
ds@700
    94
			return ptr;
ds@700
    95
ds@700
    96
		ptr++;
ds@700
    97
	}
ds@700
    98
ds@700
    99
	return NULL;
ds@700
   100
}
ds@700
   101
ds@701
   102
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
ds@700
   103
{
ds@700
   104
	unsigned long baseAddr;
ds@700
   105
ds@700
   106
	if (libPtr == NULL)
ds@700
   107
	{
ds@700
   108
		return false;
ds@700
   109
	}
ds@700
   110
ds@700
   111
#ifdef PLATFORM_WINDOWS
ds@700
   112
ds@700
   113
	MEMORY_BASIC_INFORMATION info;
ds@700
   114
	IMAGE_DOS_HEADER *dos;
ds@700
   115
	IMAGE_NT_HEADERS *pe;
ds@700
   116
	IMAGE_FILE_HEADER *file;
ds@700
   117
	IMAGE_OPTIONAL_HEADER *opt;
ds@700
   118
ds@700
   119
	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
ds@700
   120
	{
ds@700
   121
		return false;
ds@700
   122
	}
ds@700
   123
ds@700
   124
	baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
ds@700
   125
ds@700
   126
	/* All this is for our insane sanity checks :o */
ds@700
   127
	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
ds@700
   128
	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
ds@700
   129
	file = &pe->FileHeader;
ds@700
   130
	opt = &pe->OptionalHeader;
ds@700
   131
ds@700
   132
	/* Check PE magic and signature */
ds@700
   133
	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
ds@700
   134
	{
ds@700
   135
		return false;
ds@700
   136
	}
ds@700
   137
ds@700
   138
	/* Check architecture, which is 32-bit/x86 right now
ds@700
   139
	 * Should change this for 64-bit if Valve gets their act together
ds@700
   140
	 */
ds@700
   141
	if (file->Machine != IMAGE_FILE_MACHINE_I386)
ds@700
   142
	{
ds@700
   143
		return false;
ds@700
   144
	}
ds@700
   145
ds@700
   146
	/* For our purposes, this must be a dynamic library */
ds@700
   147
	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
ds@700
   148
	{
ds@700
   149
		return false;
ds@700
   150
	}
ds@700
   151
ds@700
   152
	/* Finally, we can do this */
ds@700
   153
	lib.memorySize = opt->SizeOfImage;
ds@700
   154
ds@700
   155
#elif defined PLATFORM_LINUX
ds@700
   156
ds@700
   157
	Dl_info info;
ds@700
   158
	Elf32_Ehdr *file;
ds@700
   159
	Elf32_Phdr *phdr;
ds@700
   160
	uint16_t phdrCount;
ds@700
   161
ds@700
   162
	if (!dladdr(libPtr, &info))
ds@700
   163
	{
ds@700
   164
		return false;
ds@700
   165
	}
ds@700
   166
ds@700
   167
	if (!info.dli_fbase || !info.dli_fname)
ds@700
   168
	{
ds@700
   169
		return false;
ds@700
   170
	}
ds@700
   171
ds@700
   172
	/* This is for our insane sanity checks :o */
ds@700
   173
	baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
ds@700
   174
	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
ds@700
   175
ds@700
   176
	/* Check ELF magic */
ds@700
   177
	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
ds@700
   178
	{
ds@700
   179
		return false;
ds@700
   180
	}
ds@700
   181
ds@700
   182
	/* Check ELF version */
ds@700
   183
	if (file->e_ident[EI_VERSION] != EV_CURRENT)
ds@700
   184
	{
ds@700
   185
		return false;
ds@700
   186
	}
ds@700
   187
ds@700
   188
	/* Check ELF architecture, which is 32-bit/x86 right now
ds@700
   189
	 * Should change this for 64-bit if Valve gets their act together
ds@700
   190
	 */
ds@700
   191
	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
ds@700
   192
	{
ds@700
   193
		return false;
ds@700
   194
	}
ds@700
   195
ds@700
   196
	/* For our purposes, this must be a dynamic library/shared object */
ds@700
   197
	if (file->e_type != ET_DYN)
ds@700
   198
	{
ds@700
   199
		return false;
ds@700
   200
	}
ds@700
   201
ds@700
   202
	phdrCount = file->e_phnum;
ds@700
   203
	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
ds@700
   204
	
ds@700
   205
	/* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
ds@700
   206
	for (uint16_t i = 0; i < phdrCount; i++)
ds@700
   207
	{
ds@700
   208
		Elf32_Phdr &hdr = phdr[i];
ds@700
   209
ds@700
   210
		if (hdr.p_type == PT_LOAD)
ds@700
   211
		{
ds@700
   212
			lib.memorySize += hdr.p_memsz;
ds@700
   213
		}
ds@700
   214
	}
ds@700
   215
ds@700
   216
#endif
ds@700
   217
ds@700
   218
	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
ds@700
   219
ds@700
   220
	return true;
ds@700
   221
}