sym.c 2 KB
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <libelf/libelf.h>

#include "ultra64.h"

#include "libsym.h"

int
sym_scan(const char* file, scanf_t scf, void* ctx) {
    int fd;
    Elf* elf;
    Elf32_Ehdr* ehdr;
    Elf_Scn* scn;
    Elf32_Shdr* shdr;
    Elf_Data *data, *str_data, *sym_data;
    Elf32_Sym* sym, *symtab;
    char* sname, *strtab;
    int i, j, strtlen, strdex = -1, symdex = -1;

#define ELF_STRTAB	".strtab"
#define ELF_SYMTAB	".symtab"

    if (elf_version(EV_CURRENT) == EV_NONE) {
	fprintf(stderr, "elf library out of date\n");
	return 1;
    }

    if ((fd = open(file, O_RDONLY)) < 0) {
	perror(file);
	return 1;
    }
    elf = elf_begin(fd, ELF_C_READ, (Elf*)NULL);
    if ((elf_kind(elf) != ELF_K_ELF) ||
	((ehdr = elf32_getehdr(elf)) == NULL)) {
	fprintf(stderr, "%s: not a valid ELF object file\n", file);
        close(fd);
	return 1;
    }

    /* read sections */
    for(i = 1; i < ehdr->e_shnum; i++) {
	if (((scn = elf_getscn(elf, i)) == NULL) ||
	    ((shdr = elf32_getshdr(scn)) == NULL)) {
	    fprintf(stderr, "%s: can't get section number %d\n", file, i);
	    return 1;
	}
	sname = elf_strptr(elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
	/* handle symbol table and string table specially */
	data = elf_getdata(scn, NULL);
	if (strcmp(sname, ELF_STRTAB) == 0) {
	    /* string table */
	    strtab = data->d_buf; strtlen = data->d_size;
	    /* copy to out for now */
	    str_data = data;
	    strdex = i;
	} else if(strcmp(sname, ELF_SYMTAB) == 0) {
	    /* symbol table */
	    sym_data = data;
	    symtab = sym = (Elf32_Sym*)data->d_buf;
	    symdex = i;
	}
    }
    /* check for symbol table and string table */
    if (strdex == -1 || symdex == -1) {
	fprintf(stderr, "%s: can't find symbol table or string table\n", file);
	return 1;
    }

    for(j = 0; j < sym_data->d_size/sizeof *sym; j++) {
	if ((*scf)(sym, strtab+sym->st_name, ctx)) break;
	sym++;
    }
    elf_end(elf);
    close(fd);
    return 0;
}