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 4 : nlist (const char *filename, struct nlist *nl)
61 : {
62 4 : int fd;
63 4 : Elf *elf;
64 4 : Elf_Scn *scn = NULL;
65 4 : Elf_Scn *symscn = NULL;
66 4 : GElf_Shdr shdr_mem;
67 4 : GElf_Shdr *shdr = NULL;
68 4 : Elf_Data *data;
69 4 : struct nlist_fshash *table;
70 4 : size_t nsyms;
71 4 : size_t cnt;
72 :
73 : /* Open the file. */
74 4 : fd = open (filename, O_RDONLY);
75 4 : if (fd == -1)
76 : {
77 2 : __libelf_seterrno (ELF_E_NOFILE);
78 2 : 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 2 : INTUSE(elf_version) (EV_CURRENT);
85 :
86 : /* Now get an ELF descriptor. */
87 2 : elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
88 2 : if (elf == NULL)
89 : 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 72 : while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
94 : {
95 72 : shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
96 72 : if (shdr == NULL)
97 : goto fail_close;
98 :
99 : /* That is what we are looking for. */
100 72 : if (shdr->sh_type == SHT_SYMTAB)
101 : {
102 : symscn = scn;
103 : break;
104 : }
105 :
106 : /* Better than nothing. Remember this section. */
107 70 : if (shdr->sh_type == SHT_DYNSYM)
108 2 : symscn = scn;
109 : }
110 :
111 2 : if (symscn == NULL)
112 : /* We haven't found anything. Fail. */
113 : goto fail_close;
114 :
115 : /* Re-get the section header in case we found only the dynamic symbol
116 : table. */
117 2 : if (scn == NULL)
118 : {
119 0 : shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
120 0 : if (unlikely (shdr == NULL))
121 : 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 2 : data = INTUSE(elf_getdata) (symscn, NULL);
127 2 : if (data == NULL)
128 : goto fail_close;
129 :
130 : /* How many symbols are there? */
131 4 : nsyms = (shdr->sh_size
132 2 : / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
133 :
134 : /* Create the hash table. */
135 2 : table = nlist_fshash_init (nsyms);
136 2 : 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 1154 : for (cnt = 0; cnt < nsyms; ++cnt)
144 : {
145 1152 : struct hashentry mem;
146 1152 : GElf_Sym *sym;
147 :
148 : /* Get the symbol. */
149 1152 : sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
150 1152 : if (sym == NULL)
151 0 : goto fail_dealloc;
152 :
153 : /* Get the name of the symbol. */
154 1152 : mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
155 1152 : if (mem.str == NULL)
156 : goto fail_dealloc;
157 :
158 : /* Don't allow zero-length strings. */
159 1152 : if (mem.str[0] == '\0')
160 74 : 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 1078 : (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 12 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
177 : {
178 10 : struct hashentry search;
179 10 : const struct hashentry *found;
180 :
181 : /* Search for a matching entry in the hash table. */
182 10 : search.str = nl->n_name;
183 10 : found = nlist_fshash_find (table, nl->n_name, 0, &search);
184 :
185 10 : if (found != NULL)
186 : {
187 : /* Found it. */
188 8 : nl->n_value = found->sym.st_value;
189 8 : nl->n_scnum = found->sym.st_shndx;
190 8 : nl->n_type = GELF_ST_TYPE (found->sym.st_info);
191 : /* XXX What shall we fill in the next fields? */
192 8 : nl->n_sclass = 0;
193 8 : nl->n_numaux = 0;
194 : }
195 : else
196 : {
197 : /* Not there. */
198 2 : nl->n_value = 0;
199 2 : nl->n_scnum = 0;
200 2 : nl->n_type = 0;
201 2 : nl->n_sclass = 0;
202 2 : nl->n_numaux = 0;
203 : }
204 :
205 : /* Next search request. */
206 10 : ++nl;
207 : }
208 :
209 : /* Free the resources. */
210 2 : nlist_fshash_fini (table);
211 :
212 : /* We do not need the ELF descriptor anymore. */
213 2 : (void) INTUSE(elf_end) (elf);
214 :
215 : /* Neither the file descriptor. */
216 2 : (void) close (fd);
217 :
218 2 : 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 12 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
234 : {
235 10 : nl->n_value = 0;
236 10 : nl->n_scnum = 0;
237 10 : nl->n_type = 0;
238 10 : nl->n_sclass = 0;
239 10 : nl->n_numaux = 0;
240 :
241 : /* Next entry. */
242 10 : ++nl;
243 : }
244 :
245 : return -1;
246 : }
|