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