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