[patch] Resolve ppc64 func descriptors as .func (via .opd)

Jan Kratochvil jan.kratochvil at redhat.com
Tue Oct 9 08:13:20 UTC 2012


Hi,

patch has dependency on:
	Re: [patch] Fix bias for vDSOs from core files
	https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/002649.html

(gdb) info addr main
Symbol "main" is at 0x10556708 in a file compiled without debugging.
(gdb) info addr .main
Symbol ".main" is at 0x100562d0 in a file compiled without debugging.
  Entry point address:               0x105566b8
Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [26] .opd              PROGBITS        00000000105566b8 5566b8 024458 00  WA  0   0  8
  [13] .text             PROGBITS        00000000100526a8 0526a8 36c258 00  AX  0   0  8
$ eu-addr2line -e /usr/bin/gdb -S 0x10556708 0x100562d0
FAIL:
main
??:0
??
??:0
PASS:
main
??:0
.main
??:0

So far elfutils resolves addresses from function descriptors but not the real
code addresses.

It does not work universally like bfd artificial ELF symbols do, only
dwfl_module_addrsym is patched; but I find it good enough as I could not find
some easy enough way for elfutils first-class artificial ELF symbols.

I had to add all the INCLUDES entries because ebl-hooks.h declaration depends
on Dwfl_Module now.

In backends/ppc64_get_func_pc.c I was considering fixedsizehash.h instead of
qsort + bsearch but one needs to search by a block of bytes but
fixedsizehash.h can search only by strings.

Use there conversion by
+      val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+               ? be64toh (val64) : le64toh (val64));
While I used first src/readelf.c function "convert" I do not much understand
its purpose, it does not handle properly different sizes of indata / valuedata
anyway and it is more complicated than to just convert it by hand as above.


Thanks,
Jan


backends/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* Makefile.am (INCLUDES): Add libdwfl.
	(ppc64_SRCS): Add ppc64_get_func_pc.c.
	* ppc64_get_func_pc.c: New file.
	* ppc64_init.c (ppc64_init): Install get_func_pc and destr.

libasm/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* Makefile.am (INCLUDES): Add libdwfl.

libcpu/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* Makefile.am (INCLUDES): Add libdwfl.

libdw/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* Makefile.am (INCLUDES): Add libdwfl.

libdwfl/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* dwfl_module_addrsym.c (dwfl_module_addrsym) (get_section): New
	function from ...
	(dwfl_module_addrsym) (same_section): ... here.  Call it.
	(dwfl_module_addrsym) (found_sym): New function from ...
	(dwfl_module_addrsym) (search_table): ... here.  Call it.  Try second
	time with ebl_get_func_pc.

libebl/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* Makefile.am (INCLUDES): Add libdwfl.
	(gen_SOURCES): Add eblgetfuncpc.c.
	* ebl-hooks.h (get_func_pc): New entry.
	* eblgetfuncpc.c: New file.
	* libebl.h: Include libdwfl.h.
	(ebl_get_func_pc): New declaration.
	* libeblP.h (struct ebl): New field backend.

tests/
2012-10-09  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* run-addrname-test.sh: New testcase for ppc64 function descriptors.
	* testfile66.bz2: New file.

diff --git a/backends/Makefile.am b/backends/Makefile.am
index 982ff2a..f52c493 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -29,7 +29,7 @@
 ## not, see <http://www.gnu.org/licenses/>.
 include $(top_srcdir)/config/eu.am
 INCLUDES += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
-	   -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw
+	    -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwfl
 
 
 modules = i386 sh x86_64 ia64 alpha arm sparc ppc ppc64 s390 tilegx
@@ -90,7 +90,8 @@ libebl_ppc_pic_a_SOURCES = $(ppc_SRCS)
 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
+	     ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
+	     ppc64_get_func_pc.c
 libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
 am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
 
