tools/gdc-psyfork/MemoryUtils.cpp
author David Anderson <dvander@alliedmods.net>
Thu Aug 08 22:02:42 2013 -0700 (2013-08-08)
changeset 3980 dc7dfcd855dc
parent 3574 b51285ca203f
permissions -rw-r--r--
More Windows build fix.
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@3574
    70
void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len, int &matches, bool &atFuncStart)
skamonkey@3513
    71
{
skamonkey@3513
    72
	size_t size;
skamonkey@3513
    73
	size = lseek (fd , 0 , SEEK_END);
skamonkey@3574
    74
	
skamonkey@3574
    75
	matches = 0;
skamonkey@3574
    76
	// TODO: fix this
skamonkey@3574
    77
	atFuncStart = true;
skamonkey@3513
    78
skamonkey@3513
    79
	lseek(fd, 0, SEEK_SET);
skamonkey@3513
    80
skamonkey@3513
    81
	void *map;
skamonkey@3574
    82
	char *ptr, *start, *end;
skamonkey@3513
    83
	bool found = true;
skamonkey@3513
    84
	map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
skamonkey@3513
    85
skamonkey@3513
    86
	ptr = (char *)map;
skamonkey@3574
    87
	start = ptr;
skamonkey@3513
    88
	end = ptr + size;
skamonkey@3574
    89
	
skamonkey@3574
    90
	void *firstMatch = NULL;
skamonkey@3513
    91
skamonkey@3513
    92
	while (ptr < end)
skamonkey@3513
    93
	{
skamonkey@3513
    94
		found = true;
skamonkey@3513
    95
		for (register size_t i = 0; i < len; i++)
skamonkey@3513
    96
		{
skamonkey@3513
    97
			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
skamonkey@3513
    98
			{
skamonkey@3513
    99
				found = false;
skamonkey@3513
   100
				break;
skamonkey@3513
   101
			}
skamonkey@3513
   102
		}
skamonkey@3513
   103
skamonkey@3513
   104
		if (found)
skamonkey@3574
   105
		{
skamonkey@3574
   106
			if( !firstMatch )
skamonkey@3574
   107
			{
skamonkey@3574
   108
				firstMatch = ptr;
skamonkey@3574
   109
				if( ptr - start >= 1 )
skamonkey@3574
   110
				{
skamonkey@3574
   111
					unsigned char oneBack = *(unsigned char*)((intptr_t)ptr - 1);
skamonkey@3574
   112
					if( oneBack != 0xC3 && oneBack != 0xCB && oneBack != 0xCC )
skamonkey@3574
   113
					{
skamonkey@3574
   114
						if( ptr - start >= 3 )
skamonkey@3574
   115
						{
skamonkey@3574
   116
							unsigned char threeBack = *(unsigned char*)((intptr_t)ptr - 3);
skamonkey@3574
   117
							if( threeBack != 0xCA && threeBack != 0xC2 )
skamonkey@3574
   118
							{
skamonkey@3574
   119
								atFuncStart = false;
skamonkey@3574
   120
							}
skamonkey@3574
   121
						}
skamonkey@3574
   122
						else
skamonkey@3574
   123
						{
skamonkey@3574
   124
							atFuncStart = false;
skamonkey@3574
   125
						}
skamonkey@3574
   126
					}
skamonkey@3574
   127
				}
skamonkey@3574
   128
			}
skamonkey@3574
   129
			
skamonkey@3574
   130
			++matches;
skamonkey@3574
   131
		}
skamonkey@3513
   132
skamonkey@3574
   133
		++ptr;
skamonkey@3513
   134
	}
skamonkey@3513
   135
skamonkey@3574
   136
	return firstMatch;
skamonkey@3513
   137
}
skamonkey@3513
   138
