HelenOS sources
This source file includes following definitions.
- symtab_load
- symtab_delete
- symtab_name_to_addr
- symtab_addr_to_name
- elf_hdr_check
- section_hdr_load
- chunk_load
#include <elf/elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <str.h>
#include <str_error.h>
#include <vfs/vfs.h>
#include "include/symtab.h"
static errno_t elf_hdr_check(elf_header_t *hdr);
static errno_t section_hdr_load(int fd, const elf_header_t *ehdr, int idx,
elf_section_header_t *shdr);
static errno_t chunk_load(int fd, off64_t start, size_t size, void **ptr);
errno_t symtab_load(const char *file_name, symtab_t **symtab)
{
symtab_t *stab;
elf_header_t elf_hdr;
elf_section_header_t sec_hdr;
off64_t shstrt_start;
size_t shstrt_size;
char *shstrt, *sec_name;
void *data;
aoff64_t pos = 0;
int fd;
errno_t rc;
size_t nread;
int i;
bool load_sec, sec_is_symtab;
*symtab = NULL;
stab = calloc(1, sizeof(symtab_t));
if (stab == NULL)
return ENOMEM;
rc = vfs_lookup_open(file_name, WALK_REGULAR, MODE_READ, &fd);
if (rc != EOK) {
printf("failed opening file '%s': %s\n", file_name, str_error(rc));
free(stab);
return ENOENT;
}
rc = vfs_read(fd, &pos, &elf_hdr, sizeof(elf_header_t), &nread);
if (rc != EOK || nread != sizeof(elf_header_t)) {
printf("failed reading elf header\n");
free(stab);
return EIO;
}
rc = elf_hdr_check(&elf_hdr);
if (rc != EOK) {
printf("failed header check\n");
free(stab);
return ENOTSUP;
}
rc = section_hdr_load(fd, &elf_hdr, elf_hdr.e_shstrndx, &sec_hdr);
if (rc != EOK) {
printf("failed reading shstrt header\n");
free(stab);
return ENOTSUP;
}
shstrt_start = sec_hdr.sh_offset;
shstrt_size = sec_hdr.sh_size;
rc = chunk_load(fd, shstrt_start, shstrt_size, (void **) &shstrt);
if (rc != EOK) {
printf("failed loading shstrt\n");
free(stab);
return ENOTSUP;
}
for (i = 0; i < elf_hdr.e_shnum; ++i) {
rc = section_hdr_load(fd, &elf_hdr, i, &sec_hdr);
if (rc != EOK) {
free(shstrt);
free(stab);
return ENOTSUP;
}
sec_name = shstrt + sec_hdr.sh_name;
if (str_cmp(sec_name, ".symtab") == 0 &&
sec_hdr.sh_type == SHT_SYMTAB) {
load_sec = true;
sec_is_symtab = true;
} else if (str_cmp(sec_name, ".strtab") == 0 &&
sec_hdr.sh_type == SHT_STRTAB) {
load_sec = true;
sec_is_symtab = false;
} else {
load_sec = false;
}
if (load_sec) {
rc = chunk_load(fd, sec_hdr.sh_offset, sec_hdr.sh_size,
&data);
if (rc != EOK) {
free(shstrt);
free(stab);
return ENOTSUP;
}
if (sec_is_symtab) {
stab->sym = data;
stab->sym_size = sec_hdr.sh_size;
} else {
stab->strtab = data;
stab->strtab_size = sec_hdr.sh_size;
}
}
}
free(shstrt);
vfs_put(fd);
if (stab->sym == NULL || stab->strtab == NULL) {
printf("Symbol table or string table section not found\n");
free(stab);
return ENOTSUP;
}
*symtab = stab;
return EOK;
}
void symtab_delete(symtab_t *st)
{
free(st->sym);
st->sym = NULL;
free(st->strtab);
st->strtab = NULL;
free(st);
}
errno_t symtab_name_to_addr(symtab_t *st, const char *name, uintptr_t *addr)
{
size_t i;
char *sname;
unsigned stype;
for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
if (st->sym[i].st_name == 0)
continue;
stype = elf_st_type(st->sym[i].st_info);
if (stype != STT_OBJECT && stype != STT_FUNC)
continue;
sname = st->strtab + st->sym[i].st_name;
if (str_cmp(sname, name) == 0) {
*addr = st->sym[i].st_value;
return EOK;
}
}
return ENOENT;
}
errno_t symtab_addr_to_name(symtab_t *st, uintptr_t addr, char **name,
size_t *offs)
{
size_t i;
uintptr_t saddr, best_addr;
char *sname, *best_name;
unsigned stype;
best_name = NULL;
best_addr = 0;
for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
if (st->sym[i].st_name == 0)
continue;
stype = elf_st_type(st->sym[i].st_info);
if (stype != STT_OBJECT && stype != STT_FUNC &&
stype != STT_NOTYPE) {
continue;
}
saddr = st->sym[i].st_value;
sname = st->strtab + st->sym[i].st_name;
if (sname[0] == '$')
continue;
if (saddr <= addr && (best_name == NULL || saddr > best_addr)) {
best_name = sname;
best_addr = saddr;
}
}
if (best_name == NULL)
return ENOENT;
*name = best_name;
*offs = addr - best_addr;
return EOK;
}
static errno_t elf_hdr_check(elf_header_t *ehdr)
{
return EOK;
}
static errno_t section_hdr_load(int fd, const elf_header_t *elf_hdr, int idx,
elf_section_header_t *sec_hdr)
{
errno_t rc;
size_t nread;
aoff64_t pos = elf_hdr->e_shoff + idx * sizeof(elf_section_header_t);
rc = vfs_read(fd, &pos, sec_hdr, sizeof(elf_section_header_t), &nread);
if (rc != EOK || nread != sizeof(elf_section_header_t))
return EIO;
return EOK;
}
static errno_t chunk_load(int fd, off64_t start, size_t size, void **ptr)
{
errno_t rc;
size_t nread;
aoff64_t pos = start;
*ptr = malloc(size);
if (*ptr == NULL) {
printf("failed allocating memory\n");
return ENOMEM;
}
rc = vfs_read(fd, &pos, *ptr, size, &nread);
if (rc != EOK || nread != size) {
printf("failed reading chunk\n");
free(*ptr);
*ptr = NULL;
return EIO;
}
return EOK;
}
HelenOS homepage, sources at GitHub