File libdwarf-relocation-support.patch of Package libdwarf
From: Daniel Gollub <dgollub@suse.de>
Subject: Initial ELF RELA/REL relocation support for libdwarf
Signed-off-by: Daniel Gollub <dgollub@suse.de>
---
diff --git a/libdwarf/Makefile.in b/libdwarf/Makefile.in
index 4af29b3..22e5444 100644
--- a/libdwarf/Makefile.in
+++ b/libdwarf/Makefile.in
@@ -72,6 +72,7 @@ OBJS= dwarf_abbrev.o \
dwarf_arange.o \
dwarf_die_deliv.o \
dwarf_elf_access.o \
+ dwarf_elf_relocation.o \
dwarf_error.o \
dwarf_form.o \
dwarf_frame.o \
diff --git a/libdwarf/dwarf_elf_access.c b/libdwarf/dwarf_elf_access.c
index f0ed70c..eeb4936 100644
--- a/libdwarf/dwarf_elf_access.c
+++ b/libdwarf/dwarf_elf_access.c
@@ -37,6 +37,7 @@
#include "config.h"
#include "dwarf_incl.h"
#include "dwarf_elf_access.h"
+#include "dwarf_elf_relocation.h"
#ifdef HAVE_ELF_H
#include <elf.h>
@@ -218,6 +219,9 @@ dwarf_elf_object_access_get_section_info(
*error = DW_DLE_ELF_STRPTR_ERROR;
return DW_DLV_ERROR;
}
+
+ ret_scn->section_header = shdr64;
+
return DW_DLV_OK;
}
#endif /* HAVE_ELF64_GETSHDR */
@@ -235,6 +239,9 @@ dwarf_elf_object_access_get_section_info(
*error = DW_DLE_ELF_STRPTR_ERROR;
return DW_DLV_ERROR;
}
+
+ ret_scn->section_header = shdr32;
+
return DW_DLV_OK;
}
@@ -305,6 +312,87 @@ dwarf_elf_object_access_load_section(void* obj_in,
return DW_DLV_OK;
}
+/*
+ dwarf_elf_object_access_is_relocatable
+ */
+static
+int
+dwarf_elf_object_access_is_relocatable(void* obj_in, Dwarf_Bool *is_relocatable, int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+
+ *is_relocatable = FALSE;
+
+#ifdef HAVE_ELF64_GETEHDR
+ if (obj->is_64bit) {
+ if (obj->ehdr64->e_type == ET_REL)
+ *is_relocatable = TRUE;
+ } else
+#endif
+ {
+ if (obj->ehdr32->e_type == ET_REL)
+ *is_relocatable = TRUE;
+ }
+
+ return DW_DLV_OK;
+}
+
+/*
+ dwarf_elf_object_access_apply_relocation
+ */
+static
+int
+dwarf_elf_object_access_apply_relocation(void* obj_in,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ Dwarf_Small *relocation_section,
+ Dwarf_Obj_Access_Section *relocation_section_info,
+ int* error)
+{
+ Dwarf_Half machine;
+ Elf32_Shdr *shdr32 = 0;
+ Dwarf_Bool is_rela = FALSE;
+ int res;
+
+#ifdef HAVE_ELF64_GETSHDR
+ Elf64_Shdr *shdr64 = 0;
+#endif
+
+
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+#ifdef HAVE_ELF64_GETEHDR
+ if (obj->is_64bit) {
+ machine = obj->ehdr64->e_machine;
+ shdr64 = relocation_section_info->section_header;
+ if (shdr64->sh_type == SHT_RELA) {
+ is_rela = TRUE;
+ }
+ } else
+#endif
+ {
+ machine = obj->ehdr32->e_machine;
+ shdr32 = relocation_section_info->section_header;
+ if (shdr32->sh_type == SHT_RELA) {
+ is_rela = TRUE;
+ }
+
+ }
+
+
+ res = dwarf_elf_relocation_apply(obj->is_64bit,
+ is_rela,
+ obj->endianness,
+ machine,
+ target_section,
+ symtab_section,
+ relocation_section,
+ relocation_section_info->size,
+ error);
+
+ return res;
+}
/* dwarf_elf_access method table. */
static const struct Dwarf_Obj_Access_Methods_s dwarf_elf_object_access_methods =
@@ -314,7 +402,9 @@ static const struct Dwarf_Obj_Access_Methods_s dwarf_elf_object_access_methods =
dwarf_elf_object_access_get_length_size,
dwarf_elf_object_access_get_pointer_size,
dwarf_elf_object_access_get_section_count,
- dwarf_elf_object_access_load_section
+ dwarf_elf_object_access_load_section,
+ dwarf_elf_object_access_is_relocatable,
+ dwarf_elf_object_access_apply_relocation
};
diff --git a/libdwarf/dwarf_elf_relocation.c b/libdwarf/dwarf_elf_relocation.c
new file mode 100644
index 0000000..88b44b0
--- /dev/null
+++ b/libdwarf/dwarf_elf_relocation.c
@@ -0,0 +1,517 @@
+/*
+ Copyright (C) 2000,2002,2003,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008 Novell, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+*/
+
+#include "config.h"
+#include "dwarf_incl.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+typedef struct {
+ Dwarf_ufixed64 r_offset;
+ /*Dwarf_ufixed64 r_info;*/
+ Dwarf_ufixed64 r_type;
+ Dwarf_ufixed64 r_symidx;
+ Dwarf_ufixed64 r_addend;
+} Dwarf_Elf_Rela;
+
+/* ELF RELA */
+static void
+get_rela_elf32(Dwarf_Small *data, unsigned int i, Dwarf_Elf_Rela *relap)
+{
+ Elf32_Rela *relap32;
+
+ relap32 = (Elf32_Rela*)(data + (i * sizeof(Elf32_Rela)));
+ relap->r_offset = relap32->r_offset;
+ /*
+ relap->r_info = relap32->r_info;
+ */
+ relap->r_type = ELF32_R_TYPE(relap32->r_info);
+ relap->r_symidx = ELF32_R_SYM(relap32->r_info);
+
+ relap->r_addend = relap32->r_addend;
+}
+
+static void
+get_rela_elf64(Dwarf_Small *data, unsigned int i, Dwarf_Elf_Rela *relap)
+{
+ Elf64_Rela *relap64;
+
+ relap64 = (Elf64_Rela*)(data + (i * sizeof(Elf64_Rela)));
+ relap->r_offset = relap64->r_offset;
+ /*
+ relap->r_info = relap64->r_info;
+ */
+ relap->r_type = ELF64_R_TYPE(relap64->r_info);
+ relap->r_symidx = ELF64_R_SYM(relap64->r_info);
+
+ relap->r_addend = relap64->r_addend;
+}
+
+/* ELF REL */
+static void
+get_rel_elf32(Dwarf_Small *data, unsigned int i, Dwarf_Elf_Rela *relap)
+{
+ Elf32_Rel *relp32;
+
+ relp32 = (Elf32_Rel*)(data + (i * sizeof(Elf32_Rel)));
+ relap->r_offset = relp32->r_offset;
+ /*
+ relap->r_info = relp32->r_info;
+ */
+ relap->r_type = ELF32_R_TYPE(relp32->r_info);
+ relap->r_symidx = ELF32_R_SYM(relp32->r_info);
+
+ relap->r_addend = 0;
+}
+
+static void
+get_rel_elf64(Dwarf_Small *data, unsigned int i, Dwarf_Elf_Rela *relap)
+{
+ Elf64_Rel *relp64;
+
+ relp64 = (Elf64_Rel*)(data + (i * sizeof(Elf64_Rel)));
+ relap->r_offset = relp64->r_offset;
+ /*
+ relap->r_info = relp64->r_info;
+ */
+ relap->r_type = ELF64_R_TYPE(relp64->r_info);
+ relap->r_symidx = ELF64_R_SYM(relp64->r_info);
+
+ relap->r_addend = 0;
+}
+
+static void
+get_relocations(Dwarf_Bool is_64bit, Dwarf_Bool is_rela, Dwarf_Small *data,
+ unsigned int num_relocations, Dwarf_Elf_Rela *relap)
+{
+
+ unsigned int i;
+ void (*get_relocations)(Dwarf_Small *data, unsigned int i, Dwarf_Elf_Rela *relap);
+
+ /* Handle 32/64 bit issue
+ */
+ if (is_64bit) {
+ if (is_rela) {
+ get_relocations = get_rela_elf64;
+ } else {
+ get_relocations = get_rel_elf64;
+ }
+ } else {
+ if (is_rela) {
+ get_relocations = get_rela_elf32;
+ } else {
+ get_relocations = get_rel_elf32;
+ }
+ }
+
+ for (i=0; i < num_relocations; i++) {
+ get_relocations(data, i, &(relap[i]));
+ }
+
+}
+
+static int
+get_relocation_entries(Dwarf_Bool is_64bit,
+ Dwarf_Bool is_rela,
+ Dwarf_Small *relocation_section,
+ Dwarf_Unsigned relocation_section_size,
+ Dwarf_Elf_Rela **relas,
+ unsigned int *nrelas,
+ int *error)
+{
+ unsigned int relocation_size = 0;
+
+ if (is_64bit) {
+ if (is_rela)
+ relocation_size = sizeof(Elf64_Rela);
+ else
+ relocation_size = sizeof(Elf64_Rel);
+ } else {
+ if (is_rela)
+ relocation_size = sizeof(Elf32_Rela);
+ else
+ relocation_size = sizeof(Elf32_Rel);
+ }
+
+ if (relocation_section == NULL) {
+ /* TODO: _dwarf_error() handling required? */
+ return(DW_DLV_ERROR);
+ }
+
+ if ((relocation_section_size != 0)) {
+ *nrelas = relocation_section_size/relocation_size;
+ *relas = malloc (*nrelas * sizeof(Dwarf_Elf_Rela));
+ if (!*relas) {
+ *error = DW_DLE_MAF;
+ return(DW_DLV_ERROR);
+ }
+
+ get_relocations(is_64bit, is_rela, relocation_section, *nrelas, *relas);
+ }
+ return(DW_DLV_OK);
+}
+
+static uint64_t
+byte_get_little_endian (unsigned char *field, int size)
+{
+ switch (size)
+ {
+ case 1:
+ return *field;
+
+ case 2:
+ return ((unsigned int) (field[0]))
+ | (((unsigned int) (field[1])) << 8);
+
+ case 4:
+ return ((unsigned long) (field[0]))
+ | (((unsigned long) (field[1])) << 8)
+ | (((unsigned long) (field[2])) << 16)
+ | (((unsigned long) (field[3])) << 24);
+
+ case 8:
+ if (sizeof (unsigned long long) == 8)
+ return ((unsigned long long) (field[0]))
+ | (((unsigned long long) (field[1])) << 8)
+ | (((unsigned long long) (field[2])) << 16)
+ | (((unsigned long long) (field[3])) << 24)
+ | (((unsigned long long) (field[4])) << 32)
+ | (((unsigned long long) (field[5])) << 40)
+ | (((unsigned long long) (field[6])) << 48)
+ | (((unsigned long long) (field[7])) << 56);
+ else if (sizeof (unsigned long long) == 4)
+ /* We want to extract data from an 8 byte wide field and
+ place it into a 4 byte wide field. Since this is a little
+ endian source we can just use the 4 byte extraction code. */
+ return ((unsigned long) (field[0]))
+ | (((unsigned long) (field[1])) << 8)
+ | (((unsigned long) (field[2])) << 16)
+ | (((unsigned long) (field[3])) << 24);
+
+ default:
+ fprintf(stderr, "Unhandled data length: %d\n", size);
+ abort();
+ }
+}
+
+static uint64_t
+byte_get_big_endian (unsigned char *field, int size)
+{
+ switch (size)
+ {
+ case 1:
+ return *field;
+
+ case 2:
+ return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
+
+ case 4:
+ return ((unsigned long) (field[3]))
+ | (((unsigned long) (field[2])) << 8)
+ | (((unsigned long) (field[1])) << 16)
+ | (((unsigned long) (field[0])) << 24);
+
+ case 8:
+ if (sizeof (unsigned long long) == 8)
+ return ((unsigned long long) (field[7]))
+ | (((unsigned long long) (field[6])) << 8)
+ | (((unsigned long long) (field[5])) << 16)
+ | (((unsigned long long) (field[4])) << 24)
+ | (((unsigned long long) (field[3])) << 32)
+ | (((unsigned long long) (field[2])) << 40)
+ | (((unsigned long long) (field[1])) << 48)
+ | (((unsigned long long) (field[0])) << 56);
+ else if (sizeof (unsigned long long) == 4)
+ {
+ /* Although we are extracing data from an 8 byte wide field,
+ we are returning only 4 bytes of data. */
+ field += 4;
+ return ((unsigned long) (field[3]))
+ | (((unsigned long) (field[2])) << 8)
+ | (((unsigned long) (field[1])) << 16)
+ | (((unsigned long) (field[0])) << 24);
+ }
+
+ default:
+ fprintf(stderr, "Unhandled data length: %d\n", size);
+ abort();
+ }
+}
+
+
+static void
+byte_put_little_endian (unsigned char *field, uint64_t value, int size)
+{
+ switch (size) {
+ case 8:
+ field[7] = (((value >> 24) >> 24) >> 8) & 0xff;
+ field[6] = ((value >> 24) >> 24) & 0xff;
+ field[5] = ((value >> 24) >> 16) & 0xff;
+ field[4] = ((value >> 24) >> 8) & 0xff;
+ /* Fall through. */
+ case 4:
+ field[3] = (value >> 24) & 0xff;
+ field[2] = (value >> 16) & 0xff;
+ /* Fall through. */
+ case 2:
+ field[1] = (value >> 8) & 0xff;
+ /* Fall through. */
+ case 1:
+ field[0] = value & 0xff;
+ break;
+
+ default:
+ printf ("Unhandled data length: %d\n", size);
+ abort ();
+ }
+}
+
+static void
+byte_put_big_endian (unsigned char *field, uint64_t value, int size)
+{
+ switch (size) {
+ case 8:
+ field[7] = value & 0xff;
+ field[6] = (value >> 8) & 0xff;
+ field[5] = (value >> 16) & 0xff;
+ field[4] = (value >> 24) & 0xff;
+ value >>= 16;
+ value >>= 16;
+ /* Fall through. */
+ case 4:
+ field[3] = value & 0xff;
+ field[2] = (value >> 8) & 0xff;
+ value >>= 16;
+ /* Fall through. */
+ case 2:
+ field[1] = value & 0xff;
+ value >>= 8;
+ /* Fall through. */
+ case 1:
+ field[0] = value & 0xff;
+ break;
+
+ default:
+ printf("Unhandled data length: %d\n", size);
+ abort ();
+ }
+}
+
+static Dwarf_Bool
+is_32bit_abs_reloc(unsigned int type, Dwarf_Half machine) {
+ switch (machine) {
+ case EM_386:
+ return type == R_386_32;
+ case EM_IA_64:
+ return type == R_IA64_SECREL32LSB;
+ case EM_PPC64:
+ return type == R_PPC64_ADDR32;
+ case EM_PPC:
+ return type == R_PPC_ADDR32;
+ case EM_S390:
+ return type == R_390_32;
+ case EM_X86_64:
+ return type == R_X86_64_32;
+ default:
+ return 0;
+ }
+}
+
+static Dwarf_Bool
+is_64bit_abs_reloc(unsigned int type, Dwarf_Half machine) {
+ switch (machine) {
+ case EM_IA_64:
+ return type == R_IA64_DIR64LSB;
+ case EM_PPC64:
+ return type == R_PPC64_ADDR64;
+ case EM_S390:
+ return type == R_390_64;
+ case EM_X86_64:
+ return type == R_X86_64_64;
+ default:
+ return 0;
+ }
+}
+
+static Dwarf_Bool
+is_32bit_pcrel_reloc(unsigned int type, Dwarf_Half machine) {
+ switch (machine) {
+ case EM_386:
+ return type == R_386_PC32;
+ case EM_PPC64:
+ return type == R_PPC64_REL32;
+ case EM_PPC:
+ return type == R_PPC_REL32;
+ case EM_S390:
+ return type == R_390_PC32;
+ case EM_X86_64:
+ return type == R_X86_64_PC32;
+ default:
+ return 0;
+ }
+}
+
+
+static void
+update_entry(Dwarf_Bool is_64bit, Dwarf_Bool is_rela, Dwarf_Endianness endianess,
+ Dwarf_Half machine, Dwarf_Elf_Rela *rela,
+ Dwarf_Small *target_section, Dwarf_Small *section_data)
+{
+ unsigned int type, sym_idx;
+ Elf64_Sym sym_buf;
+ Elf64_Sym *sym;
+ Elf32_Sym *sym32;
+ void (*byte_put) (unsigned char *field, uint64_t value, int size);
+ uint64_t (*byte_get) (unsigned char *field, int size);
+ Dwarf_ufixed64 offset;
+ Dwarf_sfixed64 addend;
+ Dwarf_Unsigned reloc_size;
+
+ /* Dwarf_Elf_Rela dereferencing */
+ offset = rela->r_offset;
+ addend = rela->r_addend;
+ type = rela->r_type;
+ sym_idx = rela->r_symidx;
+
+ if (is_64bit) {
+ sym = &((Elf64_Sym*)section_data)[sym_idx];
+ } else {
+ sym32 = &((Elf32_Sym*)section_data)[sym_idx];
+
+ /* Convert Elf32_Sym struct to Elf64_Sym struct. We point at
+ * an Elf64_Sym local variable (sym_buf) to allow us to use the
+ * same pointer (sym) for both 32-bit and 64-bit instances.
+ */
+ sym = &sym_buf;
+ sym->st_name = (Elf64_Word)sym32->st_name;
+ sym->st_info = sym32->st_info;
+ sym->st_other = sym32->st_other;
+ sym->st_shndx = (Elf64_Section)sym32->st_shndx;
+ sym->st_value = (Elf64_Addr)sym32->st_value;
+ sym->st_size = (Elf64_Xword)sym32->st_size;
+ }
+
+
+ /* TODO: handle REL without addend! */
+
+ /* Determine endianess */
+ if (endianess == DW_OBJECT_MSB) {
+ byte_put = byte_put_big_endian;
+ byte_get = byte_get_big_endian;
+ } else {
+ byte_put = byte_put_little_endian;
+ byte_get = byte_get_little_endian;
+ }
+
+ /* Determine relocation size */
+ if (is_32bit_abs_reloc(type, machine)) {
+ reloc_size = 4;
+ } else if (is_64bit_abs_reloc(type, machine)) {
+ reloc_size = 8;
+ } else {
+ /* TODO: implemente 16bit ... */
+ /* TODO: abort! */
+ fprintf(stderr, "Unable to determine relocate size of reloc_type: %d\n", type);
+ exit(1);
+ return;
+ }
+
+ addend = is_rela ? addend : byte_get(target_section + offset, reloc_size);
+
+ if (is_32bit_pcrel_reloc(type, machine)) {
+ /* Relative */
+ byte_put(target_section + offset,
+ (sym->st_value + addend) - offset, reloc_size);
+ } else {
+ /* Absolute */
+ byte_put(target_section + offset, sym->st_value + addend, reloc_size);
+ }
+}
+
+static int
+apply_rela_entries(Dwarf_Bool is_64bit,
+ Dwarf_Bool is_rela,
+ Dwarf_Endianness endianess,
+ Dwarf_Half machine,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ Dwarf_Elf_Rela *relas, unsigned int nrelas,
+ int *error)
+{
+ unsigned int i;
+
+ if ((target_section != NULL) && (relas != NULL)) {
+ for (i = 0; i < nrelas; i++) {
+ update_entry(is_64bit,
+ is_rela,
+ endianess,
+ machine,
+ &(relas)[i],
+ target_section,
+ symtab_section);
+ }
+ }
+
+ return DW_DLV_OK;
+}
+
+int
+dwarf_elf_relocation_apply(
+ Dwarf_Bool is_64bit,
+ Dwarf_Bool is_rela,
+ Dwarf_Endianness endianess,
+ Dwarf_Half machine,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ Dwarf_Small *relocation_section,
+ Dwarf_Unsigned relocation_section_size,
+ int *error)
+{
+ int ret;
+ Dwarf_Elf_Rela *relas;
+ unsigned int nrelas;
+
+ if ((ret = get_relocation_entries(is_64bit, is_rela,
+ relocation_section,
+ relocation_section_size,
+ &relas, &nrelas, error)))
+ return ret;
+
+ if ((ret = apply_rela_entries(is_64bit, is_rela,
+ endianess, machine,
+ target_section,
+ symtab_section,
+ relas, nrelas, error)))
+ return ret;
+
+ return DW_DLV_OK;
+}
+
diff --git a/libdwarf/dwarf_elf_relocation.h b/libdwarf/dwarf_elf_relocation.h
new file mode 100644
index 0000000..df93eb1
--- /dev/null
+++ b/libdwarf/dwarf_elf_relocation.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2000,2002,2003,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008 Novell, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+*/
+
+#ifndef DWARF_ELF_RELOCATION_H_
+#define DWARF_ELF_RELOCATION_H_
+
+/* ELF RELA and REL relocation */
+int dwarf_elf_relocation_apply(Dwarf_Bool is_64bit,
+ Dwarf_Bool is_rela,
+ Dwarf_Endianness endianess,
+ Dwarf_Half machine,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ Dwarf_Small *relocation_section,
+ Dwarf_Unsigned relocation_section_size,
+ int *error);
+
+
+#endif /*DWARF_ELF_RELOCATION_H_*/
+
diff --git a/libdwarf/dwarf_init_finish.c b/libdwarf/dwarf_init_finish.c
index 4fd7401..404592c 100644
--- a/libdwarf/dwarf_init_finish.c
+++ b/libdwarf/dwarf_init_finish.c
@@ -95,9 +95,12 @@ static int
_dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
{
const char *scn_name = 0;
+ int err, res = 0;
int foundDwarf = 0;
struct Dwarf_Obj_Access_Interface_s * obj = 0;
+ struct Dwarf_Obj_Access_Section_s doas;
+ Dwarf_Bool is_relocatable;
Dwarf_Endianness endianness;
Dwarf_Unsigned section_size = 0;
@@ -142,10 +145,6 @@ _dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
for (section_index = 0; section_index < section_count;
++section_index) {
- struct Dwarf_Obj_Access_Section_s doas;
- Dwarf_Error section_error;
- int res;
- int err;
res = obj->methods->get_section_info(obj->object,
section_index,
@@ -158,7 +157,20 @@ _dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
section_size = doas.size;
scn_name = doas.name;
- if (strncmp(scn_name, ".debug_", 7)
+ if (strcmp(scn_name, ".rela.debug_info") == 0
+ || strcmp(scn_name, ".rel.debug_info") == 0) {
+ if (dbg->de_rela_debug_info != NULL) {
+ continue;
+ }
+ if (section_size == 0) {
+ continue;
+ }
+ dbg->de_rela_debug_info_index = section_index;
+ dbg->de_rela_debug_info_size = section_size;
+ } else if (strcmp(scn_name, ".symtab") == 0) {
+ dbg->de_symtab_index = section_index;
+ dbg->de_symtab_size = section_size;
+ } else if (strncmp(scn_name, ".debug_", 7)
&& strcmp(scn_name, ".eh_frame")
)
continue;
@@ -374,10 +386,54 @@ _dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
dbg->de_debug_macinfo_size = section_size;
}
}
- if (foundDwarf) {
- return DW_DLV_OK;
+ if (!foundDwarf) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ res = obj->methods->is_relocatable(obj->object, &is_relocatable, &err);
+
+ if (res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+
+ /* Only try to relocate if:
+ * - object format is relocatable
+ * - any relocation section is available
+ */
+ if (is_relocatable
+ && dbg->de_rela_debug_info_size
+ && dbg->de_symtab_size) {
+
+ /* Load the rela- and regular debug info section in advance! */
+ res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ /* Load symtab for relocation */
+ res = _dwarf_load_symtab(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = obj->methods->get_section_info(obj->object,
+ dbg->de_rela_debug_info_index,
+ &doas, &err);
+ if (res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+
+ res = obj->methods->apply_relocation(obj->object,
+ dbg->de_debug_info,
+ dbg->de_symtab,
+ dbg->de_rela_debug_info,
+ &doas, &err);
+
+ if (res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
}
- return (DW_DLV_NO_ENTRY);
+
+ return (DW_DLV_OK);
}
@@ -517,3 +573,5 @@ dwarf_get_section_max_offsets(Dwarf_Debug dbg,
return DW_DLV_OK;
}
+
+
diff --git a/libdwarf/dwarf_opaque.h b/libdwarf/dwarf_opaque.h
index 13fe701..1b52969 100644
--- a/libdwarf/dwarf_opaque.h
+++ b/libdwarf/dwarf_opaque.h
@@ -188,6 +188,8 @@ struct Dwarf_Debug_s {
Dwarf_Signed de_fde_count;
Dwarf_Small *de_debug_info;
+ Dwarf_Small *de_rela_debug_info;
+ Dwarf_Small *de_symtab;
Dwarf_Small *de_debug_abbrev;
Dwarf_Small *de_debug_line;
Dwarf_Small *de_debug_loc;
@@ -211,6 +213,8 @@ struct Dwarf_Debug_s {
Dwarf_Small *de_debug_weaknames;
Dwarf_Unsigned de_debug_info_size;
+ Dwarf_Unsigned de_rela_debug_info_size;
+ Dwarf_Unsigned de_symtab_size;
Dwarf_Unsigned de_debug_abbrev_size;
Dwarf_Unsigned de_debug_line_size;
Dwarf_Unsigned de_debug_loc_size;
@@ -259,6 +263,8 @@ struct Dwarf_Debug_s {
Dwarf_Half de_debug_frame_eh_gnu_index;
Dwarf_Half de_debug_str_index;
Dwarf_Half de_debug_info_index;
+ Dwarf_Half de_rela_debug_info_index;
+ Dwarf_Half de_symtab_index;
Dwarf_Half de_debug_abbrev_index;
Dwarf_Half de_debug_pubtypes_index; /* DWARF3 .debug_pubtypes */
diff --git a/libdwarf/dwarf_util.c b/libdwarf/dwarf_util.c
index 6cbd92f..7040a6c 100644
--- a/libdwarf/dwarf_util.c
+++ b/libdwarf/dwarf_util.c
@@ -479,9 +479,35 @@ _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error)
}
res = _dwarf_load_section(dbg, dbg->de_debug_info_index,
&dbg->de_debug_info, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ /*
+ * Load RELA section, if present, for proper relocation itself.
+ */
+ if (dbg->de_rela_debug_info_index) {
+ res = _dwarf_load_section(dbg, dbg->de_rela_debug_info_index,
+ &dbg->de_rela_debug_info, error);
+ }
return res;
+}
+
+int
+_dwarf_load_symtab(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ int res;
+
+ if (dbg->de_symtab) {
+ return DW_DLV_OK;
+ }
+
+ res = _dwarf_load_section(dbg, dbg->de_symtab_index,
+ &dbg->de_symtab, error);
+ return res;
}
+
void
_dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,Dwarf_Hash_Table hash_table)
{
diff --git a/libdwarf/dwarf_util.h b/libdwarf/dwarf_util.h
index 7bd8883..290e8d5 100644
--- a/libdwarf/dwarf_util.h
+++ b/libdwarf/dwarf_util.h
@@ -303,6 +303,7 @@ Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug,
Dwarf_Unsigned _dwarf_length_of_cu_header_simple(Dwarf_Debug);
int _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error *error);
+int _dwarf_load_symtab(Dwarf_Debug dbg, Dwarf_Error *error);
void _dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,
struct Dwarf_Hash_Table_s* hash_table);
diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h
index c8440cc..e2ea2c6 100644
--- a/libdwarf/libdwarf.h
+++ b/libdwarf/libdwarf.h
@@ -440,7 +440,6 @@ typedef Dwarf_Unsigned Dwarf_Tag;
*/
typedef void (*Dwarf_Handler)(Dwarf_Error /*error*/, Dwarf_Ptr /*errarg*/);
-
/* Begin libdwarf Object File Interface declarations.
As of February 2008 there are multiple dwarf_reader object access
@@ -472,11 +471,18 @@ typedef struct Dwarf_Obj_Access_Section_s Dwarf_Obj_Access_Section;
method of setting up 'sections equivalents')
must arrange to return standard DWARF section
names in the 'name' field. libdwarf does
- not free the strings in 'name'. */
+ not free the strings in 'name'.
+
+ section header contains pointer to format specific
+ header information about this certain information.
+
+ */
struct Dwarf_Obj_Access_Section_s {
Dwarf_Addr addr;
Dwarf_Unsigned size;
const char* name;
+ /* TODO: Some generic value or Bool if the section is relocatable?! */
+ void *section_header;
};
/* Returned by the get_endianness function in
@@ -591,6 +597,47 @@ struct Dwarf_Obj_Access_Methods_s {
*/
int (*load_section)(void* obj, Dwarf_Half section_index,
Dwarf_Small** return_data, int* error);
+ /**
+ * is_relocatable
+ *
+ * Check if object file is relocatable.
+ *
+ * Parameters
+ * is_reloctabler - Pointer to a Dwarf_Bool for returning the
+ * relocatable status. TRUE if relocatable, FALSE otherwise.
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ */
+ int (*is_relocatable)(void* obj, Dwarf_Bool *is_relocatable, int* error);
+ /**
+ * apply_relocation
+ *
+ * Apply object file specific relocation.
+ *
+ * Parameters
+ * target_section - section to relocate
+ * symtab_section - section which points to symbol table
+ * relocation_section - section which contains relocation information
+ * relocation_section_info - information about the relocation section
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ */
+ int (*apply_relocation)(void* obj,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ Dwarf_Small *relocation_section,
+ Dwarf_Obj_Access_Section *relocation_section_info,
+ int* error);
};