]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Wire libdw relocation support into libdwfl.
authorRoland McGrath <roland@redhat.com>
Wed, 30 Jun 2010 01:47:17 +0000 (18:47 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 30 Jun 2010 01:47:17 +0000 (18:47 -0700)
12 files changed:
libdw/ChangeLog
libdw/libdwP.h
libdw/relocate.c
libdw/relocate.h
libdwfl/ChangeLog
libdwfl/derelocate.c
libdwfl/dwfl_module.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsym.c
libdwfl/dwfl_report_elf.c
libdwfl/libdwflP.h
libdwfl/relocate.c

index 0d1854c6fba8573ecd20fda78a6168ad754dc32f..c51abc60483e856006715b8e6f3ac89265a29a11 100644 (file)
@@ -1,5 +1,15 @@
 2010-06-29  Roland McGrath  <roland@redhat.com>
 
+       * libdwP.h (dwarf_file_reloc): Remove resolve_symbol member,
+       add dwflmod member instead.
+       * relocate.h: Declare __libdwfl_relocate_setup and
+       __libdwfl_relocate_symbol.
+       * relocate.c (noresolve_symbol): Removed.
+       (__libdw_relocate_begin): Initialize dwflmod instead of resolve_symbol.
+       (__libdw_relocate_shndx): Removed, now in libdwfl.
+       (digest_relocs): Call __libdwfl_relocate_setup.
+       (__libdw_relocate_address): Call __libdwfl_relocate_symbol.
+
        * dwarf_lineaddr.c: Add INTDEF.
        * libdwP.h: Add INTDECL.
 
index 8d0cb6ad2251384c4ba8c62cd7854fe900c05265..e7f66a2ffcdd4df81a3e1b7280f47e2f4b868f68 100644 (file)
@@ -218,9 +218,7 @@ struct dwarf_file_reloc
 
   struct ebl *ebl;
 
-  int (*resolve_symbol) (bool undef, Dwarf *dbg,
-                        GElf_Sym *sym, GElf_Word shndx)
-    internal_function;
+  struct Dwfl_Module *dwflmod;
 };
 
 
index a7ee6b7508192708e0d171a3d648a066cab485e1..8ac07ff929e34d30e1d884d8f43b86ef9ce15d45 100644 (file)
 #include <stdlib.h>
 
 
-static int
-internal_function
-noresolve_symbol (bool undef,
-                 Dwarf *dbg __attribute__ ((unused)),
-                 GElf_Sym *sym __attribute__ ((unused)),
-                 GElf_Word shndx __attribute__ ((unused)))
-{
-  __libdw_seterrno (undef ? DWARF_E_RELUNDEF : DWARF_E_RELOC);
-  return -1;
-}
-
 void
 internal_function
 __libdw_relocate_begin (Dwarf *dbg, Elf_Scn *relscn[IDX_last], bool incomplete)
@@ -96,7 +85,7 @@ __libdw_relocate_begin (Dwarf *dbg, Elf_Scn *relscn[IDX_last], bool incomplete)
 
   dbg->relocate = libdw_typed_alloc (dbg, struct dwarf_file_reloc);
   dbg->relocate->ebl = NULL;
-  dbg->relocate->resolve_symbol = &noresolve_symbol;
+  dbg->relocate->dwflmod = NULL;
 
   /* All we do to start with is cache the section pointers.
      We'll do the rest on demand in digest_relocs, below.  */
@@ -112,7 +101,6 @@ void
 internal_function
 __libdw_relocate_end (Dwarf *dbg)
 {
-  // XXX let dwfl preinstall, don't close here
   ebl_closebackend (dbg->relocate->ebl);
 }
 \f
@@ -240,27 +228,24 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
   if (unlikely (gelf_getshdr (r->scn, &shdr) == NULL))
     assert (!"impossible gelf_getshdr failure");
 