skamonkey@3574
   139
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len, int &matches, bool &atFuncStart)
skamonkey@3513
   140
{
skamonkey@3513
   141
	DynLibInfo lib;
skamonkey@3513
   142
	bool found;
skamonkey@3513
   143
	char *ptr, *end;
skamonkey@3574
   144
	
skamonkey@3574
   145
	matches = 0;
skamonkey@3574
   146
	// TODO: fix this
skamonkey@3574
   147
	atFuncStart = true;
skamonkey@3513
   148
skamonkey@3513
   149
	memset(&lib, 0, sizeof(DynLibInfo));
skamonkey@3513
   150
skamonkey@3513
   151
	if (!GetLibraryInfo(libPtr, lib))
skamonkey@3513
   152
	{
skamonkey@3513
   153
		return NULL;
skamonkey@3513
   154
	}
skamonkey@3574
   155
	
skamonkey@3574
   156
	void *firstMatch = NULL;
skamonkey@3513
   157
	ptr = reinterpret_cast<char *>(lib.baseAddress);
skamonkey@3513
   158
	end = ptr + lib.memorySize - 1;
skamonkey@3513
   159
skamonkey@3513
   160
	while (ptr < end)
skamonkey@3513
   161
	{
skamonkey@3513
   162
		found = true;
skamonkey@3513
   163
		for (register size_t i = 0; i < len; i++)
skamonkey@3513
   164
		{
skamonkey@3513
   165
			if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
skamonkey@3513
   166
			{
skamonkey@3513
   167
				found = false;
skamonkey@3513
   168
				break;
skamonkey@3513
   169
			}
skamonkey@3513
   170
		}
skamonkey@3513
   171
skamonkey@3513
   172
		if (found)
skamonkey@3574
   173
		{
skamonkey@3574
   174
			if( !firstMatch )
skamonkey@3574
   175
				firstMatch = ptr;
skamonkey@3574
   176
			
skamonkey@3574
   177
			++matches;
skamonkey@3574
   178
		}
skamonkey@3513
   179
skamonkey@3574
   180
		++ptr;
skamonkey@3513
   181
	}
skamonkey@3513
   182
skamonkey@3574
   183
	return firstMatch;
skamonkey@3513
   184
}
skamonkey@3513
   185