diff --git a/backends/ppc64_get_func_pc.c b/backends/ppc64_get_func_pc.c
new file mode 100644
index 0000000..f6df6e2
--- /dev/null
+++ b/backends/ppc64_get_func_pc.c
@@ -0,0 +1,195 @@
+/* Convert function descriptor SYM to the function PC value in-place.
+   Copyright (C) 2005-2010 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 "../libdwfl/libdwflP.h"
+#include <endian.h>
+
+#define BACKEND ppc64_
+#include "libebl_CPU.h"
+
+struct pc_entry
+{
+  /* sym_from must be the very first element for the use in bsearch below.  */
+  GElf_Sym sym_from;
+  Elf64_Addr st_value_to;
+  const char *name_to;
+};
+
+struct pc_table
+{
+  size_t nelem;
+  struct pc_entry a[];
+  /* Here follow strings allocated for pc_entry->name_to.  */
+};
+
+static int
+compar (const void *a_voidp, const void *b_voidp)
+{
+  const struct pc_entry *a = a_voidp;
+  const struct pc_entry *b = b_voidp;
+
+  return memcmp (&a->sym_from, &b->sym_from, sizeof (a->sym_from));
+}
+
+static void
+init (Ebl *ebl, Dwfl_Module *mod)
+{
+  int syments = dwfl_module_getsymtab (mod);
+  assert (syments >= 0);
+  GElf_Sym sym;
+  size_t funcs = 0;
+  size_t names_size = 0;
+  Elf *elf = ebl->elf;
+  if (elf == NULL)
+    return;
+  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return;
+  GElf_Word shndx, opd_shndx = 0;
+  /* Needless initialization for old GCCs.  */
+  Elf_Data *opd_data = NULL;
+  /* Needless initialization for old GCCs.  */
+  GElf_Shdr opd_shdr_mem, *opd_shdr = NULL;
+  for (int symi = 1; symi < syments; symi++)
+    {
+      if (dwfl_module_getsym (mod, symi, &sym, &shndx) == NULL
+	  || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+	continue;
+      if (sym.st_shndx != SHN_XINDEX)
+	shndx = sym.st_shndx;
+      /* Zero is invalid value but it could crash this code.  */
+      if (shndx == 0)
+	continue;
+      if (opd_shndx == 0)
+	{
+	  Elf_Scn *scn = elf_getscn (elf, shndx);
+	  if (scn == NULL)
+	    continue;
+	  opd_shdr = gelf_getshdr (scn, &opd_shdr_mem);
+	  if (opd_shdr == NULL)
+	    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;
+	  assert (opd_data->d_size == opd_shdr->sh_size);
+	  opd_shndx = shndx;
+	}
+      if (shndx != opd_shndx)
+	continue;
+      Elf64_Addr val;
+      if (sym.st_value < opd_shdr->sh_addr + mod->main_bias
+          || sym.st_value > (opd_shdr->sh_addr + mod->main_bias
+			     + opd_shdr->sh_size - sizeof (val)))
+	continue;
+      if (unlikely (sym.st_name >= mod->symstrdata->d_size))
+	continue;
+      funcs++;
+      const char *name = mod->symstrdata->d_buf + sym.st_name;
+      names_size += 1 + strlen (name) + 1;
+    }
+  struct pc_table *pc_table;
+  pc_table = malloc (sizeof (*pc_table) + funcs * sizeof (*pc_table->a)
+		     + names_size);
+  if (pc_table == NULL)
+    return;
+  ebl->backend = pc_table;
+  pc_table->nelem = 0;
+  if (funcs == 0)
+    return;
+  struct pc_entry *dest = pc_table->a;
+  char *names = (void *) (pc_table->a + funcs), *names_dest = names;
+  for (int symi = 1; symi < syments; symi++)
+    {
+      if (dwfl_module_getsym (mod, symi, &sym, &shndx) == NULL
+	  || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+	continue;
+      if (sym.st_shndx != SHN_XINDEX)
+	shndx = sym.st_shndx;
+      if (shndx != opd_shndx)
+	continue;
+      uint64_t val64;
+      if (sym.st_value < opd_shdr->sh_addr + mod->main_bias
+          || sym.st_value > (opd_shdr->sh_addr + mod->main_bias
+			     + opd_shdr->sh_size - sizeof (val64)))
+	continue;
+      val64 = *(const uint64_t *) (opd_data->d_buf + sym.st_value
+				   - (opd_shdr->sh_addr + mod->main_bias));
+      val64 = (elf_getident (elf, NULL)[EI_DATA] == ELFDATA2MSB
+               ? be64toh (val64) : le64toh (val64));
+      assert (dest < pc_table->a + funcs);
+      dest->sym_from = sym;
+      dest->st_value_to = val64 + mod->main_bias;
+      assert (sym.st_name < mod->symstrdata->d_size);
+      const char *name = mod->symstrdata->d_buf + sym.st_name;
+      dest->name_to = names_dest;
+      *names_dest++ = '.';
+      names_dest = stpcpy (names_dest, name) + 1;
+      dest++;
+      pc_table->nelem++;
+    }
+  assert (pc_table->nelem == funcs);
+  assert (dest == pc_table->a + pc_table->nelem);
+  assert (names_dest == names + names_size);
+  qsort (pc_table->a, pc_table->nelem, sizeof (*pc_table->a), compar);
+}
+
+const char *
+ppc64_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+{
+  if (ebl->backend == NULL)
+    init (ebl, mod);
+  if (ebl->backend == NULL)
+    return NULL;
+  const struct pc_table *pc_table = ebl->backend;
+  const struct pc_entry *found;
+  found = bsearch (sym, pc_table->a, pc_table->nelem, sizeof (*pc_table->a),
+		   compar);
+  if (found == NULL)
+    return NULL;
+  sym->st_value = found->st_value_to;
+  return found->name_to;
+}
+
+void
+ppc64_destr (Ebl *ebl)
+{
+  if (ebl->backend == NULL)
+    return;
+  struct pc_table *pc_table = ebl->backend;
+  free (pc_table);
+  ebl->backend = NULL;
+}
diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c
index 90d4f2b..da7d02c 100644
--- a/backends/ppc64_init.c
+++ b/backends/ppc64_init.c
@@ -64,6 +64,8 @@ ppc64_init (elf, machine, eh, ehlen)
   HOOK (eh, syscall_abi);
   HOOK (eh, core_note);
   HOOK (eh, auxv_info);
+  HOOK (eh, get_func_pc);
+  HOOK (eh, destr);
 
   return MODVERSION;
 }
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index abe5468..0552a7e 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -28,7 +28,8 @@
 ## not, see <http://www.gnu.org/licenses/>.
 ##
 include $(top_srcdir)/config/eu.am
-INCLUDES += -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl -I$(top_srcdir)/libdw
+INCLUDES += -I$(top_srcdir)/libelf -I$(top_srcdir)/libebl \
+	    -I$(top_srcdir)/libdw -I$(top_srcdir)/libdwfl
 
 GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include)
 VERSION = 1
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 8f62be2..4934c76 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -29,7 +29,7 @@
 ##
 include $(top_srcdir)/config/eu.am
 INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
