Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/dwarfreloc.c')
-rw-r--r--agent/tcf/services/dwarfreloc.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/agent/tcf/services/dwarfreloc.c b/agent/tcf/services/dwarfreloc.c
new file mode 100644
index 00000000..23377831
--- /dev/null
+++ b/agent/tcf/services/dwarfreloc.c
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements ELF relocation records handling for reading DWARF debug information.
+ *
+ * Functions in this module use exceptions to report errors, see exceptions.h
+ */
+
+#include <config.h>
+
+#if ENABLE_ELF
+
+#include <assert.h>
+#include <framework/exceptions.h>
+#include <services/dwarfreloc.h>
+
+static ELF_Section * section = NULL;
+static ELF_Section * relocs = NULL;
+static ELF_Section * symbols = NULL;
+static ELF_Section ** destination_section = NULL;
+
+static U8_T reloc_offset = 0;
+static U4_T reloc_type = 0;
+static U8_T reloc_addend = 0;
+static U4_T sym_index = 0;
+static U8_T sym_value = 0;
+
+static void * data_buf = NULL;
+static size_t data_size = 0;
+
+typedef struct ElfRelocateFunc {
+ int machine;
+ void (*func)(void);
+} ElfRelocateFunc;
+
+#include <machine/elf-mdep.h>
+
+static void relocate(void * r) {
+ ElfRelocateFunc * func;
+ if (!relocs->file->elf64) {
+ if (relocs->type == SHT_REL) {
+ Elf32_Rel bf = *(Elf32_Rel *)r;
+ if (relocs->file->byte_swap) {
+ SWAP(bf.r_offset);
+ SWAP(bf.r_info);
+ }
+ sym_index = ELF32_R_SYM(bf.r_info);
+ reloc_type = ELF32_R_TYPE(bf.r_info);
+ reloc_addend = 0;
+ }
+ else {
+ Elf32_Rela bf = *(Elf32_Rela *)r;
+ if (relocs->file->byte_swap) {
+ SWAP(bf.r_offset);
+ SWAP(bf.r_info);
+ SWAP(bf.r_addend);
+ }
+ sym_index = ELF32_R_SYM(bf.r_info);
+ reloc_type = ELF32_R_TYPE(bf.r_info);
+ reloc_addend = bf.r_addend;
+ }
+ if (sym_index != STN_UNDEF) {
+ Elf32_Sym bf = ((Elf32_Sym *)symbols->data)[sym_index];
+ if (symbols->file->byte_swap) {
+ SWAP(bf.st_name);
+ SWAP(bf.st_value);
+ SWAP(bf.st_size);
+ SWAP(bf.st_info);
+ SWAP(bf.st_other);
+ SWAP(bf.st_shndx);
+ }
+ if (symbols->file->type != ET_EXEC) {
+ switch (bf.st_shndx) {
+ case SHN_ABS:
+ sym_value = bf.st_value;
+ break;
+ case SHN_COMMON:
+ case SHN_UNDEF:
+ str_exception(ERR_INV_FORMAT, "Invalid relocation record");
+ break;
+ default:
+ if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record");
+ sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value;
+ *destination_section = symbols->file->sections + bf.st_shndx;
+ break;
+ }
+ }
+ else {
+ sym_value = bf.st_value;
+ }
+ }
+ }
+ else {
+ if (relocs->type == SHT_REL) {
+ Elf64_Rel bf = *(Elf64_Rel *)r;
+ if (relocs->file->byte_swap) {
+ SWAP(bf.r_offset);
+ SWAP(bf.r_info);
+ }
+ sym_index = ELF64_R_SYM(bf.r_info);
+ reloc_type = ELF64_R_TYPE(bf.r_info);
+ reloc_addend = 0;
+ }
+ else {
+ Elf64_Rela bf = *(Elf64_Rela *)r;
+ if (relocs->file->byte_swap) {
+ SWAP(bf.r_offset);
+ SWAP(bf.r_info);
+ SWAP(bf.r_addend);
+ }
+ sym_index = ELF64_R_SYM(bf.r_info);
+ reloc_type = ELF64_R_TYPE(bf.r_info);
+ reloc_addend = bf.r_addend;
+ }
+ if (sym_index != STN_UNDEF) {
+ Elf64_Sym bf = ((Elf64_Sym *)symbols->data)[sym_index];
+ if (symbols->file->byte_swap) {
+ SWAP(bf.st_name);
+ SWAP(bf.st_value);
+ SWAP(bf.st_size);
+ SWAP(bf.st_info);
+ SWAP(bf.st_other);
+ SWAP(bf.st_shndx);
+ }
+ if (symbols->file->type != ET_EXEC) {
+ switch (bf.st_shndx) {
+ case SHN_ABS:
+ sym_value = bf.st_value;
+ break;
+ case SHN_COMMON:
+ case SHN_UNDEF:
+ str_exception(ERR_INV_FORMAT, "Invalid relocation record");
+ break;
+ default:
+ if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record");
+ sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value;
+ *destination_section = symbols->file->sections + bf.st_shndx;
+ break;
+ }
+ }
+ else {
+ sym_value = bf.st_value;
+ }
+ }
+ }
+
+ /* For executable file we don't need to apply the relocation,
+ * all we need is destination_section */
+ if (section->file->type != ET_REL) return;
+
+ func = elf_relocate_funcs;
+ while (func->machine != section->file->machine) {
+ if (func->func == NULL) str_exception(ERR_INV_FORMAT, "Unsupported ELF machine code");
+ func++;
+ }
+ func->func();
+}
+
+void drl_relocate(ELF_Section * s, U8_T offset, void * buf, size_t size, ELF_Section ** dst) {
+ unsigned i;
+ ELF_Section * d = NULL;
+
+ if (dst == NULL) dst = &d;
+ else *dst = NULL;
+ if (!s->relocate) return;
+
+ section = s;
+ destination_section = dst;
+ reloc_offset = offset;
+ data_buf = buf;
+ data_size = size;
+ for (i = 1; i < s->file->section_cnt; i++) {
+ ELF_Section * r = s->file->sections + i;
+ if (r->size == 0) continue;
+ if (r->type != SHT_REL && r->type != SHT_RELA) continue;
+ if (r->info == s->index) {
+ uint8_t * p;
+ uint8_t * q;
+ relocs = r;
+ symbols = s->file->sections + r->link;
+ if (elf_load(relocs) < 0) exception(errno);
+ if (elf_load(symbols) < 0) exception(errno);
+ if (r->entsize == 0 || r->size % r->entsize != 0) str_exception(ERR_INV_FORMAT, "Invalid sh_entsize");
+ p = (uint8_t *)r->data;
+ q = p + r->size;
+ while (p < q) {
+ unsigned n = (q - p) / r->entsize / 2;
+ uint8_t * x = p + n * r->entsize;
+ assert(x < q);
+ if (r->file->elf64) {
+ U8_T offs = *(U8_T *)x;
+ if (r->file->byte_swap) SWAP(offs);
+ if (s->file->type != ET_REL) offs -= s->addr;
+ if (offset > offs) {
+ p = x + r->entsize;
+ continue;
+ }
+ if (offset < offs) {
+ q = x;
+ continue;
+ }
+ }
+ else {
+ U4_T offs = *(U4_T *)x;
+ if (r->file->byte_swap) SWAP(offs);
+ if (s->file->type != ET_REL) offs -= (U4_T)s->addr;
+ if (offset > offs) {
+ p = x + r->entsize;
+ continue;
+ }
+ if (offset < offs) {
+ q = x;
+ continue;
+ }
+ }
+ relocate(x);
+ return;
+ }
+ }
+ }
+}
+
+#endif /* ENABLE_ELF */

Back to the top