tools/gdc-psyfork/MemoryUtils.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Sun May 27 11:36:49 2012 -0400 (2012-05-27)
changeset 3513 50b5b98b3400
child 3574 b51285ca203f
permissions -rw-r--r--
Added "psyfork" of gdc and example scripts to tools/ (NPOTB).
skamonkey@3513
     1
/**
skamonkey@3513
     2
 * vim: set ts=4 sw=4 tw=99 noet :
skamonkey@3513
     3
 * =============================================================================
skamonkey@3513
     4
 * SourceMod
skamonkey@3513
     5
 * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
skamonkey@3513
     6
 * =============================================================================
skamonkey@3513
     7
 *
skamonkey@3513
     8
 * This program is free software; you can redistribute it and/or modify it under
skamonkey@3513
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
skamonkey@3513
    10
 * Free Software Foundation.
skamonkey@3513
    11
 * 
skamonkey@3513
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
skamonkey@3513
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
skamonkey@3513
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
skamonkey@3513
    15
 * details.
skamonkey@3513
    16
 *
skamonkey@3513
    17
 * You should have received a copy of the GNU General Public License along with
skamonkey@3513
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
skamonkey@3513
    19
 *
skamonkey@3513
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
skamonkey@3513
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
skamonkey@3513
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
skamonkey@3513
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
skamonkey@3513
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
skamonkey@3513
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
skamonkey@3513
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
skamonkey@3513
    27
 * or <http://www.sourcemod.net/license.php>.
skamonkey@3513
    28
 */
skamonkey@3513
    29
skamonkey@3513
    30
#include "MemoryUtils.h"
skamonkey@3513
    31
#ifdef PLATFORM_LINUX
skamonkey@3513
    32
#include <fcntl.h>
skamonkey@3513
    33
#include <link.h>
skamonkey@3513
    34
#include <sys/mman.h>
skamonkey@3513
    35
skamonkey@3513
    36
#define PAGE_SIZE			4096
skamonkey@3513
    37
#define PAGE_ALIGN_UP(x)	((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
skamonkey@3513
    38
#endif
skamonkey@3513
    39
#ifdef PLATFORM_APPLE
skamonkey@3513
    40
#include <mach-o/dyld_images.h>
skamonkey@3513
    41
#include <mach-o/loader.h>
skamonkey@3513
    42
#include <mach-o/nlist.h>
skamonkey@3513
    43
#endif
skamonkey@3513
    44
skamonkey@3513
    45
MemoryUtils::MemoryUtils()
skamonkey@3513
    46
{
skamonkey@3513
    47
#ifdef PLATFORM_APPLE
skamonkey@3513
    48
skamonkey@3513
    49
	/* Get pointer to struct that describes all loaded mach-o images in process */
skamonkey@3513
    50
	struct nlist list[2];
skamonkey@3513
    51
	memset(list, 0, sizeof(list));
skamonkey@3513
    52
	list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
skamonkey@3513
    53
	nlist("/usr/lib/dyld", list);
skamonkey@3513
    54
	m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
skamonkey@3513
    55
skamonkey@3513
    56
#endif
skamonkey@3513
    57
}
skamonkey@3513
    58
skamonkey@3513
    59
MemoryUtils::~MemoryUtils()
skamonkey@3513
    60
{
skamonkey@3513
    61
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
skamonkey@3513
    62
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
    63
	{
skamonkey@3513
    64
		delete m_SymTables[i];
skamonkey@3513
    65
	}
skamonkey@3513
    66
	m_SymTables.clear();
skamonkey@3513
    67
#endif
skamonkey@3513
    68
}
skamonkey@3513
    69
skamonkey@3513
    70
