custom message type for VM_INFO
[minix3.git] / sys / lib / libsa / loadfile_elf32.c
blob9a98d91c37a9dbe89566ae291d77ed61660388b0
1 /* $NetBSD: loadfile_elf32.c,v 1.30 2013/11/27 17:33:03 jakllsch Exp $ */
3 /*-
4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center and by Christos Zoulas.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 /* If not included by exec_elf64.c, ELFSIZE won't be defined. */
34 #ifndef ELFSIZE
35 #define ELFSIZE 32
36 #endif
38 #ifdef _STANDALONE
39 #include <lib/libsa/stand.h>
40 #include <lib/libkern/libkern.h>
41 #else
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <err.h>
49 #endif
51 #include <sys/param.h>
52 #include <sys/exec.h>
54 #include "loadfile.h"
56 #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
57 ((ELFSIZE == 64) && defined(BOOT_ELF64))
59 #define ELFROUND (ELFSIZE / 8)
61 #ifndef _STANDALONE
62 #include "byteorder.h"
65 * Byte swapping may be necessary in the non-_STANDLONE case because
66 * we may be built with a host compiler.
68 #define E16(f) \
69 f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
70 #define E32(f) \
71 f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
72 #define E64(f) \
73 f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
75 #define I16(f) \
76 f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
77 #define I32(f) \
78 f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
79 #define I64(f) \
80 f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
82 static void
83 internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
86 #if ELFSIZE == 32
87 I16(ehdr->e_type);
88 I16(ehdr->e_machine);
89 I32(ehdr->e_version);
90 I32(ehdr->e_entry);
91 I32(ehdr->e_phoff);
92 I32(ehdr->e_shoff);
93 I32(ehdr->e_flags);
94 I16(ehdr->e_ehsize);
95 I16(ehdr->e_phentsize);
96 I16(ehdr->e_phnum);
97 I16(ehdr->e_shentsize);
98 I16(ehdr->e_shnum);
99 I16(ehdr->e_shstrndx);
100 #elif ELFSIZE == 64
101 I16(ehdr->e_type);
102 I16(ehdr->e_machine);
103 I32(ehdr->e_version);
104 I64(ehdr->e_entry);
105 I64(ehdr->e_phoff);
106 I64(ehdr->e_shoff);
107 I32(ehdr->e_flags);
108 I16(ehdr->e_ehsize);
109 I16(ehdr->e_phentsize);
110 I16(ehdr->e_phnum);
111 I16(ehdr->e_shentsize);
112 I16(ehdr->e_shnum);
113 I16(ehdr->e_shstrndx);
114 #else
115 #error ELFSIZE is not 32 or 64
116 #endif
119 static void
120 externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
123 #if ELFSIZE == 32
124 E16(ehdr->e_type);
125 E16(ehdr->e_machine);
126 E32(ehdr->e_version);
127 E32(ehdr->e_entry);
128 E32(ehdr->e_phoff);
129 E32(ehdr->e_shoff);
130 E32(ehdr->e_flags);
131 E16(ehdr->e_ehsize);
132 E16(ehdr->e_phentsize);
133 E16(ehdr->e_phnum);
134 E16(ehdr->e_shentsize);
135 E16(ehdr->e_shnum);
136 E16(ehdr->e_shstrndx);
137 #elif ELFSIZE == 64
138 E16(ehdr->e_type);
139 E16(ehdr->e_machine);
140 E32(ehdr->e_version);
141 E64(ehdr->e_entry);
142 E64(ehdr->e_phoff);
143 E64(ehdr->e_shoff);
144 E32(ehdr->e_flags);
145 E16(ehdr->e_ehsize);
146 E16(ehdr->e_phentsize);
147 E16(ehdr->e_phnum);
148 E16(ehdr->e_shentsize);
149 E16(ehdr->e_shnum);
150 E16(ehdr->e_shstrndx);
151 #else
152 #error ELFSIZE is not 32 or 64
153 #endif
156 static void
157 internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr)
160 #if ELFSIZE == 32
161 I32(phdr->p_type);
162 I32(phdr->p_offset);
163 I32(phdr->p_vaddr);
164 I32(phdr->p_paddr);
165 I32(phdr->p_filesz);
166 I32(phdr->p_memsz);
167 I32(phdr->p_flags);
168 I32(phdr->p_align);
169 #elif ELFSIZE == 64
170 I32(phdr->p_type);
171 I32(phdr->p_offset);
172 I64(phdr->p_vaddr);
173 I64(phdr->p_paddr);
174 I64(phdr->p_filesz);
175 I64(phdr->p_memsz);
176 I64(phdr->p_flags);
177 I64(phdr->p_align);
178 #else
179 #error ELFSIZE is not 32 or 64
180 #endif
183 static void
184 internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
187 #if ELFSIZE == 32
188 I32(shdr->sh_name);
189 I32(shdr->sh_type);
190 I32(shdr->sh_flags);
191 I32(shdr->sh_addr);
192 I32(shdr->sh_offset);
193 I32(shdr->sh_size);
194 I32(shdr->sh_link);
195 I32(shdr->sh_info);
196 I32(shdr->sh_addralign);
197 I32(shdr->sh_entsize);
198 #elif ELFSIZE == 64
199 I32(shdr->sh_name);
200 I32(shdr->sh_type);
201 I64(shdr->sh_flags);
202 I64(shdr->sh_addr);
203 I64(shdr->sh_offset);
204 I64(shdr->sh_size);
205 I32(shdr->sh_link);
206 I32(shdr->sh_info);
207 I64(shdr->sh_addralign);
208 I64(shdr->sh_entsize);
209 #else
210 #error ELFSIZE is not 32 or 64
211 #endif
214 static void
215 externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
218 #if ELFSIZE == 32
219 E32(shdr->sh_name);
220 E32(shdr->sh_type);
221 E32(shdr->sh_flags);
222 E32(shdr->sh_addr);
223 E32(shdr->sh_offset);
224 E32(shdr->sh_size);
225 E32(shdr->sh_link);
226 E32(shdr->sh_info);
227 E32(shdr->sh_addralign);
228 E32(shdr->sh_entsize);
229 #elif ELFSIZE == 64
230 E32(shdr->sh_name);
231 E32(shdr->sh_type);
232 E64(shdr->sh_flags);
233 E64(shdr->sh_addr);
234 E64(shdr->sh_offset);
235 E64(shdr->sh_size);
236 E32(shdr->sh_link);
237 E32(shdr->sh_info);
238 E64(shdr->sh_addralign);
239 E64(shdr->sh_entsize);
240 #else
241 #error ELFSIZE is not 32 or 64
242 #endif
244 #else /* _STANDALONE */
246 * Byte swapping is never necessary in the _STANDALONE case because
247 * we are being built with the target compiler.
249 #define internalize_ehdr(bo, ehdr) /* nothing */
250 #define externalize_ehdr(bo, ehdr) /* nothing */
252 #define internalize_phdr(bo, phdr) /* nothing */
254 #define internalize_shdr(bo, shdr) /* nothing */
255 #define externalize_shdr(bo, shdr) /* nothing */
256 #endif /* _STANDALONE */
259 ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
261 Elf_Shdr *shp;
262 Elf_Phdr *phdr;
263 int i, j;
264 ssize_t sz;
265 int first;
266 Elf_Addr shpp;
267 Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0;
268 u_long offset = marks[MARK_START];
269 ssize_t nr;
270 struct __packed {
271 Elf_Nhdr nh;
272 uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1];
273 uint8_t desc[ELF_NOTE_NETBSD_DESCSZ];
274 } note;
275 char *shstr = NULL;
276 size_t shstrsz = 0;
277 int boot_load_ctf = 1;
279 /* some ports dont use the offset */
280 (void)&offset;
282 internalize_ehdr(elf->e_ident[EI_DATA], elf);
284 sz = elf->e_phnum * sizeof(Elf_Phdr);
285 phdr = ALLOC(sz);
287 if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) {
288 WARN(("lseek phdr"));
289 goto freephdr;
291 nr = read(fd, phdr, sz);
292 if (nr == -1) {
293 WARN(("read program headers"));
294 goto freephdr;
296 if (nr != sz) {
297 errno = EIO;
298 WARN(("read program headers"));
299 goto freephdr;
302 for (first = 1, i = 0; i < elf->e_phnum; i++) {
303 internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
305 #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
306 #define MD_LOADSEG(a) /*CONSTCOND*/0
307 #endif
308 if (MD_LOADSEG(&phdr[i]))
309 goto loadseg;
311 if (phdr[i].p_type != PT_LOAD ||
312 (phdr[i].p_flags & (PF_W|PF_X)) == 0)
313 continue;
315 #define IS_TEXT(p) (p.p_flags & PF_X)
316 #define IS_DATA(p) (p.p_flags & PF_W)
317 #define IS_BSS(p) (p.p_filesz < p.p_memsz)
319 * XXX: Assume first address is lowest
321 if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
322 (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
324 loadseg:
325 if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
326 marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
328 /* Read in segment. */
329 PROGRESS(("%s%lu", first ? "" : "+",
330 (u_long)phdr[i].p_filesz));
332 if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) {
333 WARN(("lseek text"));
334 goto freephdr;
336 nr = READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz);
337 if (nr == -1) {
338 WARN(("read text error"));
339 goto freephdr;
341 if (nr != (ssize_t)phdr[i].p_filesz) {
342 errno = EIO;
343 WARN(("read text"));
344 goto freephdr;
346 first = 0;
349 if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
350 (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
351 pos = phdr[i].p_vaddr;
352 if (minp > pos)
353 minp = pos;
354 pos += phdr[i].p_filesz;
355 if (maxp < pos)
356 maxp = pos;
359 /* Zero out bss. */
360 if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
361 PROGRESS(("+%lu",
362 (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
363 BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
364 phdr[i].p_memsz - phdr[i].p_filesz);
366 if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
367 pos += phdr[i].p_memsz - phdr[i].p_filesz;
368 if (maxp < pos)
369 maxp = pos;
372 DEALLOC(phdr, sz);
375 * Copy the ELF and section headers.
377 maxp = roundup(maxp, ELFROUND);
378 if (flags & (LOAD_HDR|COUNT_HDR)) {
379 elfp = maxp;
380 maxp += sizeof(Elf_Ehdr);
383 if (flags & (LOAD_SYM|COUNT_SYM)) {
384 if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) {
385 WARN(("lseek section headers"));
386 return 1;
388 sz = elf->e_shnum * sizeof(Elf_Shdr);
390 shp = ALLOC(sz);
392 nr = read(fd, shp, sz);
393 if (nr == -1) {
394 WARN(("read section headers"));
395 goto freeshp;
397 if (nr != sz) {
398 errno = EIO;
399 WARN(("read section headers"));
400 goto freeshp;
403 shpp = maxp;
404 maxp += roundup(sz, ELFROUND);
406 #ifndef _STANDALONE
407 /* Internalize the section headers. */
408 for (i = 0; i < elf->e_shnum; i++)
409 internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
410 #endif /* ! _STANDALONE */
413 * First load the section names section.
415 if (boot_load_ctf && (elf->e_shstrndx != 0)) {
416 if (flags & LOAD_SYM) {
417 if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
418 SEEK_SET) == -1) {
419 WARN(("lseek symbols"));
420 goto freeshp;
422 nr = READ(fd, maxp,
423 shp[elf->e_shstrndx].sh_size);
424 if (nr == -1) {
425 WARN(("read symbols"));
426 goto freeshp;
428 if (nr !=
429 (ssize_t)shp[elf->e_shstrndx].sh_size) {
430 errno = EIO;
431 WARN(("read symbols"));
432 goto freeshp;
435 shstr = ALLOC(shp[elf->e_shstrndx].sh_size);
436 shstrsz = shp[elf->e_shstrndx].sh_size;
437 if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
438 SEEK_SET) == -1) {
439 WARN(("lseek symbols"));
440 goto freeshp;
442 nr = read(fd, shstr,
443 shp[elf->e_shstrndx].sh_size);
444 if (nr == -1) {
445 WARN(("read symbols"));
446 goto freeshp;
449 shp[elf->e_shstrndx].sh_offset = maxp - elfp;
450 maxp += roundup(shp[elf->e_shstrndx].sh_size, ELFROUND);
454 * Now load the symbol sections themselves. Make sure
455 * the sections are aligned. Don't bother with any
456 * string table that isn't referenced by a symbol
457 * table.
459 for (first = 1, i = 0; i < elf->e_shnum; i++) {
460 if (i == elf->e_shstrndx) {
461 /* already loaded this section */
462 continue;
464 switch (shp[i].sh_type) {
465 case SHT_PROGBITS:
466 if (boot_load_ctf && shstr) {
467 /* got a CTF section? */
468 if (strncmp(".SUNW_ctf",
469 &shstr[shp[i].sh_name],
470 10) == 0) {
471 goto havesym;
475 /* Not loading this, so zero out the offset. */
476 shp[i].sh_offset = 0;
477 break;
478 case SHT_STRTAB:
479 for (j = 0; j < elf->e_shnum; j++)
480 if (shp[j].sh_type == SHT_SYMTAB &&
481 shp[j].sh_link == (unsigned int)i)
482 goto havesym;
483 /* FALLTHROUGH */
484 default:
485 /* Not loading this, so zero out the offset. */
486 shp[i].sh_offset = 0;
487 break;
488 havesym:
489 case SHT_SYMTAB:
490 if (flags & LOAD_SYM) {
491 PROGRESS(("%s%ld", first ? " [" : "+",
492 (u_long)shp[i].sh_size));
493 if (lseek(fd, shp[i].sh_offset,
494 SEEK_SET) == -1) {
495 WARN(("lseek symbols"));
496 goto freeshp;
498 nr = READ(fd, maxp, shp[i].sh_size);
499 if (nr == -1) {
500 WARN(("read symbols"));
501 goto freeshp;
503 if (nr != (ssize_t)shp[i].sh_size) {
504 errno = EIO;
505 WARN(("read symbols"));
506 goto freeshp;
509 shp[i].sh_offset = maxp - elfp;
510 maxp += roundup(shp[i].sh_size, ELFROUND);
511 first = 0;
512 break;
513 case SHT_NOTE:
514 if ((flags & LOAD_NOTE) == 0)
515 break;
516 if (shp[i].sh_size < sizeof(note)) {
517 shp[i].sh_offset = 0;
518 break;
520 if (lseek(fd, shp[i].sh_offset, SEEK_SET)
521 == -1) {
522 WARN(("lseek note"));
523 goto freeshp;
525 nr = read(fd, &note, sizeof(note));
526 if (nr == -1) {
527 WARN(("read note"));
528 goto freeshp;
530 if (note.nh.n_namesz ==
531 ELF_NOTE_NETBSD_NAMESZ &&
532 note.nh.n_descsz ==
533 ELF_NOTE_NETBSD_DESCSZ &&
534 note.nh.n_type ==
535 ELF_NOTE_TYPE_NETBSD_TAG &&
536 memcmp(note.name, ELF_NOTE_NETBSD_NAME,
537 sizeof(note.name)) == 0) {
538 memcpy(&netbsd_version, &note.desc,
539 sizeof(netbsd_version));
541 shp[i].sh_offset = 0;
542 break;
545 if (flags & LOAD_SYM) {
546 #ifndef _STANDALONE
547 /* Externalize the section headers. */
548 for (i = 0; i < elf->e_shnum; i++)
549 externalize_shdr(elf->e_ident[EI_DATA],
550 &shp[i]);
551 #endif /* ! _STANDALONE */
552 BCOPY(shp, shpp, sz);
554 if (first == 0)
555 PROGRESS(("]"));
557 DEALLOC(shp, sz);
560 if (shstr) {
561 DEALLOC(shstr, shstrsz);
565 * Frob the copied ELF header to give information relative
566 * to elfp.
568 if (flags & LOAD_HDR) {
569 elf->e_phoff = 0;
570 elf->e_shoff = sizeof(Elf_Ehdr);
571 elf->e_phentsize = 0;
572 elf->e_phnum = 0;
573 externalize_ehdr(elf->e_ident[EI_DATA], elf);
574 BCOPY(elf, elfp, sizeof(*elf));
575 internalize_ehdr(elf->e_ident[EI_DATA], elf);
578 marks[MARK_START] = LOADADDR(minp);
579 marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
581 * Since there can be more than one symbol section in the code
582 * and we need to find strtab too in order to do anything
583 * useful with the symbols, we just pass the whole elf
584 * header back and we let the kernel debugger find the
585 * location and number of symbols by itself.
587 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */
588 marks[MARK_SYM] = LOADADDR(elfp);
589 marks[MARK_END] = LOADADDR(maxp);
590 return 0;
591 freephdr:
592 DEALLOC(phdr, sz);
593 return 1;
594 freeshp:
595 DEALLOC(shp, sz);
596 return 1;
599 #ifdef TEST
600 #include <stdlib.h>
601 #include <fcntl.h>
602 #include <err.h>
603 #include <stdio.h>
604 u_int32_t netbsd_version;
606 main(int argc, char *argv[])
608 int fd;
609 u_long marks[MARK_MAX];
610 Elf_Ehdr elf;
611 if (argc != 2) {
612 (void)fprintf(stderr, "Usage: %s <file>\n", getprogname());
613 return 1;
615 if ((fd = open(argv[1], O_RDONLY)) == -1)
616 err(1, "Can't open `%s'", argv[1]);
617 if (read(fd, &elf, sizeof(elf)) != sizeof(elf))
618 err(1, "Can't read `%s'", argv[1]);
619 memset(marks, 0, sizeof(marks));
620 marks[MARK_START] = (u_long)malloc(2LL * 1024 * 2024 * 1024);
621 ELFNAMEEND(loadfile)(fd, &elf, marks, LOAD_ALL);
622 printf("%d\n", netbsd_version);
623 return 0;
625 #endif
627 #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */