• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
nlist(const char * filename,struct nlist * nl)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 }
248