Skip to main content
summaryrefslogtreecommitdiffstats
path: root/elf.c
diff options
context:
space:
mode:
authormoberhuber2008-01-10 19:58:38 +0000
committermoberhuber2008-01-10 19:58:38 +0000
commit3a6bbc7188e18b9439a8b25e4b59b2450294c4a1 (patch)
tree10a1daeb17915a6b78688159803cca098043262a /elf.c
downloadorg.eclipse.tcf.agent-3a6bbc7188e18b9439a8b25e4b59b2450294c4a1.tar.gz
org.eclipse.tcf.agent-3a6bbc7188e18b9439a8b25e4b59b2450294c4a1.tar.xz
org.eclipse.tcf.agent-3a6bbc7188e18b9439a8b25e4b59b2450294c4a1.zip
tcf-0.1.0 initial contributioninitial
Diffstat (limited to 'elf.c')
-rw-r--r--elf.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/elf.c b/elf.c
new file mode 100644
index 00000000..8476ca84
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements reading and caching of ELF files.
+ */
+#include "config.h"
+#if SERVICE_LineNumbers || SERVICE_Symbols
+
+#include <assert.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "elf.h"
+#include "myalloc.h"
+
+#if defined(_WRS_KERNEL)
+#elif defined(WIN32)
+#else
+# include <libelf.h>
+# define USE_LIBELF
+#endif
+
+#define MAX_CACHED_FILES 8
+
+static ELF_File * files = NULL;
+static ELFCloseListener * listeners = NULL;
+static U4_T listeners_cnt = 0;
+static U4_T listeners_max = 0;
+
+static void elf_dispose(ELF_File * file) {
+ U4_T n;
+ assert(file->ref_cnt == 0);
+ for (n = 0; n < listeners_cnt; n++) {
+ listeners[n](file);
+ }
+#ifdef USE_LIBELF
+ if (file->libelf_cache != NULL) elf_end(file->libelf_cache);
+#endif
+ if (file->fd >= 0) close(file->fd);
+ if (file->sections != NULL) {
+ for (n = 0; n < file->section_cnt; n++) {
+ loc_free(file->sections[n]);
+ }
+ loc_free(file->sections);
+ }
+ free(file->name);
+ loc_free(file);
+}
+
+ELF_File * elf_open(char * file_name) {
+ int cnt = 0;
+ int error = 0;
+ struct_stat st;
+ ELF_File * prev = NULL;
+ ELF_File * file = files;
+
+ file_name = canonicalize_file_name(file_name);
+ if (file_name == NULL) return NULL;
+ if (stat(file_name, &st) < 0) {
+ error = errno;
+ free(file_name);
+ errno = error;
+ return NULL;
+ }
+ while (file != NULL) {
+ if (strcmp(file->name, file_name) == 0 &&
+ file->dev == st.st_dev &&
+ file->ino == st.st_ino &&
+ file->mtime == st.st_mtime) {
+ if (prev != NULL) {
+ prev->next = file->next;
+ file->next = files;
+ files = file;
+ }
+ file->ref_cnt++;
+ free(file_name);
+ return file;
+ }
+ if (cnt >= MAX_CACHED_FILES && file->ref_cnt == 0) {
+ prev->next = file->next;
+ elf_dispose(file);
+ file = prev->next;
+ }
+ else {
+ prev = file;
+ file = file->next;
+ cnt++;
+ }
+ }
+
+ file = (ELF_File *)loc_alloc_zero(sizeof(ELF_File));
+ file->name = file_name;
+ file->dev = st.st_dev;
+ file->ino = st.st_ino;
+ file->mtime = st.st_mtime;
+#ifdef _WRS_KERNEL
+ if ((file->fd = open(file->name, O_RDONLY, 0)) < 0) {
+#else
+ if ((file->fd = open(file->name, O_RDONLY)) < 0) {
+#endif
+ error = errno;
+ }
+
+#ifdef USE_LIBELF
+ if (error == 0) {
+ Elf * elf;
+ Elf32_Ehdr * ehdr;
+ /* Obtain the ELF descriptor */
+ (void)elf_version(EV_CURRENT);
+ if ((elf = elf_begin(file->fd, ELF_C_READ, NULL)) == NULL) {
+ error = errno;
+ }
+ else {
+ file->libelf_cache = elf;
+ if ((ehdr = elf32_getehdr(elf)) == NULL) {
+ error = errno;
+ }
+ }
+ if (error == 0) {
+ size_t snum = 0;
+ size_t shstrndx = 0;
+ if (elf_getshnum(elf, &snum) < 0) error = errno;
+ if (error == 0) {
+ file->sections = (ELF_Section **)loc_alloc_zero(sizeof(ELF_Section *) * snum);
+ file->section_cnt = snum;
+ if (elf_getshstrndx(elf, &shstrndx) < 0) error = errno;
+ }
+ if (error == 0) {
+ /* Iterate sections */
+ Elf_Scn * scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ Elf32_Shdr * shdr = NULL;
+ char * name = NULL;
+ ELF_Section * sec = NULL;
+ if ((shdr = elf32_getshdr(scn)) == NULL) {
+ error = errno;
+ break;
+ }
+ if ((name = elf_strptr(elf, shstrndx, shdr->sh_name)) == NULL) {
+ error = errno;
+ break;
+ }
+ sec = (ELF_Section *)loc_alloc(sizeof(ELF_Section));
+ sec->file = file;
+ sec->index = elf_ndxscn(scn);
+ sec->name = name;
+ sec->type = shdr->sh_type;
+ sec->offset = shdr->sh_offset;
+ sec->size = shdr->sh_size;
+ sec->flags = shdr->sh_flags;
+ sec->addr = shdr->sh_addr;
+ sec->link = shdr->sh_link;
+ sec->info = shdr->sh_info;
+ assert(sec->index < snum);
+ file->sections[sec->index] = sec;
+ }
+ }
+ }
+ }
+#else
+ if (error == 0) {
+ error = EINVAL;
+ }
+#endif
+ if (error != 0) {
+ elf_dispose(file);
+ errno = error;
+ return NULL;
+ }
+ file->ref_cnt = 1;
+ file->next = files;
+ return files = file;
+}
+
+int elf_load(ELF_Section * section, U1_T ** address) {
+#ifdef USE_LIBELF
+ Elf * elf = (Elf *)section->file->libelf_cache;
+ Elf_Scn * scn = elf_getscn(elf, section->index);
+ Elf_Data * data = elf_getdata(scn, NULL);
+ if (data == NULL) return -1;
+ assert(data->d_buf != NULL && data->d_size == section->size);
+ *address = data->d_buf;
+ return 0;
+#else
+ *address = NULL;
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+int elf_read(ELF_Section * section, U8_T offset, U1_T * buf, U4_T size, U4_T * rd_len) {
+#ifdef USE_LIBELF
+ U4_T rd = size;
+ Elf * elf = (Elf *)section->file->libelf_cache;
+ Elf_Scn * scn = elf_getscn(elf, section->index);
+ Elf_Data * data = elf_getdata(scn, NULL);
+ if (data == NULL) return -1;
+ assert(data->d_buf != NULL && data->d_size == section->size);
+ assert(offset < section->size);
+ if (offset + rd > section->size) rd = (U4_T)(section->size - offset);
+ memcpy(buf, data->d_buf + offset, rd);
+ *rd_len = rd;
+ return 0;
+#else
+ *rd_len = 0;
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+void elf_close(ELF_File * file) {
+ assert(file != NULL);
+ assert(file->ref_cnt > 0);
+ file->ref_cnt--;
+}
+
+void elf_add_close_listener(ELFCloseListener listener) {
+ if (listeners_cnt >= listeners_max) {
+ listeners_max = listeners_max == 0 ? 16 : listeners_max * 2;
+ listeners = (ELFCloseListener *)loc_realloc(listeners, sizeof(ELFCloseListener) * listeners_max);
+ }
+ listeners[listeners_cnt++] = listener;
+}
+
+#endif

Back to the top