Commit | Line | Data |
---|---|---|
bb0cfa24 | 1 | /* |
234579bd KB |
2 | * Copyright (c) 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
4142a2c4 | 4 | * |
269a7923 | 5 | * %sccs.include.redist.c% |
bb0cfa24 DF |
6 | */ |
7 | ||
2ce81398 | 8 | #if defined(LIBC_SCCS) && !defined(lint) |
234579bd | 9 | static char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) %G%"; |
4142a2c4 | 10 | #endif /* LIBC_SCCS and not lint */ |
329a2d40 | 11 | |
8ad9a9bc CT |
12 | #include <sys/param.h> |
13 | #include <sys/mman.h> | |
14 | #include <sys/stat.h> | |
4142a2c4 | 15 | #include <sys/file.h> |
c700b355 KB |
16 | |
17 | #include <errno.h> | |
8fb9f90e BJ |
18 | #include <a.out.h> |
19 | #include <stdio.h> | |
c5980113 | 20 | #include <string.h> |
4142a2c4 KB |
21 | #include <unistd.h> |
22 | ||
c5980113 | 23 | int |
8fb9f90e | 24 | nlist(name, list) |
c5980113 | 25 | const char *name; |
8ad9a9bc | 26 | struct nlist *list; |
8fb9f90e | 27 | { |
8ad9a9bc | 28 | int fd, n; |
8fb9f90e | 29 | |
8ad9a9bc CT |
30 | fd = open(name, O_RDONLY, 0); |
31 | if (fd < 0) | |
32 | return (-1); | |
d7897fdf | 33 | n = __fdnlist(fd, list); |
8ad9a9bc CT |
34 | (void)close(fd); |
35 | return (n); | |
36 | } | |
4142a2c4 | 37 | |
8ad9a9bc | 38 | #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) |
4142a2c4 | 39 | |
8ad9a9bc CT |
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; | |
c700b355 KB |
49 | register int nent, cc; |
50 | size_t strsize; | |
8ad9a9bc CT |
51 | struct nlist nbuf[1024]; |
52 | struct exec exec; | |
53 | struct stat st; | |
4142a2c4 | 54 | |
8ad9a9bc CT |
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); | |
4142a2c4 | 59 | |
8ad9a9bc CT |
60 | symoff = N_SYMOFF(exec); |
61 | symsize = exec.a_syms; | |
62 | stroff = symoff + symsize; | |
c700b355 KB |
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 | } | |
8ad9a9bc CT |
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 | */ | |
c700b355 KB |
75 | strsize = st.st_size - stroff; |
76 | strtab = mmap(NULL, (size_t)strsize, PROT_READ, 0, fd, stroff); | |
8ad9a9bc CT |
77 | if (strtab == (char *)-1) |
78 | return (-1); | |
4142a2c4 KB |
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. | |
8ad9a9bc CT |
85 | * |
86 | * XXX clearing anything other than n_type and n_value violates | |
87 | * the semantics given in the man page. | |
4142a2c4 | 88 | */ |
8ad9a9bc CT |
89 | nent = 0; |
90 | for (p = list; !ISLAST(p); ++p) { | |
4142a2c4 KB |
91 | p->n_type = 0; |
92 | p->n_other = 0; | |
93 | p->n_desc = 0; | |
94 | p->n_value = 0; | |
8ad9a9bc | 95 | ++nent; |
329a2d40 | 96 | } |
8ad9a9bc CT |
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; | |
8fb9f90e | 107 | |
8ad9a9bc CT |
108 | if (soff == 0 || (s->n_type & N_STAB) != 0) |
109 | continue; | |
c526441c RC |
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)) { | |
8ad9a9bc CT |
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 | } | |
c526441c | 128 | } |
8ad9a9bc | 129 | } |
8fb9f90e | 130 | } |
8ad9a9bc CT |
131 | munmap(strtab, strsize); |
132 | return (nent); | |
8fb9f90e | 133 | } |