diff options
author | Eugene Tarassov | 2011-11-11 01:19:02 +0000 |
---|---|---|
committer | Eugene Tarassov | 2011-11-11 01:19:02 +0000 |
commit | a107edc216f94c5ec059fdf74541908bc7e979bb (patch) | |
tree | a0d9a448043cf5b969c2ede059b7d19a3aa64b71 /agent/tcf/services/dwarfreloc.c | |
parent | 07c7a005cded9e4b4ec842d756d0e4d79dade149 (diff) | |
download | org.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.tar.gz org.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.tar.xz org.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.zip |
Agent code is moved into separate "agent" directory, all C code moved into "tcf" directory.
Diffstat (limited to 'agent/tcf/services/dwarfreloc.c')
-rw-r--r-- | agent/tcf/services/dwarfreloc.c | 236 |
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 */ |