core/MemoryUtils.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1947 e73a1e51833b
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

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