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