GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/installboot/i386_nlist.c Lines: 0 103 0.0 %
Date: 2017-11-13 Branches: 0 107 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: i386_nlist.c,v 1.6 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
#define ELFSIZE 32
32
33
#include <sys/types.h>
34
#include <sys/mman.h>
35
#include <sys/stat.h>
36
37
#include <elf.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#include <nlist.h>
41
#include <stdint.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <unistd.h>
45
46
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
47
48
static int	__elf_fdnlist(int, struct nlist *);
49
static int	__elf_is_okay__(Elf_Ehdr *ehdr);
50
51
int	nlist_elf32(const char *, struct nlist *);
52
53
#define	ISLAST(p)	(p->n_name == 0 || p->n_name[0] == 0)
54
55
/*
56
 * __elf_is_okay__ - Determine if ehdr really
57
 * is ELF and valid for the target platform.
58
 *
59
 * WARNING:  This is NOT a ELF ABI function and
60
 * as such its use should be restricted.
61
 */
62
static int
63
__elf_is_okay__(Elf_Ehdr *ehdr)
64
{
65
	int retval = 0;
66
	/*
67
	 * We need to check magic, class size, endianess,
68
	 * and version before we look at the rest of the
69
	 * Elf_Ehdr structure.  These few elements are
70
	 * represented in a machine independent fashion.
71
	 */
72
73
	/*
74
	 * We are constructing a 32-bit executable. So we can't
75
	 * use the libc nlist.c, which would be upset. Manually
76
	 * check for the i386 values for EI_CLASS and e_machine.
77
	 */
78
79
	if (IS_ELF(*ehdr) &&
80
	    ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
81
	    ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
82
	    ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
83
84
		/* Now check the machine dependent header */
85
		if (ehdr->e_machine == EM_386 &&
86
		    ehdr->e_version == ELF_TARG_VER)
87
			retval = 1;
88
	}
89
90
	return retval;
91
}
92
93
static int
94
__elf_fdnlist(int fd, struct nlist *list)
95
{
96
	struct nlist *p;
97
	caddr_t strtab;
98
	Elf_Off symoff = 0, symstroff = 0;
99
	Elf_Word symsize = 0, symstrsize = 0;
100
	Elf_Sword nent, cc, i;
101
	Elf_Sym sbuf[1024];
102
	Elf_Sym *s;
103
	Elf_Ehdr ehdr;
104
	Elf_Shdr *shdr = NULL;
105
	Elf_Word shdr_size;
106
	struct stat st;
107
	int usemalloc = 0;
108
	size_t left, len;
109
110
	/* Make sure obj is OK */
111
	if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
112
	    !__elf_is_okay__(&ehdr) || fstat(fd, &st) < 0)
113
		return (-1);
114
115
	/* calculate section header table size */
116
	shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
117
118
	/* Make sure it's not too big to mmap */
119
	if (SIZE_MAX - ehdr.e_shoff < shdr_size ||
120
	    (S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size)) {
121
		errno = EFBIG;
122
		return (-1);
123
	}
124
125
	/* mmap section header table */
126
	shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
127
	    MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
128
	if (shdr == MAP_FAILED) {
129
		usemalloc = 1;
130
		if ((shdr = malloc(shdr_size)) == NULL)
131
			return (-1);
132
133
		if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) !=
134
		    shdr_size) {
135
			free(shdr);
136
			return (-1);
137
		}
138
	}
139
140
	/*
141
	 * Find the symbol table entry and its corresponding
142
	 * string table entry.	Version 1.1 of the ABI states
143
	 * that there is only one symbol table but that this
144
	 * could change in the future.
145
	 */
146
	for (i = 0; i < ehdr.e_shnum; i++) {
147
		if (shdr[i].sh_type == SHT_SYMTAB) {
148
			if (shdr[i].sh_link >= ehdr.e_shnum)
149
				continue;
150
			symoff = shdr[i].sh_offset;
151
			symsize = shdr[i].sh_size;
152
			symstroff = shdr[shdr[i].sh_link].sh_offset;
153
			symstrsize = shdr[shdr[i].sh_link].sh_size;
154
			break;
155
		}
156
	}
157
158
	/* Flush the section header table */
159
	if (usemalloc)
160
		free(shdr);
161
	else
162
		munmap((caddr_t)shdr, shdr_size);