void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len)
skamonkey@3513
    71
{
skamonkey@3513
    72
	size_t size;
skamonkey@3513
    73
	size = lseek (fd , 0 , SEEK_END);
skamonkey@3513
    74
skamonkey@3513
    75
	lseek(fd, 0, SEEK_SET);
skamonkey@3513
    76
skamonkey@3513
    77
	void *map;
skamonkey@3513
    78
	char *ptr, *end;
skamonkey@3513
    79
	bool found = true;
skamonkey@3513
    80
	map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
skamonkey@3513
    81
skamonkey@3513
    82
	ptr = (char *)map;
skamonkey@3513
    83
	end = ptr + size;
skamonkey@3513
    84
skamonkey@3513
    85
	while (ptr < end)
skamonkey@3513
    86
	{
skamonkey@3513
    87
		found = true;
skamonkey@3513
    88
		for (register size_t i = 0; i < len; i++)
skamonkey@3513
    89
		{
skamonkey@3513
    90
			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
skamonkey@3513
    91
			{
skamonkey@3513
    92
				found = false;
skamonkey@3513
    93
				break;
skamonkey@3513
    94
			}
skamonkey@3513
    95
		}
skamonkey@3513
    96
skamonkey@3513
    97
		if (found)
skamonkey@3513
    98
			return ptr;
skamonkey@3513
    99
skamonkey@3513
   100
		ptr++;
skamonkey@3513
   101
	}
skamonkey@3513
   102
skamonkey@3513
   103
	return NULL;
skamonkey@3513
   104
}
skamonkey@3513
   105
skamonkey@3513
   106
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
skamonkey@3513
   107
{
skamonkey@3513
   108
	DynLibInfo lib;
skamonkey@3513
   109
	bool found;
skamonkey@3513
   110
	char *ptr, *end;
skamonkey@3513
   111
skamonkey@3513
   112
	memset(&lib, 0, sizeof(DynLibInfo));
skamonkey@3513
   113
skamonkey@3513
   114
	if (!GetLibraryInfo(libPtr, lib))
skamonkey@3513
   115
	{
skamonkey@3513
   116
		return NULL;
skamonkey@3513
   117
	}
skamonkey@3513
   118
skamonkey@3513
   119
	ptr = reinterpret_cast<char *>(lib.baseAddress);
skamonkey@3513
   120
	end = ptr + lib.memorySize - 1;
skamonkey@3513
   121
skamonkey@3513
   122
	while (ptr < end)
skamonkey@3513
   123
	{
skamonkey@3513
   124
		found = true;
skamonkey@3513
   125
		for (register size_t i = 0; i < len; i++)
skamonkey@3513
   126
		{
skamonkey@3513
   127
			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
skamonkey@3513
   128
			{
skamonkey@3513
   129
				found = false;
skamonkey@3513
   130
				break;
skamonkey@3513
   131
			}
skamonkey@3513
   132
		}
skamonkey@3513
   133
skamonkey@3513
   134
		if (found)
skamonkey@3513
   135
			return ptr;
skamonkey@3513
   136
skamonkey@3513
   137
		ptr++;
skamonkey@3513
   138
	}
skamonkey@3513
   139
skamonkey@3513
   140
	return NULL;
skamonkey@3513
   141
}
skamonkey@3513
   142
