• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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      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    data = INTUSE(elf_getdata) (symscn, NULL);
124    if (data == NULL)
125      goto fail_close;
126  
127    /* How many symbols are there?  */
128    nsyms = (shdr->sh_size
129  	   / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, data->d_version));
130  
131    /* Create the hash table.  */
132    table = nlist_fshash_init (nsyms);
133    if (table == NULL)
134      {
135        __libelf_seterrno (ELF_E_NOMEM);
136        goto fail_close;
137      }
138  
139    /* Iterate over all the symbols in the section.  */
140    for (cnt = 0; cnt < nsyms; ++cnt)
141      {
142        struct hashentry mem;
143        GElf_Sym *sym;
144  
145        /* Get the symbol.  */
146        sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
147        if (sym == NULL)
148  	goto fail_dealloc;
149  
150        /* Get the name of the symbol.  */
151        mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
152        if (mem.str == NULL)
153  	goto fail_dealloc;
154  
155        /* Don't allow zero-length strings.  */
156        if (mem.str[0] == '\0')
157  	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        (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    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        search.str = nl->n_name;
180        found = nlist_fshash_find (table, nl->n_name, 0, &search);
181  
182        if (found != NULL)
183  	{
184  	  /* Found it.  */
185  	  nl->n_value = found->sym.st_value;
186  	  nl->n_scnum = found->sym.st_shndx;
187  	  nl->n_type = GELF_ST_TYPE (found->sym.st_info);
188  	  /* XXX What shall we fill in the next fields?  */
189  	  nl->n_sclass = 0;
190  	  nl->n_numaux = 0;
191  	}
192        else
193  	{
194  	  /* Not there.  */
195  	  nl->n_value = 0;
196  	  nl->n_scnum = 0;
197  	  nl->n_type = 0;
198  	  nl->n_sclass = 0;
199  	  nl->n_numaux = 0;
200  	}
201  
202        /* Next search request.  */
203        ++nl;
204      }
205  
206    /* Free the resources.  */
207    nlist_fshash_fini (table);
208  
209    /* We do not need the ELF descriptor anymore.  */
210    (void) INTUSE(elf_end) (elf);
211  
212    /* Neither the file descriptor.  */
213    (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    (void) INTUSE(elf_end) (elf);
223  
224   fail_fd:
225    /* Neither the file descriptor.  */
226    (void) close (fd);
227  
228   fail:
229    /* We have to set all entries to zero.  */
230    while (nl->n_name != NULL && nl->n_name[0] != '\0')
231      {
232        nl->n_value = 0;
233        nl->n_scnum = 0;
234        nl->n_type = 0;
235        nl->n_sclass = 0;
236        nl->n_numaux = 0;
237  
238        /* Next entry.  */
239        ++nl;
240      }
241  
242    return -1;
243  }
244