-	    -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+	    -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl -I$(srcdir)/../libasm
 AM_CFLAGS += -fpic -fdollars-in-identifiers
 LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
 LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index c6ac264..7189e91 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -32,7 +32,7 @@ DEFS += -DIS_LIBDW
 if BUILD_STATIC
 AM_CFLAGS += -fpic
 endif
-INCLUDES += -I$(srcdir)/../libelf
+INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdwfl
 VERSION = 1
 
 lib_LIBRARIES = libdw.a
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index dcc2a7a..272b31e 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -39,6 +39,23 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
   if (syments < 0)
     return NULL;
 
+  /* Return section where FIND_ADDR lies.  Return SHN_ABS otherwise.  */
+  inline GElf_Word get_section (GElf_Addr find_addr)
+    {
+      GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, find_addr);
+      Elf_Scn *scn = NULL;
+      while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+	{
+	  GElf_Shdr shdr_mem;
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+	  if (likely (shdr != NULL)
+	      && mod_addr >= shdr->sh_addr
+	      && mod_addr < shdr->sh_addr + shdr->sh_size)
+	    return elf_ndxscn (scn);
+	}
+      return SHN_ABS;
+    }
+
   /* Return true iff we consider ADDR to lie in the same section as SYM.  */
   GElf_Word addr_shndx = SHN_UNDEF;
   inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
@@ -49,23 +66,7 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
 
       /* Figure out what section ADDR lies in.  */
       if (addr_shndx == SHN_UNDEF)
