• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Extract symbol list from binary.
2    Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, version 2.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <fcntl.h>
23 #include <gelf.h>
24 #include <libelf.h>
25 #include <nlist.h>
26 #include <unistd.h>
27 
28 #include "libelfP.h"
29 
30 
31 struct hashentry
32 {
33   const char *str;
34   GElf_Sym sym;
35 };
36 #define TYPE struct hashentry
37 /* XXX Use a better hash function some day.  */
38 #define HASHFCT(str, len) INTUSE(elf_hash) (str)
39 #define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str)
40 #define CLASS static
41 #define PREFIX nlist_
42 #define xcalloc(n, m) calloc (n, m)
43 #define next_prime(s) __libelf_next_prime (s)
44 #include <fixedsizehash.h>
45 
46 
47 int
nlist(const char * filename,struct nlist * nl)48 nlist (const char *filename, struct nlist *nl)
49 {
50   int fd;
51   Elf *elf;
52   Elf_Scn *scn = NULL;
53   Elf_Scn *symscn = NULL;
54   GElf_Shdr shdr_mem;
55   GElf_Shdr *shdr = NULL;
56   Elf_Data *data;
57   struct nlist_fshash *table;
58   size_t nsyms;
59   size_t cnt;
60 
61   /* Open the file.  */
62   fd = open (filename, O_RDONLY);
63   if (fd == -1)
64     {
65       __libelf_seterrno (ELF_E_NOFILE);
66       goto fail;
67     }
68 
69   /* For compatibility reasons (`nlist' existed before ELF and libelf)
70      we don't expect the caller to set the ELF version.  Do this here
71      if it hasn't happened yet.  */
72   if (__libelf_version_initialized == 0)
73     INTUSE(elf_version) (EV_CURRENT);
74 
75   /* Now get an ELF descriptor.  */
76   elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
77   if (elf == NULL)
78     goto fail;
79 
80   /* Find a symbol table.  We prefer the real symbol table but if it
81      does not exist use the dynamic symbol table.  */
82   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
83     {
84       shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
85       if (shdr == NULL)
86 	goto fail_close;
87 
88       /* That is what we are looking for.  */
89       if (shdr->sh_type == SHT_SYMTAB)
90 	{
91 	  symscn = scn;
92 	  break;
93 	}
94 
95       /* Better than nothing.  Remember this section.  */
96       if (shdr->sh_type == SHT_DYNSYM)
97 	symscn = scn;
98     }
99 
100   if (symscn == NULL)
101     /* We haven't found anything.  Fail.  */
102     goto fail_close;
103 
104   /* Re-get the section header in case we found only the dynamic symbol
105      table.  */
106   if (scn == NULL)
107     shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
108   /* SHDR->SH_LINK now contains the index of the string section.  */
109 
110   /* Get the data for the symbol section.  */
111   data = INTUSE(elf_getdata) (symscn, NULL);
112   if (data == NULL)
113     goto fail_close;
114 
115   /* How many symbols are there?  */
116   nsyms = (shdr->sh_size
117 	   / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, data->d_version));
118 
119   /* Create the hash table.  */
120   table = nlist_fshash_init (nsyms);
121   if (table == NULL)
122     {
123       __libelf_seterrno (ELF_E_NOMEM);
124       goto fail_close;
125     }
126 
127   /* Iterate over all the symbols in the section.  */
128   for (cnt = 0; cnt < nsyms; ++cnt)
129     {
130       struct hashentry mem;
131       GElf_Sym *sym;
132 
133       /* Get the symbol.  */
134       sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
135       if (sym == NULL)
136 	goto fail_dealloc;
137 
138       /* Get the name of the symbol.  */
139       mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
140       if (mem.str == NULL)
141 	goto fail_dealloc;
142 
143       /* Don't allow zero-length strings.  */
144       if (mem.str[0] == '\0')
145 	continue;
146 
147       /* And add it to the hash table.  Note that we are using the
148          overwrite version.  This will ensure that
149 	 a) global symbols are preferred over local symbols since
150 	    they are all located at the end
151 	 b) if there are multiple local symbols with the same name
152 	    the last one is used.
153       */
154       (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
155     }
156 
157   /* Now it is time to look for the symbols the user asked for.
158      XXX What is a `null name/null string'?  This is what the
159      standard says terminates the list.  Is it a null pointer
160      or a zero-length string?  We test for both...  */
161   while (nl->n_name != NULL && nl->n_name[0] != '\0')
162     {
163       struct hashentry search;
164       const struct hashentry *found;
165 
166       /* Search for a matching entry in the hash table.  */
167       search.str = nl->n_name;
168       found = nlist_fshash_find (table, nl->n_name, 0, &search);
169 
170       if (found != NULL)
171 	{
172 	  /* Found it.  */
173 	  nl->n_value = found->sym.st_value;
174 	  nl->n_scnum = found->sym.st_shndx;
175 	  nl->n_type = GELF_ST_TYPE (found->sym.st_info);
176 	  /* XXX What shall we fill in the next fields?  */
177 	  nl->n_sclass = 0;
178 	  nl->n_numaux = 0;
179 	}
180       else
181 	{
182 	  /* Not there.  */
183 	  nl->n_value = 0;
184 	  nl->n_scnum = 0;
185 	  nl->n_type = 0;
186 	  nl->n_sclass = 0;
187 	  nl->n_numaux = 0;
188 	}
189 
190       /* Next search request.  */
191       ++nl;
192     }
193 
194   /* Free the resources.  */
195   nlist_fshash_fini (table);
196 
197   /* We do not need the ELF descriptor anymore.  */
198   (void) elf_end (elf);
199 
200   return 0;
201 
202  fail_dealloc:
203   nlist_fshash_fini (table);
204 
205  fail_close:
206   /* We do not need the ELF descriptor anymore.  */
207   (void) elf_end (elf);
208 
209  fail:
210   /* We have to set all entries to zero.  */
211   while (nl->n_name != NULL && nl->n_name[0] != '\0')
212     {
213       nl->n_value = 0;
214       nl->n_scnum = 0;
215       nl->n_type = 0;
216       nl->n_sclass = 0;
217       nl->n_numaux = 0;
218 
219       /* Next entry.  */
220       ++nl;
221     }
222 
223   return -1;
224 }
225