]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Provide virtual symbols for ppc64 function descriptors jankratochvil/ppc64bidir
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 6 Nov 2013 19:38:05 +0000 (20:38 +0100)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 2 Dec 2013 20:57:05 +0000 (21:57 +0100)
backends/
2013-11-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

Provide virtual symbols for ppc64 function descriptors.
* Makefile.am (ppc64_SRCS): Add ppc64_get_symbol.c.
* ppc64_get_symbol.c: New file.
* ppc64_init.c (ppc64_init): Install init_symbols, get_symbol and
destr.

libdwfl/
2013-11-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

* dwfl_module_addrsym.c (dwfl_module_addrsym): Adjust FIRST_GLOBAL also
for EBL_FIRST_GLOBAL.
* dwfl_module_getdwarf.c (getsym_helper): New function.
(find_symtab): Call also ebl_init_symbols.
(dwfl_module_getsymtab): Count also EBL_SYMENTS.
* dwfl_module_getsym.c (dwfl_module_getsym_elf): Count also
EBL_FIRST_GLOBAL, EBL_SYMENTS.  Call also ebl_get_symbol.
* libdwflP.h (DWFL_ERRORS): Add INVALID_INDEX.
(struct Dwfl_Module): Add fields ebl_syments and ebl_first_global.

libebl/
2013-11-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

Provide virtual symbols for ppc64 function descriptors.
* Makefile.am (gen_SOURCES): Add eblgetsymbol.c.
* ebl-hooks.h (init_symbols, get_symbol): New.
* eblgetsymbol.c: New file.
* libebl.h (ebl_getsym_t): New definition.
(ebl_init_symbols, ebl_get_symbol): New declarations.
* libeblP.h (struct ebl): New field backend.

tests/
2013-11-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

Provide virtual symbols for ppc64 function descriptors.
* Makefile.am (EXTRA_DIST): Add testfile66.bz2 and testfile66.core.bz2.
* dwflsyms.c (list_syms): Remove unused from parameter mod_name.  Print
error on dwfl_module_getsymtab error.
* run-addrname-test.sh (testfile66, testfile66.core): New tests.
* run-dwflsyms.sh (testfile66, testfile66.core, hello_ppc64.ko): New
tests.
* testfile66.bz2: New file.
* testfile66.core.bz2: New file.

Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
18 files changed:
backends/Makefile.am
backends/ppc64_get_symbol.c [new file with mode: 0644]
backends/ppc64_init.c
libdwfl/dwfl_module_addrsym.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsym.c
libdwfl/libdwflP.h
libebl/Makefile.am
libebl/ebl-hooks.h
libebl/eblgetsymbol.c [new file with mode: 0644]
libebl/libebl.h
libebl/libeblP.h
tests/Makefile.am
tests/dwflsyms.c
tests/run-addrname-test.sh
tests/run-dwflsyms.sh
tests/testfile66.bz2 [new file with mode: 0755]
tests/testfile66.core.bz2 [new file with mode: 0644]

index 9bca9941519070077a4006e7d5d9e0460b0765d6..40460ae738403c5dba1cc805fdabb650acf3dc69 100644 (file)
@@ -101,7 +101,7 @@ am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os)
 
 ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \
             ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
-            ppc_cfi.c
+            ppc_cfi.c ppc64_get_symbol.c
 libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
 am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
 
diff --git a/backends/ppc64_get_symbol.c b/backends/ppc64_get_symbol.c
new file mode 100644 (file)
index 0000000..4be84b1
--- /dev/null
@@ -0,0 +1,264 @@
+/* Provide virtual symbols for ppc64 function descriptors.
+   Copyright (C) 2013 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <endian.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define BACKEND ppc64_
+#include "libebl_CPU.h"
+
+/* Pointer to the first entry is stored into ebl->backend.
+   It has Dwfl_Module->ebl_syments entries and its memory is followed by
+   strings for the NAME entries.  */
+
+struct sym_entry
+{
+  GElf_Sym sym;
+  GElf_Word shndx;
+  const char *name;
+};
+
+/* Find section containing ADDR in its address range.  */
+
+static Elf_Scn *
+scnfindaddr (Elf *elf, GElf_Addr addr)
+{
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (likely (shdr != NULL)
+         && likely ((shdr->sh_flags & SHF_ALLOC) != 0)
+         && addr >= shdr->sh_addr
+         && addr < shdr->sh_addr + shdr->sh_size)
+       break;
+    }
+  return scn;
+}
+
+static int
+symnames_get_compar (const void *ap, const void *bp)
+{
+  const char *const *a = ap;
+  const char *const *b = bp;
+  return strcmp (*a, *b);
+}
+
+static const char **
+symnames_get (size_t syments, ebl_getsym_t *getsym, void *arg, bool is_linux,
+             size_t *symnames_countp)
+{
+  assert (syments > 0);
+  const char **symnames = malloc (syments * sizeof (*symnames));
+  if (symnames == NULL)
+    return NULL;
+  *symnames_countp = 0;
+  for (size_t symi = 0; symi < syments; symi++)
+    {
+      GElf_Sym sym;
+      const char *symname = getsym (arg, symi, &sym, NULL, NULL);
+      if (symname == NULL || symname[0] != '.')
+       continue;
+      if (GELF_ST_TYPE (sym.st_info) != STT_FUNC
+         && (! is_linux || GELF_ST_TYPE (sym.st_info) != STT_GNU_IFUNC))
+       continue;
+      symnames[(*symnames_countp)++] = &symname[1];
+    }
+  qsort (symnames, *symnames_countp, sizeof (*symnames), symnames_get_compar);
+  return symnames;
+}
+
+/* Scan all the symbols of EBL and create table of struct sym_entry entries for
+   every function symbol pointing to the .opd section.  This includes automatic
+   derefencing of the symbols via the .opd section content to create the
+   virtual symbols for the struct sym_entry entries.  As GETSYM points to
+   dwfl_module_getsym we scan all the available symbols, either
+   Dwfl_Module.main plus Dwfl_Module.aux_sym or Dwfl_Module.debug.
+   Symbols from all the available files are included in the SYMENTS count.
+
+   .opd section contents is described in:
+   http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES
+   http://www.ibm.com/developerworks/library/l-ppc/
+    - see: Function descriptors -- the .opd section  */
+
+bool
+ppc64_init_symbols (Ebl *ebl, size_t syments, GElf_Addr main_bias,
+                   ebl_getsym_t *getsym, void *arg, size_t *ebl_symentsp,
+                   int *ebl_first_globalp)
+{
+  assert (ebl != NULL);
+  assert (ebl->backend == NULL);
+  if (syments == 0)
+    return true;
+  Elf *elf = ebl->elf;
+  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return false;
+  GElf_Shdr opd_shdr_mem, *opd_shdr;
+  Elf_Data *opd_data = NULL;
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+    {
+      opd_shdr = gelf_getshdr (scn, &opd_shdr_mem);
+      if (opd_shdr == NULL || (opd_shdr->sh_flags & SHF_ALLOC) == 0)
+       continue;
+      if (strcmp (elf_strptr (elf, ehdr->e_shstrndx, opd_shdr->sh_name), ".opd")
+         != 0)
+       continue;
+      opd_data = elf_getdata (scn, NULL);
+      /* SHT_NOBITS will produce NULL D_BUF.  */
+      if (opd_data == NULL || opd_data->d_buf == NULL)
+       return false;
+      assert (opd_data->d_size == opd_shdr->sh_size);
+      break;
+    }
+  if (opd_data == NULL)
+    return true;
+  char *ident = elf_getident (elf, NULL);
+  bool is_linux = ident != NULL && ident[EI_OSABI] == ELFOSABI_LINUX;
+  size_t symnames_count;
+  const char **symnames = symnames_get (syments, getsym, arg, is_linux,
+                                       &symnames_count);
+  if (symnames == NULL)
+    return false;
+  struct sym_entry *sym_table = malloc (syments * sizeof (*sym_table));
+  if (sym_table == NULL)
+    {
+      free (symnames);
+      return false;
+    }
+  ebl->backend = sym_table;
+  size_t names_size = 0;
+  size_t ebl_syments = 0;
+  int ebl_first_global = 0;
+  for (size_t symi = 0; symi < syments; symi++)
+    {
+      GElf_Sym sym;
+      GElf_Word sym_shndx;
+      Elf *sym_elf;
+      const char *symname = getsym (arg, symi, &sym, &sym_shndx, &sym_elf);
+      if (symname == NULL || symname[0] == '.')
+       continue;
+      if (GELF_ST_TYPE (sym.st_info) != STT_FUNC
+         && (! is_linux || GELF_ST_TYPE (sym.st_info) != STT_GNU_IFUNC))
+       continue;
+      Elf_Scn *sym_scn = elf_getscn (sym_elf, sym_shndx);
+      if (sym_scn == NULL)
+       continue;
+      GElf_Shdr sym_shdr_mem, *sym_shdr;
+      sym_shdr = gelf_getshdr (sym_scn, &sym_shdr_mem);
+      if (sym_shdr == NULL)
+       continue;
+      GElf_Ehdr sym_ehdr_mem, *sym_ehdr = gelf_getehdr (sym_elf, &sym_ehdr_mem);
+      if (sym_ehdr == NULL)
+       continue;
+      if (strcmp (elf_strptr (sym_elf, sym_ehdr->e_shstrndx, sym_shdr->sh_name),
+                 ".opd")
+         != 0)
+       continue;
+      if (sym.st_value < opd_shdr->sh_addr + main_bias
+          || sym.st_value > (opd_shdr->sh_addr + main_bias
+                            + opd_shdr->sh_size - sizeof (uint64_t)))
+       continue;
+      if (bsearch (&symname, symnames, symnames_count, sizeof (*symnames),
+                  symnames_get_compar)
+         != 0)
+       continue;
+      uint64_t val64 = *(const uint64_t *) (opd_data->d_buf + sym.st_value
+                                           - (opd_shdr->sh_addr + main_bias));
+      val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+              ? be64toh (val64) : le64toh (val64));
+      Elf_Scn *entry_scn = scnfindaddr (elf, val64);
+      if (entry_scn == NULL)
+       continue;
+      if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
+       ebl_first_global++;
+      struct sym_entry *dest = &sym_table[ebl_syments];
+      dest->sym = sym;
+      dest->sym.st_value = val64 + main_bias;
+      dest->shndx = elf_ndxscn (entry_scn);
+      dest->sym.st_shndx = (dest->shndx > SHN_HIRESERVE
+                           ? SHN_XINDEX : dest->shndx);
+      dest->name = symname;
+      names_size += 1 + strlen (symname) + 1;
+      ebl_syments++;
+    }
+  free (symnames);
+  if (ebl_syments == 0)
+    {
+      free (sym_table);
+      ebl->backend = NULL;
+      return true;
+    }
+  sym_table = realloc (sym_table,
+                      ebl_syments * sizeof (*sym_table) + names_size);
+  if (sym_table == NULL)
+    return false;
+  ebl->backend = sym_table;
+  char *names = (void *) &sym_table[ebl_syments];
+  char *names_dest = names;
+  for (size_t symi = 0; symi < ebl_syments; symi++)
+    {
+      struct sym_entry *dest = &sym_table[symi];
+      const char *symname = dest->name;
+      dest->name = names_dest;
+      *names_dest++ = '.';
+      names_dest = stpcpy (names_dest, symname) + 1;
+    }
+  assert (names_dest == names + names_size);
+  *ebl_symentsp = ebl_syments;
+  *ebl_first_globalp = ebl_first_global;
+  return true;
+}
+
+const char *
+ppc64_get_symbol (Ebl *ebl, size_t ndx, GElf_Sym *symp, GElf_Word *shndxp)
+{
+  assert (ebl != NULL);
+  if (ebl->backend == NULL)
+    return NULL;
+  struct sym_entry *sym_table = ebl->backend;
+  const struct sym_entry *found = &sym_table[ndx];
+  *symp = found->sym;
+  if (shndxp)
+    *shndxp = found->shndx;
+  return found->name;
+}
+
+void
+ppc64_destr (Ebl *ebl)
+{
+  free (ebl->backend);
+}
index 1435875461d7cdb0fbe6d59c845d606b5f901b39..3ed882bbca6c2f65ecff7524b523e1bd0721ea29 100644 (file)
@@ -65,6 +65,9 @@ ppc64_init (elf, machine, eh, ehlen)
   HOOK (eh, core_note);
   HOOK (eh, auxv_info);
   HOOK (eh, abi_cfi);
