]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/nlist.c
Update llvm, clang and lldb to 3.7.0 release.
[FreeBSD/FreeBSD.git] / lib / libc / gen / nlist.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #if defined(LIBC_SCCS) && !defined(lint)
31 static char sccsid[] = "@(#)nlist.c     8.1 (Berkeley) 6/4/93";
32 #endif /* LIBC_SCCS and not lint */
33 #include <sys/cdefs.h>
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 /* There is no a.out support on arm64 */
51 #ifndef __aarch64__
52 #define _NLIST_DO_AOUT
53 #endif
54 #define _NLIST_DO_ELF
55
56 #ifdef _NLIST_DO_ELF
57 #include <machine/elf.h>
58 #include <elf-hints.h>
59 #endif
60
61 int __fdnlist(int, struct nlist *);
62 int __aout_fdnlist(int, struct nlist *);
63 int __elf_fdnlist(int, struct nlist *);
64
65 int
66 nlist(name, list)
67         const char *name;
68         struct nlist *list;
69 {
70         int fd, n;
71
72         fd = _open(name, O_RDONLY | O_CLOEXEC, 0);
73         if (fd < 0)
74                 return (-1);
75         n = __fdnlist(fd, list);
76         (void)_close(fd);
77         return (n);
78 }
79
80 static struct nlist_handlers {
81         int     (*fn)(int fd, struct nlist *list);
82 } nlist_fn[] = {
83 #ifdef _NLIST_DO_AOUT
84         { __aout_fdnlist },
85 #endif
86 #ifdef _NLIST_DO_ELF
87         { __elf_fdnlist },
88 #endif
89 };
90
91 int
92 __fdnlist(fd, list)
93         int fd;
94         struct nlist *list;
95 {
96         int n = -1, i;
97
98         for (i = 0; i < sizeof(nlist_fn) / sizeof(nlist_fn[0]); i++) {
99                 n = (nlist_fn[i].fn)(fd, list);
100                 if (n != -1)
101                         break;
102         }
103         return (n);
104 }
105
106 #define ISLAST(p)       (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
107
108 #ifdef _NLIST_DO_AOUT
109 int
110 __aout_fdnlist(fd, list)
111         int fd;
112         struct nlist *list;
113 {
114         struct nlist *p, *symtab;
115         caddr_t strtab, a_out_mmap;
116         off_t stroff, symoff;
117         u_long symsize;
118         int nent;
119         struct exec * exec;
120         struct stat st;
121
122         /* check that file is at least as large as struct exec! */
123         if ((_fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec)))
124                 return (-1);
125
126         /* Check for files too large to mmap. */
127         if (st.st_size > SIZE_T_MAX) {
128                 errno = EFBIG;
129                 return (-1);
130         }
131
132         /*
133          * Map the whole a.out file into our address space.
134          * We then find the string table withing this area.
135          * We do not just mmap the string table, as it probably
136          * does not start at a page boundary - we save ourselves a
137          * lot of nastiness by mmapping the whole file.
138          *
139          * This gives us an easy way to randomly access all the strings,
140          * without making the memory allocation permanent as with
141          * malloc/free (i.e., munmap will return it to the system).
142          */
143         a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
144         if (a_out_mmap == MAP_FAILED)
145                 return (-1);
146
147         exec = (struct exec *)a_out_mmap;
148         if (N_BADMAG(*exec)) {
149                 munmap(a_out_mmap, (size_t)st.st_size);
150                 return (-1);
151         }
152
153         symoff = N_SYMOFF(*exec);
154         symsize = exec->a_syms;
155         stroff = symoff + symsize;
156
157         /* find the string table in our mmapped area */
158         strtab = a_out_mmap + stroff;
159         symtab = (struct nlist *)(a_out_mmap + symoff);
160
161         /*
162          * clean out any left-over information for all valid entries.
163          * Type and value defined to be 0 if not found; historical
164          * versions cleared other and desc as well.  Also figure out
165          * the largest string length so don't read any more of the
166          * string table than we have to.
167          *
168          * XXX clearing anything other than n_type and n_value violates
169          * the semantics given in the man page.
170          */
171         nent = 0;
172         for (p = list; !ISLAST(p); ++p) {
173                 p->n_type = 0;
174                 p->n_other = 0;
175                 p->n_desc = 0;
176                 p->n_value = 0;
177                 ++nent;
178         }
179
180         while (symsize > 0) {
181                 int soff;
182
183                 symsize-= sizeof(struct nlist);
184                 soff = symtab->n_un.n_strx;
185
186
187                 if (soff != 0 && (symtab->n_type & N_STAB) == 0)
188                         for (p = list; !ISLAST(p); p++)
189                                 if (!strcmp(&strtab[soff], p->n_un.n_name)) {
190                                         p->n_value = symtab->n_value;
191                                         p->n_type = symtab->n_type;
192                                         p->n_desc = symtab->n_desc;
193                                         p->n_other = symtab->n_other;
194                                         if (--nent <= 0)
195                                                 break;
196                                 }
197                 symtab++;
198         }
199         munmap(a_out_mmap, (size_t)st.st_size);
200         return (nent);
201 }
202 #endif
203
204 #ifdef _NLIST_DO_ELF
205 static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int);
206
207 /*
208  * __elf_is_okay__ - Determine if ehdr really
209  * is ELF and valid for the target platform.
210  *
211  * WARNING:  This is NOT an ELF ABI function and
212  * as such its use should be restricted.
213  */
214 int
215 __elf_is_okay__(Elf_Ehdr *ehdr)
216 {
217         int retval = 0;
218         /*
219          * We need to check magic, class size, endianess,
220          * and version before we look at the rest of the
221          * Elf_Ehdr structure.  These few elements are
222          * represented in a machine independant fashion.
223          */
224         if (IS_ELF(*ehdr) &&
225             ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
226             ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
227             ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
228
229                 /* Now check the machine dependant header */
230                 if (ehdr->e_machine == ELF_TARG_MACH &&
231                     ehdr->e_version == ELF_TARG_VER)
232                         retval = 1;
233         }
234         return retval;
235 }
236
237 int
238 __elf_fdnlist(fd, list)
239         int fd;
240         struct nlist *list;
241 {
242         struct nlist *p;
243         Elf_Off symoff = 0, symstroff = 0;
244         Elf_Size symsize = 0, symstrsize = 0;
245         Elf_Ssize cc, i;
246         int nent = -1;
247         int errsave;
248         Elf_Sym sbuf[1024];
249         Elf_Sym *s;
250         Elf_Ehdr ehdr;
251         char *strtab = NULL;
252         Elf_Shdr *shdr = NULL;
253         Elf_Size shdr_size;
254         void *base;
255         struct stat st;
256
257         /* Make sure obj is OK */
258         if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
259             _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) ||
260             !__elf_is_okay__(&ehdr) ||
261             _fstat(fd, &st) < 0)
262                 return (-1);
263
264         /* calculate section header table size */
265         shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
266
267         /* Make sure it's not too big to mmap */
268         if (shdr_size > SIZE_T_MAX) {
269                 errno = EFBIG;
270                 return (-1);
271         }
272
273         /* mmap section header table */
274         base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd,
275             (off_t)ehdr.e_shoff);
276         if (base == MAP_FAILED)
277                 return (-1);
278         shdr = (Elf_Shdr *)base;
279
280         /*
281          * Find the symbol table entry and it's corresponding
282          * string table entry.  Version 1.1 of the ABI states
283          * that there is only one symbol table but that this
284          * could change in the future.
285          */
286         for (i = 0; i < ehdr.e_shnum; i++) {
287                 if (shdr[i].sh_type == SHT_SYMTAB) {
288                         symoff = shdr[i].sh_offset;
289                         symsize = shdr[i].sh_size;
290                         symstroff = shdr[shdr[i].sh_link].sh_offset;
291                         symstrsize = shdr[shdr[i].sh_link].sh_size;
292                         break;
293                 }
294         }
295
296         /* Check for files too large to mmap. */
297         if (symstrsize > SIZE_T_MAX) {
298                 errno = EFBIG;
299                 goto done;
300         }
301         /*
302          * Map string table into our address space.  This gives us
303          * an easy way to randomly access all the strings, without
304          * making the memory allocation permanent as with malloc/free
305          * (i.e., munmap will return it to the system).
306          */
307         base = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_PRIVATE, fd,
308             (off_t)symstroff);
309         if (base == MAP_FAILED)
310                 goto done;
311         strtab = (char *)base;
312
313         /*
314          * clean out any left-over information for all valid entries.
315          * Type and value defined to be 0 if not found; historical
316          * versions cleared other and desc as well.  Also figure out
317          * the largest string length so don't read any more of the
318          * string table than we have to.
319          *
320          * XXX clearing anything other than n_type and n_value violates
321          * the semantics given in the man page.
322          */
323         nent = 0;
324         for (p = list; !ISLAST(p); ++p) {
325                 p->n_type = 0;
326                 p->n_other = 0;
327                 p->n_desc = 0;
328                 p->n_value = 0;
329                 ++nent;
330         }
331
332         /* Don't process any further if object is stripped. */
333         if (symoff == 0)
334                 goto done;
335                 
336         if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) {
337                 nent = -1;
338                 goto done;
339         }
340
341         while (symsize > 0 && nent > 0) {
342                 cc = MIN(symsize, sizeof(sbuf));
343                 if (_read(fd, sbuf, cc) != cc)
344                         break;
345                 symsize -= cc;
346                 for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
347                         char *name;
348                         struct nlist *p;
349
350                         name = strtab + s->st_name;
351                         if (name[0] == '\0')
352                                 continue;
353                         for (p = list; !ISLAST(p); p++) {
354                                 if ((p->n_un.n_name[0] == '_' &&
355                                     strcmp(name, p->n_un.n_name+1) == 0)
356                                     || strcmp(name, p->n_un.n_name) == 0) {
357                                         elf_sym_to_nlist(p, s, shdr,
358                                             ehdr.e_shnum);
359                                         if (--nent <= 0)
360                                                 break;
361                                 }
362                         }
363                 }
364         }
365   done:
366         errsave = errno;
367         if (strtab != NULL)
368                 munmap(strtab, symstrsize);
369         if (shdr != NULL)
370                 munmap(shdr, shdr_size);
371         errno = errsave;
372         return (nent);
373 }
374
375 /*
376  * Convert an Elf_Sym into an nlist structure.  This fills in only the
377  * n_value and n_type members.
378  */
379 static void
380 elf_sym_to_nlist(nl, s, shdr, shnum)
381         struct nlist *nl;
382         Elf_Sym *s;
383         Elf_Shdr *shdr;
384         int shnum;
385 {
386         nl->n_value = s->st_value;
387
388         switch (s->st_shndx) {
389         case SHN_UNDEF:
390         case SHN_COMMON:
391                 nl->n_type = N_UNDF;
392                 break;
393         case SHN_ABS:
394                 nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ?
395                     N_FN : N_ABS;
396                 break;
397         default:
398                 if (s->st_shndx >= shnum)
399                         nl->n_type = N_UNDF;
400                 else {
401                         Elf_Shdr *sh = shdr + s->st_shndx;
402
403                         nl->n_type = sh->sh_type == SHT_PROGBITS ?
404                             (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) :
405                             (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF);
406                 }
407                 break;
408         }
409
410         if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
411             ELF_ST_BIND(s->st_info) == STB_WEAK)
412                 nl->n_type |= N_EXT;
413 }
414 #endif /* _NLIST_DO_ELF */