1da0c48c4Sopenharmony_ci/* Find debugging and symbol information for a module in libdwfl. 2da0c48c4Sopenharmony_ci Copyright (C) 2006-2014 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include "libdwflP.h" 34da0c48c4Sopenharmony_ci 35da0c48c4Sopenharmony_ciconst char * 36da0c48c4Sopenharmony_ciinternal_function 37da0c48c4Sopenharmony_ci__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, 38da0c48c4Sopenharmony_ci GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp, 39da0c48c4Sopenharmony_ci bool *resolved, bool adjust_st_value) 40da0c48c4Sopenharmony_ci{ 41da0c48c4Sopenharmony_ci if (unlikely (mod == NULL)) 42da0c48c4Sopenharmony_ci return NULL; 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci if (unlikely (mod->symdata == NULL)) 45da0c48c4Sopenharmony_ci { 46da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_module_getsymtab) (mod); 47da0c48c4Sopenharmony_ci if (result < 0) 48da0c48c4Sopenharmony_ci return NULL; 49da0c48c4Sopenharmony_ci } 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci /* All local symbols should come before all global symbols. If we 52da0c48c4Sopenharmony_ci have an auxiliary table make sure all the main locals come first, 53da0c48c4Sopenharmony_ci then all aux locals, then all main globals and finally all aux globals. 54da0c48c4Sopenharmony_ci And skip the auxiliary table zero undefined entry. */ 55da0c48c4Sopenharmony_ci GElf_Word shndx; 56da0c48c4Sopenharmony_ci int tndx = ndx; 57da0c48c4Sopenharmony_ci int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0; 58da0c48c4Sopenharmony_ci Elf *elf; 59da0c48c4Sopenharmony_ci Elf_Data *symdata; 60da0c48c4Sopenharmony_ci Elf_Data *symxndxdata; 61da0c48c4Sopenharmony_ci Elf_Data *symstrdata; 62da0c48c4Sopenharmony_ci if (mod->aux_symdata == NULL 63da0c48c4Sopenharmony_ci || ndx < mod->first_global) 64da0c48c4Sopenharmony_ci { 65da0c48c4Sopenharmony_ci /* main symbol table (locals). */ 66da0c48c4Sopenharmony_ci tndx = ndx; 67da0c48c4Sopenharmony_ci elf = mod->symfile->elf; 68da0c48c4Sopenharmony_ci symdata = mod->symdata; 69da0c48c4Sopenharmony_ci symxndxdata = mod->symxndxdata; 70da0c48c4Sopenharmony_ci symstrdata = mod->symstrdata; 71da0c48c4Sopenharmony_ci } 72da0c48c4Sopenharmony_ci else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero) 73da0c48c4Sopenharmony_ci { 74da0c48c4Sopenharmony_ci /* aux symbol table (locals). */ 75da0c48c4Sopenharmony_ci tndx = ndx - mod->first_global + skip_aux_zero; 76da0c48c4Sopenharmony_ci elf = mod->aux_sym.elf; 77da0c48c4Sopenharmony_ci symdata = mod->aux_symdata; 78da0c48c4Sopenharmony_ci symxndxdata = mod->aux_symxndxdata; 79da0c48c4Sopenharmony_ci symstrdata = mod->aux_symstrdata; 80da0c48c4Sopenharmony_ci } 81da0c48c4Sopenharmony_ci else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero) 82da0c48c4Sopenharmony_ci { 83da0c48c4Sopenharmony_ci /* main symbol table (globals). */ 84da0c48c4Sopenharmony_ci tndx = ndx - mod->aux_first_global + skip_aux_zero; 85da0c48c4Sopenharmony_ci elf = mod->symfile->elf; 86da0c48c4Sopenharmony_ci symdata = mod->symdata; 87da0c48c4Sopenharmony_ci symxndxdata = mod->symxndxdata; 88da0c48c4Sopenharmony_ci symstrdata = mod->symstrdata; 89da0c48c4Sopenharmony_ci } 90da0c48c4Sopenharmony_ci else 91da0c48c4Sopenharmony_ci { 92da0c48c4Sopenharmony_ci /* aux symbol table (globals). */ 93da0c48c4Sopenharmony_ci tndx = ndx - mod->syments + skip_aux_zero; 94da0c48c4Sopenharmony_ci elf = mod->aux_sym.elf; 95da0c48c4Sopenharmony_ci symdata = mod->aux_symdata; 96da0c48c4Sopenharmony_ci symxndxdata = mod->aux_symxndxdata; 97da0c48c4Sopenharmony_ci symstrdata = mod->aux_symstrdata; 98da0c48c4Sopenharmony_ci } 99da0c48c4Sopenharmony_ci sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx); 100da0c48c4Sopenharmony_ci 101da0c48c4Sopenharmony_ci if (unlikely (sym == NULL)) 102da0c48c4Sopenharmony_ci { 103da0c48c4Sopenharmony_ci __libdwfl_seterrno (DWFL_E_LIBELF); 104da0c48c4Sopenharmony_ci return NULL; 105da0c48c4Sopenharmony_ci } 106da0c48c4Sopenharmony_ci 107da0c48c4Sopenharmony_ci if (sym->st_shndx != SHN_XINDEX) 108da0c48c4Sopenharmony_ci shndx = sym->st_shndx; 109da0c48c4Sopenharmony_ci 110da0c48c4Sopenharmony_ci /* Figure out whether this symbol points into an SHF_ALLOC section. */ 111da0c48c4Sopenharmony_ci bool alloc = true; 112da0c48c4Sopenharmony_ci if ((shndxp != NULL || mod->e_type != ET_REL) 113da0c48c4Sopenharmony_ci && (sym->st_shndx == SHN_XINDEX 114da0c48c4Sopenharmony_ci || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF))) 115da0c48c4Sopenharmony_ci { 116da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 117da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem); 118da0c48c4Sopenharmony_ci alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC); 119da0c48c4Sopenharmony_ci } 120da0c48c4Sopenharmony_ci 121da0c48c4Sopenharmony_ci /* In case of an value in an allocated section the main Elf Ebl 122da0c48c4Sopenharmony_ci might know where the real value is (e.g. for function 123da0c48c4Sopenharmony_ci descriptors). */ 124da0c48c4Sopenharmony_ci 125da0c48c4Sopenharmony_ci char *ident; 126da0c48c4Sopenharmony_ci GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl); 127da0c48c4Sopenharmony_ci *resolved = false; 128da0c48c4Sopenharmony_ci if (! adjust_st_value && mod->e_type != ET_REL && alloc 129da0c48c4Sopenharmony_ci && (GELF_ST_TYPE (sym->st_info) == STT_FUNC 130da0c48c4Sopenharmony_ci || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC 131da0c48c4Sopenharmony_ci && (ident = elf_getident (elf, NULL)) != NULL 132da0c48c4Sopenharmony_ci && ident[EI_OSABI] == ELFOSABI_LINUX))) 133da0c48c4Sopenharmony_ci { 134da0c48c4Sopenharmony_ci if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) 135da0c48c4Sopenharmony_ci { 136da0c48c4Sopenharmony_ci if (elf != mod->main.elf) 137da0c48c4Sopenharmony_ci { 138da0c48c4Sopenharmony_ci st_value = dwfl_adjusted_st_value (mod, elf, st_value); 139da0c48c4Sopenharmony_ci st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value); 140da0c48c4Sopenharmony_ci } 141da0c48c4Sopenharmony_ci 142da0c48c4Sopenharmony_ci *resolved = ebl_resolve_sym_value (mod->ebl, &st_value); 143da0c48c4Sopenharmony_ci if (! *resolved) 144da0c48c4Sopenharmony_ci st_value = sym->st_value; 145da0c48c4Sopenharmony_ci } 146da0c48c4Sopenharmony_ci } 147da0c48c4Sopenharmony_ci 148da0c48c4Sopenharmony_ci if (shndxp != NULL) 149da0c48c4Sopenharmony_ci /* Yield -1 in case of a non-SHF_ALLOC section. */ 150da0c48c4Sopenharmony_ci *shndxp = alloc ? shndx : (GElf_Word) -1; 151da0c48c4Sopenharmony_ci 152da0c48c4Sopenharmony_ci switch (sym->st_shndx) 153da0c48c4Sopenharmony_ci { 154da0c48c4Sopenharmony_ci case SHN_ABS: /* XXX sometimes should use bias?? */ 155da0c48c4Sopenharmony_ci case SHN_UNDEF: 156da0c48c4Sopenharmony_ci case SHN_COMMON: 157da0c48c4Sopenharmony_ci break; 158da0c48c4Sopenharmony_ci 159da0c48c4Sopenharmony_ci default: 160da0c48c4Sopenharmony_ci if (mod->e_type == ET_REL) 161da0c48c4Sopenharmony_ci { 162da0c48c4Sopenharmony_ci /* In an ET_REL file, the symbol table values are relative 163da0c48c4Sopenharmony_ci to the section, not to the module's load base. */ 164da0c48c4Sopenharmony_ci size_t symshstrndx = SHN_UNDEF; 165da0c48c4Sopenharmony_ci Dwfl_Error result = __libdwfl_relocate_value (mod, elf, 166da0c48c4Sopenharmony_ci &symshstrndx, 167da0c48c4Sopenharmony_ci shndx, &st_value); 168da0c48c4Sopenharmony_ci if (unlikely (result != DWFL_E_NOERROR)) 169da0c48c4Sopenharmony_ci { 170da0c48c4Sopenharmony_ci __libdwfl_seterrno (result); 171da0c48c4Sopenharmony_ci return NULL; 172da0c48c4Sopenharmony_ci } 173da0c48c4Sopenharmony_ci } 174da0c48c4Sopenharmony_ci else if (alloc) 175da0c48c4Sopenharmony_ci /* Apply the bias to the symbol value. */ 176da0c48c4Sopenharmony_ci st_value = dwfl_adjusted_st_value (mod, 177da0c48c4Sopenharmony_ci *resolved ? mod->main.elf : elf, 178da0c48c4Sopenharmony_ci st_value); 179da0c48c4Sopenharmony_ci break; 180da0c48c4Sopenharmony_ci } 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci if (adjust_st_value) 183da0c48c4Sopenharmony_ci sym->st_value = st_value; 184da0c48c4Sopenharmony_ci 185da0c48c4Sopenharmony_ci if (addr != NULL) 186da0c48c4Sopenharmony_ci *addr = st_value; 187da0c48c4Sopenharmony_ci 188da0c48c4Sopenharmony_ci if (unlikely (sym->st_name >= symstrdata->d_size)) 189da0c48c4Sopenharmony_ci { 190da0c48c4Sopenharmony_ci __libdwfl_seterrno (DWFL_E_BADSTROFF); 191da0c48c4Sopenharmony_ci return NULL; 192da0c48c4Sopenharmony_ci } 193da0c48c4Sopenharmony_ci if (elfp) 194da0c48c4Sopenharmony_ci *elfp = elf; 195da0c48c4Sopenharmony_ci if (biasp) 196da0c48c4Sopenharmony_ci *biasp = dwfl_adjusted_st_value (mod, elf, 0); 197da0c48c4Sopenharmony_ci return (const char *) symstrdata->d_buf + sym->st_name; 198da0c48c4Sopenharmony_ci} 199da0c48c4Sopenharmony_ci 200da0c48c4Sopenharmony_ciconst char * 201da0c48c4Sopenharmony_cidwfl_module_getsym_info (Dwfl_Module *mod, int ndx, 202da0c48c4Sopenharmony_ci GElf_Sym *sym, GElf_Addr *addr, 203da0c48c4Sopenharmony_ci GElf_Word *shndxp, 204da0c48c4Sopenharmony_ci Elf **elfp, Dwarf_Addr *bias) 205da0c48c4Sopenharmony_ci{ 206da0c48c4Sopenharmony_ci bool resolved; 207da0c48c4Sopenharmony_ci return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias, 208da0c48c4Sopenharmony_ci &resolved, false); 209da0c48c4Sopenharmony_ci} 210da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsym_info) 211da0c48c4Sopenharmony_ci 212da0c48c4Sopenharmony_ciconst char * 213da0c48c4Sopenharmony_cidwfl_module_getsym (Dwfl_Module *mod, int ndx, 214da0c48c4Sopenharmony_ci GElf_Sym *sym, GElf_Word *shndxp) 215da0c48c4Sopenharmony_ci{ 216da0c48c4Sopenharmony_ci bool resolved; 217da0c48c4Sopenharmony_ci return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL, 218da0c48c4Sopenharmony_ci &resolved, true); 219da0c48c4Sopenharmony_ci} 220da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsym) 221