skamonkey@3513
   143
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
skamonkey@3513
   144
{
skamonkey@3513
   145
#ifdef PLATFORM_WINDOWS
skamonkey@3513
   146
skamonkey@3513
   147
	return GetProcAddress((HMODULE)handle, symbol);
skamonkey@3513
   148
	
skamonkey@3513
   149
#elif defined PLATFORM_LINUX
skamonkey@3513
   150
skamonkey@3513
   151
	struct link_map *dlmap;
skamonkey@3513
   152
	struct stat dlstat;
skamonkey@3513
   153
	int dlfile;
skamonkey@3513
   154
	uintptr_t map_base;
skamonkey@3513
   155
	Elf32_Ehdr *file_hdr;
skamonkey@3513
   156
	Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
skamonkey@3513
   157
	Elf32_Sym *symtab;
skamonkey@3513
   158
	const char *shstrtab, *strtab;
skamonkey@3513
   159
	uint16_t section_count;
skamonkey@3513
   160
	uint32_t symbol_count;
skamonkey@3513
   161
	LibSymbolTable *libtable;
skamonkey@3513
   162
	SymbolTable *table;
skamonkey@3513
   163
	AddrTable *table2;
skamonkey@3513
   164
	Symbol *symbol_entry;
skamonkey@3513
   165
skamonkey@3513
   166
	dlmap = (struct link_map *)handle;
skamonkey@3513
   167
	symtab_hdr = NULL;
skamonkey@3513
   168
	strtab_hdr = NULL;
skamonkey@3513
   169
	table = NULL;
skamonkey@3513
   170
	table2 = NULL;
skamonkey@3513
   171
	
skamonkey@3513
   172
	/* See if we already have a symbol table for this library */
skamonkey@3513
   173
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   174
	{
skamonkey@3513
   175
		libtable = m_SymTables[i];
skamonkey@3513
   176
		if (libtable->lib_base == dlmap->l_addr)
skamonkey@3513
   177
		{
skamonkey@3513
   178
			table = &libtable->table;
skamonkey@3513
   179
			table2 = &libtable->table2;
skamonkey@3513
   180
			break;
skamonkey@3513
   181
		}
skamonkey@3513
   182
	}
skamonkey@3513
   183
skamonkey@3513
   184
	/* If we don't have a symbol table for this library, then create one */
skamonkey@3513
   185
	if (table == NULL)
skamonkey@3513
   186
	{
skamonkey@3513
   187
		libtable = new LibSymbolTable();
skamonkey@3513
   188
		libtable->table.Initialize();
skamonkey@3513
   189
		libtable->table2.Initialize();
skamonkey@3513
   190
		libtable->lib_base = dlmap->l_addr;
skamonkey@3513
   191
		libtable->last_pos = 0;
skamonkey@3513
   192
		table = &libtable->table;
skamonkey@3513
   193
		table2 = &libtable->table2;
skamonkey@3513
   194
		m_SymTables.push_back(libtable);
skamonkey@3513
   195
	}
skamonkey@3513
   196
skamonkey@3513
   197
	/* See if the symbol is already cached in our table */
skamonkey@3513
   198
	symbol_entry = table->FindSymbol(symbol, strlen(symbol));
skamonkey@3513
   199
	if (symbol_entry != NULL)
skamonkey@3513
   200
	{
skamonkey@3513
   201
		return symbol_entry->address;
skamonkey@3513
   202
	}
skamonkey@3513
   203
skamonkey@3513
   204
	/* If symbol isn't in our table, then we have open the actual library */
skamonkey@3513
   205
	dlfile = open(dlmap->l_name, O_RDONLY);
skamonkey@3513
   206
	if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
skamonkey@3513
   207
	{
skamonkey@3513
   208
		close(dlfile);
skamonkey@3513
   209
		return NULL;
skamonkey@3513
   210
	}
skamonkey@3513
   211
skamonkey@3513
   212
	/* Map library file into memory */
skamonkey@3513
   213
	file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
skamonkey@3513
   214
	map_base = (uintptr_t)file_hdr;
skamonkey@3513
   215
	if (file_hdr == MAP_FAILED)
skamonkey@3513
   216
	{
skamonkey@3513
   217
		close(dlfile);
skamonkey@3513
   218
		return NULL;
skamonkey@3513
   219
	}
skamonkey@3513
   220
	close(dlfile);
skamonkey@3513
   221
skamonkey@3513
   222
	if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
skamonkey@3513
   223
	{
skamonkey@3513
   224
		munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   225
		return NULL;
skamonkey@3513
   226
	}
skamonkey@3513
   227
skamonkey@3513
   228
	sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
skamonkey@3513
   229
	section_count = file_hdr->e_shnum;
skamonkey@3513
   230
	/* Get ELF section header string table */
skamonkey@3513
   231
	shstrtab_hdr = &sections[file_hdr->e_shstrndx];
skamonkey@3513
   232
	shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
skamonkey@3513
   233
skamonkey@3513
   234
	/* Iterate sections while looking for ELF symbol table and string table */
skamonkey@3513
   235
	for (uint16_t i = 0; i < section_count; i++)
skamonkey@3513
   236
	{
skamonkey@3513
   237
		Elf32_Shdr &hdr = sections[i];
skamonkey@3513
   238
		const char *section_name = shstrtab + hdr.sh_name;
skamonkey@3513
   239
skamonkey@3513
   240
		if (strcmp(section_name, ".symtab") == 0)
skamonkey@3513
   241
		{
skamonkey@3513
   242
			symtab_hdr = &hdr;
skamonkey@3513
   243
		}
skamonkey@3513
   244
		else if (strcmp(section_name, ".strtab") == 0)
skamonkey@3513
   245
		{
skamonkey@3513
   246
			strtab_hdr = &hdr;
skamonkey@3513
   247
		}
skamonkey@3513
   248
	}
skamonkey@3513
   249
skamonkey@3513
   250
	/* Uh oh, we don't have a symbol table or a string table */
skamonkey@3513
   251
	if (symtab_hdr == NULL || strtab_hdr == NULL)
skamonkey@3513
   252
	{
skamonkey@3513
   253
		munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   254
		return NULL;
skamonkey@3513
   255
	}
skamonkey@3513
   256
skamonkey@3513
   257
	symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
skamonkey@3513
   258
	strtab = (const char *)(map_base + strtab_hdr->sh_offset);
skamonkey@3513
   259
	symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
skamonkey@3513
   260
skamonkey@3513
   261
	/* Iterate symbol table starting from the position we were at last time */
skamonkey@3513
   262
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
skamonkey@3513
   263
	{
skamonkey@3513
   264
		Elf32_Sym &sym = symtab[i];
skamonkey@3513
   265
		unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
skamonkey@3513
   266
		const char *sym_name = strtab + sym.st_name;
skamonkey@3513
   267
		Symbol *cur_sym;
skamonkey@3513
   268
skamonkey@3513
   269
		/* Skip symbols that are undefined or do not refer to functions or objects */
skamonkey@3513
   270
		if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
skamonkey@3513
   271
		{
skamonkey@3513
   272
			continue;
skamonkey@3513
   273
		}
skamonkey@3513
   274
skamonkey@3513
   275
		/* Caching symbols as we go along */
skamonkey@3513
   276
		cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
skamonkey@3513
   277
		table2->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
skamonkey@3513
   278
		if (strcmp(symbol, sym_name) == 0)
skamonkey@3513
   279
		{
skamonkey@3513
   280
			symbol_entry = cur_sym;
skamonkey@3513
   281
			libtable->last_pos = ++i;
skamonkey@3513
   282
	//		break;
skamonkey@3513
   283
		}
skamonkey@3513
   284
	}
skamonkey@3513
   285
skamonkey@3513
   286
	libtable->last_pos = symbol_count;
skamonkey@3513
   287
skamonkey@3513
   288
	munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   289
	return symbol_entry ? symbol_entry->address : NULL;
skamonkey@3513
   290
skamonkey@3513
   291
#elif defined PLATFORM_APPLE
skamonkey@3513
   292
	
skamonkey@3513
   293
	uintptr_t dlbase, linkedit_addr;
skamonkey@3513
   294
	uint32_t image_count;
skamonkey@3513
   295
	struct mach_header *file_hdr;
skamonkey@3513
   296
	struct load_command *loadcmds;
skamonkey@3513
   297
	struct segment_command *linkedit_hdr;
skamonkey@3513
   298
	struct symtab_command *symtab_hdr;
skamonkey@3513
   299
	struct nlist *symtab;
skamonkey@3513
   300
	const char *strtab;
skamonkey@3513
   301
	uint32_t loadcmd_count;
skamonkey@3513
   302
	uint32_t symbol_count;
skamonkey@3513
   303
	LibSymbolTable *libtable;
skamonkey@3513
   304
	SymbolTable *table;
skamonkey@3513
   305
	Symbol *symbol_entry;
skamonkey@3513
   306
	
skamonkey@3513
   307
	dlbase = 0;
skamonkey@3513
   308
	image_count = m_ImageList->infoArrayCount;
skamonkey@3513
   309
	linkedit_hdr = NULL;
skamonkey@3513
   310
	symtab_hdr = NULL;
skamonkey@3513
   311
	table = NULL;
skamonkey@3513
   312
	
skamonkey@3513
   313
	/* Loop through mach-o images in process.
skamonkey@3513
   314
	 * We can skip index 0 since that is just the executable.
skamonkey@3513
   315
	 */
skamonkey@3513
   316
	for (uint32_t i = 1; i < image_count; i++)
skamonkey@3513
   317
	{
skamonkey@3513
   318
		const struct dyld_image_info &info = m_ImageList->infoArray[i];
skamonkey@3513
   319
		
skamonkey@3513
   320
		/* "Load" each one until we get a matching handle */
skamonkey@3513
   321
		void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
skamonkey@3513
   322
		if (h == handle)
skamonkey@3513
   323
		{
skamonkey@3513
   324
			dlbase = (uintptr_t)info.imageLoadAddress;
skamonkey@3513
   325
			dlclose(h);
skamonkey@3513
   326
			break;
skamonkey@3513
   327
		}
skamonkey@3513
   328
		
skamonkey@3513
   329
		dlclose(h);
skamonkey@3513
   330
	}
skamonkey@3513
   331
	
skamonkey@3513
   332
	if (!dlbase)
skamonkey@3513
   333
	{
skamonkey@3513
   334
		/* Uh oh, we couldn't find a matching handle */
skamonkey@3513
   335
		return NULL;
skamonkey@3513
   336
	}
skamonkey@3513
   337
	
skamonkey@3513
   338
	/* See if we already have a symbol table for this library */
skamonkey@3513
   339
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   340
	{
skamonkey@3513
   341
		libtable = m_SymTables[i];
skamonkey@3513
   342
		if (libtable->lib_base == dlbase)
skamonkey@3513
   343
		{
skamonkey@3513
   344
			table = &libtable->table;
skamonkey@3513
   345
			break;
skamonkey@3513
   346
		}
skamonkey@3513
   347
	}
skamonkey@3513
   348
	
skamonkey@3513
   349
	/* If we don't have a symbol table for this library, then create one */
skamonkey@3513
   350
	if (table == NULL)
skamonkey@3513
   351
	{
skamonkey@3513
   352
		libtable = new LibSymbolTable();
skamonkey@3513
   353
		libtable->table.Initialize();
skamonkey@3513
   354
		libtable->lib_base = dlbase;
skamonkey@3513
   355
		libtable->last_pos = 0;
skamonkey@3513
   356
		table = &libtable->table;
skamonkey@3513
   357
		m_SymTables.push_back(libtable);
skamonkey@3513
   358
	}
skamonkey@3513
   359
	
skamonkey@3513
   360
	/* See if the symbol is already cached in our table */
skamonkey@3513
   361
	symbol_entry = table->FindSymbol(symbol, strlen(symbol));
skamonkey@3513
   362
	if (symbol_entry != NULL)
skamonkey@3513
   363
	{
skamonkey@3513
   364
		return symbol_entry->address;
skamonkey@3513
   365
	}
skamonkey@3513
   366
	
skamonkey@3513
   367
	/* If symbol isn't in our table, then we have to locate it in memory */
skamonkey@3513
   368
	
skamonkey@3513
   369
	file_hdr = (struct mach_header *)dlbase;
skamonkey@3513
   370
	loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
skamonkey@3513
   371
	loadcmd_count = file_hdr->ncmds;
skamonkey@3513
   372
	
skamonkey@3513
   373
	/* Loop through load commands until we find the ones for the symbol table */
skamonkey@3513
   374
	for (uint32_t i = 0; i < loadcmd_count; i++)
skamonkey@3513
   375
	{
skamonkey@3513
   376
		if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
skamonkey@3513
   377
		{
skamonkey@3513
   378
			struct segment_command *seg = (struct segment_command *)loadcmds;
skamonkey@3513
   379
			if (strcmp(seg->segname, "__LINKEDIT") == 0)
skamonkey@3513
   380
			{
skamonkey@3513
   381
				linkedit_hdr = seg;
skamonkey@3513
   382
				if (symtab_hdr)
skamonkey@3513
   383
				{
skamonkey@3513
   384
					break;
skamonkey@3513
   385
				}
skamonkey@3513
   386
			}
skamonkey@3513
   387
		}
skamonkey@3513
   388
		else if (loadcmds->cmd == LC_SYMTAB)
skamonkey@3513
   389
		{
skamonkey@3513
   390
			symtab_hdr = (struct symtab_command *)loadcmds;
skamonkey@3513
   391
			if (linkedit_hdr)
skamonkey@3513
   392
			{
skamonkey@3513
   393
				break;
skamonkey@3513
   394
			}
skamonkey@3513
   395
		}
skamonkey@3513
   396
skamonkey@3513
   397
		/* Load commands are not of a fixed size which is why we add the size */
skamonkey@3513
   398
		loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
skamonkey@3513
   399
	}
skamonkey@3513
   400
	
skamonkey@3513
   401
	if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
skamonkey@3513
   402
	{
skamonkey@3513
   403
		/* Uh oh, no symbol table */
skamonkey@3513
   404
		return NULL;
skamonkey@3513
   405
	}
skamonkey@3513
   406
skamonkey@3513
   407
	linkedit_addr = dlbase + linkedit_hdr->vmaddr;
skamonkey@3513
   408
	symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
skamonkey@3513
   409
	strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
skamonkey@3513
   410
	symbol_count = symtab_hdr->nsyms;
skamonkey@3513
   411
	
skamonkey@3513
   412
	/* Iterate symbol table starting from the position we were at last time */
skamonkey@3513
   413
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
skamonkey@3513
   414
	{
skamonkey@3513
   415
		struct nlist &sym = symtab[i];
skamonkey@3513
   416
		/* Ignore the prepended underscore on all symbols, so +1 here */
skamonkey@3513
   417
		const char *sym_name = strtab + sym.n_un.n_strx + 1;
skamonkey@3513
   418
		Symbol *cur_sym;
skamonkey@3513
   419
		
skamonkey@3513
   420
		/* Skip symbols that are undefined */
skamonkey@3513
   421
		if (sym.n_sect == NO_SECT)
skamonkey@3513
   422
		{
skamonkey@3513
   423
			continue;
skamonkey@3513
   424
		}
skamonkey@3513
   425
		
skamonkey@3513
   426
		/* Caching symbols as we go along */
skamonkey@3513
   427
		cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
skamonkey@3513
   428
		if (strcmp(symbol, sym_name) == 0)
skamonkey@3513
   429
		{
skamonkey@3513
   430
			symbol_entry = cur_sym;
skamonkey@3513
   431
			libtable->last_pos = ++i;
skamonkey@3513
   432
			break;
skamonkey@3513
   433
		}
skamonkey@3513
   434
	}
skamonkey@3513
   435
	
skamonkey@3513
   436
	return symbol_entry ? symbol_entry->address : NULL;
skamonkey@3513
   437
skamonkey@3513
   438
#endif
skamonkey@3513
   439
}
skamonkey@3513
   440
