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);
 };
 
 
openSUSE Build Service is sponsored by