Branch data Line data Source code
1 : : /* Extract symbol list from binary.
2 : : Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007 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 : 36 : 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 : 0 : shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
120 : : /* SHDR->SH_LINK now contains the index of the string section. */
121 : :
122 : : /* Get the data for the symbol section. */
123 : 1 : data = INTUSE(elf_getdata) (symscn, NULL);
124 [ + - ]: 1 : if (data == NULL)
125 : : goto fail_close;
126 : :
127 : : /* How many symbols are there? */
128 : 2 : nsyms = (shdr->sh_size
129 : 1 : / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, data->d_version));
130 : :
131 : : /* Create the hash table. */
132 : 1 : table = nlist_fshash_init (nsyms);
133 [ + - ]: 1 : if (table == NULL)
134 : : {
135 : 0 : __libelf_seterrno (ELF_E_NOMEM);
136 : 0 : goto fail_close;
137 : : }
138 : :
139 : : /* Iterate over all the symbols in the section. */
140 [ + + ]: 487 : for (cnt = 0; cnt < nsyms; ++cnt)
141 : : {
142 : : struct hashentry mem;
143 : : GElf_Sym *sym;
144 : :
145 : : /* Get the symbol. */
146 : 486 : sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
147 [ + - ]: 486 : if (sym == NULL)
148 : : goto fail_dealloc;
149 : :
150 : : /* Get the name of the symbol. */
151 : 486 : mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
152 [ + - ]: 486 : if (mem.str == NULL)
153 : : goto fail_dealloc;
154 : :
155 : : /* Don't allow zero-length strings. */
156 [ + + ]: 486 : if (mem.str[0] == '\0')
157 : 36 : continue;
158 : :
159 : : /* And add it to the hash table. Note that we are using the
160 : : overwrite version. This will ensure that
161 : : a) global symbols are preferred over local symbols since
162 : : they are all located at the end
163 : : b) if there are multiple local symbols with the same name
164 : : the last one is used.
165 : : */
166 : 450 : (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
167 : : }
168 : :
169 : : /* Now it is time to look for the symbols the user asked for.
170 : : XXX What is a `null name/null string'? This is what the
171 : : standard says terminates the list. Is it a null pointer
172 : : or a zero-length string? We test for both... */
173 [ + + ][ + - ]: 6 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
174 : : {
175 : : struct hashentry search;
176 : : const struct hashentry *found;
177 : :
178 : : /* Search for a matching entry in the hash table. */
179 : 5 : search.str = nl->n_name;
180 : 5 : found = nlist_fshash_find (table, nl->n_name, 0, &search);
181 : :
182 [ + + ]: 5 : if (found != NULL)
183 : : {
184 : : /* Found it. */
185 : 4 : nl->n_value = found->sym.st_value;
186 : 4 : nl->n_scnum = found->sym.st_shndx;
187 : 4 : nl->n_type = GELF_ST_TYPE (found->sym.st_info);
188 : : /* XXX What shall we fill in the next fields? */
189 : 4 : nl->n_sclass = 0;
190 : 4 : nl->n_numaux = 0;
191 : : }
192 : : else
193 : : {
194 : : /* Not there. */
195 : 1 : nl->n_value = 0;
196 : 1 : nl->n_scnum = 0;
197 : 1 : nl->n_type = 0;
198 : 1 : nl->n_sclass = 0;
199 : 1 : nl->n_numaux = 0;
200 : : }
201 : :
202 : : /* Next search request. */
203 : 5 : ++nl;
204 : : }
205 : :
206 : : /* Free the resources. */
207 : : nlist_fshash_fini (table);
208 : :
209 : : /* We do not need the ELF descriptor anymore. */
210 : 1 : (void) INTUSE(elf_end) (elf);
211 : :
212 : : /* Neither the file descriptor. */
213 : 1 : (void) close (fd);
214 : :
215 : : return 0;
216 : :
217 : : fail_dealloc:
218 : : nlist_fshash_fini (table);
219 : :
220 : : fail_close:
221 : : /* We do not need the ELF descriptor anymore. */
222 : 0 : (void) INTUSE(elf_end) (elf);
223 : :
224 : : fail_fd:
225 : : /* Neither the file descriptor. */
226 : 0 : (void) close (fd);
227 : :
228 : : fail:
229 : : /* We have to set all entries to zero. */
230 [ + + ][ + - ]: 7 : while (nl->n_name != NULL && nl->n_name[0] != '\0')
231 : : {
232 : 5 : nl->n_value = 0;
233 : 5 : nl->n_scnum = 0;
234 : 5 : nl->n_type = 0;
235 : 5 : nl->n_sclass = 0;
236 : 5 : nl->n_numaux = 0;
237 : :
238 : : /* Next entry. */
239 : 5 : ++nl;
240 : : }
241 : :
242 : : return -1;
243 : : }
|