]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/nlist.c
nlist: retire long-obsolete aout support
[FreeBSD/FreeBSD.git] / lib / libc / gen / nlist.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __SCCSID("@(#)nlist.c   8.1 (Berkeley) 6/4/93");
34 __FBSDID("$FreeBSD$");
35
36 #include "namespace.h"
37 #include <sys/param.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <arpa/inet.h>
42
43 #include <errno.h>
44 #include <a.out.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include "un-namespace.h"
49
50 #define _NLIST_DO_ELF
51
52 #ifdef _NLIST_DO_ELF
53 #include <machine/elf.h>
54 #include <elf-hints.h>
55 #endif
56
57 int __fdnlist(int, struct nlist *);
58 int __elf_fdnlist(int, struct nlist *);
59 int __elf_is_okay__(Elf_Ehdr *);
60
61 int
62 nlist(const char *name, struct nlist *list)
63 {
64         int fd, n;
65
66         fd = _open(name, O_RDONLY | O_CLOEXEC, 0);
67         if (fd < 0)
68                 return (-1);
69         n = __fdnlist(fd, list);
70         (void)_close(fd);
71         return (n);
72 }
73
74 static struct nlist_handlers {
75         int     (*fn)(int fd, struct nlist *list);
76 } nlist_fn[] = {
77 #ifdef _NLIST_DO_ELF
78         { __elf_fdnlist },
79 #endif
80 };
81
82 int
83 __fdnlist(int fd, struct nlist *list)
84 {
85         int n = -1;
86         unsigned int i;
87
88         for (i = 0; i < nitems(nlist_fn); i++) {
89                 n = (nlist_fn[i].fn)(fd, list);
90                 if (n != -1)
91                         break;
92         }
93         return (n);
94 }
95
96 #define ISLAST(p)       (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
97
98 #ifdef _NLIST_DO_ELF
99 static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int);
100
101 /*
102  * __elf_is_okay__ - Determine if ehdr really
103  * is ELF and valid for the target platform.
104  *
105  * WARNING:  This is NOT an ELF ABI function and
106  * as such its use should be restricted.
107  */
108 int
109 __elf_is_okay__(Elf_Ehdr *ehdr)
110 {
111         int retval = 0;
112         /*
113          * We need to check magic, class size, endianess,
114          * and version before we look at the rest of the
115          * Elf_Ehdr structure.  These few elements are
116          * represented in a machine independant fashion.
117          */
118         if (IS_ELF(*ehdr) &&
119             ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
120             ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
121             ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
122
123                 /* Now check the machine dependant header */
124                 if (ehdr->e_machine == ELF_TARG_MACH &&
125                     ehdr->e_version == ELF_TARG_VER)
126                         retval = 1;
127         }
128         return retval;
129 }
130
131 int
132 __elf_fdnlist(int fd, struct nlist *list)
133 {
134         struct nlist *p;
135         Elf_Off symoff = 0, symstroff = 0;
136         Elf_Size symsize = 0, symstrsize = 0;
137         Elf_Ssize cc, i;
138         int nent = -1;
139         int errsave;
140         Elf_Sym sbuf[1024];
141         Elf_Sym *s;
142         Elf_Ehdr ehdr;
143         char *strtab = NULL;
144         Elf_Shdr *shdr = NULL;
145         Elf_Size shdr_size;
146         void *base;
147         struct stat st;
148
149         /* Make sure obj is OK */
150         if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
151             _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) ||
152             !__elf_is_okay__(&ehdr) ||
153             _fstat(fd, &st) < 0)
154                 return (-1);
155
156         /* calculate section header table size */
157         shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
158
159         /* Make sure it's not too big to mmap */
160         if (shdr_size > SIZE_T_MAX) {
161                 errno = EFBIG;
162                 return (-1);
163         }
164
165         /* mmap section header table */
166         base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd,
167             (off_t)ehdr.e_shoff);
168         if (base == MAP_FAILED)
169                 return (-1);
170         shdr = (Elf_Shdr *)base;
171
172         /*
173          * Find the symbol table entry and it's corresponding
174          * string table entry.  Version 1.1 of the ABI states
175          * that there is only one symbol table but that this
176          * could change in the future.
177          */
178         for (i = 0; i < ehdr.e_shnum; i++) {
179                 if (shdr[i].sh_type == SHT_SYMTAB) {
180                         symoff = shdr[i].sh_offset;
181                         symsize = shdr[i].sh_size;
182                         symstroff = shdr[shdr[i].sh_link].sh_offset;
183                         symstrsize = shdr[shdr[i].sh_link].sh_size;
184                         break;
185                 }
186         }
187
188         /* Check for files too large to mmap. */
189         if (symstrsize > SIZE_T_MAX) {
190                 errno = EFBIG;
191                 goto done;
192         }
193         /*
194          * Map string table into our address space.  This gives us
195          * an easy way to randomly access all the strings, without
196          * making the memory allocation permanent as with malloc/free
197          * (i.e., munmap will return it to the system).
198          */
199         base = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_PRIVATE, fd,
200             (off_t)symstroff);
201         if (base == MAP_FAILED)
202                 goto done;
203         strtab = (char *)base;
204
205         /*
206          * clean out any left-over information for all valid entries.
207          * Type and value defined to be 0 if not found; historical
208          * versions cleared other and desc as well.  Also figure out
209          * the largest string length so don't read any more of the
210          * string table than we have to.
211          *
212          * XXX clearing anything other than n_type and n_value violates
213          * the semantics given in the man page.
214          */
215         nent = 0;
216         for (p = list; !ISLAST(p); ++p) {
217                 p->n_type = 0;
218                 p->n_other = 0;
219                 p->n_desc = 0;
220                 p->n_value = 0;
221                 ++nent;
222         }
223
224         /* Don't process any further if object is stripped. */
225         if (symoff == 0)
226                 goto done;
227                 
228         if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) {
229                 nent = -1;
230                 goto done;
231         }
232
233         while (symsize > 0 && nent > 0) {
234                 cc = MIN(symsize, sizeof(sbuf));
235                 if (_read(fd, sbuf, cc) != cc)
236                         break;
237                 symsize -= cc;
238                 for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
239                         char *name;
240                         struct nlist *p;
241
242                         name = strtab + s->st_name;
243                         if (name[0] == '\0')
244                                 continue;
245                         for (p = list; !ISLAST(p); p++) {
246                                 if ((p->n_un.n_name[0] == '_' &&
247                                     strcmp(name, p->n_un.n_name+1) == 0)
248                                     || strcmp(name, p->n_un.n_name) == 0) {
249                                         elf_sym_to_nlist(p, s, shdr,
250                                             ehdr.e_shnum);
251                                         if (--nent <= 0)
252                                                 break;
253                                 }
254                         }
255                 }
256         }
257   done:
258         errsave = errno;
259         if (strtab != NULL)
260                 munmap(strtab, symstrsize);
261         if (shdr != NULL)
262                 munmap(shdr, shdr_size);
263         errno = errsave;
264         return (nent);
265 }
266
267 /*
268  * Convert an Elf_Sym into an nlist structure.  This fills in only the
269  * n_value and n_type members.
270  */
271 static void
272 elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum)
273 {
274         nl->n_value = s->st_value;
275
276         switch (s->st_shndx) {
277         case SHN_UNDEF:
278         case SHN_COMMON:
279                 nl->n_type = N_UNDF;
280                 break;
281         case SHN_ABS:
282                 nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ?
283                     N_FN : N_ABS;
284                 break;
285         default:
286                 if (s->st_shndx >= shnum)
287                         nl->n_type = N_UNDF;
288                 else {
289                         Elf_Shdr *sh = shdr + s->st_shndx;
290
291                         nl->n_type = sh->sh_type == SHT_PROGBITS ?
292                             (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) :
293                             (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF);
294                 }
295                 break;
296         }
297
298         if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
299             ELF_ST_BIND(s->st_info) == STB_WEAK)
300                 nl->n_type |= N_EXT;
301 }
302 #endif /* _NLIST_DO_ELF */