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