size_t HIDDEN FindSymbol(Module *module, const char* symbolName, int index) { int i; link_map *dlmap; struct stat dlstat; int dlfile; uintptr_t map_base; Elf32_Ehdr *file_hdr; Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr; Elf32_Sym *symtab; const char *shstrtab, *strtab; uint16_t section_count; uint32_t symbol_count; size_t address; // If index > 0 then we shouldn't use dlsym, cos it will give wrong result if (index == 0) { address = (size_t)dlsym((void *)module->handle, symbolName); if (address != NULL) return address; } dlmap = (struct link_map *)module->handle; symtab_hdr = NULL; strtab_hdr = NULL; dlfile = open(dlmap->l_name, O_RDONLY); if (dlfile == -1 || fstat(dlfile, &dlstat) == -1) { close(dlfile); return NULL; } // Map library file into memory file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0); map_base = (uintptr_t)file_hdr; close(dlfile); if (file_hdr == MAP_FAILED) { return NULL; } if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF) { munmap(file_hdr, dlstat.st_size); return NULL; } sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff); section_count = file_hdr->e_shnum; // Get ELF section header string table shstrtab_hdr = §ions[file_hdr->e_shstrndx]; shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset); // Iterate sections while looking for ELF symbol table and string table for (uint16_t i = 0; i < section_count; i++) { Elf32_Shdr &hdr = sections[i]; const char *section_name = shstrtab + hdr.sh_name; //printf("Seg[%d].name = '%s'\n", i, section_name); if (strcmp(section_name, ".symtab") == 0) { symtab_hdr = &hdr; } else if (strcmp(section_name, ".strtab") == 0) { strtab_hdr = &hdr; } } if (symtab_hdr == NULL || strtab_hdr == NULL) { munmap(file_hdr, dlstat.st_size); return NULL; } symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset); strtab = (const char *)(map_base + strtab_hdr->sh_offset); symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; int mangleNameLength; int mangleNameLastLength = 1024; // Is it enouph? // If index is 0 then we need to take first entry if (index == 0) index++; // Iterate symbol table int match = 1; for (uint32_t i = 0; i < symbol_count; i++) { Elf32_Sym &sym = symtab[i]; unsigned char sym_type = ELF32_ST_TYPE(sym.st_info); const char *sym_name = strtab + sym.st_name; // Skip symbols that are undefined or do not refer to functions or objects if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT)) { continue; } if (strcmp(sym_name, symbolName) == 0) { if (match == index) { address = (size_t)(dlmap->l_addr + sym.st_value); break; } else { match++; } } // Try to find lowest length mangled name then if (sym_name[0] == '_' && sym_name[1] == 'Z' && strstr(sym_name + 2, symbolName) != NULL && (mangleNameLength = strlen(sym_name)) < mangleNameLastLength) { mangleNameLastLength = mangleNameLength; address = (size_t)(dlmap->l_addr + sym.st_value); #ifdef _DEBUG printf("FindSymbol (mangled name): symbol: \"%s\", address: %lx\n", sym_name, address); #endif } } munmap(file_hdr, dlstat.st_size); #ifdef _DEBUG printf("FindSymbol (elf): symbol: \"%s\", address: %lx\n", symbolName, address); #endif return address; }
orl_return ElfCreateSymbolHandles( elf_sec_handle elf_sec_hnd ) { int loop; int num_syms; elf_symbol_handle current; unsigned char *current_sym; Elf32_Sym *current_sym32; Elf64_Sym *current_sym64; int st_name; num_syms = elf_sec_hnd->size / elf_sec_hnd->entsize; elf_sec_hnd->assoc.sym.symbols = (elf_symbol_handle)_ClientSecAlloc( elf_sec_hnd, sizeof( elf_symbol_handle_struct ) * num_syms ); if( elf_sec_hnd->assoc.sym.symbols == NULL ) return( ORL_OUT_OF_MEMORY ); current = elf_sec_hnd->assoc.sym.symbols; current_sym = elf_sec_hnd->contents; for( loop = 0; loop < num_syms; loop++ ) { if( elf_sec_hnd->elf_file_hnd->flags & ORL_FILE_FLAG_64BIT_MACHINE ) { current_sym64 = (Elf64_Sym *)current_sym; fix_sym64_byte_order( elf_sec_hnd->elf_file_hnd, current_sym64 ); st_name = current_sym64->st_name; current->value.u._32[I64LO32] = current_sym64->st_value.u._32[I64LO32]; current->value.u._32[I64HI32] = current_sym64->st_value.u._32[I64HI32]; current->info = current_sym64->st_info; current->shndx = current_sym64->st_shndx; } else { current_sym32 = (Elf32_Sym *)current_sym; fix_sym_byte_order( elf_sec_hnd->elf_file_hnd, current_sym32 ); st_name = current_sym32->st_name; current->value.u._32[I64LO32] = current_sym32->st_value; current->value.u._32[I64HI32] = 0; current->info = current_sym32->st_info; current->shndx = current_sym32->st_shndx; } if( st_name == 0 ) { current->name = NULL; } else { current->name = (char *)( elf_sec_hnd->assoc.sym.string_table->contents + st_name ); } current->file_format = ORL_ELF; current->elf_file_hnd = elf_sec_hnd->elf_file_hnd; switch( ELF32_ST_BIND( current->info ) ) { case STB_LOCAL: current->binding = ORL_SYM_BINDING_LOCAL; break; case STB_GLOBAL: current->binding = ORL_SYM_BINDING_GLOBAL; break; case STB_WEAK: current->binding = ORL_SYM_BINDING_WEAK; break; default: current->binding = ORL_SYM_BINDING_NONE; // other? break; } switch( ELF32_ST_TYPE( current->info ) ) { case STT_OBJECT: current->type = ORL_SYM_TYPE_OBJECT; break; case STT_FUNC: current->type = ORL_SYM_TYPE_FUNCTION; break; case STT_SECTION: current->type = ORL_SYM_TYPE_SECTION; break; case STT_FILE: current->type = ORL_SYM_TYPE_FILE; break; default: current->type = ORL_SYM_TYPE_NOTYPE; break; } switch( current->shndx ) { case SHN_ABS: current->type |= ORL_SYM_TYPE_ABSOLUTE; break; case SHN_COMMON: current->type |= ORL_SYM_TYPE_COMMON; break; case SHN_UNDEF: current->type |= ORL_SYM_TYPE_UNDEFINED; break; } current++; current_sym += elf_sec_hnd->entsize; } return( ORL_OKAY ); }
Sym_table * elf_symbols(Environ *e, uByte *load, uInt loadlen) { Elf32_Ehdr *hdr = (Elf32_Ehdr*)load; Elf32_Shdr *shdr; Elf32_Shdr *symtab = NULL; Elf32_Shdr *strhdr = NULL; char *strtab; int i = 0; int num, nsyms; char *strs; Elf32_Sym *syms, *s; Sym_table *tab; if (!elf_is_exec(e, load, loadlen)) /* sanity check */ return NULL; shdr = (Elf32_Shdr*)(load + hdr->e_shoff); strtab = (char*)load + shdr[hdr->e_shstrndx].sh_offset; for (i = 0; i < hdr->e_shnum; i++) { if (strcmp(strtab + shdr[i].sh_name, ELF_SYMTAB) == 0) symtab = shdr + i; else if (strcmp(strtab + shdr[i].sh_name, ELF_STRTAB) == 0) strhdr = shdr + i; } if (symtab == NULL || strhdr == NULL) return NULL; if (symtab->sh_entsize != sizeof *syms) return NULL; strs = (char*)load + strhdr->sh_offset; s = syms = (Elf32_Sym*)(load + symtab->sh_offset); nsyms = symtab->sh_size / sizeof *syms; num = 0; /* first count the number of symbols we are interested in */ for (i = 0; i < nsyms; i++, s++) { if ((ELF32_ST_BIND(s->st_info) == STB_GLOBAL || ELF32_ST_BIND(s->st_info) == STB_LOCAL) && (ELF32_ST_TYPE(s->st_info) == STT_OBJECT || ELF32_ST_TYPE(s->st_info) == STT_FUNC)) num++; } /* allocate space for the symbols */ tab = (Sym_table*)malloc(sizeof *tab); if (tab == NULL) return NULL; memset(tab, 0, sizeof *tab); tab->list = (Sym_ent*)malloc(sizeof *tab->list * num); if (tab->list == NULL) { free(tab); return NULL; } tab->num = num; num = 0; s = syms = (Elf32_Sym*)(load + symtab->sh_offset); /* and load the table */ for (i = 0; i < nsyms; i++, s++) { if ((ELF32_ST_BIND(s->st_info) == STB_GLOBAL || ELF32_ST_BIND(s->st_info) == STB_LOCAL) && (ELF32_ST_TYPE(s->st_info) == STT_OBJECT || ELF32_ST_TYPE(s->st_info) == STT_FUNC)) { tab->list[num].name = cstrdup(strs + s->st_name); tab->list[num].addr = s->st_value; tab->list[num].type = ELF32_ST_TYPE(s->st_info) == STT_FUNC ? SYM_TEXT : SYM_DATA; DPRINTF(("tab %d: name=%P addr=%#x type=%#x\n", num, tab->list[num].name, tab->list[num].addr, tab->list[num].type)); num++; } } return tab; }
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol) { #if defined(WIN32) return GetProcAddress((HMODULE)handle, symbol); #elif defined(__linux__) void *address = dlsym(handle, symbol); if (address != NULL) { return address; } struct link_map *dlmap; struct stat dlstat; int dlfile; uintptr_t map_base; Elf32_Ehdr *file_hdr; Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr; Elf32_Sym *symtab; const char *shstrtab, *strtab; uint16_t section_count; uint32_t symbol_count; LibSymbolTable *libtable; SymbolTable *table; Symbol *symbol_entry; dlmap = (struct link_map *)handle; symtab_hdr = NULL; strtab_hdr = NULL; table = NULL; /* See if we already have a symbol table for this library */ for (size_t i = 0; i < m_SymTables.length(); i++) { libtable = m_SymTables[i]; if (libtable->lib_base == dlmap->l_addr) { 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 = dlmap->l_addr; libtable->last_pos = 0; table = &libtable->table; m_SymTables.append(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 open the actual library */ dlfile = open(dlmap->l_name, O_RDONLY); if (dlfile == -1 || fstat(dlfile, &dlstat) == -1) { close(dlfile); return NULL; } /* Map library file into memory */ file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0); map_base = (uintptr_t)file_hdr; if (file_hdr == MAP_FAILED) { close(dlfile); return NULL; } close(dlfile); if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF) { munmap(file_hdr, dlstat.st_size); return NULL; } sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff); section_count = file_hdr->e_shnum; /* Get ELF section header string table */ shstrtab_hdr = §ions[file_hdr->e_shstrndx]; shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset); /* Iterate sections while looking for ELF symbol table and string table */ for (uint16_t i = 0; i < section_count; i++) { Elf32_Shdr &hdr = sections[i]; const char *section_name = shstrtab + hdr.sh_name; if (strcmp(section_name, ".symtab") == 0) { symtab_hdr = &hdr; } else if (strcmp(section_name, ".strtab") == 0) { strtab_hdr = &hdr; } } /* Uh oh, we don't have a symbol table or a string table */ if (symtab_hdr == NULL || strtab_hdr == NULL) { munmap(file_hdr, dlstat.st_size); return NULL; } symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset); strtab = (const char *)(map_base + strtab_hdr->sh_offset); symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; /* Iterate symbol table starting from the position we were at last time */ for (uint32_t i = libtable->last_pos; i < symbol_count; i++) { Elf32_Sym &sym = symtab[i]; unsigned char sym_type = ELF32_ST_TYPE(sym.st_info); const char *sym_name = strtab + sym.st_name; Symbol *cur_sym; /* Skip symbols that are undefined or do not refer to functions or objects */ if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT)) { continue; } /* Caching symbols as we go along */ cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value)); if (strcmp(symbol, sym_name) == 0) { symbol_entry = cur_sym; libtable->last_pos = ++i; break; } } munmap(file_hdr, dlstat.st_size); return symbol_entry ? symbol_entry->address : NULL; #elif defined(__APPLE__) uintptr_t dlbase, linkedit_addr; uint32_t image_count; struct mach_header *file_hdr; struct load_command *loadcmds; struct segment_command *linkedit_hdr; 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; linkedit_hdr = NULL; symtab_hdr = NULL; table = 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.length(); 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.append(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 ones for the symbol table */ for (uint32_t i = 0; i < loadcmd_count; i++) { if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr) { struct segment_command *seg = (struct segment_command *)loadcmds; if (strcmp(seg->segname, "__LINKEDIT") == 0) { linkedit_hdr = seg; if (symtab_hdr) { break; } } } else if (loadcmds->cmd == LC_SYMTAB) { symtab_hdr = (struct symtab_command *)loadcmds; if (linkedit_hdr) { 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 (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff) { /* Uh oh, no symbol table */ return NULL; } linkedit_addr = dlbase + linkedit_hdr->vmaddr; symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff); strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff); 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 }
GElf_Sym * gelf_getsym(Elf_Data *ed, int ndx, GElf_Sym *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Sym *sym32; Elf64_Sym *sym64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_SYM) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_SYM, ec, e->e_version); assert(msz > 0); if (msz * ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { sym32 = (Elf32_Sym *) d->d_data.d_buf + ndx; dst->st_name = sym32->st_name; dst->st_value = (Elf64_Addr) sym32->st_value; dst->st_size = (Elf64_Xword) sym32->st_size; dst->st_info = ELF64_ST_INFO(ELF32_ST_BIND(sym32->st_info), ELF32_ST_TYPE(sym32->st_info)); dst->st_other = sym32->st_other; dst->st_shndx = sym32->st_shndx; } else { sym64 = (Elf64_Sym *) d->d_data.d_buf + ndx; *dst = *sym64; } return (dst); }