/******************************************************************************* * 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 #if ENABLE_ELF #include #include #include 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 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 */