+  HOOK (eh, init_symbols);
+  HOOK (eh, get_symbol);
+  HOOK (eh, destr);
 
   return MODVERSION;
 }
index 320d41f185c59ed8a8df846b4df2fc16d470eab2..b11ba75627d4f5b2029d9b8bffac47730e32d4f1 100644 (file)
@@ -179,16 +179,17 @@ dwfl_module_addrsym_elf (Dwfl_Module *mod, GElf_Addr addr,
        }
     }
 
-  /* First go through global symbols.  mod->first_global and
-     mod->aux_first_global are setup by dwfl_module_getsymtab to the
-     index of the first global symbol in those symbol tables.  Both
-     are non-zero when the table exist, except when there is only a
-     dynsym table loaded through phdrs, then first_global is zero and
-     there will be no auxiliary table.  All symbols with local binding
-     come first in the symbol table, then all globals.  The zeroth,
-     null entry, in the auxiliary table is skipped if there is a main
-     table.  */
-  int first_global = mod->first_global + mod->aux_first_global;
+  /* First go through global symbols.  mod->first_global,
+     mod->aux_first_global and mod->ebl_first_global are setup by
+     dwfl_module_getsymtab to the index of the first global symbol in
+     those symbol tables.  Both are non-zero when the table exist,
+     except when there is only a dynsym table loaded through phdrs, then
+     first_global is zero and there will be no auxiliary table.  All
+     symbols with local binding come first in the symbol table, then all
+     globals.  The zeroth, null entry, in the auxiliary table is skipped
+     if there is a main table.  */
+  int first_global = (mod->first_global + mod->aux_first_global
+                     + mod->ebl_first_global);
   if (mod->syments > 0 && mod->aux_syments > 0)
     first_global--;
   search_table (first_global == 0 ? 1 : first_global, syments);
