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.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
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)
37 if (unlikely (mod == NULL))
40 if (unlikely (mod->symdata == NULL))
42 int result = INTUSE(dwfl_module_getsymtab) (mod);
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. */
53 int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
56 Elf_Data *symxndxdata;
58 if (mod->aux_symdata == NULL
59 || ndx < mod->first_global)
61 /* main symbol table (locals). */
63 elf = mod->symfile->elf;
64 symdata = mod->symdata;
65 symxndxdata = mod->symxndxdata;
66 symstrdata = mod->symstrdata;
68 else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero)
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;
77 else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
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;
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;
95 sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
97 if (unlikely (sym == NULL))
99 __libdwfl_seterrno (DWFL_E_LIBELF);
103 if (sym->st_shndx != SHN_XINDEX)
104 shndx = sym->st_shndx;
106 /* Figure out whether this symbol points into an SHF_ALLOC section. */
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)))
113 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem);
114 alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
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
122 GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl);
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)))
130 if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
132 if (elf != mod->main.elf)
134 st_value = dwfl_adjusted_st_value (mod, elf, st_value);
135 st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value);
138 *resolved = ebl_resolve_sym_value (mod->ebl, &st_value);
140 st_value = sym->st_value;
145 /* Yield -1 in case of a non-SHF_ALLOC section. */
146 *shndxp = alloc ? shndx : (GElf_Word) -1;
148 switch (sym->st_shndx)
150 case SHN_ABS: /* XXX sometimes should use bias?? */
156 if (mod->e_type == ET_REL)
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,
164 if (unlikely (result != DWFL_E_NOERROR))
166 __libdwfl_seterrno (result);
171 /* Apply the bias to the symbol value. */
172 st_value = dwfl_adjusted_st_value (mod,
173 *resolved ? mod->main.elf : elf,
179 sym->st_value = st_value;
184 if (unlikely (sym->st_name >= symstrdata->d_size))
186 __libdwfl_seterrno (DWFL_E_BADSTROFF);
192 *biasp = dwfl_adjusted_st_value (mod, elf, 0);
193 return (const char *) symstrdata->d_buf + sym->st_name;
197 dwfl_module_getsym_info (Dwfl_Module *mod, int ndx,
198 GElf_Sym *sym, GElf_Addr *addr,
200 Elf **elfp, Dwarf_Addr *bias)
203 return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias,
206 INTDEF (dwfl_module_getsym_info)
209 dwfl_module_getsym (Dwfl_Module *mod, int ndx,
210 GElf_Sym *sym, GElf_Word *shndxp)
213 return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL,
216 INTDEF (dwfl_module_getsym)