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
31 const char *
32 internal_function
__libdwfl_getsym(Dwfl_Module * mod,int ndx,GElf_Sym * sym,GElf_Addr * addr,GElf_Word * shndxp,Elf ** elfp,Dwarf_Addr * biasp,bool * resolved,bool adjust_st_value)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
196 const char *
dwfl_module_getsym_info(Dwfl_Module * mod,int ndx,GElf_Sym * sym,GElf_Addr * addr,GElf_Word * shndxp,Elf ** elfp,Dwarf_Addr * bias)197 dwfl_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 }
INTDEF(dwfl_module_getsym_info)206 INTDEF (dwfl_module_getsym_info)
207
208 const char *
209 dwfl_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 }
216 INTDEF (dwfl_module_getsym)
217