index dd76f2579ae5a61d37985363e66de10a2bd5c5c5..223374cd6219257bff6c24677dcb4a9453c3fd5a 100644 (file)
@@ -962,6 +962,13 @@ find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
 #endif
 }
 
+static const char *
+getsym_helper (void *arg, int ndx, GElf_Sym *sym, GElf_Word *shndxp, Elf **elfp)
+{
+  Dwfl_Module *mod = arg;
+  return dwfl_module_getsym_elf (mod, ndx, sym, shndxp, elfp, NULL);
+}
+
 /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
 static void
 find_symtab (Dwfl_Module *mod)
@@ -1081,7 +1088,7 @@ find_symtab (Dwfl_Module *mod)
          mod->aux_syments = 0;
          elf_end (mod->aux_sym.elf);
          mod->aux_sym.elf = NULL;
-         return;
+         goto aux_done;
        }
 
       mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf,
@@ -1102,7 +1109,14 @@ find_symtab (Dwfl_Module *mod)
       mod->aux_symdata = elf_getdata (aux_symscn, NULL);
       if (mod->aux_symdata == NULL)
        goto aux_cleanup;
+  aux_done:;
     }
+
+  Dwfl_Error error = __libdwfl_module_getebl (mod);
+  if (error == DWFL_E_NOERROR)
+    ebl_init_symbols (mod->ebl, mod->syments + mod->aux_syments,
+                     mod->main_bias, getsym_helper, mod,
+                     &mod->ebl_syments, &mod->ebl_first_global);
 }
 
 
@@ -1259,7 +1273,7 @@ dwfl_module_getsymtab (Dwfl_Module *mod)
   find_symtab (mod);
   if (mod->symerr == DWFL_E_NOERROR)
     /* We will skip the auxiliary zero entry if there is another one.  */
-    return (mod->syments + mod->aux_syments
+    return (mod->syments + mod->aux_syments + mod->ebl_syments
            - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0));
 
   __libdwfl_seterrno (mod->symerr);
