Branch data Line data Source code
1 : : /* Find debugging and symbol information for a module in libdwfl.
2 : : Copyright (C) 2006-2013 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 : 463305583 : dwfl_module_getsym (Dwfl_Module *mod, int ndx,
33 : : GElf_Sym *sym, GElf_Word *shndxp)
34 : : {
35 [ + - ]: 463305583 : if (unlikely (mod == NULL))
36 : : return NULL;
37 : :
38 [ + + ]: 463305583 : if (unlikely (mod->symdata == NULL))
39 : : {
40 : 26 : int result = INTUSE(dwfl_module_getsymtab) (mod);
41 [ + - ]: 26 : if (result < 0)
42 : : return NULL;
43 : : }
44 : :
45 : : /* All local symbols should come before all global symbols. If we
46 : : have an auxiliary table make sure all the main locals come first,
47 : : then all aux locals, then all main globals and finally all aux globals.
48 : : And skip the auxiliary table zero undefined entry. */
49 : : GElf_Word shndx;
50 : 463305583 : int tndx = ndx;
51 [ + + ][ + + ]: 463305583 : int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
52 : : struct dwfl_file *file;
53 : : Elf_Data *symdata;
54 : : Elf_Data *symxndxdata;
55 : : Elf_Data *symstrdata;
56 [ + + ]: 463305583 : if (mod->aux_symdata == NULL
57 [ + + ]: 421 : || ndx < mod->first_global)
58 : : {
59 : : /* main symbol table (locals). */
60 : 463305169 : tndx = ndx;
61 : 463305169 : file = mod->symfile;
62 : 463305169 : symdata = mod->symdata;
63 : 463305169 : symxndxdata = mod->symxndxdata;
64 : 463305169 : symstrdata = mod->symstrdata;
65 : : }
66 [ + + ]: 414 : else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero)
67 : : {
68 : : /* aux symbol table (locals). */
69 : 191 : tndx = ndx - mod->first_global + skip_aux_zero;
70 : 191 : file = &mod->aux_sym;
71 : 191 : symdata = mod->aux_symdata;
72 : 191 : symxndxdata = mod->aux_symxndxdata;
73 : 191 : symstrdata = mod->aux_symstrdata;
74 : : }
75 [ + + ]: 223 : else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero)
76 : : {
77 : : /* main symbol table (globals). */
78 : 156 : tndx = ndx - mod->aux_first_global + skip_aux_zero;
79 : 156 : file = mod->symfile;
80 : 156 : symdata = mod->symdata;
81 : 156 : symxndxdata = mod->symxndxdata;
82 : 156 : symstrdata = mod->symstrdata;
83 : : }
84 : : else
85 : : {
86 : : /* aux symbol table (globals). */
87 : 67 : tndx = ndx - mod->syments + skip_aux_zero;
88 : 67 : file = &mod->aux_sym;
89 : 67 : symdata = mod->aux_symdata;
90 : 67 : symxndxdata = mod->aux_symxndxdata;
91 : 67 : symstrdata = mod->aux_symstrdata;
92 : : }
93 : 463305583 : sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
94 : :
95 [ - + ]: 463305583 : if (unlikely (sym == NULL))
96 : : {
97 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
98 : : return NULL;
99 : : }
100 : :
101 [ + - ]: 463305583 : if (sym->st_shndx != SHN_XINDEX)
102 : 463305583 : shndx = sym->st_shndx;
103 : :
104 : : /* Figure out whether this symbol points into an SHF_ALLOC section. */
105 : 463305583 : bool alloc = true;
106 [ - + ][ # # ]: 463305583 : if ((shndxp != NULL || mod->e_type != ET_REL)
107 [ + + ]: 463305583 : && (sym->st_shndx == SHN_XINDEX
108 : 463305583 : || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
109 : : {
110 : : GElf_Shdr shdr_mem;
111 : 381196109 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (file->elf, shndx),
112 : : &shdr_mem);
113 [ + + ][ + + ]: 381196109 : alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
114 : : }
115 : :
116 [ + - ]: 463305583 : if (shndxp != NULL)
117 : : /* Yield -1 in case of a non-SHF_ALLOC section. */
118 [ + + ]: 463305583 : *shndxp = alloc ? shndx : (GElf_Word) -1;
119 : :
120 [ + + ]: 463305583 : switch (sym->st_shndx)
121 : : {
122 : : case SHN_ABS: /* XXX sometimes should use bias?? */
123 : : case SHN_UNDEF:
124 : : case SHN_COMMON:
125 : : break;
126 : :
127 : : default:
128 [ + + ]: 381196109 : if (mod->e_type == ET_REL)
129 : : {
130 : : /* In an ET_REL file, the symbol table values are relative
131 : : to the section, not to the module's load base. */
132 : 845126 : size_t symshstrndx = SHN_UNDEF;
133 : 845126 : Dwfl_Error result = __libdwfl_relocate_value (mod, file->elf,
134 : : &symshstrndx,
135 : 845126 : shndx, &sym->st_value);
136 [ - + ]: 845126 : if (unlikely (result != DWFL_E_NOERROR))
137 : : {
138 : 845126 : __libdwfl_seterrno (result);
139 : : return NULL;
140 : : }
141 : : }
142 [ + + ]: 380350983 : else if (alloc)
143 : : /* Apply the bias to the symbol value. */
144 : 377798784 : sym->st_value = dwfl_adjusted_st_value (mod, file, sym->st_value);
145 : : break;
146 : : }
147 : :
148 [ - + ]: 463305583 : if (unlikely (sym->st_name >= symstrdata->d_size))
149 : : {
150 : 0 : __libdwfl_seterrno (DWFL_E_BADSTROFF);
151 : : return NULL;
152 : : }
153 : 463305583 : return (const char *) symstrdata->d_buf + sym->st_name;
154 : : }
155 : 377798784 : INTDEF (dwfl_module_getsym)
|