-  /* XXX let dwfl supply defaults from main file for separate debug
-     with relocs pointing to SHT_NOBITS symtab
-  r->symdata = dbg->relocate->symdata;
-  r->symstrdata = dbg->relocate->symstrdata;
-  */
-  {
-    GElf_Shdr symshdr;
-    Elf_Scn *const symscn = elf_getscn (r->scn->elf, shdr.sh_link);
-    if (unlikely (gelf_getshdr (symscn, &symshdr) == NULL))
-      return DWARF_E_RELBADSYM;
-    if (symshdr.sh_type != SHT_NOBITS)
-      {
-       r->symdata = elf_getdata (symscn, NULL);
-       if (unlikely (r->symdata == NULL))
-         return DWARF_E_RELBADSYM;
-       r->symstrdata = elf_getdata (elf_getscn (r->scn->elf, symshdr.sh_link),
-                                    NULL);
-       if (unlikely (r->symstrdata == NULL))
-         return DWARF_E_RELBADSYM;
-      }
-  }
+  /* Look for the symtab section this reloc section refers to.  */
+  GElf_Shdr symshdr;
+  Elf_Scn *const symscn = elf_getscn (r->scn->elf, shdr.sh_link);
+  if (likely (gelf_getshdr (symscn, &symshdr) != NULL)
+      && symshdr.sh_type != SHT_NOBITS)
+    {
+      r->symdata = elf_getdata (symscn, NULL);
+      r->symstrdata = elf_getdata (elf_getscn (r->scn->elf, symshdr.sh_link),
+                                  NULL);
+    }
+
+  /* Let libdwfl set up ebl and symtab pointers if it can.  */
+  if (dbg->relocate->dwflmod != NULL)
+    __libdwfl_relocate_setup (dbg, r);
+
+  /* Fail if neither direct pointers nor libdwfl backup found a symtab.  */
+  if (unlikely (r->symdata == NULL) || unlikely (r->symstrdata == NULL))
+    return DWARF_E_RELBADSYM;
 
   if (dbg->relocate->ebl == NULL)
     {
@@ -478,22 +463,6 @@ __libdw_relocatable_getsym (Dwarf *dbg, int sec_index,
   return result;
 }
 
-int
-internal_function
-__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
-                       Dwarf_Addr *val)
-{
-  GElf_Sym sym =
-    {
-      .st_shndx = shndx < SHN_LORESERVE ? shndx : SHN_XINDEX,
-      .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
-    };
-  int result = (*dbg->relocate->resolve_symbol) (false, dbg, &sym, shndx);
-  if (result == 0)
-    *val = sym.st_value + addend;
-  return result;
-}
-
 int
 internal_function
 __libdw_relocate_address (Dwarf *dbg, int sec_index,
@@ -506,13 +475,11 @@ __libdw_relocate_address (Dwarf *dbg, int sec_index,
   int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
                                           &symndx, &sym, &shndx, &addend);
   if (result > 0 && symndx != STN_UNDEF)
-    {
-      result = (*dbg->relocate->resolve_symbol)
-       (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
-        || GELF_ST_BIND (sym.st_info) > STB_WEAK,
-        dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx);
-      addend += sym.st_value;
-    }
+    result = __libdwfl_relocate_symbol
+      (dbg->relocate->sectionrel[sec_index],
+       sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
+       || GELF_ST_BIND (sym.st_info) > STB_WEAK,
+       dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx, &addend);
   if (result >= 0)
     *val = addend;
   return result;
index 6c9751879b1ca606cb0066284a96350a1b9e804e..495558bd438320ad3fee3391607aa18a2635bf17 100644 (file)
@@ -105,3 +105,11 @@ extern ptrdiff_t __libdw_ranges_relocatable (struct Dwarf_CU *cu,
                                             Dwarf_Relocatable *endp,
                                             Dwarf_Block *exprloc)
   __nonnull_attribute__ (1, 4, 5, 6) internal_function;
+
+extern void __libdwfl_relocate_setup (Dwarf *dbg, struct dwarf_section_reloc *r)
+  __nonnull_attribute__ (1, 2) internal_function;
+
+extern int __libdwfl_relocate_symbol (struct dwarf_section_reloc *r, bool undef,
+                                     Dwarf *dbg, GElf_Sym *sym,
+                                     GElf_Word shndx, GElf_Sxword *addend)
+  __nonnull_attribute__ (1, 3, 4) internal_function;
index 38cf62a08ee1d55d489b9f79846bbb9ccfa08f42..19a5eb181da34762e63ce1a419c6eff8c091ee6f 100644 (file)
@@ -1,5 +1,20 @@
 2010-06-29  Roland McGrath  <roland@redhat.com>
 
+       * derelocate.c (check_module): Don't call dwfl_module_getdwarf.
+
+       * dwfl_module_getdwarf.c (__libdwfl_relocate_setup): New function.
+       (load_dw): Set MOD->dw->relocate->dwflmod.
+       * dwfl_module.c (__libdwfl_module_free): Clear MOD->dw->relocate->ebl
+       if we set it.
+       * relocate.c (__libdw_relocate_shndx): New function.
+       (__libdwfl_relocate_symbol): New function.
+
+       * libdwflP.h (struct dwfl_file): Add member shstrndx.
+       * dwfl_module_getdwarf.c (open_elf): Set it.
+       * dwfl_report_elf.c (__libdwfl_report_elf): Likewise.
+       * derelocate.c (cache_sections): Use it.
+       * dwfl_module_getsym.c: Likewise.
+
        * dwfl_lineinfo.c: Use dwarf_lineaddr.
 
        * relocate.c (relocate_section): Remove PARTIAL flag argument.
index ee869e061ba084ecc87b3c69e5ceb781f993c051..25b2c37d46dbed064e6dcf4f91a959a40b6398dc 100644 (file)
@@ -93,14 +93,6 @@ cache_sections (Dwfl_Module *mod)
   struct secref *refs = NULL;
   size_t nrefs = 0;
 
-  size_t shstrndx;
-  if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
-    {
-    elf_error:
-      __libdwfl_seterrno (DWFL_E_LIBELF);
-      return -1;
-    }
-
   bool check_reloc_sections = false;
   Elf_Scn *scn = NULL;
   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
@@ -108,13 +100,17 @@ cache_sections (Dwfl_Module *mod)
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
       if (shdr == NULL)
-       goto elf_error;
+       {
+       elf_error:
+         __libdwfl_seterrno (DWFL_E_LIBELF);
+         return -1;
+       }
 
       if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
          && mod->e_type == ET_REL)
        {
          /* This section might not yet have been looked at.  */
-         if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
+         if (__libdwfl_relocate_value (mod, mod->main.elf, &mod->main.shstrndx,
                                        elf_ndxscn (scn),
                                        &shdr->sh_addr) != DWFL_E_NOERROR)
            continue;
@@ -125,7 +121,7 @@ cache_sections (Dwfl_Module *mod)
 
       if (shdr->sh_flags & SHF_ALLOC)
        {
-         const char *name = elf_strptr (mod->main.elf, shstrndx,
+         const char *name = elf_strptr (mod->main.elf, mod->main.shstrndx,
                                         shdr->sh_name);
          if (unlikely (name == NULL))
            goto elf_error;
@@ -298,20 +294,6 @@ check_module (Dwfl_Module *mod)
        }
     }
 
-  if (mod->dw == NULL)
-    {
-      Dwarf_Addr bias;
-      if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
-       {
-         Dwfl_Error error = dwfl_errno ();
-         if (error != DWFL_E_NO_DWARF)
-           {
-             __libdwfl_seterrno (error);
-             return true;
-           }
-       }
-    }
-
   return false;
 }
 