skamonkey@3513
   441
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
skamonkey@3513
   442
{
skamonkey@3513
   443
	uintptr_t baseAddr;
skamonkey@3513
   444
skamonkey@3513
   445
	if (libPtr == NULL)
skamonkey@3513
   446
	{
skamonkey@3513
   447
		return false;
skamonkey@3513
   448
	}
skamonkey@3513
   449
skamonkey@3513
   450
#ifdef PLATFORM_WINDOWS
skamonkey@3513
   451
skamonkey@3513
   452
	MEMORY_BASIC_INFORMATION info;
skamonkey@3513
   453
	IMAGE_DOS_HEADER *dos;
skamonkey@3513
   454
	IMAGE_NT_HEADERS *pe;
skamonkey@3513
   455
	IMAGE_FILE_HEADER *file;
skamonkey@3513
   456
	IMAGE_OPTIONAL_HEADER *opt;
skamonkey@3513
   457
skamonkey@3513
   458
	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
skamonkey@3513
   459
	{
skamonkey@3513
   460
		return false;
skamonkey@3513
   461
	}
skamonkey@3513
   462
skamonkey@3513
   463
	baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
skamonkey@3513
   464
skamonkey@3513
   465
	/* All this is for our insane sanity checks :o */
skamonkey@3513
   466
	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
skamonkey@3513
   467
	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
skamonkey@3513
   468
	file = &pe->FileHeader;
skamonkey@3513
   469
	opt = &pe->OptionalHeader;
skamonkey@3513
   470
skamonkey@3513
   471
	/* Check PE magic and signature */
skamonkey@3513
   472
	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
skamonkey@3513
   473
	{
skamonkey@3513
   474
		return false;
skamonkey@3513
   475
	}
skamonkey@3513
   476
skamonkey@3513
   477
	/* Check architecture, which is 32-bit/x86 right now
skamonkey@3513
   478
	 * Should change this for 64-bit if Valve gets their act together
skamonkey@3513
   479
	 */
skamonkey@3513
   480
	if (file->Machine != IMAGE_FILE_MACHINE_I386)
skamonkey@3513
   481
	{
skamonkey@3513
   482
		return false;
skamonkey@3513
   483
	}
skamonkey@3513
   484
skamonkey@3513
   485
	/* For our purposes, this must be a dynamic library */
skamonkey@3513
   486
	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
skamonkey@3513
   487
	{
skamonkey@3513
   488
		return false;
skamonkey@3513
   489
	}
skamonkey@3513
   490
skamonkey@3513
   491
	/* Finally, we can do this */
skamonkey@3513
   492
	lib.memorySize = opt->SizeOfImage;
skamonkey@3513
   493
skamonkey@3513
   494
#elif defined PLATFORM_LINUX
skamonkey@3513
   495
skamonkey@3513
   496
	Dl_info info;
skamonkey@3513
   497
	Elf32_Ehdr *file;
skamonkey@3513
   498
	Elf32_Phdr *phdr;
skamonkey@3513
   499
	uint16_t phdrCount;
skamonkey@3513
   500
skamonkey@3513
   501
	if (!dladdr(libPtr, &info))
skamonkey@3513
   502
	{
skamonkey@3513
   503
		return false;
skamonkey@3513
   504
	}
skamonkey@3513
   505
skamonkey@3513
   506
	if (!info.dli_fbase || !info.dli_fname)
skamonkey@3513
   507
	{
skamonkey@3513
   508
		return false;
skamonkey@3513
   509
	}
skamonkey@3513
   510
skamonkey@3513
   511
	/* This is for our insane sanity checks :o */
skamonkey@3513
   512
	baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
skamonkey@3513
   513
	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
skamonkey@3513
   514
skamonkey@3513
   515
	/* Check ELF magic */
skamonkey@3513
   516
	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
skamonkey@3513
   517
	{
skamonkey@3513
   518
		return false;
skamonkey@3513
   519
	}
skamonkey@3513
   520
skamonkey@3513
   521
	/* Check ELF version */
skamonkey@3513
   522
	if (file->e_ident[EI_VERSION] != EV_CURRENT)
skamonkey@3513
   523
	{
skamonkey@3513
   524
		return false;
skamonkey@3513
   525
	}
skamonkey@3513
   526
skamonkey@3513
   527
	/* Check ELF architecture, which is 32-bit/x86 right now
skamonkey@3513
   528
	 * Should change this for 64-bit if Valve gets their act together
skamonkey@3513
   529
	 */
skamonkey@3513
   530
	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
skamonkey@3513
   531
	{
skamonkey@3513
   532
		return false;
skamonkey@3513
   533
	}
skamonkey@3513
   534
skamonkey@3513
   535
	/* For our purposes, this must be a dynamic library/shared object */
skamonkey@3513
   536
	if (file->e_type != ET_DYN)
skamonkey@3513
   537
	{
skamonkey@3513
   538
		return false;
skamonkey@3513
   539
	}
skamonkey@3513
   540
skamonkey@3513
   541
	phdrCount = file->e_phnum;
skamonkey@3513
   542
	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
skamonkey@3513
   543
skamonkey@3513
   544
	for (uint16_t i = 0; i < phdrCount; i++)
skamonkey@3513
   545
	{
skamonkey@3513
   546
		Elf32_Phdr &hdr = phdr[i];
skamonkey@3513
   547
skamonkey@3513
   548
		/* We only really care about the segment with executable code */
skamonkey@3513
   549
		if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
skamonkey@3513
   550
		{
skamonkey@3513
   551
			/* From glibc, elf/dl-load.c:
skamonkey@3513
   552
			 * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) 
skamonkey@3513
   553
			 *             & ~(GLRO(dl_pagesize) - 1));
skamonkey@3513
   554
			 *
skamonkey@3513
   555
			 * In glibc, the segment file size is aligned up to the nearest page size and
skamonkey@3513
   556
			 * added to the virtual address of the segment. We just want the size here.
skamonkey@3513
   557
			 */
skamonkey@3513
   558
			lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
skamonkey@3513
   559
			break;
skamonkey@3513
   560
		}
skamonkey@3513
   561
	}
skamonkey@3513
   562
skamonkey@3513
   563
#elif defined PLATFORM_APPLE
skamonkey@3513
   564
skamonkey@3513
   565
	Dl_info info;
skamonkey@3513
   566
	struct mach_header *file;
skamonkey@3513
   567
	struct segment_command *seg;
skamonkey@3513
   568
	uint32_t cmd_count;
skamonkey@3513
   569
skamonkey@3513
   570
	if (!dladdr(libPtr, &info))
skamonkey@3513
   571
	{
skamonkey@3513
   572
		return false;
skamonkey@3513
   573
	}
skamonkey@3513
   574
skamonkey@3513
   575
	if (!info.dli_fbase || !info.dli_fname)
skamonkey@3513
   576
	{
skamonkey@3513
   577
		return false;
skamonkey@3513
   578
	}
skamonkey@3513
   579
skamonkey@3513
   580
	/* This is for our insane sanity checks :o */
skamonkey@3513
   581
	baseAddr = (uintptr_t)info.dli_fbase;
skamonkey@3513
   582
	file = (struct mach_header *)baseAddr;
skamonkey@3513
   583
skamonkey@3513
   584
	/* Check Mach-O magic */
skamonkey@3513
   585
	if (file->magic != MH_MAGIC)
skamonkey@3513
   586
	{
skamonkey@3513
   587
		return false;
skamonkey@3513
   588
	}
skamonkey@3513
   589
skamonkey@3513
   590
	/* Check architecture (32-bit/x86) */
skamonkey@3513
   591
	if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
skamonkey@3513
   592
	{
skamonkey@3513
   593
		return false;
skamonkey@3513
   594
	}
skamonkey@3513
   595
skamonkey@3513
   596
	/* For our purposes, this must be a dynamic library */
skamonkey@3513
   597
	if (file->filetype != MH_DYLIB)
skamonkey@3513
   598
	{
skamonkey@3513
   599
		return false;
skamonkey@3513
   600
	}
skamonkey@3513
   601
skamonkey@3513
   602
	cmd_count = file->ncmds;
skamonkey@3513
   603
	seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
skamonkey@3513
   604
	
skamonkey@3513
   605
	/* Add up memory sizes of mapped segments */
skamonkey@3513
   606
	for (uint32_t i = 0; i < cmd_count; i++)
skamonkey@3513
   607
	{		
skamonkey@3513
   608
		if (seg->cmd == LC_SEGMENT)
skamonkey@3513
   609
		{
skamonkey@3513
   610
			lib.memorySize += seg->vmsize;
skamonkey@3513
   611
		}
skamonkey@3513
   612
		
skamonkey@3513
   613
		seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
skamonkey@3513
   614
	}
skamonkey@3513
   615
skamonkey@3513
   616
#endif
skamonkey@3513
   617
skamonkey@3513
   618
	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
skamonkey@3513
   619
skamonkey@3513
   620
	return true;
skamonkey@3513
   621
}
skamonkey@3513
   622
skamonkey@3513
   623
const char* MemoryUtils::ResolveAddr(void *handle, void* addr)
skamonkey@3513
   624
{
skamonkey@3513
   625
	struct link_map *dlmap;
skamonkey@3513
   626
	dlmap = (struct link_map *)handle;
skamonkey@3513
   627
skamonkey@3513
   628
	LibSymbolTable *libtable;
skamonkey@3513
   629
	AddrTable *table2;
skamonkey@3513
   630
skamonkey@3513
   631
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   632
	{
skamonkey@3513
   633
		libtable = m_SymTables[i];
skamonkey@3513
   634
		if (libtable->lib_base == dlmap->l_addr)
skamonkey@3513
   635
		{
skamonkey@3513
   636
			table2 = &libtable->table2;
skamonkey@3513
   637
			break;
skamonkey@3513
   638
		}
skamonkey@3513
   639
	}
skamonkey@3513
   640
skamonkey@3513
   641
	if (table2 == NULL) return NULL;
skamonkey@3513
   642
	Symbol *sym = table2->FindAddr(addr);
skamonkey@3513
   643
	return sym ? sym->buffer() : NULL;
skamonkey@3513
   644
}