On Fri, 16 Nov 2012 23:28:26 +0100, Roland McGrath wrote:
I agree with Mark that this does not belong in dwfl_module_addrsym.
New patch included.
jankratochvil/ppc64-opd2
Perhaps what will be used most often is something with different
semantics: yield a name and corresponding address near the given
address.
/* Find the symbol that *ADDRESS lies inside, and return its name. Return also
its starting address in modified *ADDRESS. Return also possibly runtime
generated artificial symbols such as resolved function descriptors. */
extern const char *dwfl_module_addrname_synthetic (Dwfl_Module *mod,
GElf_Addr *address);
This is something between dwfl_module_addrname and dwfl_module_addrsym.
IMO the format interface was better, one either wants just the name or one is
interested in possibly all the other attributes (such as the function size).
Or perhaps you want to describe those semantics as, yield an ELF
symbol
(i.e. not just name, but also section, scope, and visibility info) and
corresponding address near the given address.
/* Find the symbol that ADDRESS lies inside, and return detailed
information as for dwfl_module_getsym (above). Return also possibly
runtime generated artificial symbols such as resolved function
descriptors. */
extern const char *dwfl_module_addrsym_synthetic (Dwfl_Module *mod,
GElf_Addr address,
GElf_Sym *sym,
GElf_Word *shndxp)
In my opinion there exists no real world case when one wants to use the "old"
interface (without synthetic symbols). It will happen one incorrectly uses
the non-synthetic variant while one always wants to use the synthetic variant,
making it broken on ppc64 which nobody has access to / can test.
Maybe if a new interface then it could rather return an additional flags field
where would be some indicator like BSF_SYNTHETIC where the returned symbol
came from.
Thanks,
Jan
commit 0e3e6e8ba59650c1f5136132617328d3856a8e12
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Wed Oct 10 09:48:10 2012 +0200
./
* NEWS (Version 0.156): New, with one note.
backends/
* 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.
libdw/
* libdw.map (ELFUTILS_0.156): New, with dwfl_module_addrsym_synthetic
and dwfl_module_addrname_synthetic.
libdwfl/
* dwfl_module_addrname.c (dwfl_module_addrname_synthetic): New function.
* dwfl_module_addrsym.c (dwfl_module_addrsym): Rename to ...
(addrsym): ... here, make it static and add new parameter
also_synthetic.
(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 if ALSO_SYNTHETIC.
(dwfl_module_addrsym, dwfl_module_addrsym_synthetic): New functions.
* libdwfl.h (dwfl_module_addrsym, dwfl_module_addrsym_synthetic): New
declarations.
* libdwflP.h (dwfl_module_addrsym_synthetic): New INTDECL.
libebl/
* Makefile.am (gen_SOURCES): Add eblgetfuncpc.c.
* ebl-hooks.h (get_func_pc): New entry.
* eblgetfuncpc.c: New file.
* libebl.h (struct Dwfl_Module): New declaration.
(ebl_get_func_pc): New declaration.
* libeblP.h (struct ebl): New field backend.
src/
* addr2line.c (print_addrsym): Use dwfl_module_addrsym_synthetic
instead of dwfl_module_addrsym.
(handle_address): Use dwfl_module_addrsym_synthetic instead of
dwfl_module_addrsym, new variable addr_local.
* readelf.c (format_dwarf_addr): Likewise.
tests/
* run-addrname-test.sh: New testcase for ppc64 function descriptors.
* testfile66.bz2: New file.
* Makefile.am (EXTRA_DIST): Add testfile66.bz2.
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/ChangeLog b/ChangeLog
index a05ebdf..5307a4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-11-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * NEWS (Version 0.156): New, with one note.
+
2012-10-01 Mark Wielaard <mjw(a)redhat.com>
* configure.ac: Add --enable-valgrind check.
diff --git a/NEWS b/NEWS
index e38e60c..8218113 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.156
+
+libdwfl: new functions dwfl_module_addrname_synthetic and
+ dwfl_module_addrsym_synthetic.
+
Version 0.155
libelf: elf*_xlatetomd now works for cross-endian ELF note data.
diff --git a/backends/ChangeLog b/backends/ChangeLog
index cca7113..a090167 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,10 @@
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)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.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* linux-core-note.c (prstatus_items): Rename groups of sigpend and
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 982ff2a..fa85593 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..5038b00
--- /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) 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 <assert.h>
+#include "libdwfl.h"
+#include <endian.h>
+#include <string.h>
+#include <stdlib.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);
+ 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;
+ Dwarf_Addr symbias;
+ dwfl_module_info (mod, NULL, NULL, NULL, NULL, &symbias, NULL, NULL);
+ for (int symi = 1; symi < syments; symi++)
+ {
+ GElf_Sym sym;
+ const char *symname = dwfl_module_getsym (mod, symi, &sym, &shndx);
+ if (symname == 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 + symbias
+ || sym.st_value > (opd_shdr->sh_addr + symbias
+ + opd_shdr->sh_size - sizeof (val)))
+ continue;
+ funcs++;
+ names_size += 1 + strlen (symname) + 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++)
+ {
+ GElf_Sym sym;
+ const char *symname = dwfl_module_getsym (mod, symi, &sym, &shndx);
+ if (symname == 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 + symbias
+ || sym.st_value > (opd_shdr->sh_addr + symbias
+ + opd_shdr->sh_size - sizeof (val64)))
+ continue;
+ val64 = *(const uint64_t *) (opd_data->d_buf + sym.st_value
+ - (opd_shdr->sh_addr + symbias));
+ 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 + symbias;
+ dest->name_to = names_dest;
+ *names_dest++ = '.';
+ names_dest = stpcpy (names_dest, symname) + 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/libdw/ChangeLog b/libdw/ChangeLog
index 0d35ca9..11a58f2 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2012-11-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * libdw.map (ELFUTILS_0.156): New, with dwfl_module_addrsym_synthetic
+ and dwfl_module_addrname_synthetic.
+
2012-10-09 Petr Machata <pmachata(a)redhat.com>
* dwarf_getlocation.c (__libdw_intern_expression): Handle
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 1f71d03..98cbbcd 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -254,3 +254,9 @@ ELFUTILS_0.149 {
dwfl_dwarf_line;
} ELFUTILS_0.148;
+
+ELFUTILS_0.156 {
+ global:
+ dwfl_module_addrsym_synthetic;
+ dwfl_module_addrname_synthetic;
+} ELFUTILS_0.149;
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bdd9440..1dfd53e 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,19 @@
+2012-11-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * dwfl_module_addrname.c (dwfl_module_addrname_synthetic): New function.
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Rename to ...
+ (addrsym): ... here, make it static and add new parameter
+ also_synthetic.
+ (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 if ALSO_SYNTHETIC.
+ (dwfl_module_addrsym, dwfl_module_addrsym_synthetic): New functions.
+ * libdwfl.h (dwfl_module_addrsym, dwfl_module_addrsym_synthetic): New
+ declarations.
+ * libdwflP.h (dwfl_module_addrsym_synthetic): New INTDECL.
+
2012-10-17 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_module_getdwarf.c (mod_verify_build_id): New function with code
diff --git a/libdwfl/dwfl_module_addrname.c b/libdwfl/dwfl_module_addrname.c
index 6ae0123..edb262c 100644
--- a/libdwfl/dwfl_module_addrname.c
+++ b/libdwfl/dwfl_module_addrname.c
@@ -34,3 +34,13 @@ dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
GElf_Sym sym;
return INTUSE(dwfl_module_addrsym) (mod, addr, &sym, NULL);
}
+
+const char *
+dwfl_module_addrname_synthetic (Dwfl_Module *mod, GElf_Addr *addr)
+{
+ GElf_Sym sym;
+ const char *name = INTUSE(dwfl_module_addrsym_synthetic) (mod, *addr, &sym,
+ NULL);
+ *addr = sym.st_value;
+ return name;
+}
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index fdc95fc..54fe7f1 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -31,14 +31,31 @@
/* Returns the name of the symbol "closest" to ADDR.
Never returns symbols at addresses above ADDR. */
-const char *
-dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
- GElf_Sym *closest_sym, GElf_Word *shndxp)
+static const char *
+addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Sym *closest_sym,
+ GElf_Word *shndxp, bool also_synthetic)
{
int syments = INTUSE(dwfl_module_getsymtab) (mod);
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,91 +84,108 @@ 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)
+ {
+ /* Return GELF_ST_BIND as higher-is-better integer. */
+ inline int binding_value (const GElf_Sym *symp)
{
- /* Return GELF_ST_BIND as higher-is-better integer. */
- inline int binding_value (const GElf_Sym *symp)
- {
- switch (GELF_ST_BIND (symp->st_info))
- {
- case STB_GLOBAL:
- return 3;
- case STB_WEAK:
- return 2;
- case STB_LOCAL:
- return 1;
- default:
- return 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
- || binding_value (closest_sym) < binding_value (&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
- && (binding_value (closest_sym)
- <= binding_value (&sym)))
- || (closest_sym->st_size >= sym.st_size
- && (binding_value (closest_sym)
- < binding_value (&sym)))))
+ switch (GELF_ST_BIND (symp->st_info))
+ {
+ case STB_GLOBAL:
+ return 3;
+ case STB_WEAK:
+ return 2;
+ case STB_LOCAL:
+ return 1;
+ default:
+ return 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
+ || binding_value (closest_sym) < binding_value (sym))
+ {
+ if (sym->st_size != 0)
{
- *closest_sym = sym;
+ *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
+ && (binding_value (closest_sym)
+ <= binding_value (sym)))
+ || (closest_sym->st_size >= sym->st_size
+ && (binding_value (closest_sym)
+ < binding_value (sym)))))
+ {
+ *closest_sym = *sym;
+ closest_shndx = shndx;
+ closest_name = name;
}
}
}
}
+ /* 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 (!also_synthetic || 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
@@ -194,4 +212,19 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
*shndxp = closest_shndx;
return closest_name;
}
+
+const char *
+dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Sym *closest_sym,
+ GElf_Word *shndxp)
+{
+ return addrsym (mod, addr, closest_sym, shndxp, false);
+}
INTDEF (dwfl_module_addrsym)
+
+const char *
+dwfl_module_addrsym_synthetic (Dwfl_Module *mod, GElf_Addr addr,
+ GElf_Sym *closest_sym, GElf_Word *shndxp)
+{
+ return addrsym (mod, addr, closest_sym, shndxp, true);
+}
+INTDEF (dwfl_module_addrsym_synthetic)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 000d582..a00f25e 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -424,12 +424,28 @@ extern const char *dwfl_module_getsym (Dwfl_Module *mod, int ndx,
/* Find the symbol that ADDRESS lies inside, and return its name. */
extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address);
+/* Find the symbol that *ADDRESS lies inside, and return its name. Return also
+ its starting address in modified *ADDRESS. Return also possibly runtime
+ generated artificial symbols such as resolved function descriptors. */
+extern const char *dwfl_module_addrname_synthetic (Dwfl_Module *mod,
+ GElf_Addr *address);
+
/* Find the symbol that ADDRESS lies inside, and return detailed
information as for dwfl_module_getsym (above). */
extern const char *dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr address,
GElf_Sym *sym, GElf_Word *shndxp)
__nonnull_attribute__ (3);
+/* Find the symbol that ADDRESS lies inside, and return detailed
+ information as for dwfl_module_getsym (above). Return also possibly
+ runtime generated artificial symbols such as resolved function
+ descriptors. */
+extern const char *dwfl_module_addrsym_synthetic (Dwfl_Module *mod,
+ GElf_Addr address,
+ GElf_Sym *sym,
+ GElf_Word *shndxp)
+ __nonnull_attribute__ (3);
+
/* Find the ELF section that *ADDRESS lies inside and return it.
On success, adjusts *ADDRESS to be relative to the section,
and sets *BIAS to the difference between addresses used in
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index ca8be2f..b37b9ca 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -478,6 +478,7 @@ INTDECL (dwfl_offline_section_address)
INTDECL (dwfl_module_relocate_address)
INTDECL (dwfl_module_dwarf_cfi)
INTDECL (dwfl_module_eh_cfi)
+INTDECL (dwfl_module_addrsym_synthetic)
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name,
(mod)->low_addr
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index e881ce7..029f0d7 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,12 @@
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * Makefile.am (gen_SOURCES): Add eblgetfuncpc.c.
+ * ebl-hooks.h (get_func_pc): New entry.
+ * eblgetfuncpc.c: New file.
+ * libebl.h (struct Dwfl_Module): New declaration.
+ (ebl_get_func_pc): New declaration.
+ * libeblP.h (struct ebl): New field backend.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* ebl-hooks.h (abi_cfi): Extend its comment for return value.
diff --git a/libebl/Makefile.am b/libebl/Makefile.am
index 65e6b5b..1ab08e7 100644
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -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
+ eblstother.c eblgetfuncpc.c
libebl_a_SOURCES = $(gen_SOURCES)
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index d3cf3e6..b39131d 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -155,5 +155,11 @@ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
Function returns 0 on success and -1 on error. */
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, struct 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..57ef159
--- /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, struct 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 cae31c9..6c50769 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -378,6 +378,12 @@ 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. */
+struct Dwfl_Module;
+extern const char *ebl_get_func_pc (Ebl *ebl, struct 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/src/ChangeLog b/src/ChangeLog
index 9d6fbe3..04c86c2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2012-11-18 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * addr2line.c (print_addrsym): Use dwfl_module_addrsym_synthetic
+ instead of dwfl_module_addrsym.
+ (handle_address): Use dwfl_module_addrsym_synthetic instead of
+ dwfl_module_addrsym, new variable addr_local.
+ * readelf.c (format_dwarf_addr): Likewise.
+
2012-10-12 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* readelf.c (ITEM_WRAP_COLUMN, REGISTER_WRAP_COLUMN): Merge to ...
diff --git a/src/addr2line.c b/src/addr2line.c
index 7d241f3..c27150a 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -328,7 +328,7 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
{
GElf_Sym s;
GElf_Word shndx;
- const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
+ const char *name = dwfl_module_addrsym_synthetic (mod, addr, &s, &shndx);
if (name == NULL)
{
/* No symbol name. Get a section name instead. */
@@ -495,7 +495,11 @@ handle_address (const char *string, Dwfl *dwfl)
/* First determine the function name. Use the DWARF information if
possible. */
if (! print_dwarf_function (mod, addr) && !show_symbols)
- puts (dwfl_module_addrname (mod, addr) ?: "??");
+ {
+ GElf_Addr addr_local = addr;
+
+ puts (dwfl_module_addrname_synthetic (mod, &addr_local) ?: "??");
+ }
}
if (show_symbols)
diff --git a/src/readelf.c b/src/readelf.c
index 1801c1c..8e66328 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3116,7 +3116,7 @@ format_dwarf_addr (Dwfl_Module *dwflmod,
/* See if there is a name we can give for this address. */
GElf_Sym sym;
const char *name = print_address_names
- ? dwfl_module_addrsym (dwflmod, address, &sym, NULL) : NULL;
+ ? dwfl_module_addrsym_synthetic (dwflmod, address, &sym, NULL) : NULL;
if (name != NULL)
sym.st_value = address - sym.st_value;
diff --git a/tests/ChangeLog b/tests/ChangeLog
index edb82b4..2100cc7 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,4 +1,10 @@
2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * run-addrname-test.sh: New testcase for ppc64 function descriptors.
+ * testfile66.bz2: New file.
+ * Makefile.am (EXTRA_DIST): Add testfile66.bz2.
+
+2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (EXTRA_DIST): Add testfile64.bz2, testfile65.bz2,
testfile69.core.bz2 and testfile69.so.bz2 .
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2d2484..975ef5c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -180,7 +180,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
testfile60.bz2 testfile61.bz2 \
run-readelf-vmcoreinfo.sh testfile62.bz2 \
run-readelf-mixed-corenote.sh testfile63.bz2 testfile64.bz2 \
- testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2
+ testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2 testfile66.bz2
if USE_VALGRIND
valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1"
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index cc8aa33..78c70f0 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -298,6 +298,14 @@ __vdso_time
??:0
EOF
+testfiles testfile66
+testrun_compare ../src/addr2line -S -e testfile66 0x10340 0x250 <<\EOF
+func
+??:0
+.func
+??:0
+EOF
+
testfiles testfile69.core testfile69.so
testrun_compare ../src/addr2line --core=./testfile69.core -S 0x7f0bc6a33535
0x7f0bc6a33546 <<\EOF
libstatic+0x9
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@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@iR(qMOPC<M!U)iAS_QSrP$be&teWK@Xh4y??kxH~E_K((z?!P4lv4z@9Y0sD
zK?cn^FLD~401iNn#iXf~Yy5H5(sqZpp=+#)n|DQ6r81NSyLB;KQD(6uE>?9m>Ok-8
z(YXp^O0BHJBpo)oV3bgUCvFNTfZoo@a?O8}_!iyT909f+z2<0!_i&kLzs1~<P81{s
H8flvV7_Id;
literal 0
HcmV?d00001