index d7e5413862274de2ac02632749d1114c91a894fd..4dbb1fcccd7a4036ca00808e7f76d07a3dec2ae0 100644 (file)
@@ -1,5 +1,5 @@
 /* Maintenance of module list in libdwfl.
-   Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
+   Copyright (C) 2005-2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -92,7 +92,15 @@ __libdwfl_module_free (Dwfl_Module *mod)
     }
 
   if (mod->dw != NULL)
-    INTUSE(dwarf_end) (mod->dw);
+    {
+      if (mod->dw->relocate != NULL)
+       {
+         if (mod->dw->relocate->ebl == mod->ebl)
+           mod->dw->relocate->ebl = NULL;
+       }
+
+      INTUSE(dwarf_end) (mod->dw);
+    }
 
   if (mod->ebl != NULL)
     ebl_closebackend (mod->ebl);
index 42d817a4ebe508594bed5d7d7e1b64e414f52a2c..7f4dc062b4a59a341e761027709ef22b8da872f7 100644 (file)
@@ -51,7 +51,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
-#include "../libdw/libdwP.h"   /* DWARF_E_* values are here.  */
+#include "../libdw/relocate.h"
 
 
 /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
@@ -93,6 +93,9 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
       return DWFL_E (LIBELF, elf_errno ());
     }
 
