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