skamonkey@3513
   186
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
skamonkey@3513
   187
{
skamonkey@3513
   188
#ifdef PLATFORM_WINDOWS
skamonkey@3513
   189
skamonkey@3513
   190
	return GetProcAddress((HMODULE)handle, symbol);
skamonkey@3513
   191
	
skamonkey@3513
   192
#elif defined PLATFORM_LINUX
skamonkey@3513
   193
skamonkey@3513
   194
	struct link_map *dlmap;
skamonkey@3513
   195
	struct stat dlstat;
skamonkey@3513
   196
	int dlfile;
skamonkey@3513
   197
	uintptr_t map_base;
skamonkey@3513
   198
	Elf32_Ehdr *file_hdr;
skamonkey@3513
   199
	Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
skamonkey@3513
   200
	Elf32_Sym *symtab;
skamonkey@3513
   201
	const char *shstrtab, *strtab;
skamonkey@3513
   202
	uint16_t section_count;
skamonkey@3513
   203
	uint32_t symbol_count;
skamonkey@3513
   204
	LibSymbolTable *libtable;
skamonkey@3513
   205
	SymbolTable *table;
skamonkey@3513
   206
	AddrTable *table2;
skamonkey@3513
   207
	Symbol *symbol_entry;
skamonkey@3513
   208
skamonkey@3513
   209
	dlmap = (struct link_map *)handle;
skamonkey@3513
   210
	symtab_hdr = NULL;
skamonkey@3513
   211
	strtab_hdr = NULL;
skamonkey@3513
   212
	table = NULL;
skamonkey@3513
   213
	table2 = NULL;
skamonkey@3513
   214
	
skamonkey@3513
   215
	/* See if we already have a symbol table for this library */
skamonkey@3513
   216
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   217
	{
skamonkey@3513
   218
		libtable = m_SymTables[i];
skamonkey@3513
   219
		if (libtable->lib_base == dlmap->l_addr)
skamonkey@3513
   220
		{
skamonkey@3513
   221
			table = &libtable->table;
skamonkey@3513
   222
			table2 = &libtable->table2;
skamonkey@3513
   223
			break;
skamonkey@3513
   224
		}
skamonkey@3513
   225
	}
skamonkey@3513
   226
skamonkey@3513
   227
	/* If we don't have a symbol table for this library, then create one */
skamonkey@3513
   228
	if (table == NULL)
skamonkey@3513
   229
	{
skamonkey@3513
   230
		libtable = new LibSymbolTable();
skamonkey@3513
   231
		libtable->table.Initialize();
skamonkey@3513
   232
		libtable->table2.Initialize();
skamonkey@3513
   233
		libtable->lib_base = dlmap->l_addr;
skamonkey@3513
   234
		libtable->last_pos = 0;
skamonkey@3513
   235
		table = &libtable->table;
skamonkey@3513
   236
		table2 = &libtable->table2;
skamonkey@3513
   237
		m_SymTables.push_back(libtable);
skamonkey@3513
   238
	}
skamonkey@3513
   239
skamonkey@3513
   240
	/* See if the symbol is already cached in our table */
skamonkey@3513
   241
	symbol_entry = table->FindSymbol(symbol, strlen(symbol));
skamonkey@3513
   242
	if (symbol_entry != NULL)
skamonkey@3513
   243
	{
skamonkey@3513
   244
		return symbol_entry->address;
skamonkey@3513
   245
	}
skamonkey@3513
   246
skamonkey@3513
   247
	/* If symbol isn't in our table, then we have open the actual library */
skamonkey@3513
   248
	dlfile = open(dlmap->l_name, O_RDONLY);
skamonkey@3513
   249
	if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
skamonkey@3513
   250
	{
skamonkey@3513
   251
		close(dlfile);
skamonkey@3513
   252
		return NULL;
skamonkey@3513
   253
	}
skamonkey@3513
   254
skamonkey@3513
   255
	/* Map library file into memory */
skamonkey@3513
   256
	file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
skamonkey@3513
   257
	map_base = (uintptr_t)file_hdr;
skamonkey@3513
   258
	if (file_hdr == MAP_FAILED)
skamonkey@3513
   259
	{
skamonkey@3513
   260
		close(dlfile);
skamonkey@3513
   261
		return NULL;
skamonkey@3513
   262
	}
skamonkey@3513
   263
	close(dlfile);
skamonkey@3513
   264
skamonkey@3513
   265
	if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
skamonkey@3513
   266
	{
skamonkey@3513
   267
		munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   268
		return NULL;
skamonkey@3513
   269
	}
skamonkey@3513
   270
skamonkey@3513
   271
	sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
skamonkey@3513
   272
	section_count = file_hdr->e_shnum;
skamonkey@3513
   273
	/* Get ELF section header string table */
skamonkey@3513
   274
	shstrtab_hdr = &sections[file_hdr->e_shstrndx];
skamonkey@3513
   275
	shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
skamonkey@3513
   276
skamonkey@3513
   277
	/* Iterate sections while looking for ELF symbol table and string table */
skamonkey@3513
   278
	for (uint16_t i = 0; i < section_count; i++)
skamonkey@3513
   279
	{
skamonkey@3513
   280
		Elf32_Shdr &hdr = sections[i];
skamonkey@3513
   281
		const char *section_name = shstrtab + hdr.sh_name;
skamonkey@3513
   282
skamonkey@3513
   283
		if (strcmp(section_name, ".symtab") == 0)
skamonkey@3513
   284
		{
skamonkey@3513
   285
			symtab_hdr = &hdr;
skamonkey@3513
   286
		}
skamonkey@3513
   287
		else if (strcmp(section_name, ".strtab") == 0)
skamonkey@3513
   288
		{
skamonkey@3513
   289
			strtab_hdr = &hdr;
skamonkey@3513
   290
		}
skamonkey@3513
   291
	}
skamonkey@3513
   292
skamonkey@3513
   293
	/* Uh oh, we don't have a symbol table or a string table */
skamonkey@3513
   294
	if (symtab_hdr == NULL || strtab_hdr == NULL)
skamonkey@3513
   295
	{
skamonkey@3513
   296
		munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   297
		return NULL;
skamonkey@3513
   298
	}
skamonkey@3513
   299
skamonkey@3513
   300
	symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
skamonkey@3513
   301
	strtab = (const char *)(map_base + strtab_hdr->sh_offset);
skamonkey@3513
   302
	symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
skamonkey@3513
   303
skamonkey@3513
   304
	/* Iterate symbol table starting from the position we were at last time */
skamonkey@3513
   305
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
skamonkey@3513
   306
	{
skamonkey@3513
   307
		Elf32_Sym &sym = symtab[i];
skamonkey@3513
   308
		unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
skamonkey@3513
   309
		const char *sym_name = strtab + sym.st_name;
skamonkey@3513
   310
		Symbol *cur_sym;
skamonkey@3513
   311
skamonkey@3513
   312
		/* Skip symbols that are undefined or do not refer to functions or objects */
skamonkey@3513
   313
		if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
skamonkey@3513
   314
		{
skamonkey@3513
   315
			continue;
skamonkey@3513
   316
		}
skamonkey@3513
   317
skamonkey@3513
   318
		/* Caching symbols as we go along */
skamonkey@3513
   319
		cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
skamonkey@3513
   320
		table2->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
skamonkey@3513
   321
		if (strcmp(symbol, sym_name) == 0)
skamonkey@3513
   322
		{
skamonkey@3513
   323
			symbol_entry = cur_sym;
skamonkey@3513
   324
			libtable->last_pos = ++i;
skamonkey@3513
   325
	//		break;
skamonkey@3513
   326
		}
skamonkey@3513
   327
	}
skamonkey@3513
   328
skamonkey@3513
   329
	libtable->last_pos = symbol_count;
skamonkey@3513
   330
skamonkey@3513
   331
	munmap(file_hdr, dlstat.st_size);
skamonkey@3513
   332
	return symbol_entry ? symbol_entry->address : NULL;
skamonkey@3513
   333
skamonkey@3513
   334
#elif defined PLATFORM_APPLE
skamonkey@3513
   335
	
skamonkey@3513
   336
	uintptr_t dlbase, linkedit_addr;
skamonkey@3513
   337
	uint32_t image_count;
skamonkey@3513
   338
	struct mach_header *file_hdr;
skamonkey@3513
   339
	struct load_command *loadcmds;
skamonkey@3513
   340
	struct segment_command *linkedit_hdr;
skamonkey@3513
   341
	struct symtab_command *symtab_hdr;
skamonkey@3513
   342
	struct nlist *symtab;
skamonkey@3513
   343
	const char *strtab;
skamonkey@3513
   344
	uint32_t loadcmd_count;
skamonkey@3513
   345
	uint32_t symbol_count;
skamonkey@3513
   346
	LibSymbolTable *libtable;
skamonkey@3513
   347
	SymbolTable *table;
skamonkey@3513
   348
	Symbol *symbol_entry;
skamonkey@3513
   349
	
skamonkey@3513
   350
	dlbase = 0;
skamonkey@3513
   351
	image_count = m_ImageList->infoArrayCount;
skamonkey@3513
   352
	linkedit_hdr = NULL;
skamonkey@3513
   353
	symtab_hdr = NULL;
skamonkey@3513
   354
	table = NULL;
skamonkey@3513
   355
	
skamonkey@3513
   356
	/* Loop through mach-o images in process.
skamonkey@3513
   357
	 * We can skip index 0 since that is just the executable.
skamonkey@3513
   358
	 */
skamonkey@3513
   359
	for (uint32_t i = 1; i < image_count; i++)
skamonkey@3513
   360
	{
skamonkey@3513
   361
		const struct dyld_image_info &info = m_ImageList->infoArray[i];
skamonkey@3513
   362
		
skamonkey@3513
   363
		/* "Load" each one until we get a matching handle */
skamonkey@3513
   364
		void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
skamonkey@3513
   365
		if (h == handle)
skamonkey@3513
   366
		{
skamonkey@3513
   367
			dlbase = (uintptr_t)info.imageLoadAddress;
skamonkey@3513
   368
			dlclose(h);
skamonkey@3513
   369
			break;
skamonkey@3513
   370
		}
skamonkey@3513
   371
		
skamonkey@3513
   372
		dlclose(h);
skamonkey@3513
   373
	}
skamonkey@3513
   374
	
skamonkey@3513
   375
	if (!dlbase)
skamonkey@3513
   376
	{
skamonkey@3513
   377
		/* Uh oh, we couldn't find a matching handle */
skamonkey@3513
   378
		return NULL;
skamonkey@3513
   379
	}
skamonkey@3513
   380
	
skamonkey@3513
   381
	/* See if we already have a symbol table for this library */
skamonkey@3513
   382
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   383
	{
skamonkey@3513
   384
		libtable = m_SymTables[i];
skamonkey@3513
   385
		if (libtable->lib_base == dlbase)
skamonkey@3513
   386
		{
skamonkey@3513
   387
			table = &libtable->table;
skamonkey@3513
   388
			break;
skamonkey@3513
   389
		}
skamonkey@3513
   390
	}
skamonkey@3513
   391
	
skamonkey@3513
   392
	/* If we don't have a symbol table for this library, then create one */
skamonkey@3513
   393
	if (table == NULL)
skamonkey@3513
   394
	{
skamonkey@3513
   395
		libtable = new LibSymbolTable();
skamonkey@3513
   396
		libtable->table.Initialize();
skamonkey@3513
   397
		libtable->lib_base = dlbase;
skamonkey@3513
   398
		libtable->last_pos = 0;
skamonkey@3513
   399
		table = &libtable->table;
skamonkey@3513
   400
		m_SymTables.push_back(libtable);
skamonkey@3513
   401
	}
skamonkey@3513
   402
	
skamonkey@3513
   403
	/* See if the symbol is already cached in our table */
skamonkey@3513
   404
	symbol_entry = table->FindSymbol(symbol, strlen(symbol));
skamonkey@3513
   405
	if (symbol_entry != NULL)
skamonkey@3513
   406
	{
skamonkey@3513
   407
		return symbol_entry->address;
skamonkey@3513
   408
	}
skamonkey@3513
   409
	
skamonkey@3513
   410
	/* If symbol isn't in our table, then we have to locate it in memory */
skamonkey@3513
   411
	
skamonkey@3513
   412
	file_hdr = (struct mach_header *)dlbase;
skamonkey@3513
   413
	loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
skamonkey@3513
   414
	loadcmd_count = file_hdr->ncmds;
skamonkey@3513
   415
	
skamonkey@3513
   416
	/* Loop through load commands until we find the ones for the symbol table */
skamonkey@3513
   417
	for (uint32_t i = 0; i < loadcmd_count; i++)
skamonkey@3513
   418
	{
skamonkey@3513
   419
		if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
skamonkey@3513
   420
		{
skamonkey@3513
   421
			struct segment_command *seg = (struct segment_command *)loadcmds;
skamonkey@3513
   422
			if (strcmp(seg->segname, "__LINKEDIT") == 0)
skamonkey@3513
   423
			{
skamonkey@3513
   424
				linkedit_hdr = seg;
skamonkey@3513
   425
				if (symtab_hdr)
skamonkey@3513
   426
				{
skamonkey@3513
   427
					break;
skamonkey@3513
   428
				}
skamonkey@3513
   429
			}
skamonkey@3513
   430
		}
skamonkey@3513
   431
		else if (loadcmds->cmd == LC_SYMTAB)
skamonkey@3513
   432
		{
skamonkey@3513
   433
			symtab_hdr = (struct symtab_command *)loadcmds;
skamonkey@3513
   434
			if (linkedit_hdr)
skamonkey@3513
   435
			{
skamonkey@3513
   436
				break;
skamonkey@3513
   437
			}
skamonkey@3513
   438
		}
skamonkey@3513
   439
skamonkey@3513
   440
		/* Load commands are not of a fixed size which is why we add the size */
skamonkey@3513
   441
		loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
skamonkey@3513
   442
	}
skamonkey@3513
   443
	
skamonkey@3513
   444
	if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
skamonkey@3513
   445
	{
skamonkey@3513
   446
		/* Uh oh, no symbol table */
skamonkey@3513
   447
		return NULL;
skamonkey@3513
   448
	}
skamonkey@3513
   449
skamonkey@3513
   450
	linkedit_addr = dlbase + linkedit_hdr->vmaddr;
skamonkey@3513
   451
	symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
skamonkey@3513
   452
	strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
skamonkey@3513
   453
	symbol_count = symtab_hdr->nsyms;
skamonkey@3513
   454
	
skamonkey@3513
   455
	/* Iterate symbol table starting from the position we were at last time */
skamonkey@3513
   456
	for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
skamonkey@3513
   457
	{
skamonkey@3513
   458
		struct nlist &sym = symtab[i];
skamonkey@3513
   459
		/* Ignore the prepended underscore on all symbols, so +1 here */
skamonkey@3513
   460
		const char *sym_name = strtab + sym.n_un.n_strx + 1;
skamonkey@3513
   461
		Symbol *cur_sym;
skamonkey@3513
   462
		
skamonkey@3513
   463
		/* Skip symbols that are undefined */
skamonkey@3513
   464
		if (sym.n_sect == NO_SECT)
skamonkey@3513
   465
		{
skamonkey@3513
   466
			continue;
skamonkey@3513
   467
		}
skamonkey@3513
   468
		
skamonkey@3513
   469
		/* Caching symbols as we go along */
skamonkey@3513
   470
		cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
skamonkey@3513
   471
		if (strcmp(symbol, sym_name) == 0)
skamonkey@3513
   472
		{
skamonkey@3513
   473
			symbol_entry = cur_sym;
skamonkey@3513
   474
			libtable->last_pos = ++i;
skamonkey@3513
   475
			break;
skamonkey@3513
   476
		}
skamonkey@3513
   477
	}
skamonkey@3513
   478
	
skamonkey@3513
   479
	return symbol_entry ? symbol_entry->address : NULL;
skamonkey@3513
   480
skamonkey@3513
   481
#endif
skamonkey@3513
   482
}
skamonkey@3513
   483
