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 <[email protected]> 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 <[email protected]> diff --git a/ChangeLog b/ChangeLog index a05ebdf..9c206bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-11-20 Jan Kratochvil <[email protected]> + + * NEWS (Version 0.156): New, with one note. + 2012-10-01 Mark Wielaard <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]> + + * libdw.map (ELFUTILS_0.156): New. + 2012-10-09 Petr Machata <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 <[email protected]> + + * 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 <[email protected]> * 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 _______________________________________________ elfutils-devel mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/elfutils-devel
