GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/nlist.c Lines: 0 105 0.0 %
Date: 2017-11-13 Branches: 0 109 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: nlist.c,v 1.69 2017/10/27 16:47:08 mpi Exp $ */
2
/*
3
 * Copyright (c) 1989, 1993
4
 *	The Regents of the University of California.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the University nor the names of its contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include <sys/types.h>
32
#include <sys/mman.h>
33
#include <sys/stat.h>
34
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <stdint.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
#include <a.out.h>		/* pulls in nlist.h */
43
#include <elf.h>
44
45
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
46
47
int	__fdnlist(int, struct nlist *);
48
PROTO_NORMAL(__fdnlist);
49
50
#define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
51
52
/*
53
 * __elf_is_okay__ - Determine if ehdr really
54
 * is ELF and valid for the target platform.
55
 *
56
 * WARNING:  This is NOT a ELF ABI function and
57
 * as such its use should be restricted.
58
 */
59
static int
60
__elf_is_okay__(Elf_Ehdr *ehdr)
61
{
62
	int retval = 0;
63
	/*
64
	 * We need to check magic, class size, endianess,
65
	 * and version before we look at the rest of the
66
	 * Elf_Ehdr structure.  These few elements are
67
	 * represented in a machine independent fashion.
68
	 */
69
	if (IS_ELF(*ehdr) &&
70
	    ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
71
	    ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
72
	    ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
73
74
		/* Now check the machine dependent header */
75
		if (ehdr->e_machine == ELF_TARG_MACH &&
76
		    ehdr->e_version == ELF_TARG_VER)
77
			retval = 1;
78
	}
79
80
	if (ehdr->e_shentsize != sizeof(Elf_Shdr))
81
		return 0;
82
83
	return retval;
84
}
85
86
int
87
__fdnlist(int fd, struct nlist *list)
88
{
89
	struct nlist *p;
90
	caddr_t strtab;
91
	Elf_Off symoff = 0, symstroff = 0;
92
	Elf_Word symsize = 0, symstrsize = 0;
93
	Elf_Sword nent, cc, i;
94
	Elf_Sym sbuf[1024];
95
	Elf_Sym *s;
96
	Elf_Ehdr ehdr;
97
	Elf_Shdr *shdr = NULL;
98
	Elf_Word shdr_size;
99
	struct stat st;
100
	int usemalloc = 0;
101
	size_t left, len;
102
103
	/* Make sure obj is OK */
104
	if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr) ||
105
	    !__elf_is_okay__(&ehdr) || fstat(fd, &st) < 0)
106
		return (-1);
107
108
	/* calculate section header table size */
109
	shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
110
111
	/* Make sure it's not too big to mmap */
112
	if (SIZE_MAX - ehdr.e_shoff < shdr_size ||
113
	    (S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size)) {
114
		errno = EFBIG;
115
		return (-1);
116
	}
117
118
	/* mmap section header table */
119
	shdr = mmap(NULL, shdr_size, PROT_READ, MAP_SHARED|MAP_FILE, fd,
120
	    ehdr.e_shoff);
121
	if (shdr == MAP_FAILED) {
122
		usemalloc = 1;
123
		if ((shdr = malloc(shdr_size)) == NULL)
124
			return (-1);
125
126
		if (pread(fd, shdr, shdr_size, ehdr.e_shoff) != shdr_size) {
127
			free(shdr);
128
			return (-1);
129
		}
130
	}
131
132
	/*
133
	 * Find the symbol table entry and its corresponding
134
	 * string table entry.	Version 1.1 of the ABI states
135
	 * that there is only one symbol table but that this
136
	 * could change in the future.
137
	 */
138
	for (i = 0; i < ehdr.e_shnum; i++) {
139
		if (shdr[i].sh_type == SHT_SYMTAB) {
140
			if (shdr[i].sh_link >= ehdr.e_shnum)
141
				continue;
142
			symoff = shdr[i].sh_offset;
143
			symsize = shdr[i].sh_size;
144
			symstroff = shdr[shdr[i].sh_link].sh_offset;
145
			symstrsize = shdr[shdr[i].sh_link].sh_size;
146
			break;
147
		}
148
	}
149
150
	/* Flush the section header table */
151
	if (usemalloc)
152
		free(shdr);
153
	else
154
		munmap((caddr_t)shdr, shdr_size);
155
156
	/*
157
	 * clean out any left-over information for all valid entries.
158
	 * Type and value defined to be 0 if not found; historical
159
	 * versions cleared other and desc as well.  Also figure out
160
	 * the largest string length so don't read any more of the
161
	 * string table than we have to.
162
	 *
163
	 * XXX clearing anything other than n_type and n_value violates
164
	 * the semantics given in the man page.
165
	 */
