1.1 --- a/core/MemoryUtils.cpp Thu May 13 04:19:39 2010 -0500
1.2 +++ b/core/MemoryUtils.cpp Thu May 13 04:20:41 2010 -0500
1.3 @@ -2,7 +2,7 @@
1.4 * vim: set ts=4 sw=4 tw=99 noet :
1.5 * =============================================================================
1.6 * SourceMod
1.7 - * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
1.8 + * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
1.9 * =============================================================================
1.10 *
1.11 * This program is free software; you can redistribute it and/or modify it under
1.12 @@ -34,30 +34,31 @@
1.13 #include <link.h>
1.14 #include <sys/mman.h>
1.15 #endif
1.16 +#ifdef PLATFORM_APPLE
1.17 +#include <mach-o/dyld_images.h>
1.18 +#include <mach-o/loader.h>
1.19 +#include <mach-o/nlist.h>
1.20 +#endif
1.21
1.22 MemoryUtils g_MemUtils;
1.23
1.24 -#if 0
1.25 MemoryUtils::MemoryUtils()
1.26 {
1.27 -#ifdef PLATFORM_WINDOWS
1.28 -
1.29 - SYSTEM_INFO info;
1.30 - GetSystemInfo(&info);
1.31 +#ifdef PLATFORM_APPLE
1.32
1.33 - m_PageSize = info.dwPageSize;
1.34 -
1.35 -#elif defined PLATFORM_POSIX
1.36 -
1.37 - m_PageSize = sysconf(_SC_PAGE_SIZE);
1.38 + /* Get pointer to struct that describes all loaded mach-o images in process */
1.39 + struct nlist list[2];
1.40 + memset(list, 0, sizeof(list));
1.41 + list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
1.42 + nlist("/usr/lib/dyld", list);
1.43 + m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
1.44
1.45 #endif
1.46 }
1.47 -#endif
1.48
1.49 MemoryUtils::~MemoryUtils()
1.50 {
1.51 -#ifdef PLATFORM_LINUX
1.52 +#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
1.53 for (size_t i = 0; i < m_SymTables.size(); i++)
1.54 {
1.55 delete m_SymTables[i];
1.56 @@ -113,7 +114,7 @@
1.57 #ifdef PLATFORM_WINDOWS
1.58
1.59 return GetProcAddress((HMODULE)handle, symbol);
1.60 -
1.61 +
1.62 #elif defined PLATFORM_LINUX
1.63
1.64 struct link_map *dlmap;
1.65 @@ -248,12 +249,140 @@
1.66 munmap(file_hdr, dlstat.st_size);
1.67 return symbol_entry ? symbol_entry->address : NULL;
1.68
1.69 +#elif defined PLATFORM_APPLE
1.70 +
1.71 + uintptr_t dlbase;
1.72 + uint32_t image_count;
1.73 + struct mach_header *file_hdr;
1.74 + struct load_command *loadcmds;
1.75 + struct symtab_command *symtab_hdr;
1.76 + struct nlist *symtab;
1.77 + const char *strtab;
1.78 + uint32_t loadcmd_count;
1.79 + uint32_t symbol_count;
1.80 + LibSymbolTable *libtable;
1.81 + SymbolTable *table;
1.82 + Symbol *symbol_entry;
1.83 +
1.84 + dlbase = 0;
1.85 + image_count = m_ImageList->infoArrayCount;
1.86 + symtab_hdr = NULL;
1.87 +
1.88 + /* Loop through mach-o images in process.
1.89 + * We can skip index 0 since that is just the executable.
1.90 + */
1.91 + for (uint32_t i = 1; i < image_count; i++)
1.92 + {
1.93 + const struct dyld_image_info &info = m_ImageList->infoArray[i];
1.94 +
1.95 + /* "Load" each one until we get a matching handle */
1.96 + void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
1.97 + if (h == handle)
1.98 + {
1.99 + dlbase = (uintptr_t)info.imageLoadAddress;
1.100 + dlclose(h);
1.101 + break;
1.102 + }
1.103 +
1.104 + dlclose(h);
1.105 + }
1.106 +
1.107 + if (!dlbase)
1.108 + {
1.109 + /* Uh oh, we couldn't find a matching handle */
1.110 + return NULL;
1.111 + }
1.112 +
1.113 + /* See if we already have a symbol table for this library */
1.114 + for (size_t i = 0; i < m_SymTables.size(); i++)
1.115 + {
1.116 + libtable = m_SymTables[i];
1.117 + if (libtable->lib_base == dlbase)
1.118 + {
1.119 + table = &libtable->table;
1.120 + break;
1.121 + }
1.122 + }
1.123 +
1.124 + /* If we don't have a symbol table for this library, then create one */
1.125 + if (table == NULL)
1.126 + {
1.127 + libtable = new LibSymbolTable();
1.128 + libtable->table.Initialize();
1.129 + libtable->lib_base = dlbase;
1.130 + libtable->last_pos = 0;
1.131 + table = &libtable->table;
1.132 + m_SymTables.push_back(libtable);
1.133 + }
1.134 +
1.135 + /* See if the symbol is already cached in our table */
1.136 + symbol_entry = table->FindSymbol(symbol, strlen(symbol));
1.137 + if (symbol_entry != NULL)
1.138 + {
1.139 + return symbol_entry->address;
1.140 + }
1.141 +
1.142 + /* If symbol isn't in our table, then we have to locate it in memory */
1.143 +
1.144 + file_hdr = (struct mach_header *)dlbase;
1.145 + loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
1.146 + loadcmd_count = file_hdr->ncmds;
1.147 +
1.148 + /* Loop through load commands until we find the one for the symbol table */
1.149 + for (uint32_t i = 0; i < loadcmd_count; i++)
1.150 + {
1.151 + if (loadcmds->cmd == LC_SYMTAB)
1.152 + {
1.153 + symtab_hdr = (struct symtab_command *)loadcmds;
1.154 + break;
1.155 + }
1.156 +
1.157 + /* Load commands are not of a fixed size which is why we add the size */
1.158 + loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
1.159 + }
1.160 +
1.161 + if (!symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
1.162 + {
1.163 + /* Uh oh, no symbol table */
1.164 + return NULL;
1.165 + }
1.166 +
1.167 + symtab = (struct nlist *)(dlbase + symtab_hdr->symoff);
1.168 + strtab = (const char *)(dlbase + symtab_hdr->stroff);
1.169 + symbol_count = symtab_hdr->nsyms;
1.170 +
1.171 + /* Iterate symbol table starting from the position we were at last time */
1.172 + for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
1.173 + {
1.174 + struct nlist &sym = symtab[i];
1.175 + /* Ignore the prepended underscore on all symbols, so +1 here */
1.176 + const char *sym_name = strtab + sym.n_un.n_strx + 1;
1.177 + Symbol *cur_sym;
1.178 +
1.179 + /* Skip symbols that are undefined */
1.180 + if (sym.n_sect == NO_SECT)
1.181 + {
1.182 + continue;
1.183 + }
1.184 +
1.185 + /* Caching symbols as we go along */
1.186 + cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
1.187 + if (strcmp(symbol, sym_name) == 0)
1.188 + {
1.189 + symbol_entry = cur_sym;
1.190 + libtable->last_pos = ++i;
1.191 + break;
1.192 + }
1.193 + }
1.194 +
1.195 + return symbol_entry ? symbol_entry->address : NULL;
1.196 +
1.197 #endif
1.198 }
1.199
1.200 bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
1.201 {
1.202 - unsigned long baseAddr;
1.203 + uintptr_t baseAddr;
1.204
1.205 if (libPtr == NULL)
1.206 {
1.207 @@ -273,7 +402,7 @@
1.208 return false;
1.209 }
1.210
1.211 - baseAddr = reinterpret_cast<unsigned long>(info.AllocationBase);
1.212 + baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
1.213
1.214 /* All this is for our insane sanity checks :o */
1.215 dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
1.216 @@ -322,7 +451,7 @@
1.217 }
1.218
1.219 /* This is for our insane sanity checks :o */
1.220 - baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
1.221 + baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
1.222 file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
1.223
1.224 /* Check ELF magic */
1.225 @@ -364,6 +493,59 @@
1.226 lib.memorySize += hdr.p_memsz;
1.227 }
1.228 }
1.229 +
1.230 +#elif defined PLATFORM_APPLE
1.231 +
1.232 + Dl_info info;
1.233 + struct mach_header *file;
1.234 + struct segment_command *seg;
1.235 + uint32_t cmd_count;
1.236 +
1.237 + if (!dladdr(libPtr, &info))
1.238 + {
1.239 + return false;
1.240 + }
1.241 +
1.242 + if (!info.dli_fbase || !info.dli_fname)
1.243 + {
1.244 + return false;
1.245 + }
1.246 +
1.247 + /* This is for our insane sanity checks :o */
1.248 + baseAddr = (uintptr_t)info.dli_fbase;
1.249 + file = (struct mach_header *)baseAddr;
1.250 +
1.251 + /* Check Mach-O magic */
1.252 + if (file->magic != MH_MAGIC)
1.253 + {
1.254 + return false;
1.255 + }
1.256 +
1.257 + /* Check architecture (32-bit/x86) */
1.258 + if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
1.259 + {
1.260 + return false;
1.261 + }
1.262 +
1.263 + /* For our purposes, this must be a dynamic library */
1.264 + if (file->filetype != MH_DYLIB)
1.265 + {
1.266 + return false;
1.267 + }
1.268 +
1.269 + cmd_count = file->ncmds;
1.270 + seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
1.271 +
1.272 + /* Add up memory sizes of mapped segments */
1.273 + for (uint32_t i = 0; i < cmd_count; i++)
1.274 + {
1.275 + if (seg->cmd == LC_SEGMENT)
1.276 + {
1.277 + lib.memorySize += seg->vmsize;
1.278 + }
1.279 +
1.280 + seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
1.281 + }
1.282
1.283 #endif
1.284