1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 06/04/93"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/param.h> 13 #include <sys/mman.h> 14 #include <sys/stat.h> 15 #include <sys/file.h> 16 17 #include <errno.h> 18 #include <a.out.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 int 24 nlist(name, list) 25 const char *name; 26 struct nlist *list; 27 { 28 int fd, n; 29 30 fd = open(name, O_RDONLY, 0); 31 if (fd < 0) 32 return (-1); 33 n = __fdnlist(fd, list); 34 (void)close(fd); 35 return (n); 36 } 37 38 #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) 39 40 int 41 __fdnlist(fd, list) 42 register int fd; 43 register struct nlist *list; 44 { 45 register struct nlist *p, *s; 46 register caddr_t strtab; 47 register off_t stroff, symoff; 48 register u_long symsize; 49 register int nent, cc; 50 size_t strsize; 51 struct nlist nbuf[1024]; 52 struct exec exec; 53 struct stat st; 54 55 if (lseek(fd, (off_t)0, SEEK_SET) == -1 || 56 read(fd, &exec, sizeof(exec)) != sizeof(exec) || 57 N_BADMAG(exec) || fstat(fd, &st) < 0) 58 return (-1); 59 60 symoff = N_SYMOFF(exec); 61 symsize = exec.a_syms; 62 stroff = symoff + symsize; 63 64 /* Check for files too large to mmap. */ 65 if (st.st_size - stroff > SIZE_T_MAX) { 66 errno = EFBIG; 67 return (-1); 68 } 69 /* 70 * Map string table into our address space. This gives us 71 * an easy way to randomly access all the strings, without 72 * making the memory allocation permanent as with malloc/free 73 * (i.e., munmap will return it to the system). 74 */ 75 strsize = st.st_size - stroff; 76 strtab = mmap(NULL, (size_t)strsize, PROT_READ, 0, fd, stroff); 77 if (strtab == (char *)-1) 78 return (-1); 79 /* 80 * clean out any left-over information for all valid entries. 81 * Type and value defined to be 0 if not found; historical 82 * versions cleared other and desc as well. Also figure out 83 * the largest string length so don't read any more of the 84 * string table than we have to. 85 * 86 * XXX clearing anything other than n_type and n_value violates 87 * the semantics given in the man page. 88 */ 89 nent = 0; 90 for (p = list; !ISLAST(p); ++p) { 91 p->n_type = 0; 92 p->n_other = 0; 93 p->n_desc = 0; 94 p->n_value = 0; 95 ++nent; 96 } 97 if (lseek(fd, symoff, SEEK_SET) == -1) 98 return (-1); 99 100 while (symsize > 0) { 101 cc = MIN(symsize, sizeof(nbuf)); 102 if (read(fd, nbuf, cc) != cc) 103 break; 104 symsize -= cc; 105 for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) { 106 register int soff = s->n_un.n_strx; 107 108 if (soff == 0 || (s->n_type & N_STAB) != 0) 109 continue; 110 for (p = list; !ISLAST(p); p++) { 111 char *cp = p->n_un.n_name; 112 113 /* 114 * MIPS doesn't use '_' in front of symbols. 115 * Strip the '_' to be compatible with other 116 * systems. 117 */ 118 if (cp[0] == '_') 119 cp++; 120 if (!strcmp(&strtab[soff], cp)) { 121 p->n_value = s->n_value; 122 p->n_type = s->n_type; 123 p->n_desc = s->n_desc; 124 p->n_other = s->n_other; 125 if (--nent <= 0) 126 break; 127 } 128 } 129 } 130 } 131 munmap(strtab, strsize); 132 return (nent); 133 } 134