+  if (unlikely (elf_getshdrstrndx (file->elf, &file->shstrndx)))
+    file->shstrndx = SHN_UNDEF;
+
   /* The addresses in an ET_EXEC file are absolute.  The lowest p_vaddr of
      the main file can differ from that of the debug file due to prelink.
      But that doesn't not change addresses that symbols, debuginfo, or
@@ -679,7 +682,7 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
   if (mod->dw->relocate != NULL)
     {
       assert (mod->e_type == ET_REL);
-      // mod->dw->relocate->dwflmod = mod;
+      mod->dw->relocate->dwflmod = mod;
     }
 
   /* Until we have iterated through all CU's, we might do lazy lookups.  */
@@ -688,6 +691,30 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
   return DWFL_E_NOERROR;
 }
 
+/* This is called from libdw/relocate.c when we need to digest relocs.  */
+void
+internal_function
+__libdwfl_relocate_setup (Dwarf *dbg, struct dwarf_section_reloc *r)
+{
+  Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+  assert (mod->dw == dbg);
+
+  if (dbg->relocate->ebl == NULL)
+    {
+      (void) __libdwfl_module_getebl (mod);
+      dbg->relocate->ebl = mod->ebl;
+    }
+
+  if (r->symdata == NULL)
+    {
+      find_symtab (mod);
+      r->symdata = mod->symdata;
+      r->symstrdata = mod->symstrdata;
+      r->symxndxdata = mod->symxndxdata;
+    }
+}
+
 /* Try to start up libdw on either the main file or the debuginfo file.  */
 static void
 find_dw (Dwfl_Module *mod)