index 319f97586c7e4c154e2ad78aabbfa3af879c95d6..42eb43bbc43f95a908f36019be7262845dd51cd0 100644 (file)
@@ -54,8 +54,7 @@ dwfl_module_getsym_elf (Dwfl_Module *mod, int ndx,
   Elf_Data *symdata;
   Elf_Data *symxndxdata;
   Elf_Data *symstrdata;
-  if (mod->aux_symdata == NULL
-      || ndx < mod->first_global)
+  if (ndx < mod->first_global)
     {
       /* main symbol table (locals).  */
       tndx = ndx;
@@ -73,24 +72,61 @@ dwfl_module_getsym_elf (Dwfl_Module *mod, int ndx,
       symxndxdata = mod->aux_symxndxdata;
       symstrdata = mod->aux_symstrdata;
     }
-  else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
+  else if (ndx < (mod->first_global + mod->aux_first_global
+                 + mod->ebl_first_global - skip_aux_zero))
+    {
+      /* ebl symbol lookup (locals).  */
+      symdata = NULL;
+      tndx = ndx - (mod->first_global + mod->aux_first_global - skip_aux_zero);
+    }
+  else if ((size_t) ndx < (mod->syments + mod->aux_first_global
+                          + mod->ebl_first_global - skip_aux_zero))
     {
       /* main symbol table (globals).  */
-      tndx = ndx - mod->aux_first_global + skip_aux_zero;
+      tndx = ndx - (mod->aux_first_global + mod->ebl_first_global
+                   - skip_aux_zero);
       elf = mod->symfile->elf;
       symdata = mod->symdata;
       symxndxdata = mod->symxndxdata;
       symstrdata = mod->symstrdata;
     }
-  else
+  else if ((size_t) ndx < (mod->syments + mod->aux_syments
+                          + mod->ebl_first_global - skip_aux_zero))
     {
       /* aux symbol table (globals).  */
-      tndx = ndx - mod->syments + skip_aux_zero;
+      tndx = ndx - (mod->syments + mod->ebl_first_global - skip_aux_zero);
       elf = mod->aux_sym.elf;
       symdata = mod->aux_symdata;
       symxndxdata = mod->aux_symxndxdata;
       symstrdata = mod->aux_symstrdata;
     }
+  else if ((size_t) ndx < (mod->syments + mod->aux_syments
+                          + mod->ebl_syments - skip_aux_zero))
+    {
+      /* ebl symbol lookup (globals).  */
+      symdata = NULL;
+      tndx = ndx - (mod->syments + mod->aux_syments - skip_aux_zero);
+    }
+  else
+    {
+      /* out of range NDX.  */
+      __libdwfl_seterrno (DWFL_E_INVALID_INDEX);
+      return NULL;
+    }
+
+  if (symdata == NULL)
+    {
+      const char *name = ebl_get_symbol (mod->ebl, tndx, sym, shndxp);
+      if (likely (name != NULL))
+       {
+         if (elfp)
+           *elfp = mod->main.elf;
+         return name;
+       }
+      __libdwfl_seterrno (DWFL_E_LIBEBL);
+      return NULL;
+    }
+
   sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
 
   if (unlikely (sym == NULL))
index ba1c758d5867884cfe22d0e9b13524ac4978097a..89e78fc17a6adccc596e8626da7666d0b11dc436 100644 (file)
@@ -89,7 +89,8 @@ typedef struct Dwfl_Process Dwfl_Process;
   DWFL_ERROR (ATTACH_STATE_CONFLICT, N_("Dwfl already has attached state"))   \
   DWFL_ERROR (NO_ATTACH_STATE, N_("Dwfl has no attached state"))             \
   DWFL_ERROR (NO_UNWIND, N_("Unwinding not supported for this architecture")) \
-  DWFL_ERROR (INVALID_ARGUMENT, N_("Invalid argument"))
+  DWFL_ERROR (INVALID_ARGUMENT, N_("Invalid argument"))                              \
+  DWFL_ERROR (INVALID_INDEX, N_("invalid section index"))
 
 #define DWFL_ERROR(name, text) DWFL_E_##name,
 typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error;
@@ -173,8 +174,10 @@ struct Dwfl_Module
   Elf_Data *aux_symdata;       /* Data in the auxiliary ELF symbol table.  */
   size_t syments;              /* sh_size / sh_entsize of that section.  */
   size_t aux_syments;          /* sh_size / sh_entsize of aux_sym section.  */
+  size_t ebl_syments;          /* Number of symbols from ebl_getsym.  */
   int first_global;            /* Index of first global symbol of table.  */
   int aux_first_global;                /* Index of first global of aux_sym table.  */
+  int ebl_first_global;                /* Index of first global from ebl_getsym.  */
   Elf_Data *symstrdata;                /* Data for its string table.  */
   Elf_Data *aux_symstrdata;    /* Data for aux_sym string table.  */
   Elf_Data *symxndxdata;       /* Data in the extended section index table. */
index 4487c5f9797d89929047a1d48dce5da20fe4ab84..1fb3da311b0728c042029d7bbd823bf561bd7a9f 100644 (file)
@@ -54,7 +54,7 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \
              eblreginfo.c eblnonerelocp.c eblrelativerelocp.c \
              eblsysvhashentrysize.c eblauxvinfo.c eblcheckobjattr.c \
              ebl_check_special_section.c ebl_syscall_abi.c eblabicfi.c \
-             eblstother.c eblinitreg.c
+             eblstother.c eblinitreg.c eblgetsymbol.c
 
 libebl_a_SOURCES = $(gen_SOURCES)
 
index cb52fee4060004bc34924a1b6b4f1eaa0e5cbea6..7204514bae36f0b03fc18fcfdb5717eb51985d6d 100644 (file)
@@ -162,5 +162,14 @@ bool EBLHOOK(set_initial_registers_tid) (pid_t tid,
                                         ebl_tid_registers_t *setfunc,
                                         void *arg);
 
+/* See ebl_init_symbols.  */
+bool EBLHOOK(init_symbols) (Ebl *ebl, size_t syments, GElf_Addr main_bias,
+                           ebl_getsym_t *getsym, void *arg,
+                           size_t *ebl_symentsp, int *ebl_first_globalp);
+
+/* See ebl_get_symbol.  */
+const char *EBLHOOK(get_symbol) (Ebl *ebl, size_t ndx, GElf_Sym *symp,
+                                GElf_Word *shndxp);
+
 /* Destructor for ELF backend handle.  */
 void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblgetsymbol.c b/libebl/eblgetsymbol.c
new file mode 100644 (file)
index 0000000..ef664bf
--- /dev/null
@@ -0,0 +1,57 @@
+/* Provide virtual symbols from backend.
+   Copyright (C) 2013 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libeblP.h>
+#include <assert.h>
+
+bool
+ebl_init_symbols (Ebl *ebl, size_t syments, GElf_Addr main_bias,
+                 ebl_getsym_t *getsym, void *arg, size_t *ebl_symentsp,
+                 int *ebl_first_globalp)
+{
+  *ebl_symentsp = 0;
+  *ebl_first_globalp = 0;
+  if (ebl == NULL)
+    return false;
+  if (ebl->init_symbols == NULL)
+    return true;
+  return ebl->init_symbols (ebl, syments, main_bias, getsym, arg, ebl_symentsp,
+                           ebl_first_globalp);
+}
+
+const char *
+ebl_get_symbol (Ebl *ebl, size_t ndx, GElf_Sym *symp, GElf_Word *shndxp)
+{
+  if (ebl == NULL || ebl->get_symbol == NULL)
+    return NULL;
+  return ebl->get_symbol (ebl, ndx, symp, shndxp);
+}
index 045a198092cefba033be2f1e42d049436b6899a8..d81715321cc8bc0ebdd36374e15175fdba7142f2 100644 (file)
@@ -402,6 +402,34 @@ extern bool ebl_set_initial_registers_tid (Ebl *ebl,
 extern size_t ebl_frame_nregs (Ebl *ebl)
   __nonnull_attribute__ (1);
 
+/* Callback type for ebl_init_symbols,
+   it is forwarded to dwfl_module_getsym_elf.  */
+typedef const char *(ebl_getsym_t) (void *arg, int ndx, GElf_Sym *symp,
+                                   GElf_Word *shndxp, Elf **elfp)
+  __nonnull_attribute__ (3);
+
+/* Initialize virtual backend symbol table for EBL->elf currently containing
+   SYMENTS symbols, EBL->elf is using MAIN_BIAS.  GETSYM is a callback to fetch
+   the existing EBL->elf symbols, ARG is an opaque parameter for GETSYM.
+   Fill in *EBL_SYMENTSP with the total number of virtual symbols found,
+   *EBL_FIRST_GLOBALP of them are local.  Function must be called exactly once
+   for new EBL.  Function returns false if there was an error; *EBL_SYMENTSP
+   and *EBL_FIRST_GLOBALP are left as zero in such case.  If function returns
+   true (success) *EBL_SYMENTSP and *EBL_FIRST_GLOBALP still can be zero,
+   if the file does not contain any matching symbols.  */
+extern bool ebl_init_symbols (Ebl *ebl, size_t syments, Dwarf_Addr symbias,
+                             ebl_getsym_t *getsym, void *arg,
+                             size_t *ebl_symentsp, int *ebl_first_globalp)
+  __nonnull_attribute__ (1, 4, 6, 7);
+
+/* Return NDXth virtual backend symbol from MOD, store it to *SYM and its
+   section to *SHNDX.  Return its name.  NDX must be less than *EBL_SYMENTSP
+   returned by init_symbols above.  SHNDXP may be NULL.  Returned name is valid
+   as long as EBL is valid.  */
+extern const char *ebl_get_symbol (Ebl *ebl, size_t ndx, GElf_Sym *symp,
+                                  GElf_Word *shndxp)
+  __nonnull_attribute__ (1, 3);
+
 #ifdef __cplusplus
 }
 #endif
index 4f4137d59b78c4d4cc3dc4aee7ed1fdd584b4e25..328205074a28b9a2459f99b98595623a53f3c627 100644 (file)
@@ -66,6 +66,9 @@ struct ebl
 
   /* Internal data.  */
   void *dlhandle;
+
+  /* Data specific to the backend.  */
+  void *backend;
 };
 
 
