1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/gdc/MemoryUtils.cpp Fri Oct 01 12:15:43 2010 -0700
1.3 @@ -0,0 +1,615 @@
1.4 +/**
1.5 + * vim: set ts=4 sw=4 tw=99 noet :
1.6 + * =============================================================================
1.7 + * SourceMod
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 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + */
1.32 +
1.33 +#include "MemoryUtils.h"
1.34 +#ifdef PLATFORM_LINUX
1.35 +#include <fcntl.h>
1.36 +#include <link.h>
1.37 +#include <sys/mman.h>
1.38 +
1.39 +#define PAGE_SIZE 4096
1.40 +#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
1.41 +#endif
1.42 +#ifdef PLATFORM_APPLE
1.43 +#include <mach-o/dyld_images.h>
1.44 +#include <mach-o/loader.h>
1.45 +#include <mach-o/nlist.h>
1.46 +#endif
1.47 +
1.48 +//MemoryUtils g_MemUtils;
1.49 +
1.50 +MemoryUtils::MemoryUtils()
1.51 +{
1.52 +#ifdef PLATFORM_APPLE
1.53 +
1.54 + /* Get pointer to struct that describes all loaded mach-o images in process */
1.55 + struct nlist list[2];
1.56 + memset(list, 0, sizeof(list));
1.57 + list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
1.58 + nlist("/usr/lib/dyld", list);
1.59 + m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
1.60 +
1.61 +#endif
1.62 +}
1.63 +
1.64 +MemoryUtils::~MemoryUtils()
1.65 +{
1.66 +#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
1.67 + for (size_t i = 0; i < m_SymTables.size(); i++)
1.68 + {
1.69 + delete m_SymTables[i];
1.70 + }
1.71 + m_SymTables.clear();
1.72 +#endif
1.73 +}
1.74 +
1.75 +/*void MemoryUtils::OnSourceModAllInitialized()
1.76 +{
1.77 + sharesys->AddInterface(NULL, this);
1.78 +}*/
1.79 +
1.80 +void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
1.81 +{
1.82 + DynLibInfo lib;
1.83 + bool found;
1.84 + char *ptr, *end;
1.85 +
1.86 + memset(&lib, 0, sizeof(DynLibInfo));
1.87 +
1.88 + if (!GetLibraryInfo(libPtr, lib))
1.89 + {
1.90 + return NULL;
1.91 + }
1.92 +
1.93 + ptr = reinterpret_cast<char *>(lib.baseAddress);
1.94 + end = ptr + lib.memorySize;
1.95 +
1.96 + while (ptr < end)
1.97 + {
1.98 + found = true;
1.99 + for (register size_t i = 0; i < len; i++)
1.100 + {
1.101 + if (pattern[i] != '\x2A' && pattern[i] != ptr[i])
1.102 + {
1.103 + found = false;
1.104 + break;
1.105 + }
1.106 + }
1.107 +
1.108 + if (found)
1.109 + return ptr;
1.110 +
1.111 + ptr++;
1.112 + }
1.113 +
1.114 + return NULL;
1.115 +}
1.116 +
1.117 +void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
1.118 +{
1.119 +#ifdef PLATFORM_WINDOWS
1.120 +
1.121 + return GetProcAddress((HMODULE)handle, symbol);
1.122 +
1.123 +#elif defined PLATFORM_LINUX
1.124 +
1.125 + struct link_map *dlmap;
1.126 + struct stat dlstat;
1.127 + int dlfile;
1.128 + uintptr_t map_base;
1.129 + Elf32_Ehdr *file_hdr;
1.130 + Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
1.131 + Elf32_Sym *symtab;
1.132 + const char *shstrtab, *strtab;
1.133 + uint16_t section_count;
1.134 + uint32_t symbol_count;
1.135 + LibSymbolTable *libtable;
1.136 + SymbolTable *table;
1.137 + AddrTable *table2;
1.138 + Symbol *symbol_entry;
1.139 +
1.140 + dlmap = (struct link_map *)handle;
1.141 + symtab_hdr = NULL;
1.142 + strtab_hdr = NULL;
1.143 + table = NULL;
1.144 + table2 = NULL;
1.145 +
1.146 + /* See if we already have a symbol table for this library */
1.147 + for (size_t i = 0; i < m_SymTables.size(); i++)
1.148 + {
1.149 + libtable = m_SymTables[i];
1.150 + if (libtable->lib_base == dlmap->l_addr)
1.151 + {
1.152 + table = &libtable->table;
1.153 + table2 = &libtable->table2;
1.154 + break;
1.155 + }
1.156 + }
1.157 +
1.158 + /* If we don't have a symbol table for this library, then create one */
1.159 + if (table == NULL)
1.160 + {
1.161 + libtable = new LibSymbolTable();
1.162 + libtable->table.Initialize();
1.163 + libtable->table2.Initialize();
1.164 + libtable->lib_base = dlmap->l_addr;
1.165 + libtable->last_pos = 0;
1.166 + table = &libtable->table;
1.167 + table2 = &libtable->table2;
1.168 + m_SymTables.push_back(libtable);
1.169 + }
1.170 +
1.171 + /* See if the symbol is already cached in our table */
1.172 + symbol_entry = table->FindSymbol(symbol, strlen(symbol));
1.173 + if (symbol_entry != NULL)
1.174 + {
1.175 + return symbol_entry->address;
1.176 + }
1.177 +
1.178 + /* If symbol isn't in our table, then we have open the actual library */
1.179 + dlfile = open(dlmap->l_name, O_RDONLY);
1.180 + if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
1.181 + {
1.182 + close(dlfile);
1.183 + return NULL;
1.184 + }
1.185 +
1.186 + /* Map library file into memory */
1.187 + file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
1.188 + map_base = (uintptr_t)file_hdr;
1.189 + if (file_hdr == MAP_FAILED)
1.190 + {
1.191 + close(dlfile);
1.192 + return NULL;
1.193 + }
1.194 + close(dlfile);
1.195 +
1.196 + if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
1.197 + {
1.198 + munmap(file_hdr, dlstat.st_size);
1.199 + return NULL;
1.200 + }
1.201 +
1.202 + sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
1.203 + section_count = file_hdr->e_shnum;
1.204 + /* Get ELF section header string table */
1.205 + shstrtab_hdr = §ions[file_hdr->e_shstrndx];
1.206 + shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
1.207 +
1.208 + /* Iterate sections while looking for ELF symbol table and string table */
1.209 + for (uint16_t i = 0; i < section_count; i++)
1.210 + {
1.211 + Elf32_Shdr &hdr = sections[i];
1.212 + const char *section_name = shstrtab + hdr.sh_name;
1.213 +
1.214 + if (strcmp(section_name, ".symtab") == 0)
1.215 + {
1.216 + symtab_hdr = &hdr;
1.217 + }
1.218 + else if (strcmp(section_name, ".strtab") == 0)
1.219 + {
1.220 + strtab_hdr = &hdr;
1.221 + }
1.222 + }
1.223 +
1.224 + /* Uh oh, we don't have a symbol table or a string table */
1.225 + if (symtab_hdr == NULL || strtab_hdr == NULL)
1.226 + {
1.227 + munmap(file_hdr, dlstat.st_size);
1.228 + return NULL;
1.229 + }
1.230 +
1.231 + symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
1.232 + strtab = (const char *)(map_base + strtab_hdr->sh_offset);
1.233 + symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
1.234 +
1.235 + /* Iterate symbol table starting from the position we were at last time */
1.236 + for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
1.237 + {
1.238 + Elf32_Sym &sym = symtab[i];
1.239 + unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
1.240 + const char *sym_name = strtab + sym.st_name;
1.241 + Symbol *cur_sym;
1.242 +
1.243 + /* Skip symbols that are undefined or do not refer to functions or objects */
1.244 + if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
1.245 + {
1.246 + continue;
1.247 + }
1.248 +
1.249 + /* Caching symbols as we go along */
1.250 + cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
1.251 + table2->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
1.252 + if (strcmp(symbol, sym_name) == 0)
1.253 + {
1.254 + symbol_entry = cur_sym;
1.255 + libtable->last_pos = ++i;
1.256 + // break;
1.257 + }
1.258 + }
1.259 +
1.260 + libtable->last_pos = symbol_count;
1.261 +
1.262 + munmap(file_hdr, dlstat.st_size);
1.263 + return symbol_entry ? symbol_entry->address : NULL;
1.264 +
1.265 +#elif defined PLATFORM_APPLE
1.266 +
1.267 + uintptr_t dlbase, linkedit_addr;
1.268 + uint32_t image_count;
1.269 + struct mach_header *file_hdr;
1.270 + struct load_command *loadcmds;
1.271 + struct segment_command *linkedit_hdr;
1.272 + struct symtab_command *symtab_hdr;
1.273 + struct nlist *symtab;
1.274 + const char *strtab;
1.275 + uint32_t loadcmd_count;
1.276 + uint32_t symbol_count;
1.277 + LibSymbolTable *libtable;
1.278 + SymbolTable *table;
1.279 + Symbol *symbol_entry;
1.280 +
1.281 + dlbase = 0;
1.282 + image_count = m_ImageList->infoArrayCount;
1.283 + linkedit_hdr = NULL;
1.284 + symtab_hdr = NULL;
1.285 + table = NULL;
1.286 +
1.287 + /* Loop through mach-o images in process.
1.288 + * We can skip index 0 since that is just the executable.
1.289 + */
1.290 + for (uint32_t i = 1; i < image_count; i++)
1.291 + {
1.292 + const struct dyld_image_info &info = m_ImageList->infoArray[i];
1.293 +
1.294 + /* "Load" each one until we get a matching handle */
1.295 + void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
1.296 + if (h == handle)
1.297 + {
1.298 + dlbase = (uintptr_t)info.imageLoadAddress;
1.299 + dlclose(h);
1.300 + break;
1.301 + }
1.302 +
1.303 + dlclose(h);
1.304 + }
1.305 +
1.306 + if (!dlbase)
1.307 + {
1.308 + /* Uh oh, we couldn't find a matching handle */
1.309 + return NULL;
1.310 + }
1.311 +
1.312 + /* See if we already have a symbol table for this library */
1.313 + for (size_t i = 0; i < m_SymTables.size(); i++)
1.314 + {
1.315 + libtable = m_SymTables[i];
1.316 + if (libtable->lib_base == dlbase)
1.317 + {
1.318 + table = &libtable->table;
1.319 + break;
1.320 + }
1.321 + }
1.322 +
1.323 + /* If we don't have a symbol table for this library, then create one */
1.324 + if (table == NULL)
1.325 + {
1.326 + libtable = new LibSymbolTable();
1.327 + libtable->table.Initialize();
1.328 + libtable->lib_base = dlbase;
1.329 + libtable->last_pos = 0;
1.330 + table = &libtable->table;
1.331 + m_SymTables.push_back(libtable);
1.332 + }
1.333 +
1.334 + /* See if the symbol is already cached in our table */
1.335 + symbol_entry = table->FindSymbol(symbol, strlen(symbol));
1.336 + if (symbol_entry != NULL)
1.337 + {
1.338 + return symbol_entry->address;
1.339 + }
1.340 +
1.341 + /* If symbol isn't in our table, then we have to locate it in memory */
1.342 +
1.343 + file_hdr = (struct mach_header *)dlbase;
1.344 + loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
1.345 + loadcmd_count = file_hdr->ncmds;
1.346 +
1.347 + /* Loop through load commands until we find the ones for the symbol table */
1.348 + for (uint32_t i = 0; i < loadcmd_count; i++)
1.349 + {
1.350 + if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
1.351 + {
1.352 + struct segment_command *seg = (struct segment_command *)loadcmds;
1.353 + if (strcmp(seg->segname, "__LINKEDIT") == 0)
1.354 + {
1.355 + linkedit_hdr = seg;
1.356 + if (symtab_hdr)
1.357 + {
1.358 + break;
1.359 + }
1.360 + }
1.361 + }
1.362 + else if (loadcmds->cmd == LC_SYMTAB)
1.363 + {
1.364 + symtab_hdr = (struct symtab_command *)loadcmds;
1.365 + if (linkedit_hdr)
1.366 + {
1.367 + break;
1.368 + }
1.369 + }
1.370 +
1.371 + /* Load commands are not of a fixed size which is why we add the size */
1.372 + loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
1.373 + }
1.374 +
1.375 + if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
1.376 + {
1.377 + /* Uh oh, no symbol table */
1.378 + return NULL;
1.379 + }
1.380 +
1.381 + linkedit_addr = dlbase + linkedit_hdr->vmaddr;
1.382 + symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
1.383 + strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
1.384 + symbol_count = symtab_hdr->nsyms;
1.385 +
1.386 + /* Iterate symbol table starting from the position we were at last time */
1.387 + for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
1.388 + {
1.389 + struct nlist &sym = symtab[i];
1.390 + /* Ignore the prepended underscore on all symbols, so +1 here */
1.391 + const char *sym_name = strtab + sym.n_un.n_strx + 1;
1.392 + Symbol *cur_sym;
1.393 +
1.394 + /* Skip symbols that are undefined */
1.395 + if (sym.n_sect == NO_SECT)
1.396 + {
1.397 + continue;
1.398 + }
1.399 +
1.400 + /* Caching symbols as we go along */
1.401 + cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
1.402 + if (strcmp(symbol, sym_name) == 0)
1.403 + {
1.404 + symbol_entry = cur_sym;
1.405 + libtable->last_pos = ++i;
1.406 + break;
1.407 + }
1.408 + }
1.409 +
1.410 + return symbol_entry ? symbol_entry->address : NULL;
1.411 +
1.412 +#endif
1.413 +}
1.414 +
1.415 +bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
1.416 +{
1.417 + uintptr_t baseAddr;
1.418 +
1.419 + if (libPtr == NULL)
1.420 + {
1.421 + return false;
1.422 + }
1.423 +
1.424 +#ifdef PLATFORM_WINDOWS
1.425 +
1.426 + MEMORY_BASIC_INFORMATION info;
1.427 + IMAGE_DOS_HEADER *dos;
1.428 + IMAGE_NT_HEADERS *pe;
1.429 + IMAGE_FILE_HEADER *file;
1.430 + IMAGE_OPTIONAL_HEADER *opt;
1.431 +
1.432 + if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
1.433 + {
1.434 + return false;
1.435 + }
1.436 +
1.437 + baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
1.438 +
1.439 + /* All this is for our insane sanity checks :o */
1.440 + dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr);
1.441 + pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew);
1.442 + file = &pe->FileHeader;
1.443 + opt = &pe->OptionalHeader;
1.444 +
1.445 + /* Check PE magic and signature */
1.446 + if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1.447 + {
1.448 + return false;
1.449 + }
1.450 +
1.451 + /* Check architecture, which is 32-bit/x86 right now
1.452 + * Should change this for 64-bit if Valve gets their act together
1.453 + */
1.454 + if (file->Machine != IMAGE_FILE_MACHINE_I386)
1.455 + {
1.456 + return false;
1.457 + }
1.458 +
1.459 + /* For our purposes, this must be a dynamic library */
1.460 + if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
1.461 + {
1.462 + return false;
1.463 + }
1.464 +
1.465 + /* Finally, we can do this */
1.466 + lib.memorySize = opt->SizeOfImage;
1.467 +
1.468 +#elif defined PLATFORM_LINUX
1.469 +
1.470 + Dl_info info;
1.471 + Elf32_Ehdr *file;
1.472 + Elf32_Phdr *phdr;
1.473 + uint16_t phdrCount;
1.474 +
1.475 + if (!dladdr(libPtr, &info))
1.476 + {
1.477 + return false;
1.478 + }
1.479 +
1.480 + if (!info.dli_fbase || !info.dli_fname)
1.481 + {
1.482 + return false;
1.483 + }
1.484 +
1.485 + /* This is for our insane sanity checks :o */
1.486 + baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase);
1.487 + file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
1.488 +
1.489 + /* Check ELF magic */
1.490 + if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
1.491 + {
1.492 + return false;
1.493 + }
1.494 +
1.495 + /* Check ELF version */
1.496 + if (file->e_ident[EI_VERSION] != EV_CURRENT)
1.497 + {
1.498 + return false;
1.499 + }
1.500 +
1.501 + /* Check ELF architecture, which is 32-bit/x86 right now
1.502 + * Should change this for 64-bit if Valve gets their act together
1.503 + */
1.504 + if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
1.505 + {
1.506 + return false;
1.507 + }
1.508 +
1.509 + /* For our purposes, this must be a dynamic library/shared object */
1.510 + if (file->e_type != ET_DYN)
1.511 + {
1.512 + return false;
1.513 + }
1.514 +
1.515 + phdrCount = file->e_phnum;
1.516 + phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
1.517 +
1.518 + for (uint16_t i = 0; i < phdrCount; i++)
1.519 + {
1.520 + Elf32_Phdr &hdr = phdr[i];
1.521 +
1.522 + /* We only really care about the segment with executable code */
1.523 + if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R))
1.524 + {
1.525 + /* From glibc, elf/dl-load.c:
1.526 + * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
1.527 + * & ~(GLRO(dl_pagesize) - 1));
1.528 + *
1.529 + * In glibc, the segment file size is aligned up to the nearest page size and
1.530 + * added to the virtual address of the segment. We just want the size here.
1.531 + */
1.532 + lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz);
1.533 + break;
1.534 + }
1.535 + }
1.536 +
1.537 +#elif defined PLATFORM_APPLE
1.538 +
1.539 + Dl_info info;
1.540 + struct mach_header *file;
1.541 + struct segment_command *seg;
1.542 + uint32_t cmd_count;
1.543 +
1.544 + if (!dladdr(libPtr, &info))
1.545 + {
1.546 + return false;
1.547 + }
1.548 +
1.549 + if (!info.dli_fbase || !info.dli_fname)
1.550 + {
1.551 + return false;
1.552 + }
1.553 +
1.554 + /* This is for our insane sanity checks :o */
1.555 + baseAddr = (uintptr_t)info.dli_fbase;
1.556 + file = (struct mach_header *)baseAddr;
1.557 +
1.558 + /* Check Mach-O magic */
1.559 + if (file->magic != MH_MAGIC)
1.560 + {
1.561 + return false;
1.562 + }
1.563 +
1.564 + /* Check architecture (32-bit/x86) */
1.565 + if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL)
1.566 + {
1.567 + return false;
1.568 + }
1.569 +
1.570 + /* For our purposes, this must be a dynamic library */
1.571 + if (file->filetype != MH_DYLIB)
1.572 + {
1.573 + return false;
1.574 + }
1.575 +
1.576 + cmd_count = file->ncmds;
1.577 + seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header));
1.578 +
1.579 + /* Add up memory sizes of mapped segments */
1.580 + for (uint32_t i = 0; i < cmd_count; i++)
1.581 + {
1.582 + if (seg->cmd == LC_SEGMENT)
1.583 + {
1.584 + lib.memorySize += seg->vmsize;
1.585 + }
1.586 +
1.587 + seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize);
1.588 + }
1.589 +
1.590 +#endif
1.591 +
1.592 + lib.baseAddress = reinterpret_cast<void *>(baseAddr);
1.593 +
1.594 + return true;
1.595 +}
1.596 +
1.597 +const char* MemoryUtils::ResolveAddr(void *handle, void* addr)
1.598 +{
1.599 + struct link_map *dlmap;
1.600 + dlmap = (struct link_map *)handle;
1.601 +
1.602 + LibSymbolTable *libtable;
1.603 + AddrTable *table2;
1.604 +
1.605 + for (size_t i = 0; i < m_SymTables.size(); i++)
1.606 + {
1.607 + libtable = m_SymTables[i];
1.608 + if (libtable->lib_base == dlmap->l_addr)
1.609 + {
1.610 + table2 = &libtable->table2;
1.611 + break;
1.612 + }
1.613 + }
1.614 +
1.615 + if (table2 == NULL) return NULL;
1.616 + Symbol *sym = table2->FindAddr(addr);
1.617 + return sym ? sym->buffer() : NULL;
1.618 +}