Annotation of sys/arch/amd64/stand/installboot/nlist.c, Revision 1.1.1.1
1.1 nbrk 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: * 3. 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 rcsid[] = "$OpenBSD: nlist.c,v 1.3 2007/04/10 17:47:54 miod Exp $";
32: #endif /* LIBC_SCCS and not lint */
33:
34: #include <sys/types.h>
35: #include <sys/param.h>
36: #include <sys/mman.h>
37: #include <sys/stat.h>
38:
39: #include <errno.h>
40: #include <fcntl.h>
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
44: #include <unistd.h>
45: #include <a.out.h> /* pulls in nlist.h */
46:
47: #ifdef _NLIST_DO_ELF
48: #include <elf_abi.h>
49: #include <olf_abi.h>
50: #endif
51:
52: #ifdef _NLIST_DO_ECOFF
53: #include <sys/exec_ecoff.h>
54: #endif
55:
56: int __fdnlist(int, struct nlist *);
57: int __aout_fdnlist(int, struct nlist *);
58: int __ecoff_fdnlist(int, struct nlist *);
59: int __elf_fdnlist(int, struct nlist *);
60: #ifdef _NLIST_DO_ELF
61: int __elf_is_okay__(register Elf_Ehdr *ehdr);
62: #endif
63:
64: #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
65:
66: #ifdef _NLIST_DO_AOUT
67: int
68: __aout_fdnlist(fd, list)
69: register int fd;
70: register struct nlist *list;
71: {
72: register struct nlist *p, *s;
73: register char *strtab;
74: register off_t symoff, stroff;
75: register u_long symsize;
76: register int nent, cc;
77: int strsize, usemalloc = 0;
78: struct nlist nbuf[1024];
79: struct exec exec;
80:
81: if (pread(fd, &exec, sizeof(exec), (off_t)0) != sizeof(exec) ||
82: N_BADMAG(exec) || exec.a_syms == NULL)
83: return (-1);
84:
85: stroff = N_STROFF(exec);
86: symoff = N_SYMOFF(exec);
87: symsize = exec.a_syms;
88:
89: /* Read in the size of the string table. */
90: if (pread(fd, (void *)&strsize, sizeof(strsize), stroff) !=
91: sizeof(strsize))
92: return (-1);
93: else
94: stroff += sizeof(strsize);
95:
96: /*
97: * Read in the string table. We try mmap, but that will fail
98: * for /dev/ksyms so fall back on malloc. Since OpenBSD's malloc(3)
99: * returns memory to the system on free this does not cause bloat.
100: */
101: strsize -= sizeof(strsize);
102: strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED|MAP_FILE,
103: fd, stroff);
104: if (strtab == MAP_FAILED) {
105: usemalloc = 1;
106: if ((strtab = (char *)malloc(strsize)) == NULL)
107: return (-1);
108: errno = EIO;
109: if (pread(fd, strtab, strsize, stroff) != strsize) {
110: nent = -1;
111: goto aout_done;
112: }
113: }
114:
115: /*
116: * clean out any left-over information for all valid entries.
117: * Type and value defined to be 0 if not found; historical
118: * versions cleared other and desc as well. Also figure out
119: * the largest string length so don't read any more of the
120: * string table than we have to.
121: *
122: * XXX clearing anything other than n_type and n_value violates
123: * the semantics given in the man page.
124: */
125: nent = 0;
126: for (p = list; !ISLAST(p); ++p) {
127: p->n_type = 0;
128: p->n_other = 0;
129: p->n_desc = 0;
130: p->n_value = 0;
131: ++nent;
132: }
133:
134: while (symsize > 0) {
135: cc = MIN(symsize, sizeof(nbuf));
136: if (pread(fd, nbuf, cc, symoff) != cc)
137: break;
138: symsize -= cc;
139: symoff += cc;
140: for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
141: char *sname = strtab + s->n_un.n_strx - sizeof(int);
142:
143: if (s->n_un.n_strx == 0 || (s->n_type & N_STAB) != 0)
144: continue;
145: for (p = list; !ISLAST(p); p++) {
146: char *pname = p->n_un.n_name;
147:
148: if (*sname != '_' && *pname == '_')
149: pname++;
150: if (!strcmp(sname, pname)) {
151: p->n_value = s->n_value;
152: p->n_type = s->n_type;
153: p->n_desc = s->n_desc;
154: p->n_other = s->n_other;
155: if (--nent <= 0)
156: break;
157: }
158: }
159: }
160: }
161: aout_done:
162: if (usemalloc)
163: free(strtab);
164: else
165: munmap(strtab, strsize);
166: return (nent);
167: }
168: #endif /* _NLIST_DO_AOUT */
169:
170: #ifdef _NLIST_DO_ECOFF
171: #define check(off, size) ((off < 0) || (off + size > mappedsize))
172: #define BAD do { rv = -1; goto out; } while (0)
173: #define BADUNMAP do { rv = -1; goto unmap; } while (0)
174:
175: int
176: __ecoff_fdnlist(fd, list)
177: register int fd;
178: register struct nlist *list;
179: {
180: struct nlist *p;
181: struct ecoff_exechdr *exechdrp;
182: struct ecoff_symhdr *symhdrp;
183: struct ecoff_extsym *esyms;
184: struct stat st;
185: char *mappedfile;
186: size_t mappedsize;
187: u_long symhdroff, extstroff;
188: u_int symhdrsize;
189: int rv, nent;
190: long i, nesyms;
191:
192: rv = -3;
193:
194: if (fstat(fd, &st) < 0)
195: BAD;
196: if (st.st_size > SIZE_T_MAX) {
197: errno = EFBIG;
198: BAD;
199: }
200: mappedsize = st.st_size;
201: mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_SHARED|MAP_FILE,
202: fd, 0);
203: if (mappedfile == MAP_FAILED)
204: BAD;
205:
206: if (check(0, sizeof *exechdrp))
207: BADUNMAP;
208: exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
209:
210: if (ECOFF_BADMAG(exechdrp))
211: BADUNMAP;
212:
213: symhdroff = exechdrp->f.f_symptr;
214: symhdrsize = exechdrp->f.f_nsyms;
215:
216: if (check(symhdroff, sizeof *symhdrp) ||
217: sizeof *symhdrp != symhdrsize)
218: BADUNMAP;
219: symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
220:
221: nesyms = symhdrp->esymMax;
222: if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
223: BADUNMAP;
224: esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
225: extstroff = symhdrp->cbSsExtOffset;
226:
227: /*
228: * clean out any left-over information for all valid entries.
229: * Type and value defined to be 0 if not found; historical
230: * versions cleared other and desc as well.
231: *
232: * XXX clearing anything other than n_type and n_value violates
233: * the semantics given in the man page.
234: */
235: nent = 0;
236: for (p = list; !ISLAST(p); ++p) {
237: p->n_type = 0;
238: p->n_other = 0;
239: p->n_desc = 0;
240: p->n_value = 0;
241: ++nent;
242: }
243:
244: for (i = 0; i < nesyms; i++) {
245: for (p = list; !ISLAST(p); p++) {
246: char *nlistname;
247: char *symtabname;
248:
249: nlistname = p->n_un.n_name;
250: if (*nlistname == '_')
251: nlistname++;
252: symtabname =
253: &mappedfile[extstroff + esyms[i].es_strindex];
254:
255: if (!strcmp(symtabname, nlistname)) {
256: p->n_value = esyms[i].es_value;
257: p->n_type = N_EXT; /* XXX */
258: p->n_desc = 0; /* XXX */
259: p->n_other = 0; /* XXX */
260: if (--nent <= 0)
261: break;
262: }
263: }
264: }
265: rv = nent;
266:
267: unmap:
268: munmap(mappedfile, mappedsize);
269: out:
270: return (rv);
271: }
272: #endif /* _NLIST_DO_ECOFF */
273:
274: #ifdef _NLIST_DO_ELF
275: /*
276: * __elf_is_okay__ - Determine if ehdr really
277: * is ELF and valid for the target platform.
278: *
279: * WARNING: This is NOT a ELF ABI function and
280: * as such its use should be restricted.
281: */
282: int
283: __elf_is_okay__(ehdr)
284: register Elf_Ehdr *ehdr;
285: {
286: register int retval = 0;
287: /*
288: * We need to check magic, class size, endianess,
289: * and version before we look at the rest of the
290: * Elf_Ehdr structure. These few elements are
291: * represented in a machine independent fashion.
292: */
293: if ((IS_ELF(*ehdr) || IS_OLF(*ehdr)) &&
294: ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
295: ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
296: ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
297:
298: /* Now check the machine dependant header */
299: if (ehdr->e_machine == ELF_TARG_MACH &&
300: ehdr->e_version == ELF_TARG_VER)
301: retval = 1;
302: }
303:
304: return retval;
305: }
306:
307: int
308: __elf_fdnlist(fd, list)
309: register int fd;
310: register struct nlist *list;
311: {
312: register struct nlist *p;
313: register caddr_t strtab;
314: register Elf_Off symoff = 0, symstroff = 0;
315: register Elf_Word symsize = 0, symstrsize = 0;
316: register Elf_Sword nent, cc, i;
317: Elf_Sym sbuf[1024];
318: Elf_Sym *s;
319: Elf_Ehdr ehdr;
320: Elf_Shdr *shdr = NULL;
321: Elf_Word shdr_size;
322: struct stat st;
323: int usemalloc = 0;
324:
325: /* Make sure obj is OK */
326: if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
327: /* !__elf_is_okay__(&ehdr) || */ fstat(fd, &st) < 0)
328: return (-1);
329:
330: /* calculate section header table size */
331: shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
332:
333: /* mmap section header table */
334: shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
335: MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
336: if (shdr == MAP_FAILED) {
337: usemalloc = 1;
338: if ((shdr = malloc(shdr_size)) == NULL)
339: return (-1);
340: if (pread(fd, shdr, shdr_size, ehdr.e_shoff) != shdr_size) {
341: free(shdr);
342: return (-1);
343: }
344: }
345:
346: /*
347: * Find the symbol table entry and its corresponding
348: * string table entry. Version 1.1 of the ABI states
349: * that there is only one symbol table but that this
350: * could change in the future.
351: */
352: for (i = 0; i < ehdr.e_shnum; i++) {
353: if (shdr[i].sh_type == SHT_SYMTAB) {
354: symoff = shdr[i].sh_offset;
355: symsize = shdr[i].sh_size;
356: symstroff = shdr[shdr[i].sh_link].sh_offset;
357: symstrsize = shdr[shdr[i].sh_link].sh_size;
358: break;
359: }
360: }
361:
362: /* Flush the section header table */
363: if (usemalloc)
364: free(shdr);
365: else
366: munmap((caddr_t)shdr, shdr_size);
367:
368: /*
369: * Map string table into our address space. This gives us
370: * an easy way to randomly access all the strings, without
371: * making the memory allocation permanent as with malloc/free
372: * (i.e., munmap will return it to the system).
373: */
374: if (usemalloc) {
375: if ((strtab = malloc(symstrsize)) == NULL)
376: return (-1);
377: if (pread(fd, strtab, symstrsize, symstroff) != symstrsize) {
378: free(strtab);
379: return (-1);
380: }
381: } else {
382: strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
383: MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
384: if (strtab == MAP_FAILED)
385: return (-1);
386: }
387: /*
388: * clean out any left-over information for all valid entries.
389: * Type and value defined to be 0 if not found; historical
390: * versions cleared other and desc as well. Also figure out
391: * the largest string length so don't read any more of the
392: * string table than we have to.
393: *
394: * XXX clearing anything other than n_type and n_value violates
395: * the semantics given in the man page.
396: */
397: nent = 0;
398: for (p = list; !ISLAST(p); ++p) {
399: p->n_type = 0;
400: p->n_other = 0;
401: p->n_desc = 0;
402: p->n_value = 0;
403: ++nent;
404: }
405:
406: /* Don't process any further if object is stripped. */
407: /* ELFism - dunno if stripped by looking at header */
408: if (symoff == 0)
409: goto elf_done;
410:
411: while (symsize > 0) {
412: cc = MIN(symsize, sizeof(sbuf));
413: if (pread(fd, sbuf, cc, symoff) != cc)
414: break;
415: symsize -= cc;
416: symoff += cc;
417: for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
418: int soff = s->st_name;
419:
420: if (soff == 0)
421: continue;
422: for (p = list; !ISLAST(p); p++) {
423: char *sym;
424:
425: /*
426: * First we check for the symbol as it was
427: * provided by the user. If that fails,
428: * skip the first char if it's an '_' and
429: * try again.
430: * XXX - What do we do when the user really
431: * wants '_foo' and the are symbols
432: * for both 'foo' and '_foo' in the
433: * table and 'foo' is first?
434: */
435: sym = p->n_un.n_name;
436: if (strcmp(&strtab[soff], sym) != 0 &&
437: ((sym[0] == '_') &&
438: strcmp(&strtab[soff], sym + 1) != 0))
439: continue;
440:
441: p->n_value = s->st_value;
442:
443: /* XXX - type conversion */
444: /* is pretty rude. */
445: switch(ELF_ST_TYPE(s->st_info)) {
446: case STT_NOTYPE:
447: switch (s->st_shndx) {
448: case SHN_UNDEF:
449: p->n_type = N_UNDF;
450: break;
451: case SHN_ABS:
452: p->n_type = N_ABS;
453: break;
454: case SHN_COMMON:
455: p->n_type = N_COMM;
456: break;
457: default:
458: p->n_type = N_COMM | N_EXT;
459: break;
460: }
461: break;
462: case STT_OBJECT:
463: p->n_type = N_DATA;
464: break;
465: case STT_FUNC:
466: p->n_type = N_TEXT;
467: break;
468: case STT_FILE:
469: p->n_type = N_FN;
470: break;
471: }
472: if (ELF_ST_BIND(s->st_info) ==
473: STB_LOCAL)
474: p->n_type = N_EXT;
475: p->n_desc = 0;
476: p->n_other = 0;
477: if (--nent <= 0)
478: break;
479: }
480: }
481: }
482: elf_done:
483: if (usemalloc)
484: free(strtab);
485: else
486: munmap(strtab, symstrsize);
487: return (nent);
488: }
489: #endif /* _NLIST_DO_ELF */
490:
491:
492: static struct nlist_handlers {
493: int (*fn)(int fd, struct nlist *list);
494: } nlist_fn[] = {
495: #ifdef _NLIST_DO_AOUT
496: { __aout_fdnlist },
497: #endif
498: #ifdef _NLIST_DO_ELF
499: { __elf_fdnlist },
500: #endif
501: #ifdef _NLIST_DO_ECOFF
502: { __ecoff_fdnlist },
503: #endif
504: };
505:
506: int
507: __fdnlist(fd, list)
508: register int fd;
509: register struct nlist *list;
510: {
511: int n = -1, i;
512:
513: for (i = 0; i < sizeof(nlist_fn)/sizeof(nlist_fn[0]); i++) {
514: n = (nlist_fn[i].fn)(fd, list);
515: if (n != -1)
516: break;
517: }
518: return (n);
519: }
520:
521:
522: int
523: nlist(name, list)
524: const char *name;
525: struct nlist *list;
526: {
527: int fd, n;
528:
529: fd = open(name, O_RDONLY, 0);
530: if (fd < 0)
531: return (-1);
532: n = __fdnlist(fd, list);
533: (void)close(fd);
534: return (n);
535: }
CVSweb