summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ia64/libuwx/src/uwx_symbols.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ia64/libuwx/src/uwx_symbols.c')
-rw-r--r--sys/contrib/ia64/libuwx/src/uwx_symbols.c850
1 files changed, 850 insertions, 0 deletions
diff --git a/sys/contrib/ia64/libuwx/src/uwx_symbols.c b/sys/contrib/ia64/libuwx/src/uwx_symbols.c
new file mode 100644
index 0000000..b91c2db
--- /dev/null
+++ b/sys/contrib/ia64/libuwx/src/uwx_symbols.c
@@ -0,0 +1,850 @@
+/*
+Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef USE_CLEAN_NAMESPACE
+#define fopen _fopen
+#define fseek _fseek
+#define fread _fread
+#define fclose _fclose
+#endif /* USE_CLEAN_NAMESPACE */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <elf.h>
+
+#include "uwx.h"
+#include "uwx_env.h"
+
+#ifdef USE_CLEAN_NAMESPACE
+/*
+ * Moved the defines above the include of stdio.h,
+ * so we don't need these unless that causes problems
+ * and we have to move them back down here.
+ * #define fopen _fopen
+ * #define fseek _fseek
+ * #define fread _fread
+ * #define fclose _fclose
+ * extern FILE *_fopen(const char *, const char *);
+ * extern int _fseek(FILE *, long int, int);
+ * extern size_t _fread(void *, size_t, size_t, FILE *);
+ * extern int _fclose(FILE *);
+ */
+#endif /* USE_CLEAN_NAMESPACE */
+
+struct uwx_symbol_cache {
+ char *module_name;
+ int nsyms;
+ uint64_t *sym_values;
+ char **sym_names;
+ char *strings;
+};
+
+
+int uwx_read_func_symbols(
+ struct uwx_env *env,
+ struct uwx_symbol_cache *cache,
+ char *module_name);
+
+
+int uwx_find_symbol(
+ struct uwx_env *env,
+ struct uwx_symbol_cache **symbol_cache_p,
+ char *module_name,
+ uint64_t relip,
+ char **func_name_p,
+ uint64_t *offset_p)
+{
+ int status;
+ int i;
+ uint64_t offset;
+ uint64_t best_offset;
+ char *best_name;
+ struct symbol *sym;
+ struct uwx_symbol_cache *cache = NULL;
+
+ /* Allocate a symbol cache on first call */
+ if (symbol_cache_p != NULL)
+ cache = *symbol_cache_p;
+ if (cache == NULL) {
+ cache = (struct uwx_symbol_cache *)
+ (*env->allocate_cb)(sizeof(struct uwx_symbol_cache));
+ if (cache == NULL)
+ return UWX_ERR_NOMEM;
+ cache->module_name = NULL;
+ cache->nsyms = 0;
+ cache->sym_values = NULL;
+ cache->sym_names = NULL;
+ cache->strings = NULL;
+ if (symbol_cache_p != NULL)
+ *symbol_cache_p = cache;
+ }
+
+ /* Read function symbols from the object file */
+ status = uwx_read_func_symbols(env, cache, module_name);
+ if (status != UWX_OK)
+ return status;
+
+ /* Search for best match */
+ best_offset = ~(uint64_t)0;
+ best_name = NULL;
+ for (i = 0; i < cache->nsyms; i++) {
+ if (cache->sym_values[i] == relip) {
+ *func_name_p = cache->sym_names[i];
+ *offset_p = 0;
+ if (symbol_cache_p == NULL)
+ uwx_release_symbol_cache(env, cache);
+ return UWX_OK;
+ }
+ if (relip > cache->sym_values[i]) {
+ offset = relip - cache->sym_values[i];
+ if (offset < best_offset) {
+ best_offset = offset;
+ best_name = cache->sym_names[i];
+ }
+ }
+ }
+ if (best_name == NULL)
+ return UWX_ERR_NOSYM;
+
+ if (symbol_cache_p == NULL)
+ uwx_release_symbol_cache(env, cache);
+
+ *func_name_p = best_name;
+ *offset_p = best_offset;
+ return UWX_OK;
+}
+
+
+void uwx_release_symbol_cache(
+ struct uwx_env *env,
+ struct uwx_symbol_cache *symbol_cache)
+{
+ if (symbol_cache->module_name != NULL)
+ (*env->free_cb)(symbol_cache->module_name);
+ if (symbol_cache->sym_values != NULL)
+ (*env->free_cb)(symbol_cache->sym_values);
+ if (symbol_cache->sym_names != NULL)
+ (*env->free_cb)(symbol_cache->sym_names);
+ if (symbol_cache->strings != NULL)
+ (*env->free_cb)(symbol_cache->strings);
+ (*env->free_cb)(symbol_cache);
+}
+
+
+#define ELF_ERR_NOMEM UWX_ERR_NOMEM /* Out of memory */
+#define ELF_ERR_OPEN UWX_ERR_NOSYM /* Can't open file */
+
+#define ELF_ERR_NOHEADER UWX_ERR_NOSYM /* Can't read ELF header */
+#define ELF_ERR_NOTELF UWX_ERR_NOSYM /* Not an ELF file */
+#define ELF_ERR_HEADER_SIZE UWX_ERR_NOSYM /* Invalid e_ehsize */
+#define ELF_ERR_INVALID_CLASS UWX_ERR_NOSYM /* Invalid EI_CLASS */
+#define ELF_ERR_INVALID_DATA UWX_ERR_NOSYM /* Invalid EI_DATA */
+
+#define ELF_ERR_READ_SECTHDR UWX_ERR_NOSYM /* Can't read section headers */
+#define ELF_ERR_SECTHDR_SIZE UWX_ERR_NOSYM /* Invalid e_shentsize */
+
+#define ELF_ERR_READ_PROGHDR UWX_ERR_NOSYM /* Can't read program headers */
+#define ELF_ERR_PROGHDR_SIZE UWX_ERR_NOSYM /* Invalid e_phentsize */
+
+#define ELF_ERR_READ_SECTION UWX_ERR_NOSYM /* Can't read section contents */
+
+#define ELF_ERR_READ_SYMTAB UWX_ERR_NOSYM /* Can't read symbol table */
+#define ELF_ERR_SYMTAB_SIZE UWX_ERR_NOSYM /* Invalid sh_entsize for symtab */
+
+
+struct elf_file {
+ uint64_t phoff;
+ uint64_t shoff;
+ uint64_t text_base;
+ uint64_t text_end;
+ alloc_cb allocate_cb;
+ free_cb free_cb;
+ const char *filename;
+ FILE *fd;
+ struct elf_section *sections;
+ struct elf_symbol *symbols;
+ char *symbol_strings;
+ int native_data;
+ int source_class;
+ int source_data;
+ int ehsize;
+ int phentsize;
+ int phnum;
+ int shentsize;
+ int shnum;
+ int nsyms;
+};
+
+struct elf_section {
+ uint64_t flags;
+ uint64_t addr;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t entsize;
+ char *contents;
+ struct elf_symbol *symbols;
+ int type;
+ int link;
+ int info;
+ int nelems;
+};
+
+struct elf_symbol {
+ uint64_t value;
+ char *namep;
+ int name;
+ int type;
+ int shndx;
+};
+
+
+static void elf_swap_bytes(char *buf, char *template)
+{
+ int i;
+ int sz;
+ char temp[16];
+
+ while (sz = *template++) {
+ if (sz > 16)
+ exit(1);
+ for (i = 0; i < sz; i++)
+ temp[i] = buf[i];
+ for (i = 0; i < sz; i++)
+ buf[i] = temp[sz-i-1];
+ buf += sz;
+ }
+}
+
+
+static int elf_read_section(struct elf_file *ef, int shndx)
+{
+ struct elf_section *sect;
+
+ if (shndx < 0 || shndx > ef->shnum)
+ return 0;
+
+ sect = &ef->sections[shndx];
+
+ /* Return if section has already been read */
+ if (sect->contents != NULL)
+ return 0;
+
+ sect->contents = (*ef->allocate_cb)(sect->size);
+ if (sect->contents == NULL)
+ return ELF_ERR_NOMEM;
+
+ fseek(ef->fd, (long)sect->offset, SEEK_SET);
+ if (fread(sect->contents, 1, sect->size, ef->fd) != sect->size)
+ return ELF_ERR_READ_SECTION;
+
+ return 0;
+}
+
+
+static char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0};
+static char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0};
+
+static int elf_read_symtab_section(struct elf_file *ef, int shndx)
+{
+ int i;
+ int nsyms;
+ long size;
+ union {
+ Elf32_Sym sym32;
+ Elf64_Sym sym64;
+ } sym;
+ struct elf_section *sect;
+ struct elf_symbol *syms;
+ struct elf_symbol *symp;
+ char *strtab;
+
+ sect = &ef->sections[shndx];
+
+ /* Return if section has already been read */
+ if (sect->symbols != NULL)
+ return 0;
+
+ if (ef->source_class == ELFCLASS32) {
+ if (sect->entsize != sizeof(sym.sym32))
+ return ELF_ERR_SYMTAB_SIZE;
+ }
+ else {
+ if (sect->entsize != sizeof(sym.sym64))
+ return ELF_ERR_SYMTAB_SIZE;
+ }
+
+ nsyms = sect->nelems;
+ syms = (struct elf_symbol *)
+ (*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms);
+ if (syms == NULL)
+ return ELF_ERR_NOMEM;
+
+ /* Read the symbol table */
+ fseek(ef->fd, (long)sect->offset, SEEK_SET);
+ for (i = 0; i < nsyms; i++) {
+
+ symp = &syms[i];
+
+ /* Read the next symbol table entry */
+ if (fread((char *)&sym, sect->entsize, 1, ef->fd) != 1) {
+ (*ef->free_cb)(syms);
+ return ELF_ERR_READ_SYMTAB;
+ }
+
+ /* Get fields from appropriate structure */
+ if (ef->source_class == ELFCLASS32) {
+ /* Swap bytes if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&sym, template_elf32_sym);
+ symp->name = sym.sym32.st_name;
+ symp->type = sym.sym32.st_info & 0x0f;
+ symp->shndx = sym.sym32.st_shndx;
+ symp->value = sym.sym32.st_value;
+ }
+ else {
+ /* Swap bytes if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&sym, template_elf64_sym);
+ symp->name = sym.sym64.st_name;
+ symp->type = sym.sym64.st_info & 0x0f;
+ symp->shndx = sym.sym64.st_shndx;
+ symp->value = sym.sym64.st_value;
+ }
+ symp->namep = NULL;
+
+ }
+
+ /* Read the symbol string table and convert section names */
+ /* from string table offsets to pointers */
+ if (sect->link > 0 && sect->link < ef->shnum) {
+ if (elf_read_section(ef, sect->link) == 0) {
+ strtab = ef->sections[sect->link].contents;
+ for (i = 0; i < nsyms; i++) {
+ symp = &syms[i];
+ symp->namep = strtab + symp->name;
+ }
+ ef->symbol_strings = strtab;
+ ef->sections[sect->link].contents = NULL;
+ }
+ }
+
+ sect->symbols = syms;
+ return 0;
+}
+
+
+static char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0};
+static char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0};
+
+static int elf_read_prog_hdrs(struct elf_file *ef)
+{
+ int i;
+ union {
+ Elf32_Phdr hdr32;
+ Elf64_Phdr hdr64;
+ } header;
+ uint64_t vaddr;
+ uint64_t memsz;
+ uint64_t unwind_base;
+ int type;
+
+ if (ef->phnum == 0)
+ return 0;
+
+ if (ef->source_class == ELFCLASS32) {
+ if (ef->phentsize != sizeof(header.hdr32))
+ return ELF_ERR_PROGHDR_SIZE;
+ }
+ else {
+ if (ef->phentsize != sizeof(header.hdr64))
+ return ELF_ERR_PROGHDR_SIZE;
+ }
+
+ /* Look for the PT_IA_64_UNWIND segment */
+ /* (That will help us identify the text segment) */
+
+ fseek(ef->fd, (long)ef->phoff, SEEK_SET);
+ for (i = 0; i < ef->phnum; i++) {
+
+ /* Read the next program header */
+ if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
+ return ELF_ERR_READ_PROGHDR;
+
+ /* Get fields from appropriate structure */
+ if (ef->source_class == ELFCLASS32) {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf32_phdr);
+ type = header.hdr32.p_type;
+ vaddr = header.hdr32.p_vaddr;
+ }
+ else {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf64_phdr);
+ type = header.hdr64.p_type;
+ vaddr = header.hdr64.p_vaddr;
+ }
+
+ if (type == PT_IA_64_UNWIND) {
+ unwind_base = vaddr;
+ break;
+ }
+
+ }
+
+ /* Now look for the PT_LOAD segment that includes the unwind segment */
+
+ fseek(ef->fd, (long)ef->phoff, SEEK_SET);
+ for (i = 0; i < ef->phnum; i++) {
+
+ /* Read the next program header */
+ if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
+ return ELF_ERR_READ_PROGHDR;
+
+ /* Get fields from appropriate structure */
+ if (ef->source_class == ELFCLASS32) {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf32_phdr);
+ type = header.hdr32.p_type;
+ vaddr = header.hdr32.p_vaddr;
+ memsz = header.hdr32.p_memsz;
+ }
+ else {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf64_phdr);
+ type = header.hdr64.p_type;
+ vaddr = header.hdr64.p_vaddr;
+ memsz = header.hdr64.p_memsz;
+ }
+
+ if (type == PT_LOAD &&
+ vaddr <= unwind_base && unwind_base < vaddr + memsz) {
+ ef->text_base = vaddr;
+ ef->text_end = vaddr + memsz;
+ break;
+ }
+
+ }
+
+ return 0;
+}
+
+
+static char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0};
+static char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0};
+
+static int elf_read_sect_hdrs(struct elf_file *ef)
+{
+ int i;
+ long size;
+ int err;
+ union {
+ Elf32_Shdr hdr32;
+ Elf64_Shdr hdr64;
+ } header;
+ struct elf_section *sect;
+ char *shstrtab;
+
+ if (ef->source_class == ELFCLASS32) {
+ if (ef->shentsize != sizeof(header.hdr32))
+ return ELF_ERR_SECTHDR_SIZE;
+ }
+ else {
+ if (ef->shentsize != sizeof(header.hdr64))
+ return ELF_ERR_SECTHDR_SIZE;
+ }
+
+ fseek(ef->fd, (long)ef->shoff, SEEK_SET);
+ ef->sections = (struct elf_section *)
+ (*ef->allocate_cb)(sizeof(struct elf_section) * ef->shnum);
+ if (ef->sections == NULL)
+ return ELF_ERR_NOMEM;
+
+ /* Read the section header table */
+ for (i = 0; i < ef->shnum; i++) {
+
+ sect = &ef->sections[i];
+
+ /* Read the next section header */
+ if (fread((char *)&header, ef->shentsize, 1, ef->fd) != 1) {
+ (*ef->free_cb)(ef->sections);
+ return ELF_ERR_READ_SECTHDR;
+ }
+
+ /* Get fields from appropriate structure */
+ if (ef->source_class == ELFCLASS32) {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf32_shdr);
+ sect->type = header.hdr32.sh_type;
+ sect->flags = header.hdr32.sh_flags;
+ sect->addr = header.hdr32.sh_addr;
+ sect->offset = header.hdr32.sh_offset;
+ sect->size = header.hdr32.sh_size;
+ sect->link = header.hdr32.sh_link;
+ sect->info = header.hdr32.sh_info;
+ sect->entsize = header.hdr32.sh_entsize;
+ }
+ else {
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header, template_elf64_shdr);
+ sect->type = header.hdr64.sh_type;
+ sect->flags = header.hdr64.sh_flags;
+ sect->addr = header.hdr64.sh_addr;
+ sect->offset = header.hdr64.sh_offset;
+ sect->size = header.hdr64.sh_size;
+ sect->link = header.hdr64.sh_link;
+ sect->info = header.hdr64.sh_info;
+ sect->entsize = header.hdr64.sh_entsize;
+ }
+ sect->contents = NULL;
+ sect->symbols = NULL;
+ if (sect->entsize > 0)
+ sect->nelems = sect->size / sect->entsize;
+
+ }
+
+ return 0;
+}
+
+
+static char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0};
+static char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0};
+
+static int elf_read_header(struct elf_file *ef)
+{
+ union {
+ char ident[EI_NIDENT];
+ Elf32_Ehdr hdr32;
+ Elf64_Ehdr hdr64;
+ } header;
+
+ /* Read the ELF header */
+ fseek(ef->fd, 0L, SEEK_SET);
+ if (fread((char *)header.ident, EI_NIDENT, 1, ef->fd) != 1) {
+ return ELF_ERR_NOHEADER;
+ }
+
+ /* Verify that this is an ELF file */
+ if (header.ident[EI_MAG0] != ELFMAG0 ||
+ header.ident[EI_MAG1] != ELFMAG1 ||
+ header.ident[EI_MAG2] != ELFMAG2 ||
+ header.ident[EI_MAG3] != ELFMAG3) {
+ return ELF_ERR_NOTELF;
+ }
+
+ /* Get header fields from the byte array e_ident */
+ /* (These are independent of EI_CLASS and EI_DATA) */
+ ef->source_class = header.ident[EI_CLASS];
+ ef->source_data = header.ident[EI_DATA];
+
+ /* Verify EI_CLASS and EI_DATA */
+ if (header.ident[EI_CLASS] != ELFCLASS32 &&
+ header.ident[EI_CLASS] != ELFCLASS64) {
+ return ELF_ERR_INVALID_CLASS;
+ }
+ if (header.ident[EI_DATA] != ELFDATA2LSB &&
+ header.ident[EI_DATA] != ELFDATA2MSB) {
+ return ELF_ERR_INVALID_DATA;
+ }
+
+ /* Get remaining header fields from appropriate structure */
+ if (ef->source_class == ELFCLASS32) {
+ if (fread((char *)&header.hdr32 + EI_NIDENT,
+ sizeof(header.hdr32) - EI_NIDENT, 1, ef->fd) != 1)
+ return ELF_ERR_NOHEADER;
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header + EI_NIDENT, template_elf32_ehdr);
+ ef->phoff = header.hdr32.e_phoff;
+ ef->shoff = header.hdr32.e_shoff;
+ ef->ehsize = header.hdr32.e_ehsize;
+ ef->phentsize = header.hdr32.e_phentsize;
+ ef->phnum = header.hdr32.e_phnum;
+ ef->shentsize = header.hdr32.e_shentsize;
+ ef->shnum = header.hdr32.e_shnum;
+ if (ef->ehsize != sizeof(header.hdr32)) {
+ return ELF_ERR_HEADER_SIZE;
+ }
+ }
+ else {
+ if (fread((char *)&header.hdr64 + EI_NIDENT,
+ sizeof(header.hdr64) - EI_NIDENT, 1, ef->fd) != 1)
+ return ELF_ERR_NOHEADER;
+ /* Swap bytes in header fields if necessary */
+ if (ef->source_data != ef->native_data)
+ elf_swap_bytes((char *)&header + EI_NIDENT, template_elf64_ehdr);
+ ef->phoff = header.hdr64.e_phoff;
+ ef->shoff = header.hdr64.e_shoff;
+ ef->ehsize = header.hdr64.e_ehsize;
+ ef->phentsize = header.hdr64.e_phentsize;
+ ef->phnum = header.hdr64.e_phnum;
+ ef->shentsize = header.hdr64.e_shentsize;
+ ef->shnum = header.hdr64.e_shnum;
+ if (ef->ehsize != sizeof(header.hdr64)) {
+ return ELF_ERR_HEADER_SIZE;
+ }
+ }
+
+ return 0;
+}
+
+
+static struct elf_file *elf_new(struct uwx_env *env)
+{
+ int native_be;
+ char *p;
+ struct elf_file *ef;
+
+ ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file));
+ if (ef == NULL)
+ return NULL;
+
+ /* Determine the native byte order */
+ p = (char *)&native_be;
+ native_be = 1; /* Assume big-endian */
+ *p = 0; /* Sets be == 0 only if little-endian */
+
+ ef->allocate_cb = env->allocate_cb;
+ ef->free_cb = env->free_cb;
+ ef->filename = NULL;
+ ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB);
+ ef->fd = NULL;
+ ef->source_class = 0;
+ ef->source_data = 0;
+ ef->phoff = 0;
+ ef->shoff = 0;
+ ef->text_base = 0;
+ ef->text_end = 0;
+ ef->ehsize = 0;
+ ef->phentsize = 0;
+ ef->phnum = 0;
+ ef->shentsize = 0;
+ ef->shnum = 0;
+ ef->sections = NULL;
+ ef->symbols = NULL;
+ ef->symbol_strings = NULL;
+ ef->nsyms = 0;
+ return ef;
+}
+
+
+static int elf_open(struct elf_file *ef, const char *filename)
+{
+ int err;
+
+ ef->filename = filename;
+
+ ef->fd = fopen(filename, "r");
+ if (ef->fd == NULL)
+ return ELF_ERR_OPEN;
+
+ if ((err = elf_read_header(ef)) != 0)
+ return err;
+
+ if ((err = elf_read_sect_hdrs(ef)) != 0)
+ return err;
+
+ if ((err = elf_read_prog_hdrs(ef)) != 0)
+ return err;
+
+ return 0;
+}
+
+
+static void elf_free_sections(struct elf_file *ef)
+{
+ int i;
+ struct elf_section *sect;
+
+ for (i = 0; i < ef->shnum; i++) {
+ sect = &ef->sections[i];
+ if (sect->contents != NULL)
+ (*ef->free_cb)(sect->contents);
+ if ((sect->type == SHT_SYMTAB || sect->type == SHT_DYNSYM)
+ && sect->symbols != NULL)
+ (*ef->free_cb)(sect->symbols);
+ }
+ (*ef->free_cb)(ef->sections);
+}
+
+
+static void elf_close(struct elf_file *ef)
+{
+ if (ef->fd != NULL) {
+ fclose(ef->fd);
+ ef->fd = NULL;
+ }
+}
+
+
+static void elf_free(struct elf_file *ef)
+{
+ elf_close(ef);
+ if (ef->sections != NULL)
+ elf_free_sections(ef);
+ (*ef->free_cb)(ef);
+}
+
+
+static int elf_read_symbols(struct elf_file *ef)
+{
+ int i;
+ int err;
+ struct elf_section *sect;
+
+ for (i = 1; i < ef->shnum; i++) {
+ sect = &ef->sections[i];
+ if (sect->type == SHT_SYMTAB) {
+ if (elf_read_symtab_section(ef, i) == 0) {
+ ef->symbols = sect->symbols;
+ ef->nsyms = sect->nelems;
+#ifdef DEBUG_SYMBOLS
+ printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms);
+#endif /* DEBUG_SYMBOLS */
+ return 0;
+ }
+ }
+ }
+ for (i = 1; i < ef->shnum; i++) {
+ sect = &ef->sections[i];
+ if (sect->type == SHT_DYNSYM) {
+ if (elf_read_symtab_section(ef, i) == 0) {
+ ef->symbols = sect->symbols;
+ ef->nsyms = sect->nelems;
+#ifdef DEBUG_SYMBOLS
+ printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms);
+#endif /* DEBUG_SYMBOLS */
+ return 0;
+ }
+ }
+ }
+ return UWX_ERR_NOSYM;
+}
+
+
+#define SYM_IS_DEFINED(sym) \
+ ((sym)->shndx != SHN_UNDEF)
+
+#define SYM_IS_IN_TEXT_SEGMENT(value) \
+ ((value) >= ef->text_base && (value) < ef->text_end)
+
+#define SYM_HAS_INTERESTING_TYPE(type) ( \
+ (type) == STT_FUNC || \
+ (type) == STT_OBJECT || \
+ (type) == STT_HP_STUB \
+ )
+
+#define SYM_IS_INTERESTING(sym) ( \
+ SYM_IS_DEFINED(sym) && \
+ SYM_IS_IN_TEXT_SEGMENT((sym)->value) && \
+ SYM_HAS_INTERESTING_TYPE((sym)->type) \
+ )
+
+int uwx_read_func_symbols(
+ struct uwx_env *env,
+ struct uwx_symbol_cache *cache,
+ char *module_name)
+{
+ int i, j;
+ int status;
+ struct elf_file *ef;
+ struct elf_symbol *sym;
+ int nfuncsyms;
+ char **names;
+ uint64_t *values;
+
+ if (module_name != NULL &&
+ cache->module_name != NULL &&
+ strcmp(module_name, cache->module_name) == 0)
+ return UWX_OK;
+
+ if (cache->sym_names != NULL)
+ (*env->free_cb)(cache->sym_names);
+ if (cache->sym_values != NULL)
+ (*env->free_cb)(cache->sym_values);
+ if (cache->strings != NULL)
+ (*env->free_cb)(cache->strings);
+
+ ef = elf_new(env);
+ if (ef == NULL)
+ return UWX_ERR_NOMEM;
+ status = elf_open(ef, module_name);
+ if (status != 0)
+ return UWX_ERR_NOSYM;
+ status = elf_read_symbols(ef);
+ if (status != 0)
+ return UWX_ERR_NOSYM;
+
+ nfuncsyms = 0;
+ for (i = 0; i < ef->nsyms; i++) {
+ sym = &ef->symbols[i];
+ if (SYM_IS_INTERESTING(sym))
+ nfuncsyms++;
+ }
+
+ names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *));
+ if (names == NULL)
+ return UWX_ERR_NOMEM;
+ values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t));
+ if (values == NULL)
+ return UWX_ERR_NOMEM;
+
+ j = 0;
+ for (i = 0; i < ef->nsyms; i++) {
+ sym = &ef->symbols[i];
+ if (SYM_IS_INTERESTING(sym)) {
+ if (j >= nfuncsyms) /* should not happen! */
+ break;
+ names[j] = sym->namep;
+ values[j] = sym->value - ef->text_base;
+ j++;
+ }
+ }
+
+ cache->module_name = (char *)(*env->allocate_cb)(strlen(module_name)+1);
+ if (cache->module_name != NULL) {
+ strcpy(cache->module_name, module_name);
+ cache->nsyms = nfuncsyms;
+ cache->sym_names = names;
+ cache->sym_values = values;
+ cache->strings = ef->symbol_strings;
+ ef->symbol_strings = NULL;
+ }
+
+ elf_close(ef);
+ elf_free(ef);
+
+#ifdef DEBUG_SYMBOLS
+ printf("Cached %d interesting symbols\n", nfuncsyms);
+#endif /* DEBUG_SYMBOLS */
+
+ return UWX_OK;
+}
OpenPOWER on IntegriCloud