Annotation of sys/arch/amd64/stand/installboot/nlist.c, Revision 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