-	{
-	  GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
-	  Elf_Scn *scn = NULL;
-	  addr_shndx = SHN_ABS;
-	  while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
-	    {
-	      GElf_Shdr shdr_mem;
-	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-	      if (likely (shdr != NULL)
-		  && mod_addr >= shdr->sh_addr
-		  && mod_addr < shdr->sh_addr + shdr->sh_size)
-		{
-		  addr_shndx = elf_ndxscn (scn);
-		  break;
-		}
-	    }
-	}
+	addr_shndx = get_section (addr);
 
       return shndx == addr_shndx;
     }
@@ -83,80 +84,95 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
   /* Keep track of the lowest address a relevant sizeless symbol could have.  */
   GElf_Addr min_label = 0;
 
-  /* Look through the symbol table for a matching symbol.  */
-  inline void search_table (int start, int end)
+  /* Consider one symbol SYM.  */
+  inline void found_sym (const GElf_Sym *sym, GElf_Word shndx, const char *name)
     {
-      for (int i = start; i < end; ++i)
+      if (name != NULL && name[0] != '\0'
+	  && sym->st_shndx != SHN_UNDEF
+	  && sym->st_value <= addr
+	  && GELF_ST_TYPE (sym->st_info) != STT_SECTION
+	  && GELF_ST_TYPE (sym->st_info) != STT_FILE
+	  && GELF_ST_TYPE (sym->st_info) != STT_TLS)
 	{
-	  GElf_Sym sym;
-	  GElf_Word shndx;
-	  const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
-	  if (name != NULL && name[0] != '\0'
-	      && sym.st_shndx != SHN_UNDEF
-	      && sym.st_value <= addr
-	      && GELF_ST_TYPE (sym.st_info) != STT_SECTION
-	      && GELF_ST_TYPE (sym.st_info) != STT_FILE
-	      && GELF_ST_TYPE (sym.st_info) != STT_TLS)
-	    {
-	      /* Even if we don't choose this symbol, its existence excludes
-		 any sizeless symbol (assembly label) that is below its upper
-		 bound.  */
-	      if (sym.st_value + sym.st_size > min_label)
-		min_label = sym.st_value + sym.st_size;
+	  /* Even if we don't choose this symbol, its existence excludes
+	     any sizeless symbol (assembly label) that is below its upper
+	     bound.  */
+	  if (sym->st_value + sym->st_size > min_label)
+	    min_label = sym->st_value + sym->st_size;
 
-	      if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
-		{
+	  if (sym->st_size == 0 || addr - sym->st_value < sym->st_size)
+	    {
 #define BIND_PREF(sym)							\
-  (GELF_ST_BIND ((sym).st_info) == STB_GLOBAL				\
-   ? 3 : (GELF_ST_BIND ((sym).st_info) == STB_WEAK			\
-	  ? 2 : (GELF_ST_BIND ((sym).st_info) == STB_LOCAL ? 1 : 0)))
-		  /* This symbol is a better candidate than the current one
-		     if it's closer to ADDR or is global when it was local.  */
-		  if (closest_name == NULL
-		      || closest_sym->st_value < sym.st_value
-		      || BIND_PREF (*closest_sym) < BIND_PREF (sym))
-		    {
-		      if (sym.st_size != 0)
-			{
-			  *closest_sym = sym;
-			  closest_shndx = shndx;
-			  closest_name = name;
-			}
-		      else if (closest_name == NULL
-			       && sym.st_value >= min_label
-			       && same_section (&sym, shndx))
-			{
-			  /* Handwritten assembly symbols sometimes have no
-			     st_size.  If no symbol with proper size includes
-			     the address, we'll use the closest one that is in
-			     the same section as ADDR.  */
-			  sizeless_sym = sym;
-			  sizeless_shndx = shndx;
-			  sizeless_name = name;
-			}
-		    }
-		  /* When the beginning of its range is no closer,
-		     the end of its range might be.  Otherwise follow
-		     GELF_ST_BIND preference.  If all are equal prefer
-		     the first symbol found.  */
-		  else if (sym.st_size != 0
-			   && closest_sym->st_value == sym.st_value
-			   && ((closest_sym->st_size > sym.st_size
-			        && BIND_PREF (*closest_sym) <= BIND_PREF (sym))
-			       || (closest_sym->st_size >= sym.st_size
-				   && (BIND_PREF (*closest_sym)
-				       < BIND_PREF (sym)))))
+   (GELF_ST_BIND ((sym)->st_info) == STB_GLOBAL				\
+    ? 3 : (GELF_ST_BIND ((sym)->st_info) == STB_WEAK			\
+	   ? 2 : (GELF_ST_BIND ((sym)->st_info) == STB_LOCAL ? 1 : 0)))
+	      /* This symbol is a better candidate than the current one
+		 if it's closer to ADDR or is global when it was local.  */
+	      if (closest_name == NULL
+		  || closest_sym->st_value < sym->st_value
+		  || BIND_PREF (closest_sym) < BIND_PREF (sym))
+		{
+		  if (sym->st_size != 0)
 		    {
-		      *closest_sym = sym;
+		      *closest_sym = *sym;
 		      closest_shndx = shndx;
 		      closest_name = name;
 		    }
-#undef BIND_PREF
+		  else if (closest_name == NULL
+			   && sym->st_value >= min_label
+			   && same_section (sym, shndx))
+		    {
+		      /* Handwritten assembly symbols sometimes have no
+			 st_size.  If no symbol with proper size includes
+			 the address, we'll use the closest one that is in
+			 the same section as ADDR.  */
+		      sizeless_sym = *sym;
+		      sizeless_shndx = shndx;
+		      sizeless_name = name;
+		    }
+		}
+	      /* When the beginning of its range is no closer,
+		 the end of its range might be.  Otherwise follow
+		 GELF_ST_BIND preference.  If all are equal prefer
+		 the first symbol found.  */
+	      else if (sym->st_size != 0
+		       && closest_sym->st_value == sym->st_value
+		       && ((closest_sym->st_size > sym->st_size
+			    && BIND_PREF (closest_sym) <= BIND_PREF (sym))
+			   || (closest_sym->st_size >= sym->st_size
+			       && (BIND_PREF (closest_sym) < BIND_PREF (sym)))))
+		{
+		  *closest_sym = *sym;
+		  closest_shndx = shndx;
+		  closest_name = name;
 		}
+#undef BIND_PREF
 	    }
 	}
     }
 
+  /* Look through the symbol table for a matching symbol.  */
+  inline void search_table (int start, int end)
+    {
+      for (int i = start; i < end; ++i)
+	{
+	  GElf_Sym sym;
+	  GElf_Word shndx;
+	  const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
+	  found_sym (&sym, shndx, name);
+	  if (name == NULL || GELF_ST_TYPE (sym.st_info) != STT_FUNC)
+	    continue;
+	  Dwfl_Error error = __libdwfl_module_getebl (mod);
+	  if (error != DWFL_E_NOERROR)
+	    continue;
+	  name = ebl_get_func_pc (mod->ebl, mod, &sym);
+	  if (name == NULL)
+	    continue;
+	  shndx = get_section (sym.st_value);
+	  found_sym (&sym, shndx, name);
+	}
+    }
+
   /* First go through global symbols.  mod->first_global is setup by
      dwfl_module_getsymtab to the index of the first global symbol in
      the module's symbol table, or -1 when unknown.  All symbols with
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index 65e6b5b..db24518 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -29,7 +29,8 @@
 ##
 include $(top_srcdir)/config/eu.am
 AM_CFLAGS += -fpic
-INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdw -I$(srcdir)/../libasm
+INCLUDES += -I$(srcdir)/../libelf -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl \
+	    -I$(srcdir)/../libasm
 VERSION = 1
 LIBEBL_SUBDIR = @LIBEBL_SUBDIR@
 
@@ -54,7 +55,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
+	      eblstother.c eblgetfuncpc.c
 
 libebl_a_SOURCES = $(gen_SOURCES)
 
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index f629bce..6510e98 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -154,5 +154,10 @@ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
 /* Supply the machine-specific state of CFI before CIE initial programs.  */
 int EBLHOOK(abi_cfi) (Ebl *ebl, Dwarf_CIE *abi_info);
 
+/* *SYM must be STT_FUNC.  Then if it describes a function descriptor (PPC64)
+   convert in-place its data and return a possibly different new name for it.
+   The name is valid as long as EBL is valid.  */
+const char *EBLHOOK(get_func_pc) (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym);
+
 /* Destructor for ELF backend handle.  */
 void EBLHOOK(destr) (struct ebl *);
diff --git a/libebl/eblgetfuncpc.c b/libebl/eblgetfuncpc.c
new file mode 100644
index 0000000..f67c08f
--- /dev/null
+++ b/libebl/eblgetfuncpc.c
@@ -0,0 +1,46 @@
+/* Convert function descriptor SYM to the function PC value in-place.
+   Copyright (C) 2012 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>
+
+const char *
+ebl_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+{
+  if (ebl == NULL)
+    return NULL;
+  assert (sym != NULL);
+  assert (GELF_ST_TYPE (sym->st_info) == STT_FUNC);
+  if (ebl->get_func_pc == NULL)
+    return NULL;
+  return ebl->get_func_pc (ebl, mod, sym);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index 0d5621d..6f67451 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -31,6 +31,7 @@
 
 #include <gelf.h>
 #include "libdw.h"
+#include "libdwfl.h"
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -375,6 +376,10 @@ extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type,
 			  const char **name, const char **format)
   __nonnull_attribute__ (1, 3, 4);
 
+/* Convert function descriptor SYM to the function PC value in-place.  */
+extern const char *ebl_get_func_pc (Ebl *ebl, Dwfl_Module *mod, GElf_Sym *sym)
+  __nonnull_attribute__ (1, 2, 3);
+
 
 #ifdef __cplusplus
 }
diff --git a/libebl/libeblP.h b/libebl/libeblP.h
index 5ec26a4..c8196bd 100644
--- a/libebl/libeblP.h
+++ b/libebl/libeblP.h
@@ -62,6 +62,9 @@ struct ebl
 
   /* Internal data.  */
   void *dlhandle;
+
+  /* Data specific to the backend.  */
+  void *backend;
 };
 
 
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index 4feb193..4dd6018 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -298,4 +298,12 @@ __vdso_time
 ??:0
 EOF
 