skamonkey@3513
   484
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
skamonkey@3513
   485
{
skamonkey@3513
   486
	uintptr_t baseAddr;
skamonkey@3513
   487
skamonkey@3513
   488
	if (libPtr == NULL)
skamonkey@3513
   489
	{
skamonkey@3513
   490
		return false;
skamonkey@3513
   491
	}
skamonkey@3513
   492
skamonkey@3513
   493
#ifdef PLATFORM_WINDOWS
skamonkey@3513
   494
skamonkey@3513
   495
	MEMORY_BASIC_INFORMATION info;
skamonkey@3513
   496
	IMAGE_DOS_HEADER *dos;
skamonkey@3513
   497
	IMAGE_NT_HEADERS *pe;
skamonkey@3513
   498
	IMAGE_FILE_HEADER *file;
skamonkey@3513
   499
	IMAGE_OPTIONAL_HEADER *opt;
skamonkey@3513
   500
skamonkey@3513
   501
	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
skamonkey@3513
   502
	{
skamonkey@3513
   503
		return false;
skamonkey@3513
   504
	}
skamonkey@3513
   505
skamonkey@3513
   506
	baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
skamonkey@3513
   507
skamonkey@3513
   508
	/* All this is for our insane sanity checks :o */
skamonkey@3513
   509
	dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
skamonkey@3513
   510
	pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
skamonkey@3513
   511
	file = &pe->FileHeader;
skamonkey@3513
   512
	opt = &pe->OptionalHeader;
skamonkey@3513
   513
skamonkey@3513
   514
	/* Check PE magic and signature */
skamonkey@3513
   515
	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
skamonkey@3513
   516
	{
skamonkey@3513
   517
		return false;
skamonkey@3513
   518
	}
skamonkey@3513
   519
skamonkey@3513
   520
	/* Check architecture, which is 32-bit/x86 right now
skamonkey@3513
   521
	 * Should change this for 64-bit if Valve gets their act together
skamonkey@3513
   522
	 */
skamonkey@3513
   523
	if (file->Machine != IMAGE_FILE_MACHINE_I386)
skamonkey@3513
   524
	{
skamonkey@3513
   525
		return false;
skamonkey@3513
   526
	}
skamonkey@3513
   527
skamonkey@3513
   528
	/* For our purposes, this must be a dynamic library */
skamonkey@3513
   529
	if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
skamonkey@3513
   530
	{
skamonkey@3513
   531
		return false;
skamonkey@3513
   532
	}
skamonkey@3513
   533
skamonkey@3513
   534
	/* Finally, we can do this */
skamonkey@3513
   535
	lib.memorySize = opt->SizeOfImage;
skamonkey@3513
   536
skamonkey@3513
   537
#elif defined PLATFORM_LINUX
skamonkey@3513
   538
skamonkey@3513
   539
	Dl_info info;
skamonkey@3513
   540
	Elf32_Ehdr *file;
skamonkey@3513
   541
	Elf32_Phdr *phdr;
skamonkey@3513
   542
	uint16_t phdrCount;
skamonkey@3513
   543
skamonkey@3513
   544
	if (!dladdr(libPtr, &info))
skamonkey@3513
   545
	{
skamonkey@3513
   546
		return false;
skamonkey@3513
   547
	}
skamonkey@3513
   548
skamonkey@3513
   549
	if (!info.dli_fbase || !info.dli_fname)
skamonkey@3513
   550
	{
skamonkey@3513
   551
		return false;
skamonkey@3513
   552
	}
skamonkey@3513
   553
skamonkey@3513
   554
	/* This is for our insane sanity checks :o */
skamonkey@3513
   555
	baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
skamonkey@3513
   556
	file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
skamonkey@3513
   557
skamonkey@3513
   558
	/* Check ELF magic */
skamonkey@3513
   559
	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
skamonkey@3513
   560
	{
skamonkey@3513
   561
		return false;
skamonkey@3513
   562
	}
skamonkey@3513
   563
skamonkey@3513
   564
	/* Check ELF version */
skamonkey@3513
   565
	if (file->e_ident[EI_VERSION] != EV_CURRENT)
skamonkey@3513
   566
	{
skamonkey@3513
   567
		return false;
skamonkey@3513
   568
	}
skamonkey@3513
   569
skamonkey@3513
   570
	/* Check ELF architecture, which is 32-bit/x86 right now
skamonkey@3513
   571
	 * Should change this for 64-bit if Valve gets their act together
skamonkey@3513
   572
	 */
skamonkey@3513
   573
	if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
skamonkey@3513
   574
	{
skamonkey@3513
   575
		return false;
skamonkey@3513
   576
	}
skamonkey@3513
   577
skamonkey@3513
   578
	/* For our purposes, this must be a dynamic library/shared object */
skamonkey@3513
   579
	if (file->e_type != ET_DYN)
skamonkey@3513
   580
	{
skamonkey@3513
   581
		return false;
skamonkey@3513
   582
	}
skamonkey@3513
   583
skamonkey@3513
   584
	phdrCount = file->e_phnum;
skamonkey@3513
   585
	phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
skamonkey@3513
   586
skamonkey@3513
   587
	for (uint16_t i = 0; i < phdrCount; i++)
skamonkey@3513
   588
	{
skamonkey@3513
   589
		Elf32_Phdr &hdr = phdr[i];
skamonkey@3513
   590
skamonkey@3513
   591
		/* We only really care about the segment with executable code */
skamonkey@3513
   592
		if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
skamonkey@3513
   593
		{
skamonkey@3513
   594
			/* From glibc, elf/dl-load.c:
skamonkey@3513
   595
			 * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) 
skamonkey@3513
   596
			 *             & ~(GLRO(dl_pagesize) - 1));
skamonkey@3513
   597
			 *
skamonkey@3513
   598
			 * In glibc, the segment file size is aligned up to the nearest page size and
skamonkey@3513
   599
			 * added to the virtual address of the segment. We just want the size here.
skamonkey@3513
   600
			 */
skamonkey@3513
   601
			lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
skamonkey@3513
   602
			break;
skamonkey@3513
   603
		}
skamonkey@3513
   604
	}
skamonkey@3513
   605
skamonkey@3513
   606
#elif defined PLATFORM_APPLE
skamonkey@3513
   607
skamonkey@3513
   608
	Dl_info info;
skamonkey@3513
   609
	struct mach_header *file;
skamonkey@3513
   610
	struct segment_command *seg;
skamonkey@3513
   611
	uint32_t cmd_count;
skamonkey@3513
   612
skamonkey@3513
   613
	if (!dladdr(libPtr, &info))
skamonkey@3513
   614
	{
skamonkey@3513
   615
		return false;
skamonkey@3513
   616
	}
skamonkey@3513
   617
skamonkey@3513
   618
	if (!info.dli_fbase || !info.dli_fname)
skamonkey@3513
   619
	{
skamonkey@3513
   620
		return false;
skamonkey@3513
   621
	}
skamonkey@3513
   622
skamonkey@3513
   623
	/* This is for our insane sanity checks :o */
skamonkey@3513
   624
	baseAddr = (uintptr_t)info.dli_fbase;
skamonkey@3513
   625
	file = (struct mach_header *)baseAddr;
skamonkey@3513
   626
skamonkey@3513
   627
	/* Check Mach-O magic */
skamonkey@3513
   628
	if (file->magic != MH_MAGIC)
skamonkey@3513
   629
	{
skamonkey@3513
   630
		return false;
skamonkey@3513
   631
	}
skamonkey@3513
   632
skamonkey@3513
   633
	/* Check architecture (32-bit/x86) */
skamonkey@3513
   634
	if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
skamonkey@3513
   635
	{
skamonkey@3513
   636
		return false;
skamonkey@3513
   637
	}
skamonkey@3513
   638
skamonkey@3513
   639
	/* For our purposes, this must be a dynamic library */
skamonkey@3513
   640
	if (file->filetype != MH_DYLIB)
skamonkey@3513
   641
	{
skamonkey@3513
   642
		return false;
skamonkey@3513
   643
	}
skamonkey@3513
   644
skamonkey@3513
   645
	cmd_count = file->ncmds;
skamonkey@3513
   646
	seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
skamonkey@3513
   647
	
skamonkey@3513
   648
	/* Add up memory sizes of mapped segments */
skamonkey@3513
   649
	for (uint32_t i = 0; i < cmd_count; i++)
skamonkey@3513
   650
	{		
skamonkey@3513
   651
		if (seg->cmd == LC_SEGMENT)
skamonkey@3513
   652
		{
skamonkey@3513
   653
			lib.memorySize += seg->vmsize;
skamonkey@3513
   654
		}
skamonkey@3513
   655
		
skamonkey@3513
   656
		seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
skamonkey@3513
   657
	}
skamonkey@3513
   658
skamonkey@3513
   659
#endif
skamonkey@3513
   660
skamonkey@3513
   661
	lib.baseAddress = reinterpret_cast<void *>(baseAddr);
skamonkey@3513
   662
skamonkey@3513
   663
	return true;
skamonkey@3513
   664
}
skamonkey@3513
   665
skamonkey@3513
   666
const char* MemoryUtils::ResolveAddr(void *handle, void* addr)
skamonkey@3513
   667
{
skamonkey@3513
   668
	struct link_map *dlmap;
skamonkey@3513
   669
	dlmap = (struct link_map *)handle;
skamonkey@3513
   670
skamonkey@3513
   671
	LibSymbolTable *libtable;
skamonkey@3513
   672
	AddrTable *table2;
skamonkey@3513
   673
skamonkey@3513
   674
	for (size_t i = 0; i < m_SymTables.size(); i++)
skamonkey@3513
   675
	{
skamonkey@3513
   676
		libtable = m_SymTables[i];
skamonkey@3513
   677
		if (libtable->lib_base == dlmap->l_addr)
skamonkey@3513
   678
		{
skamonkey@3513
   679
			table2 = &libtable->table2;
skamonkey@3513
   680
			break;
skamonkey@3513
   681
		}
skamonkey@3513
   682
	}
skamonkey@3513
   683
skamonkey@3513
   684
	if (table2 == NULL) return NULL;
skamonkey@3513
   685
	Symbol *sym = table2->FindAddr(addr);
skamonkey@3513
   686
	return sym ? sym->buffer() : NULL;
skamonkey@3513
   687
}