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 : : #include <unistd.h>
39 : :
40 : : #include "libelfP.h"
41 : :
42 : :
43 : : struct hashentry
44 : : {
45 : : const char *str;
46 : : GElf_Sym sym;
47 : : };
48 : : #define TYPE struct hashentry
49 : : /* XXX Use a better hash function some day. */
50 : : #define HASHFCT(str, len) INTUSE(elf_hash) (str)
51 : : #define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str)
52 : : #define CLASS static
53 : : #define PREFIX nlist_
54 : : #define xcalloc(n, m) calloc (n, m)
55 : : #define next_prime(s) __libelf_next_prime (s)
56 : : #include <fixedsizehash.h>
57 : :
58 : :
59 : : int
60 : 2 : nlist (const char *filename, struct nlist *nl)
61 : : {
62 : 2 : int fd;
63 : 2 : Elf *elf;
64 : 2 : Elf_Scn *scn = NULL;
65 : 2 : Elf_Scn *symscn = NULL;
66 : 2 : GElf_Shdr shdr_mem;
67 : 2 : GElf_Shdr *shdr = NULL;
68 : 2 : Elf_Data *data;
69 : 2 : struct nlist_fshash *table;
70 : 2 : size_t nsyms;
71 : 2 : size_t cnt;
72 : :
73 : : /* Open the file. */
74 : 2 : fd = open (filename, O_RDONLY);
75 [ + + ]: 2 : if (fd == -1)
76 : : {
77 : 1 : __libelf_seterrno (ELF_E_NOFILE);
78 : 1 : goto fail;
79 : : }
80 : :
81 : : /* For compatibility reasons (`nlist' existed before ELF and libelf)
82 : : we don't expect the caller to set the ELF version. Do this here
83 : : as if it hasn't happened yet. */
84 : 1 : INTUSE(elf_version) (EV_CURRENT);
85 : :
86 : : /* Now get an ELF descriptor. */
87 : 1 : elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
88 [ - + ]: 1 : if (elf == NULL)
89 : 0 : goto fail_fd;
90 : :
91 : : /* Find a symbol table. We prefer the real symbol table but if it
92 : : does not exist use the dynamic symbol table. */
93 [ + - ]: 35 : while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
94 : : {
95 : 35 : shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
96 [ - + ]: 35 : if (shdr == NULL)
97 : 0 : goto fail_close;
98 : :
99 : : /* That is what we are looking for. */
100 [ + + ]: 35 : if (shdr->sh_type == SHT_SYMTAB)
101 : : {
102 : : symscn = scn;
103 : : break;
104 : : }
105 : :
106 : : /* Better than nothing. Remember this section. */
107 [ + + ]: 34 : if (shdr->sh_type == SHT_DYNSYM)
108 : 1 : symscn = scn;
109 : : }
110 : :
111 [ - + ]: 1 : if (symscn == NULL)
112 : : /* We haven't found anything. Fail. */
113 : 0 : goto fail_close;
114 : :
115 : : /* Re-get the section header in case we found only the dynamic symbol
116 : : table. */
117 [ - + ]: 1 : if (scn == NULL)
118 : : {
119 : 0 : shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
120 [ # # ]: 0 : if (unlikely (shdr == NULL))
121 : 0 : goto fail_close;
122 : : }
123 : : /* SHDR->SH_LINK now contains the index of the string section. */
124 : :
125 : : /* Get the data for the symbol section. */
126 : 1 : data = INTUSE(elf_getdata) (symscn, NULL);
127 [ - + ]: 1 : if (data == NULL)
128 : 0 : goto fail_close;
129 : :
130 : : /* How many symbols are there? */
131 : 2 : nsyms = (shdr->sh_size
132 : 1 : / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
133 : :
134 : : /* Create the hash table. */
135 : 1 : table = nlist_fshash_init (nsyms);
136 [ - + ]: 1 : if (table == NULL)
137 : : {
138 : 0 : __libelf_seterrno (ELF_E_NOMEM);
139 : 0 : goto fail_close;
140 : : }
141 : :
142 : : /* Iterate over all the symbols in the section. */
143 [ + + ]: 890 : for (cnt = 0; cnt < nsyms; ++cnt)
144 : : {
145 : 889 : struct hashentry mem;
146 : 889 : GElf_Sym *sym;
147 : :
148 : : /* Get the symbol. */
149 : 889 : sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
150 [ - + ]: 889 : if (sym == NULL)
151 : 0 : goto fail_dealloc;
152 : :
153 : : /* Get the name of the symbol. */
154 : 889 : mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
155 [ - + ]: 889 : if (mem.str == NULL)
156 : 0 : goto fail_dealloc;
157 : :
158 : : /* Don't allow zero-length strings. */
159 [ + + ]: 889 : if (mem.str[0] == '\0')
160 : 36 : continue;
161 : :
162 : : /* And add it to the hash table. Note that we are using the
163 : : overwrite version. This will ensure that
164 : : a) global symbols are preferred over local symbols since
165 : : they are all located at the end
166 : : b) if there are multiple local symbols with the same name
167 : : the last one is used.
168 : : */
169 : 853 : (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
170 : : }
171 : :
172 : : /* Now it is time to look for the symbols the user asked for.
173 : : XXX What is a `null name/null string'? This is what the
174 : : standard says terminates the list. Is it a null pointer
175 : : or a zero-length string? We test for both... */
176 [ + + + - ]: 6 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
177 : : {
178 : 5 : struct hashentry search;
179 : 5 : const struct hashentry *found;
180 : :
181 : : /* Search for a matching entry in the hash table. */
182 : 5 : search.str = nl->n_name;
183 : 5 : found = nlist_fshash_find (table, nl->n_name, 0, &search);
184 : :
185 [ + + ]: 5 : if (found != NULL)
186 : : {
187 : : /* Found it. */
188 : 4 : nl->n_value = found->sym.st_value;
189 : 4 : nl->n_scnum = found->sym.st_shndx;
190 : 4 : nl->n_type = GELF_ST_TYPE (found->sym.st_info);
191 : : /* XXX What shall we fill in the next fields? */
192 : 4 : nl->n_sclass = 0;
193 : 4 : nl->n_numaux = 0;
194 : : }
195 : : else
196 : : {
197 : : /* Not there. */
198 : 1 : nl->n_value = 0;
199 : 1 : nl->n_scnum = 0;
200 : 1 : nl->n_type = 0;
201 : 1 : nl->n_sclass = 0;
202 : 1 : nl->n_numaux = 0;
203 : : }
204 : :
205 : : /* Next search request. */
206 : 5 : ++nl;
207 : : }
208 : :
209 : : /* Free the resources. */
210 : 1 : nlist_fshash_fini (table);
211 : :
212 : : /* We do not need the ELF descriptor anymore. */
213 : 1 : (void) INTUSE(elf_end) (elf);
214 : :
215 : : /* Neither the file descriptor. */
216 : 1 : (void) close (fd);
217 : :
218 : 1 : return 0;
219 : :
220 : 0 : fail_dealloc:
221 : 0 : nlist_fshash_fini (table);
222 : :
223 : 0 : fail_close:
224 : : /* We do not need the ELF descriptor anymore. */
225 : 0 : (void) INTUSE(elf_end) (elf);
226 : :
227 : 0 : fail_fd:
228 : : /* Neither the file descriptor. */
229 : 0 : (void) close (fd);
230 : :
231 : : fail:
232 : : /* We have to set all entries to zero. */
233 [ + + + - ]: 6 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
234 : : {
235 : 5 : nl->n_value = 0;
236 : 5 : nl->n_scnum = 0;
237 : 5 : nl->n_type = 0;
238 : 5 : nl->n_sclass = 0;
239 : 5 : nl->n_numaux = 0;
240 : :
241 : : /* Next entry. */
242 : 5 : ++nl;
243 : : }
244 : :
245 : : return -1;
246 : : }
|