Hi Mark,
jankratochvil/ppc64-opd3
On Mon, 19 Nov 2012 20:23:23 +0100, Mark Wielaard wrote:
> /* Find the symbol that is nearest ADDRESS, and return its name.
Return
> the real symbol addressin *FUNCADDR. Return also possibly dereferenced
> function descriptors. */
> extern const char *dwfl_module_func_addrname (Dwfl_Module *mod,
> GElf_Addr address,
> GElf_Addr *funcaddr);
Yes, or maybe an GElf_Off that provides the offset from the start of the
named code block associated with the given address. Since I think the name
and the offset from the start of the code block is what is usually needed.
One can of course derive one from the other, so it doesn't really matter
I think whether you provide the address or offset.
Chose GElf_Addr when you have left that option.
> Finding just function types is not useful in practice, we need
to find any
> symbol type. And then the new interface fully supersedes the old interface.
Maybe if we can express this generically as a "filter" that lets you select
which symbols you are interested in and how to transform the matching
function symbol value (through architecture specific hooks)?
But I do think this is a different function from the generic symbol (name)
one. This is to get code name/addresses.
Not sure what did you mean by the paragraph. The code picks now arbitrary
symbol type, the same like dwfl_module_addrname or dwfl_module_addrsym do.
Thanks,
Jan
commit 2263ce06754b2156fa39af355aebfb460b64ce51
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.
libdwfl/
* dwfl_module_addrname.c (dwfl_module_codename): New function.
* dwfl_module_addrsym.c (dwfl_module_addrsym): Rename to ...
(addrsym): ... here, make it static and add new parameters
funcaddr_return and also_func_pc. New variable funcaddr_local, use it
for funcaddr_return.
(addrsym) (get_section): New function from ...
(addrsym) (same_section): ... here. Call it. Change parameter sym to
funcaddr, use it.
(addrsym): New variable sizeless_funcaddr.
(dwfl_module_addrsym) (found_sym): New function from ...
(dwfl_module_addrsym) (search_table): ... here. Call it. Use FUNCADDR
instead of SYM.ST_VALUE. Try second time with ebl_get_func_pc if
ALSO_FUNC_PC.
(addrsym): Use SIZELESS_FUNCADDR instead of SIZELESS_SYM.ST_VALUE.
Return also *FUNCADDR_RETURN.
(dwfl_module_addrsym, dwfl_module_codesym): New functions.
* libdwfl.h (dwfl_module_codename, dwfl_module_codesym): New
declarations.
* libdwflP.h (dwfl_module_codesym): 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): Remove variables s and shndx, add
variable funcaddr. Call dwfl_module_codename instead of
dwfl_module_addrsym. Adjust the code for FUNCADDR.
(handle_address): Use dwfl_module_codename instead of
dwfl_module_addrsym.
* readelf.c (format_dwarf_addr): Remove variable sym, add variable
funcaddr. Call dwfl_module_codename instead of dwfl_module_addrsym.
Use FUNCADDR instead of SYM.
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..9c206bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-11-20 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..c27c3e0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.156
+
+libdwfl: New functions dwfl_module_codename and dwfl_module_codesym.
+
Version 0.155
libelf: elf*_xlatetomd now works for cross-endian ELF note data.
diff --git a/backends/ChangeLog b/backends/ChangeLog
index cca7113..3e42989 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,10 @@
+2012-11-20 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..98d3ecb
--- /dev/null
+++ b/backends/ppc64_get_func_pc.c
@@ -0,0 +1,196 @@
+/* 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 must be the very first element for the use in bsearch below. */
+ GElf_Sym sym;
+ Elf64_Addr funcaddr;
+ const char *new_name;
+};
+
+struct pc_table
+{
+ size_t nelem;
+ struct pc_entry a[];
+ /* Here follow strings allocated for pc_entry->new_name. */
+};
+
+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, &b->sym, sizeof (a->sym));
+}
+
+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 = sym;
+ dest->funcaddr = val64 + symbias;
+ dest->new_name = 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, const GElf_Sym *sym,
+ GElf_Addr *funcaddr)
+{
+ 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;
+ *funcaddr = found->funcaddr;
+ return found->new_name;
+}
+
+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..e2b691b 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2012-11-20 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * libdw.map (ELFUTILS_0.156): New.
+
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..6e90e15 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_codename;
+ dwfl_module_codesym;
+} ELFUTILS_0.149;
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bdd9440..355e664 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,25 @@
+2012-11-20 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * dwfl_module_addrname.c (dwfl_module_codename): New function.
+ * dwfl_module_addrsym.c (dwfl_module_addrsym): Rename to ...
+ (addrsym): ... here, make it static and add new parameters
+ funcaddr_return and also_func_pc. New variable funcaddr_local, use it
+ for funcaddr_return.
+ (addrsym) (get_section): New function from ...
+ (addrsym) (same_section): ... here. Call it. Change parameter sym to
+ funcaddr, use it.
+ (addrsym): New variable sizeless_funcaddr.
+ (dwfl_module_addrsym) (found_sym): New function from ...
+ (dwfl_module_addrsym) (search_table): ... here. Call it. Use FUNCADDR
+ instead of SYM.ST_VALUE. Try second time with ebl_get_func_pc if
+ ALSO_FUNC_PC.
+ (addrsym): Use SIZELESS_FUNCADDR instead of SIZELESS_SYM.ST_VALUE.
+ Return also *FUNCADDR_RETURN.
+ (dwfl_module_addrsym, dwfl_module_codesym): New functions.
+ * libdwfl.h (dwfl_module_codename, dwfl_module_codesym): New
+ declarations.
+ * libdwflP.h (dwfl_module_codesym): 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..5a8f228 100644
--- a/libdwfl/dwfl_module_addrname.c
+++ b/libdwfl/dwfl_module_addrname.c
@@ -34,3 +34,12 @@ 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_codename (Dwfl_Module *mod, GElf_Addr address, GElf_Addr *funcaddr)
+{
+ GElf_Sym sym;
+ const char *name = INTUSE(dwfl_module_codesym) (mod, address, &sym, NULL,
+ funcaddr);
+ return name;
+}
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index fdc95fc..4014494 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -31,41 +31,46 @@
/* 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, GElf_Addr *funcaddr_return, bool also_func_pc)
{
int syments = INTUSE(dwfl_module_getsymtab) (mod);
if (syments < 0)
return NULL;
+ GElf_Addr funcaddr_local;
+ if (funcaddr_return == NULL)
+ funcaddr_return = &funcaddr_local;
+
+ /* 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)
+ inline bool same_section (GElf_Addr funcaddr, GElf_Word shndx)
{
/* For absolute symbols and the like, only match exactly. */
if (shndx >= SHN_LORESERVE)
- return sym->st_value == addr;
+ return funcaddr == 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;
}
@@ -79,95 +84,117 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
const char *sizeless_name = NULL;
GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF };
GElf_Word sizeless_shndx = SHN_UNDEF;
+ GElf_Addr sizeless_funcaddr = 0;
/* 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,
+ GElf_Addr funcaddr)
{
- for (int i = start; i < end; ++i)
+ if (name != NULL && name[0] != '\0'
+ && sym->st_shndx != SHN_UNDEF
+ && funcaddr <= 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 (funcaddr + sym->st_size > min_label)
+ min_label = funcaddr + sym->st_size;
- if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
+ if (sym->st_size == 0 || addr - funcaddr < 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
+ || *funcaddr_return < funcaddr
+ || binding_value (closest_sym) < binding_value (sym))
+ {
+ if (sym->st_size != 0)
{
- *closest_sym = sym;
+ *closest_sym = *sym;
closest_shndx = shndx;
closest_name = name;
+ *funcaddr_return = funcaddr;
+ }
+ else if (closest_name == NULL
+ && funcaddr >= min_label
+ && same_section (funcaddr, 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;
+ sizeless_funcaddr = funcaddr;
}
}
+ /* 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
+ && *funcaddr_return == funcaddr
+ && ((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;
+ *funcaddr_return = funcaddr;
+ }
}
}
}
+ /* 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, sym.st_value);
+ if (!also_func_pc || name == NULL)
+ continue;
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error != DWFL_E_NOERROR)
+ continue;
+ GElf_Addr funcaddr;
+ name = ebl_get_func_pc (mod->ebl, mod, &sym, &funcaddr);
+ if (name == NULL)
+ continue;
+ shndx = get_section (funcaddr);
+ found_sym (&sym, shndx, name, funcaddr);
+ }
+ }
+
/* 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
@@ -177,21 +204,37 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
/* If we found nothing searching the global symbols, then try the locals.
Unless we have a global sizeless symbol that matches exactly. */
if (closest_name == NULL && mod->first_global > 1
- && (sizeless_name == NULL || sizeless_sym.st_value != addr))
+ && (sizeless_name == NULL || sizeless_funcaddr != addr))
search_table (1, mod->first_global);
/* If we found no proper sized symbol to use, fall back to the best
candidate sizeless symbol we found, if any. */
if (closest_name == NULL
- && sizeless_name != NULL && sizeless_sym.st_value >= min_label)
+ && sizeless_name != NULL && sizeless_funcaddr >= min_label)
{
*closest_sym = sizeless_sym;
closest_shndx = sizeless_shndx;
closest_name = sizeless_name;
+ *funcaddr_return = sizeless_funcaddr;
}
if (shndxp != NULL)
*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, NULL, false);
+}
INTDEF (dwfl_module_addrsym)
+
+const char *
+dwfl_module_codesym (Dwfl_Module *mod, GElf_Addr address, GElf_Sym *closest_sym,
+ GElf_Word *shndxp, GElf_Addr *funcaddr)
+{
+ return addrsym (mod, address, closest_sym, shndxp, funcaddr, true);
+}
+INTDEF (dwfl_module_codesym)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 000d582..5eb585a 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -424,12 +424,27 @@ 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 code addrees *FUNCADDR. This function can
+ handle function descriptors, contrary to dwfl_module_addrname. */
+extern const char *dwfl_module_codename (Dwfl_Module *mod, GElf_Addr address,
+ GElf_Addr *funcaddr);
+
/* 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 its
+ starting code addrees *FUNCADDR. This function can handle function
+ descriptors, contrary to dwfl_module_addrsym. */
+extern const char *dwfl_module_codesym (Dwfl_Module *mod, GElf_Addr address,
+ GElf_Sym *sym, GElf_Word *shndxp,
+ GElf_Addr *funcaddr)
+ __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..d37261c 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_codesym)
/* 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..004ff9d 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,12 @@
+2012-11-20 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..967d261 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);
+/* Find for function descriptor SYM its starting code address *FUNCADDR
+ and return its new name. This function implements handling of
+ function descriptors. The name is valid as long as EBL is valid. */
+const char *EBLHOOK(get_func_pc) (Ebl *ebl, struct Dwfl_Module *mod,
+ const GElf_Sym *sym, GElf_Addr *funcaddr);
+
/* 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..0f5795f
--- /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, const GElf_Sym *sym,
+ GElf_Addr *funcaddr)
+{
+ if (ebl == NULL)
+ return NULL;
+ assert (sym != NULL);
+ if (ebl->get_func_pc == NULL)
+ return NULL;
+ return ebl->get_func_pc (ebl, mod, sym, funcaddr);
+}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index cae31c9..a677887 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -378,6 +378,14 @@ extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type,
const char **name, const char **format)
__nonnull_attribute__ (1, 3, 4);
+/* Find for function descriptor SYM its starting code address *FUNCADDR
+ and return its new name. This function implements handling of
+ function descriptors. */
+struct Dwfl_Module;
+extern const char *ebl_get_func_pc (Ebl *ebl, struct Dwfl_Module *mod,
+ const GElf_Sym *sym, GElf_Addr *funcaddr)
+ __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..d48fc90 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
+2012-11-20 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * addr2line.c (print_addrsym): Remove variables s and shndx, add
+ variable funcaddr. Call dwfl_module_codename instead of
+ dwfl_module_addrsym. Adjust the code for FUNCADDR.
+ (handle_address): Use dwfl_module_codename instead of
+ dwfl_module_addrsym.
+ * readelf.c (format_dwarf_addr): Remove variable sym, add variable
+ funcaddr. Call dwfl_module_codename instead of dwfl_module_addrsym.
+ Use FUNCADDR instead of SYM.
+
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..54b2898 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -326,9 +326,8 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
static void
print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
{
- GElf_Sym s;
- GElf_Word shndx;
- const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
+ GElf_Addr funcaddr;
+ const char *name = dwfl_module_codename (mod, addr, &funcaddr);
if (name == NULL)
{
/* No symbol name. Get a section name instead. */
@@ -340,10 +339,10 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
else
printf ("(%s)+%#" PRIx64 "\n", name, addr);
}
- else if (addr == s.st_value)
+ else if (addr == funcaddr)
puts (name);
else
- printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value);
+ printf ("%s+%#" PRIx64 "\n", name, addr - funcaddr);
}
static int
@@ -495,7 +494,7 @@ 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) ?: "??");
+ puts (dwfl_module_codename (mod, addr, NULL) ?: "??");
}
if (show_symbols)
diff --git a/src/readelf.c b/src/readelf.c
index 1801c1c..a9ab070 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3114,11 +3114,11 @@ format_dwarf_addr (Dwfl_Module *dwflmod,
int address_size, Dwarf_Addr address)
{
/* See if there is a name we can give for this address. */
- GElf_Sym sym;
+ GElf_Addr funcaddr;
const char *name = print_address_names
- ? dwfl_module_addrsym (dwflmod, address, &sym, NULL) : NULL;
+ ? dwfl_module_codename (dwflmod, address, &funcaddr) : NULL;
if (name != NULL)
- sym.st_value = address - sym.st_value;
+ funcaddr = address - funcaddr;
/* Relativize the address. */
int n = dwfl_module_relocations (dwflmod);
@@ -3130,24 +3130,24 @@ format_dwarf_addr (Dwfl_Module *dwflmod,
char *result;
if ((name != NULL
- ? (sym.st_value != 0
+ ? (funcaddr != 0
? (scn != NULL
? (address_size == 0
? asprintf (&result,
gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64
">"),
- scn, address, name, sym.st_value)
+ scn, address, name, funcaddr)
: asprintf (&result,
gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64
">"),
scn, 2 + address_size * 2, address,
- name, sym.st_value))
+ name, funcaddr))
: (address_size == 0
? asprintf (&result,
gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
- address, name, sym.st_value)
+ address, name, funcaddr)
: asprintf (&result,
gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
2 + address_size * 2, address,
- name, sym.st_value)))
+ name, funcaddr)))
: (scn != NULL
? (address_size == 0
? asprintf (&result,
diff --git a/tests/ChangeLog b/tests/ChangeLog
index edb82b4..7320624 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2012-11-20 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,
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