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#include "libdwflP.h" 30 31const char * 32internal_function 33__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, 34 GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp, 35 bool *resolved, bool adjust_st_value) 36{ 37 if (unlikely (mod == NULL)) 38 return NULL; 39 40 if (unlikely (mod->symdata == NULL)) 41 { 42 int result = INTUSE(dwfl_module_getsymtab) (mod); 43 if (result < 0) 44 return NULL; 45 } 46 47 /* All local symbols should come before all global symbols. If we 48 have an auxiliary table make sure all the main locals come first, 49 then all aux locals, then all main globals and finally all aux globals. 50 And skip the auxiliary table zero undefined entry. */ 51 GElf_Word shndx; 52 int tndx = ndx; 53 int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0; 54 Elf *elf; 55 Elf_Data *symdata; 56 Elf_Data *symxndxdata; 57 Elf_Data *symstrdata; 58 if (mod->aux_symdata == NULL 59 || ndx < mod->first_global) 60 { 61 /* main symbol table (locals). */ 62 tndx = ndx; 63 elf = mod->symfile->elf; 64 symdata = mod->symdata; 65 symxndxdata = mod->symxndxdata; 66 symstrdata = mod->symstrdata; 67 } 68 else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero) 69 { 70 /* aux symbol table (locals). */ 71 tndx = ndx - mod->first_global + skip_aux_zero; 72 elf = mod->aux_sym.elf; 73 symdata = mod->aux_symdata; 74 symxndxdata = mod->aux_symxndxdata; 75 symstrdata = mod->aux_symstrdata; 76 } 77 else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero) 78 { 79 /* main symbol table (globals). */ 80 tndx = ndx - mod->aux_first_global + skip_aux_zero; 81 elf = mod->symfile->elf; 82 symdata = mod->symdata; 83 symxndxdata = mod->symxndxdata; 84 symstrdata = mod->symstrdata; 85 } 86 else 87 { 88 /* aux symbol table (globals). */ 89 tndx = ndx - mod->syments + skip_aux_zero; 90 elf = mod->aux_sym.elf; 91 symdata = mod->aux_symdata; 92 symxndxdata = mod->aux_symxndxdata; 93 symstrdata = mod->aux_symstrdata; 94 } 95 sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx); 96 97 if (unlikely (sym == NULL)) 98 { 99 __libdwfl_seterrno (DWFL_E_LIBELF); 100 return NULL; 101 } 102 103 if (sym->st_shndx != SHN_XINDEX) 104 shndx = sym->st_shndx; 105 106 /* Figure out whether this symbol points into an SHF_ALLOC section. */ 107 bool alloc = true; 108 if ((shndxp != NULL || mod->e_type != ET_REL) 109 && (sym->st_shndx == SHN_XINDEX 110 || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF))) 111 { 112 GElf_Shdr shdr_mem; 113 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem); 114 alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC); 115 } 116 117 /* In case of an value in an allocated section the main Elf Ebl 118 might know where the real value is (e.g. for function 119 descriptors). */ 120 121 char *ident; 122 GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl); 123 *resolved = false; 124 if (! adjust_st_value && mod->e_type != ET_REL && alloc 125 && (GELF_ST_TYPE (sym->st_info) == STT_FUNC 126 || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC 127 && (ident = elf_getident (elf, NULL)) != NULL 128 && ident[EI_OSABI] == ELFOSABI_LINUX))) 129 { 130 if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) 131 { 132 if (elf != mod->main.elf) 133 { 134 st_value = dwfl_adjusted_st_value (mod, elf, st_value); 135 st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value); 136 } 137 138 *resolved = ebl_resolve_sym_value (mod->ebl, &st_value); 139 if (! *resolved) 140 st_value = sym->st_value; 141 } 142 } 143 144 if (shndxp != NULL) 145 /* Yield -1 in case of a non-SHF_ALLOC section. */ 146 *shndxp = alloc ? shndx : (GElf_Word) -1; 147 148 switch (sym->st_shndx) 149 { 150 case SHN_ABS: /* XXX sometimes should use bias?? */ 151 case SHN_UNDEF: 152 case SHN_COMMON: 153 break; 154 155 default: 156 if (mod->e_type == ET_REL) 157 { 158 /* In an ET_REL file, the symbol table values are relative 159 to the section, not to the module's load base. */ 160 size_t symshstrndx = SHN_UNDEF; 161 Dwfl_Error result = __libdwfl_relocate_value (mod, elf, 162 &symshstrndx, 163 shndx, &st_value); 164 if (unlikely (result != DWFL_E_NOERROR)) 165 { 166 __libdwfl_seterrno (result); 167 return NULL; 168 } 169 } 170 else if (alloc) 171 /* Apply the bias to the symbol value. */ 172 st_value = dwfl_adjusted_st_value (mod, 173 *resolved ? mod->main.elf : elf, 174 st_value); 175 break; 176 } 177 178 if (adjust_st_value) 179 sym->st_value = st_value; 180 181 if (addr != NULL) 182 *addr = st_value; 183 184 if (unlikely (sym->st_name >= symstrdata->d_size)) 185 { 186 __libdwfl_seterrno (DWFL_E_BADSTROFF); 187 return NULL; 188 } 189 if (elfp) 190 *elfp = elf; 191 if (biasp) 192 *biasp = dwfl_adjusted_st_value (mod, elf, 0); 193 return (const char *) symstrdata->d_buf + sym->st_name; 194} 195 196const char * 197dwfl_module_getsym_info (Dwfl_Module *mod, int ndx, 198 GElf_Sym *sym, GElf_Addr *addr, 199 GElf_Word *shndxp, 200 Elf **elfp, Dwarf_Addr *bias) 201{ 202 bool resolved; 203 return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias, 204 &resolved, false); 205} 206INTDEF (dwfl_module_getsym_info) 207 208const char * 209dwfl_module_getsym (Dwfl_Module *mod, int ndx, 210 GElf_Sym *sym, GElf_Word *shndxp) 211{ 212 bool resolved; 213 return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL, 214 &resolved, true); 215} 216INTDEF (dwfl_module_getsym) 217