+testfiles testfile66
+testrun_compare ../src/addr2line -S -e testfile66 0x10340 0x250 <<\EOF
+func
+??:0
+.func
+??:0
+EOF
+
 exit 0
diff --git a/tests/testfile66.bz2 b/tests/testfile66.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..db07f25415729927f4e2b4985c5668c8e2ee10a2
GIT binary patch
literal 569
zcmV-90>=G9T4*^jL0KkKSrloeYybi*|NH;`Q+Gmd_t9I$azOv*{$$8R5dZ){00;sg
zN(3VzzyZ?W%~)z`O*V<ChK5r#X)zd>fu;fm0WvhiG}9)JQGyXYL8JhU5NHRe007X?
z$Qoh*0BMi_;L)Q%&}a;pfXL9u01Y(A003Zs0!0dH8USbj00000000000H3&^h5+h?
zHGH8oS#&k;tR%<0nFK6&-#1i4RnYl;-bpN9k2InZwNKHPIa5z$l?D9dtf^2;aFZ>;
z6H2`TaFp50B|IFU9;meM2nk4CXKdt!?6iqh`+DOs7204JFHHaexzT9oele)vNXcO|
z&aXz&bgUpHL5Q+$&J at iFQZPa%v>5P$Ld;?WwHgw?W$OZSUT)aw=i|cU?V{^+uO+T&
zsc1>77*MKpaR&z&l3<3FBTF`AA*kg!f+LXQdlF0z1|<OGVw|;E3MDuVYg}lF1kIB*
z2MO?2(vv|()kGjFhM>|aV;0;9Y&kKvJQ6|?q76u^Sl}`<LIO+NDfU1C1=+J>CXwR7
zvQ|1 at iR(qMOPC<M!U)iAS_QSrP$be&teWK at Xh4y??kxH~E_K((z?!P4lv4z at 9Y0sD
zK?cn^FLD~401iNn#iXf~Yy5H5(sqZpp=+#)n|DQ6r81NSyLB;KQD(6uE>?9m>Ok-8
z(YXp^O0BHJBpo)oV3bgUCvFNTfZoo at a?O8}_!iyT909f+z2<0!_i&kLzs1~<P81{s
H8flvV7_Id;

literal 0
HcmV?d00001



More information about the elfutils-devel mailing list