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