171 lines
3.9 KiB
C
Executable File
171 lines
3.9 KiB
C
Executable File
/*
|
|
nlist.c - implementation of the nlist(3) function.
|
|
Copyright (C) 1995 Michael Riepe <riepe@ifwsn4.ifw.uni-hannover.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <private.h>
|
|
#include <nlist.h>
|
|
#include <fcntl.h>
|
|
|
|
struct hash {
|
|
const char* name;
|
|
unsigned long hash;
|
|
Elf32_Sym* sym;
|
|
};
|
|
|
|
static int
|
|
_elf_nlist(Elf *elf, struct nlist *nl) {
|
|
Elf_Scn *symtab = NULL;
|
|
Elf_Scn *strtab = NULL;
|
|
Elf_Data *symdata;
|
|
Elf_Data *strdata;
|
|
Elf32_Ehdr *ehdr;
|
|
Elf32_Shdr *shdr;
|
|
Elf_Scn *scn;
|
|
Elf32_Sym *symbols;
|
|
const char *strings;
|
|
unsigned nsymbols;
|
|
unsigned nstrings;
|
|
unsigned i;
|
|
const char *name;
|
|
struct hash *table;
|
|
unsigned nhash;
|
|
unsigned long hash;
|
|
unsigned long j;
|
|
|
|
if (!(ehdr = elf32_getehdr(elf))) {
|
|
return -1;
|
|
}
|
|
scn = NULL;
|
|
while ((scn = elf_nextscn(elf, scn))) {
|
|
if (!(shdr = elf32_getshdr(scn))) {
|
|
return -1;
|
|
}
|
|
if (shdr->sh_type == SHT_SYMTAB) {
|
|
strtab = elf_getscn(elf, shdr->sh_link);
|
|
symtab = scn;
|
|
break;
|
|
}
|
|
if (shdr->sh_type == SHT_DYNSYM) {
|
|
strtab = elf_getscn(elf, shdr->sh_link);
|
|
symtab = scn;
|
|
}
|
|
}
|
|
if (elf_errno()) {
|
|
return -1;
|
|
}
|
|
symdata = elf_getdata(symtab, NULL);
|
|
strdata = elf_getdata(strtab, NULL);
|
|
if (!symdata || !strdata) {
|
|
return -1;
|
|
}
|
|
symbols = (Elf32_Sym*)symdata->d_buf;
|
|
strings = (const char*)strdata->d_buf;
|
|
nsymbols = symdata->d_size / sizeof(Elf32_Sym);
|
|
nstrings = strdata->d_size;
|
|
if (!symbols || !strings || !nsymbols || !nstrings) {
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* build a simple hash table
|
|
*/
|
|
nhash = 3 * nsymbols - 4;
|
|
if (!(table = (struct hash*)malloc(nhash * sizeof(*table)))) {
|
|
return -1;
|
|
}
|
|
for (i = 0; i < nhash; i++) {
|
|
table[i].name = NULL;
|
|
}
|
|
for (i = 1; i < nsymbols; i++) {
|
|
if (symbols[i].st_name < 0 && symbols[i].st_name >= nstrings) {
|
|
free(table);
|
|
return -1;
|
|
}
|
|
if (symbols[i].st_name == 0) {
|
|
continue;
|
|
}
|
|
name = strings + symbols[i].st_name;
|
|
hash = elf_hash(name);
|
|
for (j = hash; table[j %= nhash].name; j += 3) {
|
|
if (table[j].hash != hash) {
|
|
continue;
|
|
}
|
|
if (table[j].name == name || !strcmp(table[j].name, name)) {
|
|
break;
|
|
}
|
|
}
|
|
table[j].hash = hash;
|
|
table[j].name = name;
|
|
table[j].sym = &symbols[i];
|
|
}
|
|
|
|
/*
|
|
* symbol lookup
|
|
*/
|
|
for (i = 0; (name = nl[i].n_name) && *name; i++) {
|
|
hash = elf_hash(name);
|
|
for (j = hash; table[j %= nhash].name; j += 3) {
|
|
if (table[j].hash == hash && !strcmp(table[j].name, name)) {
|
|
break;
|
|
}
|
|
}
|
|
if (table[j].name) {
|
|
nl[i].n_value = table[j].sym->st_value;
|
|
nl[i].n_scnum = table[j].sym->st_shndx;
|
|
}
|
|
else {
|
|
nl[i].n_value = 0;
|
|
nl[i].n_scnum = 0;
|
|
}
|
|
/*
|
|
* this needs more work
|
|
*/
|
|
nl[i].n_type = 0;
|
|
nl[i].n_sclass = 0;
|
|
nl[i].n_numaux = 0;
|
|
}
|
|
free(table);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nlist(const char *filename, struct nlist *nl) {
|
|
int result = -1;
|
|
unsigned oldver;
|
|
Elf *elf;
|
|
int fd;
|
|
|
|
if ((oldver = elf_version(EV_CURRENT)) != EV_NONE) {
|
|
if ((fd = open(filename, O_RDONLY)) != -1) {
|
|
if ((elf = elf_begin(fd, ELF_C_READ, NULL))) {
|
|
result = _elf_nlist(elf, nl);
|
|
elf_end(elf);
|
|
}
|
|
close(fd);
|
|
}
|
|
elf_version(oldver);
|
|
}
|
|
if (result) {
|
|
while (nl->n_name && *nl->n_name) {
|
|
nl->n_value = 0;
|
|
nl++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|