xref: /openbsd/sys/lib/libsa/loadfile.c (revision 78b63d65)
1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2 /* $OpenBSD: loadfile.c,v 1.1 2001/06/23 01:47:40 drahn 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  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the NetBSD
23  *	Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 /*
42  * Copyright (c) 1992, 1993
43  *	The Regents of the University of California.  All rights reserved.
44  *
45  * This code is derived from software contributed to Berkeley by
46  * Ralph Campbell.
47  *
48  * Redistribution and use in source and binary forms, with or without
49  * modification, are permitted provided that the following conditions
50  * are met:
51  * 1. Redistributions of source code must retain the above copyright
52  *    notice, this list of conditions and the following disclaimer.
53  * 2. Redistributions in binary form must reproduce the above copyright
54  *    notice, this list of conditions and the following disclaimer in the
55  *    documentation and/or other materials provided with the distribution.
56  * 3. All advertising materials mentioning features or use of this software
57  *    must display the following acknowledgement:
58  *	This product includes software developed by the University of
59  *	California, Berkeley and its contributors.
60  * 4. Neither the name of the University nor the names of its contributors
61  *    may be used to endorse or promote products derived from this software
62  *    without specific prior written permission.
63  *
64  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74  * SUCH DAMAGE.
75  *
76  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
77  */
78 
79 #ifdef _STANDALONE
80 #include <lib/libkern/libkern.h>
81 #include <lib/libsa/stand.h>
82 #else
83 #include <stdio.h>
84 #include <string.h>
85 #include <errno.h>
86 #include <stdlib.h>
87 #include <unistd.h>
88 #include <fcntl.h>
89 #include <err.h>
90 #endif
91 
92 #include <sys/param.h>
93 #include <sys/exec.h>
94 
95 #include "loadfile.h"
96 
97 #ifdef BOOT_ECOFF
98 #include <sys/exec_ecoff.h>
99 static int coff_exec __P((int, struct ecoff_exechdr *, u_long *, int));
100 #endif
101 #ifdef BOOT_ELF
102 #include <sys/exec_elf.h>
103 static int elf_exec __P((int, Elf_Ehdr *, u_long *, int));
104 #endif
105 #ifdef BOOT_AOUT
106 #include <sys/exec_aout.h>
107 static int aout_exec __P((int, struct exec *, u_long *, int));
108 #endif
109 
110 /*
111  * Open 'filename', read in program and and return 0 if ok 1 on error.
112  * Fill in marks
113  */
114 int
115 loadfile(fname, marks, flags)
116 	const char *fname;
117 	u_long *marks;
118 	int flags;
119 {
120 	union {
121 #ifdef BOOT_ECOFF
122 		struct ecoff_exechdr coff;
123 #endif
124 #ifdef BOOT_ELF
125 		Elf_Ehdr elf;
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 #ifdef BOOT_ELF
153 	if (memcmp(hdr.elf.e_ident, ELFMAG, SELFMAG) == 0 &&
154 	    hdr.elf.e_ident[EI_CLASS] == ELFCLASS) {
155 		rval = elf_exec(fd, &hdr.elf, marks, flags);
156 	} else
157 #endif
158 #ifdef BOOT_AOUT
159 	if (OKMAGIC(N_GETMAGIC(hdr.aout))
160 #ifndef NO_MID_CHECK
161 	    && N_GETMID(hdr.aout) == MID_MACHINE
162 #endif
163 	    ) {
164 		rval = aout_exec(fd, &hdr.aout, marks, flags);
165 	} else
166 #endif
167 	{
168 		rval = 1;
169 		errno = EFTYPE;
170 		WARN(("%s", fname ? fname : "<default>"));
171 	}
172 
173 	if (rval == 0) {
174 		PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START]));
175 		return fd;
176 	}
177 err:
178 	(void)close(fd);
179 	return -1;
180 }
181 
182 #ifdef BOOT_ECOFF
183 static int
184 coff_exec(fd, coff, marks, flags)
185 	int fd;
186 	struct ecoff_exechdr *coff;
187 	u_long *marks;
188 	int flags;
189 {
190 	paddr_t offset = marks[MARK_START];
191 	paddr_t minp = ~0, maxp = 0, pos;
192 
193 	/* Read in text. */
194 	if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1)  {
195 		WARN(("lseek text"));
196 		return 1;
197 	}
198 
199 	if (coff->a.tsize != 0) {
200 		if (flags & LOAD_TEXT) {
201 			PROGRESS(("%lu", coff->a.tsize));
202 			if (READ(fd, coff->a.text_start, coff->a.tsize) !=
203 			    coff->a.tsize) {
204 				return 1;
205 			}
206 		}
207 		else {
208 			if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) {
209 				WARN(("read text"));
210 				return 1;
211 			}
212 		}
213 		if (flags & (COUNT_TEXT|LOAD_TEXT)) {
214 			pos = coff->a.text_start;
215 			if (minp > pos)
216 				minp = pos;
217 			pos += coff->a.tsize;
218 			if (maxp < pos)
219 				maxp = pos;
220 		}
221 	}
222 
223 	/* Read in data. */
224 	if (coff->a.dsize != 0) {
225 		if (flags & LOAD_DATA) {
226 			PROGRESS(("+%lu", coff->a.dsize));
227 			if (READ(fd, coff->a.data_start, coff->a.dsize) !=
228 			    coff->a.dsize) {
229 				WARN(("read data"));
230 				return 1;
231 			}
232 		}
233 		if (flags & (COUNT_DATA|LOAD_DATA)) {
234 			pos = coff->a.data_start;
235 			if (minp > pos)
236 				minp = pos;
237 			pos += coff->a.dsize;
238 			if (maxp < pos)
239 				maxp = pos;
240 		}
241 	}
242 
243 	/* Zero out bss. */
244 	if (coff->a.bsize != 0) {
245 		if (flags & LOAD_BSS) {
246 			PROGRESS(("+%lu", coff->a.bsize));
247 			BZERO(coff->a.bss_start, coff->a.bsize);
248 		}
249 		if (flags & (COUNT_BSS|LOAD_BSS)) {
250 			pos = coff->a.bss_start;
251 			if (minp > pos)
252 				minp = pos;
253 			pos = coff->a.bsize;
254 			if (maxp < pos)
255 				maxp = pos;
256 		}
257 	}
258 
259 	marks[MARK_START] = LOADADDR(minp);
260 	marks[MARK_ENTRY] = LOADADDR(coff->a.entry);
261 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
262 	marks[MARK_SYM] = LOADADDR(maxp);
263 	marks[MARK_END] = LOADADDR(maxp);
264 	return 0;
265 }
266 #endif /* BOOT_ECOFF */
267 
268 #ifdef BOOT_ELF
269 static int
270 elf_exec(fd, elf, marks, flags)
271 	int fd;
272 	Elf_Ehdr *elf;
273 	u_long *marks;
274 	int flags;
275 {
276 	Elf_Shdr *shp;
277 	Elf_Off off;
278 	int i;
279 	size_t sz;
280 	int first;
281 	int havesyms;
282 	paddr_t minp = ~0, maxp = 0, pos;
283 	paddr_t offset = marks[MARK_START], shpp, elfp;
284 
285 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
286 		Elf_Phdr phdr;
287 		if (lseek(fd, elf->e_phoff + sizeof(phdr) * i, SEEK_SET)
288 		    == -1)  {
289 			WARN(("lseek phdr"));
290 			return 1;
291 		}
292 		if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) {
293 			WARN(("read phdr"));
294 			return 1;
295 		}
296 		if (phdr.p_type != PT_LOAD ||
297 		    (phdr.p_flags & (PF_W|PF_X)) == 0)
298 			continue;
299 
300 #define IS_TEXT(p)	(p.p_flags & PF_X)
301 #define IS_DATA(p)	(p.p_flags & PF_W)
302 #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
303 		/*
304 		 * XXX: Assume first address is lowest
305 		 */
306 		if ((IS_TEXT(phdr) && (flags & LOAD_TEXT)) ||
307 		    (IS_DATA(phdr) && (flags & LOAD_DATA))) {
308 
309 			/* Read in segment. */
310 			PROGRESS(("%s%lu", first ? "" : "+",
311 			    (u_long)phdr.p_filesz));
312 
313 			if (lseek(fd, phdr.p_offset, SEEK_SET) == -1)  {
314 				WARN(("lseek text"));
315 				return 1;
316 			}
317 			if (READ(fd, phdr.p_vaddr, phdr.p_filesz) !=
318 			    phdr.p_filesz) {
319 				WARN(("read text"));
320 				return 1;
321 			}
322 			first = 0;
323 
324 		}
325 		if ((IS_TEXT(phdr) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
326 		    (IS_DATA(phdr) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
327 			pos = phdr.p_vaddr;
328 			if (minp > pos)
329 				minp = pos;
330 			pos += phdr.p_filesz;
331 			if (maxp < pos)
332 				maxp = pos;
333 		}
334 
335 		/* Zero out bss. */
336 		if (IS_BSS(phdr) && (flags & LOAD_BSS)) {
337 			PROGRESS(("+%lu",
338 			    (u_long)(phdr.p_memsz - phdr.p_filesz)));
339 			BZERO((phdr.p_vaddr + phdr.p_filesz),
340 			    phdr.p_memsz - phdr.p_filesz);
341 		}
342 		if (IS_BSS(phdr) && (flags & (LOAD_BSS|COUNT_BSS))) {
343 			pos += phdr.p_memsz - phdr.p_filesz;
344 			if (maxp < pos)
345 				maxp = pos;
346 		}
347 	}
348 
349 	/*
350 	 * Copy the ELF and section headers.
351 	 */
352 	maxp = roundup(maxp, sizeof(long));
353 	if (flags & (LOAD_HDR|COUNT_HDR)) {
354 		elfp = maxp;
355 		maxp += sizeof(Elf_Ehdr);
356 	}
357 
358 	if (flags & (LOAD_SYM|COUNT_SYM)) {
359 		if (lseek(fd, elf->e_shoff, SEEK_SET) == -1)  {
360 			WARN(("lseek section headers"));
361 			return 1;
362 		}
363 		sz = elf->e_shnum * sizeof(Elf_Shdr);
364 
365 		shp = ALLOC(sz);
366 
367 		if (read(fd, shp, sz) != sz) {
368 			WARN(("read section headers"));
369 			return 1;
370 		}
371 
372 		shpp = maxp;
373 		maxp += roundup(sz, sizeof(long));
374 
375 		/*
376 		 * Now load the symbol sections themselves.  Make sure the
377 		 * sections are aligned. Don't bother with string tables if
378 		 * there are no symbol sections.
379 		 */
380 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long));
381 
382 		for (havesyms = i = 0; i < elf->e_shnum; i++)
383 			if (shp[i].sh_type == SHT_SYMTAB)
384 				havesyms = 1;
385 
386 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
387 			if (shp[i].sh_type == SHT_SYMTAB ||
388 			    shp[i].sh_type == SHT_STRTAB) {
389 				if (havesyms && (flags & LOAD_SYM)) {
390 					PROGRESS(("%s%ld", first ? " [" : "+",
391 					    (u_long)shp[i].sh_size));
392 					if (lseek(fd, shp[i].sh_offset,
393 					    SEEK_SET) == -1) {
394 						WARN(("lseek symbols"));
395 						FREE(shp, sz);
396 						return 1;
397 					}
398 					if (READ(fd, maxp, shp[i].sh_size) !=
399 					    shp[i].sh_size) {
400 						WARN(("read symbols"));
401 						FREE(shp, sz);
402 						return 1;
403 					}
404 				}
405 				maxp += roundup(shp[i].sh_size,
406 				    sizeof(long));
407 				shp[i].sh_offset = off;
408 				off += roundup(shp[i].sh_size, sizeof(long));
409 				first = 0;
410 			}
411 		}
412 		if (flags & LOAD_SYM) {
413 			BCOPY(shp, shpp, sz);
414 			FREE(shp, sz);
415 
416 			if (havesyms && first == 0)
417 				PROGRESS(("]"));
418 		}
419 	}
420 
421 	/*
422 	 * Frob the copied ELF header to give information relative
423 	 * to elfp.
424 	 */
425 	if (flags & LOAD_HDR) {
426 		elf->e_phoff = 0;
427 		elf->e_shoff = sizeof(Elf_Ehdr);
428 		elf->e_phentsize = 0;
429 		elf->e_phnum = 0;
430 		BCOPY(elf, elfp, sizeof(*elf));
431 	}
432 
433 	marks[MARK_START] = LOADADDR(minp);
434 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
435 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
436 	marks[MARK_SYM] = LOADADDR(elfp);
437 	marks[MARK_END] = LOADADDR(maxp);
438 	return 0;
439 }
440 #endif /* BOOT_ELF */
441 
442 #ifdef BOOT_AOUT
443 static int
444 aout_exec(fd, x, marks, flags)
445 	int fd;
446 	struct exec *x;
447 	u_long *marks;
448 	int flags;
449 {
450 	u_long entry = x->a_entry;
451 	paddr_t aoutp = 0;
452 	paddr_t minp, maxp;
453 	int cc;
454 	paddr_t offset = marks[MARK_START];
455 	u_long magic = N_GETMAGIC(*x);
456 	int sub;
457 
458 	/* In OMAGIC and NMAGIC, exec header isn't part of text segment */
459 	if (magic == OMAGIC || magic == NMAGIC)
460 		sub = 0;
461 	else
462 		sub = sizeof(*x);
463 
464 	minp = maxp = ALIGNENTRY(entry);
465 
466 	if (lseek(fd, sizeof(*x), SEEK_SET) == -1)  {
467 		WARN(("lseek text"));
468 		return 1;
469 	}
470 
471 	/*
472 	 * Leave a copy of the exec header before the text.
473 	 * The kernel may use this to verify that the
474 	 * symbols were loaded by this boot program.
475 	 */
476 	if (magic == OMAGIC || magic == NMAGIC) {
477 		if (flags & LOAD_HDR && maxp >= sizeof(*x))
478 			BCOPY(x, maxp - sizeof(*x), sizeof(*x));
479 	}
480 	else {
481 		if (flags & LOAD_HDR)
482 			BCOPY(x, maxp, sizeof(*x));
483 		if (flags & (LOAD_HDR|COUNT_HDR))
484 			maxp += sizeof(*x);
485 	}
486 
487 	/*
488 	 * Read in the text segment.
489 	 */
490 	if (flags & LOAD_TEXT) {
491 		PROGRESS(("%ld", x->a_text));
492 
493 		if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) {
494 			WARN(("read text"));
495 			return 1;
496 		}
497 	} else {
498 		if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) {
499 			WARN(("seek text"));
500 			return 1;
501 		}
502 	}
503 	if (flags & (LOAD_TEXT|COUNT_TEXT))
504 		maxp += x->a_text - sub;
505 
506 	/*
507 	 * Provide alignment if required
508 	 */
509 	if (magic == ZMAGIC || magic == NMAGIC) {
510 		int size = -(unsigned int)maxp & (__LDPGSZ - 1);
511 
512 		if (flags & LOAD_TEXTA) {
513 			PROGRESS(("/%d", size));
514 			BZERO(maxp, size);
515 		}
516 
517 		if (flags & (LOAD_TEXTA|COUNT_TEXTA))
518 			maxp += size;
519 	}
520 
521 	/*
522 	 * Read in the data segment.
523 	 */
524 	if (flags & LOAD_DATA) {
525 		PROGRESS(("+%ld", x->a_data));
526 
527 		if (READ(fd, maxp, x->a_data) != x->a_data) {
528 			WARN(("read data"));
529 			return 1;
530 		}
531 	}
532 	else {
533 		if (lseek(fd, x->a_data, SEEK_CUR) == -1) {
534 			WARN(("seek data"));
535 			return 1;
536 		}
537 	}
538 	if (flags & (LOAD_DATA|COUNT_DATA))
539 		maxp += x->a_data;
540 
541 	/*
542 	 * Zero out the BSS section.
543 	 * (Kernel doesn't care, but do it anyway.)
544 	 */
545 	if (flags & LOAD_BSS) {
546 		PROGRESS(("+%ld", x->a_bss));
547 
548 		BZERO(maxp, x->a_bss);
549 	}
550 
551 	if (flags & (LOAD_BSS|COUNT_BSS))
552 		maxp += x->a_bss;
553 
554 	/*
555 	 * Read in the symbol table and strings.
556 	 * (Always set the symtab size word.)
557 	 */
558 	if (flags & LOAD_SYM)
559 		BCOPY(&x->a_syms, maxp, sizeof(x->a_syms));
560 
561 	if (flags & (LOAD_SYM|COUNT_SYM)) {
562 		maxp += sizeof(x->a_syms);
563 		aoutp = maxp;
564 	}
565 
566 	if (x->a_syms > 0) {
567 		/* Symbol table and string table length word. */
568 
569 		if (flags & LOAD_SYM) {
570 			PROGRESS(("+[%ld", x->a_syms));
571 
572 			if (READ(fd, maxp, x->a_syms) != x->a_syms) {
573 				WARN(("read symbols"));
574 				return 1;
575 			}
576 		} else  {
577 			if (lseek(fd, x->a_syms, SEEK_CUR) == -1) {
578 				WARN(("seek symbols"));
579 				return 1;
580 			}
581 		}
582 		if (flags & (LOAD_SYM|COUNT_SYM))
583 			maxp += x->a_syms;
584 
585 		if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) {
586 			WARN(("read string table"));
587 			return 1;
588 		}
589 
590 		if (flags & LOAD_SYM) {
591 			BCOPY(&cc, maxp, sizeof(cc));
592 
593 			/* String table. Length word includes itself. */
594 
595 			PROGRESS(("+%d]", cc));
596 		}
597 		if (flags & (LOAD_SYM|COUNT_SYM))
598 			maxp += sizeof(cc);
599 
600 		cc -= sizeof(int);
601 		if (cc <= 0) {
602 			WARN(("symbol table too short"));
603 			return 1;
604 		}
605 
606 		if (flags & LOAD_SYM) {
607 			if (READ(fd, maxp, cc) != cc) {
608 				WARN(("read strings"));
609 				return 1;
610 			}
611 		} else {
612 			if (lseek(fd, cc, SEEK_CUR) == -1) {
613 				WARN(("seek strings"));
614 				return 1;
615 			}
616 		}
617 		if (flags & (LOAD_SYM|COUNT_SYM))
618 			maxp += cc;
619 	}
620 
621 	marks[MARK_START] = LOADADDR(minp);
622 	marks[MARK_ENTRY] = LOADADDR(entry);
623 	marks[MARK_NSYM] = x->a_syms;
624 	marks[MARK_SYM] = LOADADDR(aoutp);
625 	marks[MARK_END] = LOADADDR(maxp);
626 	return 0;
627 }
628 #endif /* BOOT_AOUT */
629