index a74830ba3ecfb603583cdb537c1c818640f90050..f57333c895550b45d4dc4f8e48f2ba989249118f 100644 (file)
@@ -245,7 +245,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             run-backtrace-native-core.sh run-backtrace-native-core-biarch.sh \
             run-backtrace-core-x86_64.sh run-backtrace-core-i386.sh \
             backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \
-            backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2
+            backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 \
+            testfile66.bz2 testfile66.core.bz2
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no'
index 10c01f1f02a5228610c4bdf002f1707726db5f80..19f1dbebe86d9fe11564d805e604d7469fbad3a1 100644 (file)
@@ -106,13 +106,16 @@ addr_in_section (Elf *elf, GElf_Word shndx, GElf_Addr addr)
 
 static int
 list_syms (struct Dwfl_Module *mod,
-          void **user __attribute__ ((unused)),
-          const char *mod_name __attribute__ ((unused)),
+          void **user __attribute__ ((unused)), const char *mod_name,
           Dwarf_Addr low_addr __attribute__ ((unused)),
           void *arg __attribute__ ((unused)))
 {
   int syms = dwfl_module_getsymtab (mod);
-  assert (syms >= 0);
+  if (syms < 0)
+    {
+      printf ("%s: %s\n", mod_name, dwfl_errmsg (-1));
+      return DWARF_CB_OK;
+    }
 
   for (int ndx = 0; ndx < syms; ndx++)
     {
index 8624074fa17474784917c62306c7712251f9c878..bdf8ea6a0834faf4bd68f4efe452d079345dd27a 100755 (executable)
@@ -298,6 +298,45 @@ __vdso_time
 ??:0
 EOF
 
+#      .section        ".text"
+#      .globl _start
+#      .section        ".opd","aw"
+#_start:       .quad   .L._start,.TOC.@tocbase
+#      .previous
+#      .type   _start, @function
+#.L._start:
+#      .byte   0x7d, 0x82, 0x10, 0x08
+#      .size   _start,.-.L._start
+testfiles testfile66 testfile66.core
+testrun_compare ${abs_top_builddir}/src/addr2line -S -e testfile66 _start 0x103d0 0x103d3 0x103d4 ._start 0x2d8 0x2db 0x2dc <<\EOF
+_start
+??:0
+_start
+??:0
+_start+0x3
+??:0
+()+0x103d4
+??:0
+._start
+??:0
+._start
+??:0
+._start+0x3
+??:0
+()+0x2dc
+??:0
+EOF
+testrun_compare ${abs_top_builddir}/src/addr2line -S -e testfile66 --core=testfile66.core _start 0x461c03d0 ._start 0x461b02d8 <<\EOF
+_start
+??:0
+_start
+??:0
+._start
+??:0
+._start
+??:0
+EOF
+
 testfiles testfile69.core testfile69.so
 testrun_compare ${abs_top_builddir}/src/addr2line --core=./testfile69.core -S 0x7f0bc6a33535 0x7f0bc6a33546 <<\EOF
 libstatic+0x9
index 3cd7bf3687a5d5d23b5b6a0753a59895ab51a06e..60909051fa2b390aa2d39fe8bb71fce8eff24ada 100755 (executable)
@@ -362,4 +362,104 @@ testrun_compare ${abs_builddir}/dwflsyms -e testfilebasmin <<\EOF
    8: FUNC     GLOBAL  bar (44) 0x40017a, rel: 0x40017a (.text)
 EOF
 
+testfiles testfile66
+testrun_compare ${abs_builddir}/dwflsyms -e testfile66 <<\EOF
+   0: NOTYPE   LOCAL    (0) 0
+   1: SECTION  LOCAL    (0) 0x190
+   2: SECTION  LOCAL    (0) 0x1a4
+   3: SECTION  LOCAL    (0) 0x1c8
+   4: SECTION  LOCAL    (0) 0x1f8
+   5: SECTION  LOCAL    (0) 0x288
+   6: SECTION  LOCAL    (0) 0x2a8
+   7: SECTION  LOCAL    (0) 0x2d8
+   8: SECTION  LOCAL    (0) 0x102e0
+   9: SECTION  LOCAL    (0) 0x103d0
+  10: SECTION  LOCAL    (0) 0x103e8
+  11: SECTION  LOCAL    (0) 0x103e8
+  12: OBJECT   LOCAL   _DYNAMIC (0) 0x102e0
+  13: FUNC     GLOBAL  _start (4) 0x103d0, rel: 0x103d0 (.opd)
+  14: NOTYPE   GLOBAL  __bss_start (0) 0x103f0
+  15: NOTYPE   GLOBAL  _edata (0) 0x103f0
+  16: NOTYPE   GLOBAL  _end (0) 0x103f0
+  17: FUNC     GLOBAL  ._start (4) 0x2d8, rel: 0x2d8 (.text)
+EOF
+
+testfiles testfile66.core
+testrun_compare ${abs_builddir}/dwflsyms -e testfile66 --core=testfile66.core <<\EOF
+   0: NOTYPE   LOCAL    (0) 0
+   1: SECTION  LOCAL    (0) 0xfffb1af0410
+   2: NOTYPE   GLOBAL  __kernel_datapage_offset (0) 0xfffb1af05dc
+   3: OBJECT   GLOBAL  LINUX_2.6.15 (0) 0
+   4: NOTYPE   GLOBAL  __kernel_clock_getres (64) 0xfffb1af052c
+   5: NOTYPE   GLOBAL  __kernel_get_tbfreq (24) 0xfffb1af0620
+   6: NOTYPE   GLOBAL  __kernel_gettimeofday (84) 0xfffb1af0440
+   7: NOTYPE   GLOBAL  __kernel_sync_dicache (20) 0xfffb1af06c4
+   8: NOTYPE   GLOBAL  __kernel_sync_dicache_p5 (20) 0xfffb1af06c4
+   9: NOTYPE   GLOBAL  __kernel_sigtramp_rt64 (12) 0xfffb1af0418
+  10: NOTYPE   GLOBAL  __kernel_clock_gettime (152) 0xfffb1af0494
+  11: NOTYPE   GLOBAL  __kernel_get_syscall_map (44) 0xfffb1af05f4
+ld64.so.1: Callback returned failure
+   0: NOTYPE   LOCAL    (0) 0
+   1: SECTION  LOCAL    (0) 0x461b0190
+   2: SECTION  LOCAL    (0) 0x461b01a4
+   3: SECTION  LOCAL    (0) 0x461b01c8
+   4: SECTION  LOCAL    (0) 0x461b01f8
+   5: SECTION  LOCAL    (0) 0x461b0288
+   6: SECTION  LOCAL    (0) 0x461b02a8
+   7: SECTION  LOCAL    (0) 0x461b02d8
+   8: SECTION  LOCAL    (0) 0x461c02e0
+   9: SECTION  LOCAL    (0) 0x461c03d0
+  10: SECTION  LOCAL    (0) 0x461c03e8
+  11: SECTION  LOCAL    (0) 0x461c03e8
+  12: OBJECT   LOCAL   _DYNAMIC (0) 0x102e0
+  13: FUNC     GLOBAL  _start (4) 0x461c03d0, rel: 0x103d0 (.opd)
+  14: NOTYPE   GLOBAL  __bss_start (0) 0x103f0
+  15: NOTYPE   GLOBAL  _edata (0) 0x103f0
+  16: NOTYPE   GLOBAL  _end (0) 0x103f0
+  17: FUNC     GLOBAL  ._start (4) 0x461b02d8, rel: 0x2d8 (.text)
+EOF
+
+# Test the already present dot-prefixed names do not get duplicated.
+testfiles hello_ppc64.ko
+testrun_compare ${abs_builddir}/dwflsyms -e hello_ppc64.ko <<\EOF
+   0: NOTYPE   LOCAL    (0) 0
+   1: SECTION  LOCAL    (0) 0
+   2: SECTION  LOCAL    (0) 0x94
+   3: SECTION  LOCAL    (0) 0xba
+   4: SECTION  LOCAL    (0) 0xd0
+   5: SECTION  LOCAL    (0) 0x13a
+   6: SECTION  LOCAL    (0) 0x13a
+   7: SECTION  LOCAL    (0) 0x150
+   8: SECTION  LOCAL    (0) 0x170
+   9: SECTION  LOCAL    (0) 0x188
+  10: SECTION  LOCAL    (0) 0x410
+  11: SECTION  LOCAL    (0) 0x434
+  12: SECTION  LOCAL    (0) 0x438
+  13: SECTION  LOCAL    (0) 0x438
+  14: SECTION  LOCAL    (0) 0
+  15: SECTION  LOCAL    (0) 0
+  16: SECTION  LOCAL    (0) 0
+  17: SECTION  LOCAL    (0) 0
+  18: SECTION  LOCAL    (0) 0
+  19: SECTION  LOCAL    (0) 0
+  20: SECTION  LOCAL    (0) 0
+  21: SECTION  LOCAL    (0) 0
+  22: SECTION  LOCAL    (0) 0
+  23: SECTION  LOCAL    (0) 0
+  24: FILE     LOCAL   init.c (0) 0
+  25: FILE     LOCAL   exit.c (0) 0
+  26: FILE     LOCAL   hello.mod.c (0) 0
+  27: OBJECT   LOCAL   __mod_srcversion23 (35) 0xd0
+  28: OBJECT   LOCAL   __module_depends (9) 0xf8
+  29: OBJECT   LOCAL   __mod_vermagic5 (50) 0x108
+  30: OBJECT   GLOBAL  __this_module (648) 0x188
+  31: FUNC     GLOBAL  .cleanup_module (72) 0x4c, rel: 0x4c (.text)
+  32: FUNC     GLOBAL  cleanup_module (24) 0x160, rel: 0x10 (.opd)
+  33: NOTYPE   GLOBAL  .printk (0) 0
+  34: FUNC     GLOBAL  init_module (24) 0x150, rel: 0 (.opd)
+  35: NOTYPE   GLOBAL  ._mcount (0) 0
+  36: FUNC     GLOBAL  .init_module (76) 0, rel: 0 (.text)
+  37: NOTYPE   GLOBAL  _mcount (0) 0
+EOF
+
 exit 0
diff --git a/tests/testfile66.bz2 b/tests/testfile66.bz2
new file mode 100755 (executable)
index 0000000..4797590
Binary files /dev/null and b/tests/testfile66.bz2 differ
diff --git a/tests/testfile66.core.bz2 b/tests/testfile66.core.bz2
new file mode 100644 (file)
index 0000000..12e2d44
Binary files /dev/null and b/tests/testfile66.core.bz2 differ