Branch data Line data Source code
1 : : /* Extract symbol list from binary.
2 : : Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <fcntl.h>
35 : : #include <gelf.h>
36 : : #include <libelf.h>
37 : : #include <nlist.h>
38 : :
39 : : #include "libelfP.h"
40 : :
41 : :
42 : : struct hashentry
43 : : {
44 : : const char *str;
45 : : GElf_Sym sym;
46 : : };
47 : : #define TYPE struct hashentry
48 : : /* XXX Use a better hash function some day. */
49 : : #define HASHFCT(str, len) INTUSE(elf_hash) (str)
50 : : #define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str)
51 : : #define CLASS static
52 : : #define PREFIX nlist_
53 : : #define xcalloc(n, m) calloc (n, m)
54 : : #define next_prime(s) __libelf_next_prime (s)
55 : : #include <fixedsizehash.h>
56 : :
57 : :
58 : : int
59 : 4 : nlist (const char *filename, struct nlist *nl)
60 : : {
61 : 4 : int fd;
62 : 4 : Elf *elf;
63 : 4 : Elf_Scn *scn = NULL;
64 : 4 : Elf_Scn *symscn = NULL;
65 : 4 : GElf_Shdr shdr_mem;
66 : 4 : GElf_Shdr *shdr = NULL;
67 : 4 : Elf_Data *data;
68 : 4 : struct nlist_fshash *table;
69 : 4 : size_t nsyms;
70 : 4 : size_t cnt;
71 : :
72 : : /* Open the file. */
73 : 4 : fd = open (filename, O_RDONLY);
74 [ + + ]: 4 : if (fd == -1)
75 : : {
76 : 2 : __libelf_seterrno (ELF_E_NOFILE);
77 : 2 : goto fail;
78 : : }
79 : :
80 : : /* For compatibility reasons (`nlist' existed before ELF and libelf)
81 : : we don't expect the caller to set the ELF version. Do this here
82 : : as if it hasn't happened yet. */
83 : 2 : INTUSE(elf_version) (EV_CURRENT);
84 : :
85 : : /* Now get an ELF descriptor. */
86 : 2 : elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
87 [ - + ]: 2 : if (elf == NULL)
88 : 0 : goto fail_fd;
89 : :
90 : : /* Find a symbol table. We prefer the real symbol table but if it
91 : : does not exist use the dynamic symbol table. */
92 [ + - ]: 76 : while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
93 : : {
94 : 76 : shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
95 [ - + ]: 76 : if (shdr == NULL)
96 : 0 : goto fail_close;
97 : :
98 : : /* That is what we are looking for. */
99 [ + + ]: 76 : if (shdr->sh_type == SHT_SYMTAB)
100 : : {
101 : : symscn = scn;
102 : : break;
103 : : }
104 : :
105 : : /* Better than nothing. Remember this section. */
106 [ + + ]: 74 : if (shdr->sh_type == SHT_DYNSYM)
107 : 2 : symscn = scn;
108 : : }
109 : :
110 [ - + ]: 2 : if (symscn == NULL)
111 : : /* We haven't found anything. Fail. */
112 : 0 : goto fail_close;
113 : :
114 : : /* Re-get the section header in case we found only the dynamic symbol
115 : : table. */
116 [ - + ]: 2 : if (scn == NULL)
117 : : {
118 : 0 : shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
119 [ # # ]: 0 : if (unlikely (shdr == NULL))
120 : 0 : goto fail_close;
121 : : }
122 : : /* SHDR->SH_LINK now contains the index of the string section. */
123 : :
124 : : /* Get the data for the symbol section. */
125 : 2 : data = INTUSE(elf_getdata) (symscn, NULL);
126 [ - + ]: 2 : if (data == NULL)
127 : 0 : goto fail_close;
128 : :
129 : : /* How many symbols are there? */
130 : 4 : nsyms = (shdr->sh_size
131 : 2 : / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
132 : :
133 : : /* Create the hash table. */
134 : 2 : table = nlist_fshash_init (nsyms);
135 [ - + ]: 2 : if (table == NULL)
136 : : {
137 : 0 : __libelf_seterrno (ELF_E_NOMEM);
138 : 0 : goto fail_close;
139 : : }
140 : :
141 : : /* Iterate over all the symbols in the section. */
142 [ + + ]: 1180 : for (cnt = 0; cnt < nsyms; ++cnt)
143 : : {
144 : 1178 : struct hashentry mem;
145 : 1178 : GElf_Sym *sym;
146 : :
147 : : /* Get the symbol. */
148 : 1178 : sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
149 [ - + ]: 1178 : if (sym == NULL)
150 : 0 : goto fail_dealloc;
151 : :
152 : : /* Get the name of the symbol. */
153 : 1178 : mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
154 [ - + ]: 1178 : if (mem.str == NULL)
155 : 0 : goto fail_dealloc;
156 : :
157 : : /* Don't allow zero-length strings. */
158 [ + + ]: 1178 : if (mem.str[0] == '\0')
159 : 4 : continue;
160 : :
161 : : /* And add it to the hash table. Note that we are using the
162 : : overwrite version. This will ensure that
163 : : a) global symbols are preferred over local symbols since
164 : : they are all located at the end
165 : : b) if there are multiple local symbols with the same name
166 : : the last one is used.
167 : : */
168 : 1174 : (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
169 : : }
170 : :
171 : : /* Now it is time to look for the symbols the user asked for.
172 : : XXX What is a `null name/null string'? This is what the
173 : : standard says terminates the list. Is it a null pointer
174 : : or a zero-length string? We test for both... */
175 [ + + + - ]: 12 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
176 : : {
177 : 10 : struct hashentry search;
178 : 10 : const struct hashentry *found;
179 : :
180 : : /* Search for a matching entry in the hash table. */
181 : 10 : search.str = nl->n_name;
182 : 10 : found = nlist_fshash_find (table, nl->n_name, 0, &search);
183 : :
184 [ + + ]: 10 : if (found != NULL)
185 : : {
186 : : /* Found it. */
187 : 8 : nl->n_value = found->sym.st_value;
188 : 8 : nl->n_scnum = found->sym.st_shndx;
189 : 8 : nl->n_type = GELF_ST_TYPE (found->sym.st_info);
190 : : /* XXX What shall we fill in the next fields? */
191 : 8 : nl->n_sclass = 0;
192 : 8 : nl->n_numaux = 0;
193 : : }
194 : : else
195 : : {
196 : : /* Not there. */
197 : 2 : nl->n_value = 0;
198 : 2 : nl->n_scnum = 0;
199 : 2 : nl->n_type = 0;
200 : 2 : nl->n_sclass = 0;
201 : 2 : nl->n_numaux = 0;
202 : : }
203 : :
204 : : /* Next search request. */
205 : 10 : ++nl;
206 : : }
207 : :
208 : : /* Free the resources. */
209 : 2 : nlist_fshash_fini (table);
210 : :
211 : : /* We do not need the ELF descriptor anymore. */
212 : 2 : (void) INTUSE(elf_end) (elf);
213 : :
214 : : /* Neither the file descriptor. */
215 : 2 : (void) close (fd);
216 : :
217 : 2 : return 0;
218 : :
219 : 0 : fail_dealloc:
220 : 0 : nlist_fshash_fini (table);
221 : :
222 : 0 : fail_close:
223 : : /* We do not need the ELF descriptor anymore. */
224 : 0 : (void) INTUSE(elf_end) (elf);
225 : :
226 : 0 : fail_fd:
227 : : /* Neither the file descriptor. */
228 : 0 : (void) close (fd);
229 : :
230 : : fail:
231 : : /* We have to set all entries to zero. */
232 [ + + + - ]: 12 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
233 : : {
234 : 10 : nl->n_value = 0;
235 : 10 : nl->n_scnum = 0;
236 : 10 : nl->n_type = 0;
237 : 10 : nl->n_sclass = 0;
238 : 10 : nl->n_numaux = 0;
239 : :
240 : : /* Next entry. */
241 : 10 : ++nl;
242 : : }
243 : :
244 : : return -1;
245 : : }
|