166
	nent = 0;
167
	for (p = list; !ISLAST(p); ++p) {
168
		p->n_type = 0;
169
		p->n_other = 0;
170
		p->n_desc = 0;
171
		p->n_value = 0;
172
		++nent;
173
	}
174
175
	/* Don't process any further if object is stripped. */
176
	/* ELFism - dunno if stripped by looking at header */
177
	if (symoff == 0)
178
		return nent;
179
180
	/* Check for files too large to mmap. */
181
	if (SIZE_MAX - symstrsize < symstroff ||
182
	    (S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size)) {
183
		errno = EFBIG;
184
		return (-1);
185
	}
186
187
	/*
188
	 * Map string table into our address space.  This gives us
189
	 * an easy way to randomly access all the strings, without
190
	 * making the memory allocation permanent as with malloc/free
191
	 * (i.e., munmap will return it to the system).
192
	 */
193
	if (usemalloc) {
194
		if ((strtab = malloc(symstrsize)) == NULL)
195
			return (-1);
196
		if (pread(fd, strtab, symstrsize, symstroff) != symstrsize) {
197
			free(strtab);
198
			return (-1);
199
		}
200
	} else {
201
		strtab = mmap(NULL, symstrsize, PROT_READ, MAP_SHARED|MAP_FILE,
202
		    fd, symstroff);
203
		if (strtab == MAP_FAILED)
204
			return (-1);
205
	}
206
207
	while (symsize >= sizeof(Elf_Sym)) {
208
		cc = MINIMUM(symsize, sizeof(sbuf));
209
		if (pread(fd, sbuf, cc, symoff) != cc)
210
			break;
211
		symsize -= cc;
212
		symoff += cc;
213
		for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
214
			Elf_Word soff = s->st_name;
215
216
			if (soff == 0 || soff >= symstrsize)
217
				continue;
218
			left = symstrsize - soff;
219
220
			for (p = list; !ISLAST(p); p++) {
221
				char *sym;
222
223
				/*
224
				 * First we check for the symbol as it was
225
				 * provided by the user. If that fails
226
				 * and the first char is an '_', skip over
227
				 * the '_' and try again.
228
				 * XXX - What do we do when the user really
229
				 *       wants '_foo' and there are symbols
230
				 *       for both 'foo' and '_foo' in the
231
				 *	 table and 'foo' is first?
232
				 */
233
				sym = p->n_un.n_name;
234
				len = strlen(sym);
235
236
				if ((len >= left ||
237
				    strcmp(&strtab[soff], sym) != 0) &&
238
				    (sym[0] != '_' || len - 1 >= left ||
239
				     strcmp(&strtab[soff], sym + 1) != 0))
240
					continue;
241
242
				p->n_value = s->st_value;
243
244
				/* XXX - type conversion */
245
				/*	 is pretty rude. */
246
				switch(ELF_ST_TYPE(s->st_info)) {
247
				case STT_NOTYPE:
248
					switch (s->st_shndx) {
249
					case SHN_UNDEF:
250
						p->n_type = N_UNDF;
251
						break;
252
					case SHN_ABS:
253
						p->n_type = N_ABS;
254
						break;
255
					case SHN_COMMON:
256
						p->n_type = N_COMM;
257
						break;
258
					default:
259
						p->n_type = N_COMM | N_EXT;
260
						break;
261
					}
262
					break;
263
				case STT_OBJECT:
264
					p->n_type = N_DATA;
265
					break;
266
				case STT_FUNC:
267
					p->n_type = N_TEXT;
268
					break;
269
				case STT_FILE:
270
					p->n_type = N_FN;
271
					break;
272
				}
273
				if (ELF_ST_BIND(s->st_info) == STB_LOCAL)
274
					p->n_type = N_EXT;
275
				p->n_desc = 0;
276
				p->n_other = 0;
277
				if (--nent <= 0)
278
					break;
279
			}
280
		}
281
	}
282
	if (usemalloc)
283
		free(strtab);
284
	else
285
		munmap(strtab, symstrsize);
286
	return (nent);
287
}
288
DEF_STRONG(__fdnlist);
289
290
int
291
nlist(const char *name, struct nlist *list)
292
{
293
	int fd, n;
294
295
	fd = open(name, O_RDONLY, 0);
296
	if (fd < 0)
297
		return (-1);
298
	n = __fdnlist(fd, list);
299
	(void)close(fd);
300
	return (n);
301
}