packaging: update homepage url
[platform/upstream/elfutils.git] / libelf / nlist.c
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 nlist (const char *filename, struct nlist *nl)
61 {
62   int fd;
63   Elf *elf;
64   Elf_Scn *scn = NULL;
65   Elf_Scn *symscn = NULL;
66   GElf_Shdr shdr_mem;
67   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   fd = open (filename, O_RDONLY);
75   if (fd == -1)
76     {
77       __libelf_seterrno (ELF_E_NOFILE);
78       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   if (__libelf_version_initialized == 0)
85     INTUSE(elf_version) (EV_CURRENT);
86
87   /* Now get an ELF descriptor.  */
88   elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
89   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   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
95     {
96       shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
97       if (shdr == NULL)
98         goto fail_close;
99
100       /* That is what we are looking for.  */
101       if (shdr->sh_type == SHT_SYMTAB)
102         {
103           symscn = scn;
104           break;
105         }
106
107       /* Better than nothing.  Remember this section.  */
108       if (shdr->sh_type == SHT_DYNSYM)
109         symscn = scn;
110     }
111
112   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   if (scn == NULL)
119     {
120       shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
121       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   data = INTUSE(elf_getdata) (symscn, NULL);
128   if (data == NULL)
129     goto fail_close;
130
131   /* How many symbols are there?  */
132   nsyms = (shdr->sh_size
133            / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
134
135   /* Create the hash table.  */
136   table = nlist_fshash_init (nsyms);
137   if (table == NULL)
138     {
139       __libelf_seterrno (ELF_E_NOMEM);
140       goto fail_close;
141     }
142
143   /* Iterate over all the symbols in the section.  */
144   for (cnt = 0; cnt < nsyms; ++cnt)
145     {
146       struct hashentry mem;
147       GElf_Sym *sym;
148
149       /* Get the symbol.  */
150       sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
151       if (sym == NULL)
152         goto fail_dealloc;
153
154       /* Get the name of the symbol.  */
155       mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
156       if (mem.str == NULL)
157         goto fail_dealloc;
158
159       /* Don't allow zero-length strings.  */
160       if (mem.str[0] == '\0')
161         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       (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   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       search.str = nl->n_name;
184       found = nlist_fshash_find (table, nl->n_name, 0, &search);
185
186       if (found != NULL)
187         {
188           /* Found it.  */
189           nl->n_value = found->sym.st_value;
190           nl->n_scnum = found->sym.st_shndx;
191           nl->n_type = GELF_ST_TYPE (found->sym.st_info);
192           /* XXX What shall we fill in the next fields?  */
193           nl->n_sclass = 0;
194           nl->n_numaux = 0;
195         }
196       else
197         {
198           /* Not there.  */
199           nl->n_value = 0;
200           nl->n_scnum = 0;
201           nl->n_type = 0;
202           nl->n_sclass = 0;
203           nl->n_numaux = 0;
204         }
205
206       /* Next search request.  */
207       ++nl;
208     }
209
210   /* Free the resources.  */
211   nlist_fshash_fini (table);
212
213   /* We do not need the ELF descriptor anymore.  */
214   (void) INTUSE(elf_end) (elf);
215
216   /* Neither the file descriptor.  */
217   (void) close (fd);
218
219   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   (void) INTUSE(elf_end) (elf);
227
228  fail_fd:
229   /* Neither the file descriptor.  */
230   (void) close (fd);
231
232  fail:
233   /* We have to set all entries to zero.  */
234   while (nl->n_name != NULL && nl->n_name[0] != '\0')
235     {
236       nl->n_value = 0;
237       nl->n_scnum = 0;
238       nl->n_type = 0;
239       nl->n_sclass = 0;
240       nl->n_numaux = 0;
241
242       /* Next entry.  */
243       ++nl;
244     }
245
246   return -1;
247 }