index f78e6ec03fdcf3fc3296705d5bf319dbd8974b94..8cf2078403157127231eac030787a9a68f391088 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2006,2007,2009 Red Hat, Inc.
+   Copyright (C) 2006-2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -102,9 +102,8 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
        {
          /* In an ET_REL file, the symbol table values are relative
             to the section, not to the module's load base.  */
-         size_t symshstrndx = SHN_UNDEF;
          Dwfl_Error result = __libdwfl_relocate_value (mod, mod->symfile->elf,
-                                                       &symshstrndx,
+                                                       &mod->symfile->shstrndx,
                                                        shndx, &sym->st_value);
          if (unlikely (result != DWFL_E_NOERROR))
            {
index 062a647fd214f9f3b0b7f7069b382a2fdf9bace4..0a10ad1b70be95c0dfa2efbc1037c80bc13a7867 100644 (file)
@@ -250,6 +250,8 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
          m->main.elf = elf;
          m->main.bias = bias;
          m->e_type = ehdr->e_type;
+         if (unlikely (elf_getshdrstrndx (elf, &m->main.shstrndx)))
+           m->main.shstrndx = SHN_UNDEF;
        }
       else
        {
index 504b0fb1c651138cd148a058a127d38fce844af2..555c5bf042059875929b8e35d8280e578fba4aa4 100644 (file)
@@ -140,6 +140,7 @@ struct dwfl_file
   bool relocated;              /* Partial relocation of all sections done.  */
 
   Elf *elf;
+  size_t shstrndx;             /* Cache of elf_getshdrstrndx on elf.  */
   GElf_Addr bias;              /* Actual load address - p_vaddr.  */
 };
 
index 0313749a17f3bd166e19d7226dcf7c1a932ab1b9..b89de37efd8dd9c088d93435e5067c692ca5a04b 100644 (file)
@@ -48,6 +48,7 @@
    <http://www.openinventionnetwork.com>.  */
 
 #include "libdwflP.h"
+#include "../libdw/relocate.h"
 
 typedef uint8_t GElf_Byte;
 
@@ -615,3 +616,102 @@ __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
                               relocscn, gelf_getshdr (relocscn, &shdr_mem),
                               tscn, false));
 }
+
+int
+internal_function
+__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
+                       Dwarf_Addr *val)
+{
+  Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+  if (unlikely (mod == NULL)
+      || unlikely (mod->dwfl->callbacks->section_address == NULL))
+    {
+      __libdw_seterrno (DWARF_E_RELOC);
+      return -1;
+    }
+
+  assert (mod->dw == dbg);
+  assert (dbg->elf == mod->debug.elf);
+
+  *val = addend;
+  switch (__libdwfl_relocate_value (mod, mod->debug.elf, &mod->debug.shstrndx,
+                                   shndx, val))
+    {
+    case DWFL_E_NOERROR:
+      return 0;
+
+    case DWFL_E_LIBELF:
+      __libdw_seterrno (DWARF_E_RELBADSYM);
+      break;
+
+    default:
+      __libdw_seterrno (DWARF_E_RELUNDEF);
+      break;
+    }
+
+  return -1;
+}
+
+int
+internal_function
+__libdwfl_relocate_symbol (struct dwarf_section_reloc *r, bool undef,
+                          Dwarf *dbg, GElf_Sym *sym, GElf_Word shndx,
+                          GElf_Sxword *addend)
+{
+  if (!undef)
+    {
+      if (likely (__libdw_relocate_shndx (dbg, shndx, sym->st_value,
+                                         &sym->st_value) == 0))
+       {
+         *addend += sym->st_value;
+         return 1;
+       }
+    }
+  else
+    {
+      Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+      if (unlikely (mod == NULL)
+         || unlikely (mod->dwfl->callbacks->section_address == NULL))
+       {
+         __libdw_seterrno (DWARF_E_RELOC);
+         return -1;
+       }
+
+      assert (mod->dw == dbg);
+      assert (dbg->elf == mod->debug.elf);
+
+      assert (r->symdata != NULL);
+      assert (r->symstrdata != NULL);
+
+      Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
+      assert (symelf == mod->debug.elf || symelf == mod->main.elf);
+      struct reloc_symtab_cache symtab =
+       {
+         .symelf = symelf,
+         .symdata = r->symdata,
+         .symstrdata = r->symstrdata,
+         .symxndxdata = r->symxndxdata,
+         .symshstrndx = (symelf == mod->main.elf ? mod->main.shstrndx
+                         : mod->debug.shstrndx),
+       };
+
+      switch (resolve_symbol (mod, &symtab, sym, shndx))
+       {
+       case DWFL_E_NOERROR:
+         return 0;
+
+       case DWFL_E_LIBELF:
+       case DWFL_E_BADSTROFF:
+         __libdw_seterrno (DWARF_E_RELBADSYM);
+         break;
+
+       default:
+         __libdw_seterrno (DWARF_E_RELUNDEF);
+         break;
+       }
+    }
+
+  return -1;
+}