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