163
164
	/*
165
	 * clean out any left-over information for all valid entries.
166
	 * Type and value defined to be 0 if not found; historical
167
	 * versions cleared other and desc as well.  Also figure out
168
	 * the largest string length so don't read any more of the
169
	 * string table than we have to.
170
	 *
171
	 * XXX clearing anything other than n_type and n_value violates
172
	 * the semantics given in the man page.
173
	 */
174
	nent = 0;
175
	for (p = list; !ISLAST(p); ++p) {
176
		p->n_type = 0;
177
		p->n_other = 0;
178
		p->n_desc = 0;
179
		p->n_value = 0;
180
		++nent;
181
	}
182
183
	/* Don't process any further if object is stripped. */
184
	/* ELFism - dunno if stripped by looking at header */
185
	if (symoff == 0)
186
		return nent;
187
188
	/* Check for files too large to mmap. */
189
	if (SIZE_MAX - symstrsize < symstroff ||
190
	    (S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size)) {
191
		errno = EFBIG;
192
		return (-1);
193
	}
194
195
	/*
196
	 * Map string table into our address space.  This gives us
197
	 * an easy way to randomly access all the strings, without
198
	 * making the memory allocation permanent as with malloc/free
199
	 * (i.e., munmap will return it to the system).
200
	 */
201
	if (usemalloc) {
202
		if ((strtab = malloc(symstrsize)) == NULL)
203
			return (-1);
204
		if (pread(fd, strtab, symstrsize, (off_t)symstroff) !=
205
		    symstrsize) {
206
			free(strtab);
207
			return (-1);
208
		}
209
	} else {
210
		strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
211
		    MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
212
		if (strtab == MAP_FAILED)
213
			return (-1);
214
	}
215
216
	while (symsize >= sizeof(Elf_Sym)) {
217
		cc = MINIMUM(symsize, sizeof(sbuf));
218
		if (pread(fd, sbuf, cc, (off_t)symoff) != cc)
219
			break;
220
		symsize -= cc;
221
		symoff += cc;
222
		for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
223
			Elf_Word soff = s->st_name;
224
225
			if (soff == 0 || soff >= symstrsize)
226
				continue;
227
			left = symstrsize - soff;
228
229
			for (p = list; !ISLAST(p); p++) {
230
				char *sym;
231
232
				/*
233
				 * First we check for the symbol as it was
234
				 * provided by the user. If that fails
235
				 * and the first char is an '_', skip over
236
				 * the '_' and try again.
237
				 * XXX - What do we do when the user really
238
				 *       wants '_foo' and there are symbols
239
				 *       for both 'foo' and '_foo' in the
240
				 *	 table and 'foo' is first?
241
				 */
242
				sym = p->n_name;
243
				len = strlen(sym);
244
245
				if ((len >= left ||
246
				    strcmp(&strtab[soff], sym) != 0) &&
247
				    (sym[0] != '_' || len - 1 >= left ||
248
				     strcmp(&strtab[soff], sym + 1) != 0))
249
					continue;
250
251
				p->n_value = s->st_value;
252
253
				/* XXX - type conversion */
254
				/*	 is pretty rude. */
255
				switch(ELF_ST_TYPE(s->st_info)) {
256
				case STT_NOTYPE:
257
					switch (s->st_shndx) {
258
					case SHN_UNDEF:
259
						p->n_type = N_UNDF;
260
						break;
261
					case SHN_ABS:
262
						p->n_type = N_ABS;
263
						break;
264
					case SHN_COMMON:
265
						p->n_type = N_COMM;
266
						break;
267
					default:
268
						p->n_type = N_COMM | N_EXT;
269
						break;
270
					}
271
					break;
272
				case STT_OBJECT:
273
					p->n_type = N_DATA;
274
					break;
275
				case STT_FUNC:
276
					p->n_type = N_TEXT;
277
					break;
278
				case STT_FILE:
279
					p->n_type = N_FN;
280
					break;
281
				}
282
				if (ELF_ST_BIND(s->st_info) == STB_LOCAL)
283
					p->n_type = N_EXT;
284
				p->n_desc = 0;
285
				p->n_other = 0;
286
				if (--nent <= 0)
287
					break;
288
			}
289
		}
290
	}
291
	if (usemalloc)
292
		free(strtab);
293
	else
294
		munmap(strtab, symstrsize);
295
	return (nent);
296
}
297
298
int
299
nlist_elf32(const char *name, struct nlist *list)
300
{
301
	int fd, n;
302
303
	fd = open(name, O_RDONLY, 0);
304
	if (fd < 0)
305
		return (-1);
306
	n = __elf_fdnlist(fd, list);
307
	close(fd);
308
309
	return (n);
310
}