blob: 42d2b6792eb19d53327ab91e35ac8ff191476bba [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Find debugging and symbol information for a module in libdwfl.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2006-2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004
Elliott Hughes03333822015-02-18 22:19:45 -08005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08007
Elliott Hughes03333822015-02-18 22:19:45 -08008 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080021 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
Elliott Hughes03333822015-02-18 22:19:45 -080025 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080028
29#include "libdwflP.h"
30
31const char *
Elliott Hughes03333822015-02-18 22:19:45 -080032internal_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)
Ben Cheng25b3c042013-11-20 14:45:36 -080036{
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
Elliott Hughes03333822015-02-18 22:19:45 -080047 /* 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. */
Ben Cheng25b3c042013-11-20 14:45:36 -080051 GElf_Word shndx;
Elliott Hughes03333822015-02-18 22:19:45 -080052 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
Ben Cheng25b3c042013-11-20 14:45:36 -080097 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;
Elliott Hughes03333822015-02-18 22:19:45 -0800113 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem);
Ben Cheng25b3c042013-11-20 14:45:36 -0800114 alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
115 }
116
Elliott Hughes03333822015-02-18 22:19:45 -0800117 /* 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
Ben Cheng25b3c042013-11-20 14:45:36 -0800144 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;
Elliott Hughes03333822015-02-18 22:19:45 -0800161 Dwfl_Error result = __libdwfl_relocate_value (mod, elf,
Ben Cheng25b3c042013-11-20 14:45:36 -0800162 &symshstrndx,
Elliott Hughes03333822015-02-18 22:19:45 -0800163 shndx, &st_value);
Ben Cheng25b3c042013-11-20 14:45:36 -0800164 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. */
Elliott Hughes03333822015-02-18 22:19:45 -0800172 st_value = dwfl_adjusted_st_value (mod,
173 *resolved ? mod->main.elf : elf,
174 st_value);
Ben Cheng25b3c042013-11-20 14:45:36 -0800175 break;
176 }
177
Elliott Hughes03333822015-02-18 22:19:45 -0800178 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))
Ben Cheng25b3c042013-11-20 14:45:36 -0800185 {
186 __libdwfl_seterrno (DWFL_E_BADSTROFF);
187 return NULL;
188 }
Elliott Hughes03333822015-02-18 22:19:45 -0800189 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);
Ben Cheng25b3c042013-11-20 14:45:36 -0800215}
216INTDEF (dwfl_module_getsym)