Add support for Mac OS X to ResolveSymbol() and FindPattern() in IMemUtils (bug 4392, r=dvander).
This commit is contained in:
parent
31f223bff5
commit
5ef40e15c4
@ -2,7 +2,7 @@
|
|||||||
* vim: set ts=4 sw=4 tw=99 noet :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@ -34,30 +34,31 @@
|
|||||||
#include <link.h>
|
#include <link.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
#include <mach-o/nlist.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
MemoryUtils g_MemUtils;
|
MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
#if 0
|
|
||||||
MemoryUtils::MemoryUtils()
|
MemoryUtils::MemoryUtils()
|
||||||
{
|
{
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_APPLE
|
||||||
|
|
||||||
SYSTEM_INFO info;
|
/* Get pointer to struct that describes all loaded mach-o images in process */
|
||||||
GetSystemInfo(&info);
|
struct nlist list[2];
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
m_PageSize = info.dwPageSize;
|
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
|
||||||
|
nlist("/usr/lib/dyld", list);
|
||||||
#elif defined PLATFORM_POSIX
|
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
|
||||||
|
|
||||||
m_PageSize = sysconf(_SC_PAGE_SIZE);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
MemoryUtils::~MemoryUtils()
|
MemoryUtils::~MemoryUtils()
|
||||||
{
|
{
|
||||||
#ifdef PLATFORM_LINUX
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
{
|
{
|
||||||
delete m_SymTables[i];
|
delete m_SymTables[i];
|
||||||
@ -248,12 +249,140 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
|||||||
munmap(file_hdr, dlstat.st_size);
|
munmap(file_hdr, dlstat.st_size);
|
||||||
return symbol_entry ? symbol_entry->address : NULL;
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#elif defined PLATFORM_APPLE
|
||||||
|
|
||||||
|
uintptr_t dlbase;
|
||||||
|
uint32_t image_count;
|
||||||
|
struct mach_header *file_hdr;
|
||||||
|
struct load_command *loadcmds;
|
||||||
|
struct symtab_command *symtab_hdr;
|
||||||
|
struct nlist *symtab;
|
||||||
|
const char *strtab;
|
||||||
|
uint32_t loadcmd_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlbase = 0;
|
||||||
|
image_count = m_ImageList->infoArrayCount;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
|
||||||
|
/* Loop through mach-o images in process.
|
||||||
|
* We can skip index 0 since that is just the executable.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 1; i < image_count; i++)
|
||||||
|
{
|
||||||
|
const struct dyld_image_info &info = m_ImageList->infoArray[i];
|
||||||
|
|
||||||
|
/* "Load" each one until we get a matching handle */
|
||||||
|
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
|
||||||
|
if (h == handle)
|
||||||
|
{
|
||||||
|
dlbase = (uintptr_t)info.imageLoadAddress;
|
||||||
|
dlclose(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlclose(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dlbase)
|
||||||
|
{
|
||||||
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlbase)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlbase;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.push_back(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have to locate it in memory */
|
||||||
|
|
||||||
|
file_hdr = (struct mach_header *)dlbase;
|
||||||
|
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
|
||||||
|
loadcmd_count = file_hdr->ncmds;
|
||||||
|
|
||||||
|
/* Loop through load commands until we find the one for the symbol table */
|
||||||
|
for (uint32_t i = 0; i < loadcmd_count; i++)
|
||||||
|
{
|
||||||
|
if (loadcmds->cmd == LC_SYMTAB)
|
||||||
|
{
|
||||||
|
symtab_hdr = (struct symtab_command *)loadcmds;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load commands are not of a fixed size which is why we add the size */
|
||||||
|
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
|
||||||
|
{
|
||||||
|
/* Uh oh, no symbol table */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab = (struct nlist *)(dlbase + symtab_hdr->symoff);
|
||||||
|
strtab = (const char *)(dlbase + symtab_hdr->stroff);
|
||||||
|
symbol_count = symtab_hdr->nsyms;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
struct nlist &sym = symtab[i];
|
||||||
|
/* Ignore the prepended underscore on all symbols, so +1 here */
|
||||||
|
const char *sym_name = strtab + sym.n_un.n_strx + 1;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined */
|
||||||
|
if (sym.n_sect == NO_SECT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||||
{
|
{
|
||||||
unsigned long baseAddr;
|
uintptr_t baseAddr;
|
||||||
|
|
||||||
if (libPtr == NULL)
|
if (libPtr == NULL)
|
||||||
{
|
{
|
||||||
@ -273,7 +402,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
|
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||||
|
|
||||||
/* All this is for our insane sanity checks :o */
|
/* All this is for our insane sanity checks :o */
|
||||||
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
|
||||||
@ -322,7 +451,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This is for our insane sanity checks :o */
|
/* This is for our insane sanity checks :o */
|
||||||
baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
|
baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
|
||||||
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
|
file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
|
||||||
|
|
||||||
/* Check ELF magic */
|
/* Check ELF magic */
|
||||||
@ -365,6 +494,59 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined PLATFORM_APPLE
|
||||||
|
|
||||||
|
Dl_info info;
|
||||||
|
struct mach_header *file;
|
||||||
|
struct segment_command *seg;
|
||||||
|
uint32_t cmd_count;
|
||||||
|
|
||||||
|
if (!dladdr(libPtr, &info))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.dli_fbase || !info.dli_fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is for our insane sanity checks :o */
|
||||||
|
baseAddr = (uintptr_t)info.dli_fbase;
|
||||||
|
file = (struct mach_header *)baseAddr;
|
||||||
|
|
||||||
|
/* Check Mach-O magic */
|
||||||
|
if (file->magic != MH_MAGIC)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check architecture (32-bit/x86) */
|
||||||
|
if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For our purposes, this must be a dynamic library */
|
||||||
|
if (file->filetype != MH_DYLIB)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_count = file->ncmds;
|
||||||
|
seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
|
||||||
|
|
||||||
|
/* Add up memory sizes of mapped segments */
|
||||||
|
for (uint32_t i = 0; i < cmd_count; i++)
|
||||||
|
{
|
||||||
|
if (seg->cmd == LC_SEGMENT)
|
||||||
|
{
|
||||||
|
lib.memorySize += seg->vmsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* vim: set ts=4 sw=4 tw=99 noet :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2000 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
#include <IMemoryUtils.h>
|
#include <IMemoryUtils.h>
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#ifdef PLATFORM_LINUX
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include "sm_symtable.h"
|
#include "sm_symtable.h"
|
||||||
|
|
||||||
@ -47,13 +47,11 @@ struct DynLibInfo
|
|||||||
size_t memorySize;
|
size_t memorySize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef PLATFORM_LINUX
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
typedef uint32_t Elf32_Addr;
|
|
||||||
|
|
||||||
struct LibSymbolTable
|
struct LibSymbolTable
|
||||||
{
|
{
|
||||||
SymbolTable table;
|
SymbolTable table;
|
||||||
Elf32_Addr lib_base;
|
uintptr_t lib_base;
|
||||||
uint32_t last_pos;
|
uint32_t last_pos;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@ -63,6 +61,7 @@ class MemoryUtils :
|
|||||||
public SMGlobalClass
|
public SMGlobalClass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
MemoryUtils();
|
||||||
~MemoryUtils();
|
~MemoryUtils();
|
||||||
public: // SMGlobalClass
|
public: // SMGlobalClass
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
@ -71,9 +70,12 @@ public: // IMemoryUtils
|
|||||||
void *ResolveSymbol(void *handle, const char *symbol);
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
public:
|
public:
|
||||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||||
#ifdef PLATFORM_LINUX
|
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||||
private:
|
private:
|
||||||
CVector<LibSymbolTable *> m_SymTables;
|
CVector<LibSymbolTable *> m_SymTables;
|
||||||
|
#ifdef PLATFORM_APPLE
|
||||||
|
struct dyld_all_image_infos *m_ImageList;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,11 +67,14 @@ namespace SourceMod
|
|||||||
/**
|
/**
|
||||||
* @brief Retrieves a symbol pointer from a dynamic library.
|
* @brief Retrieves a symbol pointer from a dynamic library.
|
||||||
*
|
*
|
||||||
* Note: On Linux, this function is able to resolve symbols that are hidden via GCC's
|
* Note: On Linux and Mac OS X, this function is able to resolve symbols that are hidden
|
||||||
* -fvisibility=hidden option.
|
* via GCC's -fvisibility=hidden option.
|
||||||
|
*
|
||||||
|
* Note: On Mac OS X, the symbol name should be passed without the prepended underscore,
|
||||||
|
* as this is how dlsym() would expect it.
|
||||||
*
|
*
|
||||||
* @param handle Operating system specific handle that points to dynamic library.
|
* @param handle Operating system specific handle that points to dynamic library.
|
||||||
* This comes from dlopen() on Linux or LoadLibrary() on Windows.
|
* This comes from dlopen() on Linux/OS X or LoadLibrary() on Windows.
|
||||||
* @param symbol Symbol name.
|
* @param symbol Symbol name.
|
||||||
* @return Symbol pointer, or NULL if not found.
|
* @return Symbol pointer, or NULL if not found.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user