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