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