xref: /openbsd-src/sys/lib/libsa/loadfile.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2 /* $OpenBSD: loadfile.c,v 1.18 2008/06/26 05:42:20 ray Exp $ */
3 
4 /*-
5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center and by Christos Zoulas.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 1992, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Ralph Campbell.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
66  */
67 
68 #ifdef _STANDALONE
69 #include <lib/libkern/libkern.h>
70 #include <lib/libsa/stand.h>
71 #else
72 #include <stdio.h>
73 #include <string.h>
74 #include <errno.h>
75 #include <stdlib.h>
76 #include <unistd.h>
77 #include <fcntl.h>
78 #include <err.h>
79 #endif
80 
81 #include <sys/param.h>
82 #include <sys/exec.h>
83 
84 #include "loadfile.h"
85 
86 #ifdef BOOT_ECOFF
87 #include <sys/exec_ecoff.h>
88 static int coff_exec(int, struct ecoff_exechdr *, u_long *, int);
89 #endif
90 #ifdef BOOT_AOUT
91 /* #include <sys/exec_aout.h> done from <sys/exec.h> above */
92 static int aout_exec(int, struct exec *, u_long *, int);
93 #endif
94 
95 #ifdef BOOT_ELF
96 #include <sys/exec_elf.h>
97 #if defined(BOOT_ELF32) && defined(BOOT_ELF64)
98 /*
99  * Both defined, so elf32_exec() and elf64_exec() need to be separately
100  * created (can't do it by including loadfile_elf.c here).
101  */
102 int elf32_exec(int, Elf32_Ehdr *, u_long *, int);
103 int elf64_exec(int, Elf64_Ehdr *, u_long *, int);
104 #else
105 #include "loadfile_elf.c"
106 #endif
107 #endif
108 
109 /*
110  * Open 'filename', read in program and return -1 on error otherwise fd,
111  * with file still open.
112  * Also fills in marks.
113  */
114 int
115 loadfile(const char *fname, u_long *marks, int flags)
116 {
117 	union {
118 #ifdef BOOT_ECOFF
119 		struct ecoff_exechdr coff;
120 #endif
121 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32)
122 		Elf32_Ehdr elf32;
123 #endif
124 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64)
125 		Elf64_Ehdr elf64;
126 #endif
127 #ifdef BOOT_AOUT
128 		struct exec aout;
129 #endif
130 
131 	} hdr;
132 	ssize_t nr;
133 	int fd, rval;
134 
135 	/* Open the file. */
136 	if ((fd = open(fname, 0)) < 0) {
137 		WARN(("open %s", fname ? fname : "<default>"));
138 		return -1;
139 	}
140 
141 	/* Read the exec header. */
142 	if ((nr = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) {
143 		WARN(("read header"));
144 		goto err;
145 	}
146 
147 #ifdef BOOT_ECOFF
148 	if (!ECOFF_BADMAG(&hdr.coff)) {
149 		rval = coff_exec(fd, &hdr.coff, marks, flags);
150 	} else
151 #endif
152 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32)
153 	if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
154 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
155 		rval = elf32_exec(fd, &hdr.elf32, marks, flags);
156 	} else
157 #endif
158 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64)
159 	if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
160 	    hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
161 		rval = elf64_exec(fd, &hdr.elf64, marks, flags);
162 	} else
163 #endif
164 #ifdef BOOT_AOUT
165 	if (OKMAGIC(N_GETMAGIC(hdr.aout))
166 #ifndef NO_MID_CHECK
167 	    && N_GETMID(hdr.aout) == MID_MACHINE
168 #endif
169 	    ) {
170 		rval = aout_exec(fd, &hdr.aout, marks, flags);
171 	} else
172 #endif
173 	{
174 		rval = 1;
175 		errno = EFTYPE;
176 		WARN(("%s", fname ? fname : "<default>"));
177 	}
178 
179 	if (rval == 0) {
180 		PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START]));
181 		return fd;
182 	}
183 err:
184 	(void)close(fd);
185 	return -1;
186 }
187 
188 #ifdef BOOT_ECOFF
189 static int
190 coff_exec(int fd, struct ecoff_exechdr *coff, u_long *marks, int flags)
191 {
192 	paddr_t offset = marks[MARK_START];
193 	paddr_t minp = ~0, maxp = 0, pos;
194 
195 	/* Read in text. */
196 	if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1)  {
197 		WARN(("lseek text"));
198 		return 1;
199 	}
200 
201 	if (coff->a.tsize != 0) {
202 		if (flags & LOAD_TEXT) {
203 			PROGRESS(("%lu", coff->a.tsize));
204 			if (READ(fd, coff->a.text_start, coff->a.tsize) !=
205 			    coff->a.tsize) {
206 				return 1;
207 			}
208 		}
209 		else {
210 			if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) {
211 				WARN(("read text"));
212 				return 1;
213 			}
214 		}
215 		if (flags & (COUNT_TEXT|LOAD_TEXT)) {
216 			pos = coff->a.text_start;
217 			if (minp > pos)
218 				minp = pos;
219 			pos += coff->a.tsize;
220 			if (maxp < pos)
221 				maxp = pos;
222 		}
223 	}
224 
225 	/* Read in data. */
226 	if (coff->a.dsize != 0) {
227 		if (flags & LOAD_DATA) {
228 			PROGRESS(("+%lu", coff->a.dsize));
229 			if (READ(fd, coff->a.data_start, coff->a.dsize) !=
230 			    coff->a.dsize) {
231 				WARN(("read data"));
232 				return 1;
233 			}
234 		}
235 		if (flags & (COUNT_DATA|LOAD_DATA)) {
236 			pos = coff->a.data_start;
237 			if (minp > pos)
238 				minp = pos;
239 			pos += coff->a.dsize;
240 			if (maxp < pos)
241 				maxp = pos;
242 		}
243 	}
244 
245 	/* Zero out bss. */
246 	if (coff->a.bsize != 0) {
247 		if (flags & LOAD_BSS) {
248 			PROGRESS(("+%lu", coff->a.bsize));
249 			BZERO(coff->a.bss_start, coff->a.bsize);
250 		}
251 		if (flags & (COUNT_BSS|LOAD_BSS)) {
252 			pos = coff->a.bss_start;
253 			if (minp > pos)
254 				minp = pos;
255 			pos = coff->a.bsize;
256 			if (maxp < pos)
257 				maxp = pos;
258 		}
259 	}
260 
261 	marks[MARK_START] = LOADADDR(minp);
262 	marks[MARK_ENTRY] = LOADADDR(coff->a.entry);
263 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
264 	marks[MARK_SYM] = LOADADDR(maxp);
265 	marks[MARK_END] = LOADADDR(maxp);
266 	return 0;
267 }
268 #endif /* BOOT_ECOFF */
269 
270 #ifdef BOOT_AOUT
271 static int
272 aout_exec(int fd, struct exec *x, u_long *marks, int flags)
273 {
274 	u_long entry = x->a_entry;
275 	paddr_t aoutp = 0;
276 	paddr_t minp, maxp;
277 	int cc;
278 	paddr_t offset = marks[MARK_START];
279 	u_long magic = N_GETMAGIC(*x);
280 	int sub;
281 
282 	/* In OMAGIC and NMAGIC, exec header isn't part of text segment */
283 	if (magic == OMAGIC || magic == NMAGIC)
284 		sub = 0;
285 	else
286 		sub = sizeof(*x);
287 
288 	minp = maxp = ALIGNENTRY(entry);
289 
290 	if (lseek(fd, sizeof(*x), SEEK_SET) == -1)  {
291 		WARN(("lseek text"));
292 		return 1;
293 	}
294 
295 	/*
296 	 * Leave a copy of the exec header before the text.
297 	 * The kernel may use this to verify that the
298 	 * symbols were loaded by this boot program.
299 	 */
300 	if (magic == OMAGIC || magic == NMAGIC) {
301 		if (flags & LOAD_HDR && maxp >= sizeof(*x))
302 			BCOPY(x, maxp - sizeof(*x), sizeof(*x));
303 	}
304 	else {
305 		if (flags & LOAD_HDR)
306 			BCOPY(x, maxp, sizeof(*x));
307 		if (flags & (LOAD_HDR|COUNT_HDR)) {
308 			minp += sizeof(*x);
309 			maxp += sizeof(*x);
310 		}
311 	}
312 
313 	/*
314 	 * Read in the text segment.
315 	 */
316 	if (flags & LOAD_TEXT) {
317 		PROGRESS(("%d", x->a_text));
318 
319 		if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) {
320 			WARN(("read text"));
321 			return 1;
322 		}
323 	} else {
324 		if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) {
325 			WARN(("seek text"));
326 			return 1;
327 		}
328 	}
329 	if (flags & (LOAD_TEXT|COUNT_TEXT))
330 		maxp += x->a_text - sub;
331 
332 	/*
333 	 * Provide alignment if required
334 	 */
335 	if (magic == ZMAGIC || magic == NMAGIC) {
336 		int size = -(unsigned int)maxp & (__LDPGSZ - 1);
337 
338 		if (flags & LOAD_TEXTA) {
339 			PROGRESS(("/%d", size));
340 			BZERO(maxp, size);
341 		}
342 
343 		if (flags & (LOAD_TEXTA|COUNT_TEXTA))
344 			maxp += size;
345 	}
346 
347 	/*
348 	 * Read in the data segment.
349 	 */
350 	if (flags & LOAD_DATA) {
351 		PROGRESS(("+%d", x->a_data));
352 
353 		if (READ(fd, maxp, x->a_data) != x->a_data) {
354 			WARN(("read data"));
355 			return 1;
356 		}
357 	}
358 	else {
359 		if (lseek(fd, x->a_data, SEEK_CUR) == -1) {
360 			WARN(("seek data"));
361 			return 1;
362 		}
363 	}
364 	if (flags & (LOAD_DATA|COUNT_DATA))
365 		maxp += x->a_data;
366 
367 	/*
368 	 * Zero out the BSS section.
369 	 * (Kernel doesn't care, but do it anyway.)
370 	 */
371 	if (flags & LOAD_BSS) {
372 		PROGRESS(("+%d", x->a_bss));
373 
374 		BZERO(maxp, x->a_bss);
375 	}
376 
377 	if (flags & (LOAD_BSS|COUNT_BSS))
378 		maxp += x->a_bss;
379 
380 	/*
381 	 * Read in the symbol table and strings.
382 	 * (Always set the symtab size word.)
383 	 */
384 	if (flags & LOAD_SYM)
385 		BCOPY(&x->a_syms, maxp, sizeof(x->a_syms));
386 
387 	if (flags & (LOAD_SYM|COUNT_SYM)) {
388 		maxp += sizeof(x->a_syms);
389 		aoutp = maxp;
390 	}
391 
392 	if (x->a_syms > 0) {
393 		/* Symbol table and string table length word. */
394 
395 		if (flags & LOAD_SYM) {
396 			PROGRESS(("+[%d", x->a_syms));
397 
398 			if (READ(fd, maxp, x->a_syms) != x->a_syms) {
399 				WARN(("read symbols"));
400 				return 1;
401 			}
402 		} else  {
403 			if (lseek(fd, x->a_syms, SEEK_CUR) == -1) {
404 				WARN(("seek symbols"));
405 				return 1;
406 			}
407 		}
408 		if (flags & (LOAD_SYM|COUNT_SYM))
409 			maxp += x->a_syms;
410 
411 		if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) {
412 			WARN(("read string table"));
413 			return 1;
414 		}
415 
416 		if (flags & LOAD_SYM) {
417 			BCOPY(&cc, maxp, sizeof(cc));
418 
419 			/* String table. Length word includes itself. */
420 
421 			PROGRESS(("+%d]", cc));
422 		}
423 		if (flags & (LOAD_SYM|COUNT_SYM))
424 			maxp += sizeof(cc);
425 
426 		cc -= sizeof(int);
427 		if (cc <= 0) {
428 			WARN(("symbol table too short"));
429 			return 1;
430 		}
431 
432 		if (flags & LOAD_SYM) {
433 			if (READ(fd, maxp, cc) != cc) {
434 				WARN(("read strings"));
435 				return 1;
436 			}
437 		} else {
438 			if (lseek(fd, cc, SEEK_CUR) == -1) {
439 				WARN(("seek strings"));
440 				return 1;
441 			}
442 		}
443 		if (flags & (LOAD_SYM|COUNT_SYM))
444 			maxp += cc;
445 	}
446 
447 	marks[MARK_START] = LOADADDR(minp);
448 	marks[MARK_ENTRY] = LOADADDR(entry);
449 	marks[MARK_NSYM] = x->a_syms;
450 	marks[MARK_SYM] = LOADADDR(aoutp);
451 	marks[MARK_END] = LOADADDR(maxp);
452 	return 0;
453 }
454 #endif /* BOOT_AOUT */
455