1*0a6a1f1dSLionel Sambuc /* $NetBSD: loadfile_elf32.c,v 1.31 2015/07/25 07:06:11 isaki Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
558a2b000SEvgeniy Ivanov * All rights reserved.
658a2b000SEvgeniy Ivanov *
758a2b000SEvgeniy Ivanov * This code is derived from software contributed to The NetBSD Foundation
858a2b000SEvgeniy Ivanov * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
958a2b000SEvgeniy Ivanov * NASA Ames Research Center and by Christos Zoulas.
1058a2b000SEvgeniy Ivanov *
1158a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
1258a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
1358a2b000SEvgeniy Ivanov * are met:
1458a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
1558a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
1658a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1758a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
1858a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
1958a2b000SEvgeniy Ivanov *
2058a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2158a2b000SEvgeniy Ivanov * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2258a2b000SEvgeniy Ivanov * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2358a2b000SEvgeniy Ivanov * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2458a2b000SEvgeniy Ivanov * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2558a2b000SEvgeniy Ivanov * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2658a2b000SEvgeniy Ivanov * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2758a2b000SEvgeniy Ivanov * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2858a2b000SEvgeniy Ivanov * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2958a2b000SEvgeniy Ivanov * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3058a2b000SEvgeniy Ivanov * POSSIBILITY OF SUCH DAMAGE.
3158a2b000SEvgeniy Ivanov */
3258a2b000SEvgeniy Ivanov
3358a2b000SEvgeniy Ivanov /* If not included by exec_elf64.c, ELFSIZE won't be defined. */
3458a2b000SEvgeniy Ivanov #ifndef ELFSIZE
3558a2b000SEvgeniy Ivanov #define ELFSIZE 32
3658a2b000SEvgeniy Ivanov #endif
3758a2b000SEvgeniy Ivanov
3858a2b000SEvgeniy Ivanov #ifdef _STANDALONE
3958a2b000SEvgeniy Ivanov #include <lib/libsa/stand.h>
4058a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
4158a2b000SEvgeniy Ivanov #else
4258a2b000SEvgeniy Ivanov #include <stdio.h>
4358a2b000SEvgeniy Ivanov #include <string.h>
4458a2b000SEvgeniy Ivanov #include <errno.h>
4558a2b000SEvgeniy Ivanov #include <stdlib.h>
4658a2b000SEvgeniy Ivanov #include <unistd.h>
4758a2b000SEvgeniy Ivanov #include <fcntl.h>
4858a2b000SEvgeniy Ivanov #include <err.h>
4958a2b000SEvgeniy Ivanov #endif
5058a2b000SEvgeniy Ivanov
5158a2b000SEvgeniy Ivanov #include <sys/param.h>
5258a2b000SEvgeniy Ivanov #include <sys/exec.h>
5358a2b000SEvgeniy Ivanov
5458a2b000SEvgeniy Ivanov #include "loadfile.h"
5558a2b000SEvgeniy Ivanov
5658a2b000SEvgeniy Ivanov #if ((ELFSIZE == 32) && defined(BOOT_ELF32)) || \
5758a2b000SEvgeniy Ivanov ((ELFSIZE == 64) && defined(BOOT_ELF64))
5858a2b000SEvgeniy Ivanov
5958a2b000SEvgeniy Ivanov #define ELFROUND (ELFSIZE / 8)
6058a2b000SEvgeniy Ivanov
6158a2b000SEvgeniy Ivanov #ifndef _STANDALONE
6258a2b000SEvgeniy Ivanov #include "byteorder.h"
6358a2b000SEvgeniy Ivanov
6458a2b000SEvgeniy Ivanov /*
6558a2b000SEvgeniy Ivanov * Byte swapping may be necessary in the non-_STANDLONE case because
6658a2b000SEvgeniy Ivanov * we may be built with a host compiler.
6758a2b000SEvgeniy Ivanov */
6858a2b000SEvgeniy Ivanov #define E16(f) \
6958a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_htole16(f) : sa_htobe16(f)
7058a2b000SEvgeniy Ivanov #define E32(f) \
7158a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_htole32(f) : sa_htobe32(f)
7258a2b000SEvgeniy Ivanov #define E64(f) \
7358a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_htole64(f) : sa_htobe64(f)
7458a2b000SEvgeniy Ivanov
7558a2b000SEvgeniy Ivanov #define I16(f) \
7658a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_le16toh(f) : sa_be16toh(f)
7758a2b000SEvgeniy Ivanov #define I32(f) \
7858a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_le32toh(f) : sa_be32toh(f)
7958a2b000SEvgeniy Ivanov #define I64(f) \
8058a2b000SEvgeniy Ivanov f = (bo == ELFDATA2LSB) ? sa_le64toh(f) : sa_be64toh(f)
8158a2b000SEvgeniy Ivanov
8258a2b000SEvgeniy Ivanov static void
internalize_ehdr(Elf_Byte bo,Elf_Ehdr * ehdr)8358a2b000SEvgeniy Ivanov internalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
8458a2b000SEvgeniy Ivanov {
8558a2b000SEvgeniy Ivanov
8658a2b000SEvgeniy Ivanov #if ELFSIZE == 32
8758a2b000SEvgeniy Ivanov I16(ehdr->e_type);
8858a2b000SEvgeniy Ivanov I16(ehdr->e_machine);
8958a2b000SEvgeniy Ivanov I32(ehdr->e_version);
9058a2b000SEvgeniy Ivanov I32(ehdr->e_entry);
9158a2b000SEvgeniy Ivanov I32(ehdr->e_phoff);
9258a2b000SEvgeniy Ivanov I32(ehdr->e_shoff);
9358a2b000SEvgeniy Ivanov I32(ehdr->e_flags);
9458a2b000SEvgeniy Ivanov I16(ehdr->e_ehsize);
9558a2b000SEvgeniy Ivanov I16(ehdr->e_phentsize);
9658a2b000SEvgeniy Ivanov I16(ehdr->e_phnum);
9758a2b000SEvgeniy Ivanov I16(ehdr->e_shentsize);
9858a2b000SEvgeniy Ivanov I16(ehdr->e_shnum);
9958a2b000SEvgeniy Ivanov I16(ehdr->e_shstrndx);
10058a2b000SEvgeniy Ivanov #elif ELFSIZE == 64
10158a2b000SEvgeniy Ivanov I16(ehdr->e_type);
10258a2b000SEvgeniy Ivanov I16(ehdr->e_machine);
10358a2b000SEvgeniy Ivanov I32(ehdr->e_version);
10458a2b000SEvgeniy Ivanov I64(ehdr->e_entry);
10558a2b000SEvgeniy Ivanov I64(ehdr->e_phoff);
10658a2b000SEvgeniy Ivanov I64(ehdr->e_shoff);
10758a2b000SEvgeniy Ivanov I32(ehdr->e_flags);
10858a2b000SEvgeniy Ivanov I16(ehdr->e_ehsize);
10958a2b000SEvgeniy Ivanov I16(ehdr->e_phentsize);
11058a2b000SEvgeniy Ivanov I16(ehdr->e_phnum);
11158a2b000SEvgeniy Ivanov I16(ehdr->e_shentsize);
11258a2b000SEvgeniy Ivanov I16(ehdr->e_shnum);
11358a2b000SEvgeniy Ivanov I16(ehdr->e_shstrndx);
11458a2b000SEvgeniy Ivanov #else
11558a2b000SEvgeniy Ivanov #error ELFSIZE is not 32 or 64
11658a2b000SEvgeniy Ivanov #endif
11758a2b000SEvgeniy Ivanov }
11858a2b000SEvgeniy Ivanov
11958a2b000SEvgeniy Ivanov static void
externalize_ehdr(Elf_Byte bo,Elf_Ehdr * ehdr)12058a2b000SEvgeniy Ivanov externalize_ehdr(Elf_Byte bo, Elf_Ehdr *ehdr)
12158a2b000SEvgeniy Ivanov {
12258a2b000SEvgeniy Ivanov
12358a2b000SEvgeniy Ivanov #if ELFSIZE == 32
12458a2b000SEvgeniy Ivanov E16(ehdr->e_type);
12558a2b000SEvgeniy Ivanov E16(ehdr->e_machine);
12658a2b000SEvgeniy Ivanov E32(ehdr->e_version);
12758a2b000SEvgeniy Ivanov E32(ehdr->e_entry);
12858a2b000SEvgeniy Ivanov E32(ehdr->e_phoff);
12958a2b000SEvgeniy Ivanov E32(ehdr->e_shoff);
13058a2b000SEvgeniy Ivanov E32(ehdr->e_flags);
13158a2b000SEvgeniy Ivanov E16(ehdr->e_ehsize);
13258a2b000SEvgeniy Ivanov E16(ehdr->e_phentsize);
13358a2b000SEvgeniy Ivanov E16(ehdr->e_phnum);
13458a2b000SEvgeniy Ivanov E16(ehdr->e_shentsize);
13558a2b000SEvgeniy Ivanov E16(ehdr->e_shnum);
13658a2b000SEvgeniy Ivanov E16(ehdr->e_shstrndx);
13758a2b000SEvgeniy Ivanov #elif ELFSIZE == 64
13858a2b000SEvgeniy Ivanov E16(ehdr->e_type);
13958a2b000SEvgeniy Ivanov E16(ehdr->e_machine);
14058a2b000SEvgeniy Ivanov E32(ehdr->e_version);
14158a2b000SEvgeniy Ivanov E64(ehdr->e_entry);
14258a2b000SEvgeniy Ivanov E64(ehdr->e_phoff);
14358a2b000SEvgeniy Ivanov E64(ehdr->e_shoff);
14458a2b000SEvgeniy Ivanov E32(ehdr->e_flags);
14558a2b000SEvgeniy Ivanov E16(ehdr->e_ehsize);
14658a2b000SEvgeniy Ivanov E16(ehdr->e_phentsize);
14758a2b000SEvgeniy Ivanov E16(ehdr->e_phnum);
14858a2b000SEvgeniy Ivanov E16(ehdr->e_shentsize);
14958a2b000SEvgeniy Ivanov E16(ehdr->e_shnum);
15058a2b000SEvgeniy Ivanov E16(ehdr->e_shstrndx);
15158a2b000SEvgeniy Ivanov #else
15258a2b000SEvgeniy Ivanov #error ELFSIZE is not 32 or 64
15358a2b000SEvgeniy Ivanov #endif
15458a2b000SEvgeniy Ivanov }
15558a2b000SEvgeniy Ivanov
15658a2b000SEvgeniy Ivanov static void
internalize_phdr(Elf_Byte bo,Elf_Phdr * phdr)15758a2b000SEvgeniy Ivanov internalize_phdr(Elf_Byte bo, Elf_Phdr *phdr)
15858a2b000SEvgeniy Ivanov {
15958a2b000SEvgeniy Ivanov
16058a2b000SEvgeniy Ivanov #if ELFSIZE == 32
16158a2b000SEvgeniy Ivanov I32(phdr->p_type);
16258a2b000SEvgeniy Ivanov I32(phdr->p_offset);
16358a2b000SEvgeniy Ivanov I32(phdr->p_vaddr);
16458a2b000SEvgeniy Ivanov I32(phdr->p_paddr);
16558a2b000SEvgeniy Ivanov I32(phdr->p_filesz);
16658a2b000SEvgeniy Ivanov I32(phdr->p_memsz);
16758a2b000SEvgeniy Ivanov I32(phdr->p_flags);
16858a2b000SEvgeniy Ivanov I32(phdr->p_align);
16958a2b000SEvgeniy Ivanov #elif ELFSIZE == 64
17058a2b000SEvgeniy Ivanov I32(phdr->p_type);
17158a2b000SEvgeniy Ivanov I32(phdr->p_offset);
17258a2b000SEvgeniy Ivanov I64(phdr->p_vaddr);
17358a2b000SEvgeniy Ivanov I64(phdr->p_paddr);
17458a2b000SEvgeniy Ivanov I64(phdr->p_filesz);
17558a2b000SEvgeniy Ivanov I64(phdr->p_memsz);
17658a2b000SEvgeniy Ivanov I64(phdr->p_flags);
17758a2b000SEvgeniy Ivanov I64(phdr->p_align);
17858a2b000SEvgeniy Ivanov #else
17958a2b000SEvgeniy Ivanov #error ELFSIZE is not 32 or 64
18058a2b000SEvgeniy Ivanov #endif
18158a2b000SEvgeniy Ivanov }
18258a2b000SEvgeniy Ivanov
18358a2b000SEvgeniy Ivanov static void
internalize_shdr(Elf_Byte bo,Elf_Shdr * shdr)18458a2b000SEvgeniy Ivanov internalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
18558a2b000SEvgeniy Ivanov {
18658a2b000SEvgeniy Ivanov
18758a2b000SEvgeniy Ivanov #if ELFSIZE == 32
18858a2b000SEvgeniy Ivanov I32(shdr->sh_name);
18958a2b000SEvgeniy Ivanov I32(shdr->sh_type);
19058a2b000SEvgeniy Ivanov I32(shdr->sh_flags);
19158a2b000SEvgeniy Ivanov I32(shdr->sh_addr);
19258a2b000SEvgeniy Ivanov I32(shdr->sh_offset);
19358a2b000SEvgeniy Ivanov I32(shdr->sh_size);
19458a2b000SEvgeniy Ivanov I32(shdr->sh_link);
19558a2b000SEvgeniy Ivanov I32(shdr->sh_info);
19658a2b000SEvgeniy Ivanov I32(shdr->sh_addralign);
19758a2b000SEvgeniy Ivanov I32(shdr->sh_entsize);
19858a2b000SEvgeniy Ivanov #elif ELFSIZE == 64
19958a2b000SEvgeniy Ivanov I32(shdr->sh_name);
20058a2b000SEvgeniy Ivanov I32(shdr->sh_type);
20158a2b000SEvgeniy Ivanov I64(shdr->sh_flags);
20258a2b000SEvgeniy Ivanov I64(shdr->sh_addr);
20358a2b000SEvgeniy Ivanov I64(shdr->sh_offset);
20458a2b000SEvgeniy Ivanov I64(shdr->sh_size);
20558a2b000SEvgeniy Ivanov I32(shdr->sh_link);
20658a2b000SEvgeniy Ivanov I32(shdr->sh_info);
20758a2b000SEvgeniy Ivanov I64(shdr->sh_addralign);
20858a2b000SEvgeniy Ivanov I64(shdr->sh_entsize);
20958a2b000SEvgeniy Ivanov #else
21058a2b000SEvgeniy Ivanov #error ELFSIZE is not 32 or 64
21158a2b000SEvgeniy Ivanov #endif
21258a2b000SEvgeniy Ivanov }
21358a2b000SEvgeniy Ivanov
21458a2b000SEvgeniy Ivanov static void
externalize_shdr(Elf_Byte bo,Elf_Shdr * shdr)21558a2b000SEvgeniy Ivanov externalize_shdr(Elf_Byte bo, Elf_Shdr *shdr)
21658a2b000SEvgeniy Ivanov {
21758a2b000SEvgeniy Ivanov
21858a2b000SEvgeniy Ivanov #if ELFSIZE == 32
21958a2b000SEvgeniy Ivanov E32(shdr->sh_name);
22058a2b000SEvgeniy Ivanov E32(shdr->sh_type);
22158a2b000SEvgeniy Ivanov E32(shdr->sh_flags);
22258a2b000SEvgeniy Ivanov E32(shdr->sh_addr);
22358a2b000SEvgeniy Ivanov E32(shdr->sh_offset);
22458a2b000SEvgeniy Ivanov E32(shdr->sh_size);
22558a2b000SEvgeniy Ivanov E32(shdr->sh_link);
22658a2b000SEvgeniy Ivanov E32(shdr->sh_info);
22758a2b000SEvgeniy Ivanov E32(shdr->sh_addralign);
22858a2b000SEvgeniy Ivanov E32(shdr->sh_entsize);
22958a2b000SEvgeniy Ivanov #elif ELFSIZE == 64
23058a2b000SEvgeniy Ivanov E32(shdr->sh_name);
23158a2b000SEvgeniy Ivanov E32(shdr->sh_type);
23258a2b000SEvgeniy Ivanov E64(shdr->sh_flags);
23358a2b000SEvgeniy Ivanov E64(shdr->sh_addr);
23458a2b000SEvgeniy Ivanov E64(shdr->sh_offset);
23558a2b000SEvgeniy Ivanov E64(shdr->sh_size);
23658a2b000SEvgeniy Ivanov E32(shdr->sh_link);
23758a2b000SEvgeniy Ivanov E32(shdr->sh_info);
23858a2b000SEvgeniy Ivanov E64(shdr->sh_addralign);
23958a2b000SEvgeniy Ivanov E64(shdr->sh_entsize);
24058a2b000SEvgeniy Ivanov #else
24158a2b000SEvgeniy Ivanov #error ELFSIZE is not 32 or 64
24258a2b000SEvgeniy Ivanov #endif
24358a2b000SEvgeniy Ivanov }
24458a2b000SEvgeniy Ivanov #else /* _STANDALONE */
24558a2b000SEvgeniy Ivanov /*
24658a2b000SEvgeniy Ivanov * Byte swapping is never necessary in the _STANDALONE case because
24758a2b000SEvgeniy Ivanov * we are being built with the target compiler.
24858a2b000SEvgeniy Ivanov */
24958a2b000SEvgeniy Ivanov #define internalize_ehdr(bo, ehdr) /* nothing */
25058a2b000SEvgeniy Ivanov #define externalize_ehdr(bo, ehdr) /* nothing */
25158a2b000SEvgeniy Ivanov
25258a2b000SEvgeniy Ivanov #define internalize_phdr(bo, phdr) /* nothing */
25358a2b000SEvgeniy Ivanov
25458a2b000SEvgeniy Ivanov #define internalize_shdr(bo, shdr) /* nothing */
25558a2b000SEvgeniy Ivanov #define externalize_shdr(bo, shdr) /* nothing */
25658a2b000SEvgeniy Ivanov #endif /* _STANDALONE */
25758a2b000SEvgeniy Ivanov
25858a2b000SEvgeniy Ivanov int
ELFNAMEEND(loadfile)25958a2b000SEvgeniy Ivanov ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
26058a2b000SEvgeniy Ivanov {
26158a2b000SEvgeniy Ivanov Elf_Shdr *shp;
26258a2b000SEvgeniy Ivanov Elf_Phdr *phdr;
26358a2b000SEvgeniy Ivanov int i, j;
26458a2b000SEvgeniy Ivanov ssize_t sz;
26558a2b000SEvgeniy Ivanov int first;
26658a2b000SEvgeniy Ivanov Elf_Addr shpp;
26758a2b000SEvgeniy Ivanov Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0;
26858a2b000SEvgeniy Ivanov u_long offset = marks[MARK_START];
26958a2b000SEvgeniy Ivanov ssize_t nr;
27058a2b000SEvgeniy Ivanov struct __packed {
27158a2b000SEvgeniy Ivanov Elf_Nhdr nh;
27258a2b000SEvgeniy Ivanov uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1];
27358a2b000SEvgeniy Ivanov uint8_t desc[ELF_NOTE_NETBSD_DESCSZ];
27458a2b000SEvgeniy Ivanov } note;
27558a2b000SEvgeniy Ivanov char *shstr = NULL;
27684d9c625SLionel Sambuc size_t shstrsz = 0;
27758a2b000SEvgeniy Ivanov int boot_load_ctf = 1;
27858a2b000SEvgeniy Ivanov
27958a2b000SEvgeniy Ivanov /* some ports dont use the offset */
28058a2b000SEvgeniy Ivanov (void)&offset;
28158a2b000SEvgeniy Ivanov
28258a2b000SEvgeniy Ivanov internalize_ehdr(elf->e_ident[EI_DATA], elf);
28358a2b000SEvgeniy Ivanov
28458a2b000SEvgeniy Ivanov sz = elf->e_phnum * sizeof(Elf_Phdr);
28558a2b000SEvgeniy Ivanov phdr = ALLOC(sz);
28658a2b000SEvgeniy Ivanov
28758a2b000SEvgeniy Ivanov if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) {
28858a2b000SEvgeniy Ivanov WARN(("lseek phdr"));
28958a2b000SEvgeniy Ivanov goto freephdr;
29058a2b000SEvgeniy Ivanov }
29158a2b000SEvgeniy Ivanov nr = read(fd, phdr, sz);
29258a2b000SEvgeniy Ivanov if (nr == -1) {
29358a2b000SEvgeniy Ivanov WARN(("read program headers"));
29458a2b000SEvgeniy Ivanov goto freephdr;
29558a2b000SEvgeniy Ivanov }
29658a2b000SEvgeniy Ivanov if (nr != sz) {
29758a2b000SEvgeniy Ivanov errno = EIO;
29858a2b000SEvgeniy Ivanov WARN(("read program headers"));
29958a2b000SEvgeniy Ivanov goto freephdr;
30058a2b000SEvgeniy Ivanov }
30158a2b000SEvgeniy Ivanov
30258a2b000SEvgeniy Ivanov for (first = 1, i = 0; i < elf->e_phnum; i++) {
30358a2b000SEvgeniy Ivanov internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]);
30458a2b000SEvgeniy Ivanov
30558a2b000SEvgeniy Ivanov #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */
30658a2b000SEvgeniy Ivanov #define MD_LOADSEG(a) /*CONSTCOND*/0
30758a2b000SEvgeniy Ivanov #endif
30858a2b000SEvgeniy Ivanov if (MD_LOADSEG(&phdr[i]))
30958a2b000SEvgeniy Ivanov goto loadseg;
31058a2b000SEvgeniy Ivanov
31158a2b000SEvgeniy Ivanov if (phdr[i].p_type != PT_LOAD ||
31258a2b000SEvgeniy Ivanov (phdr[i].p_flags & (PF_W|PF_X)) == 0)
31358a2b000SEvgeniy Ivanov continue;
31458a2b000SEvgeniy Ivanov
31558a2b000SEvgeniy Ivanov #define IS_TEXT(p) (p.p_flags & PF_X)
31658a2b000SEvgeniy Ivanov #define IS_DATA(p) (p.p_flags & PF_W)
31758a2b000SEvgeniy Ivanov #define IS_BSS(p) (p.p_filesz < p.p_memsz)
31858a2b000SEvgeniy Ivanov /*
31958a2b000SEvgeniy Ivanov * XXX: Assume first address is lowest
32058a2b000SEvgeniy Ivanov */
32158a2b000SEvgeniy Ivanov if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
32258a2b000SEvgeniy Ivanov (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
32358a2b000SEvgeniy Ivanov
32458a2b000SEvgeniy Ivanov loadseg:
32558a2b000SEvgeniy Ivanov if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i]))
32658a2b000SEvgeniy Ivanov marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr);
32758a2b000SEvgeniy Ivanov
32858a2b000SEvgeniy Ivanov /* Read in segment. */
32958a2b000SEvgeniy Ivanov PROGRESS(("%s%lu", first ? "" : "+",
33058a2b000SEvgeniy Ivanov (u_long)phdr[i].p_filesz));
33158a2b000SEvgeniy Ivanov
33258a2b000SEvgeniy Ivanov if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) {
33358a2b000SEvgeniy Ivanov WARN(("lseek text"));
33458a2b000SEvgeniy Ivanov goto freephdr;
33558a2b000SEvgeniy Ivanov }
33658a2b000SEvgeniy Ivanov nr = READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz);
33758a2b000SEvgeniy Ivanov if (nr == -1) {
33858a2b000SEvgeniy Ivanov WARN(("read text error"));
33958a2b000SEvgeniy Ivanov goto freephdr;
34058a2b000SEvgeniy Ivanov }
34158a2b000SEvgeniy Ivanov if (nr != (ssize_t)phdr[i].p_filesz) {
34258a2b000SEvgeniy Ivanov errno = EIO;
34358a2b000SEvgeniy Ivanov WARN(("read text"));
34458a2b000SEvgeniy Ivanov goto freephdr;
34558a2b000SEvgeniy Ivanov }
34658a2b000SEvgeniy Ivanov first = 0;
34758a2b000SEvgeniy Ivanov
34858a2b000SEvgeniy Ivanov }
34958a2b000SEvgeniy Ivanov if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) ||
35058a2b000SEvgeniy Ivanov (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) {
35158a2b000SEvgeniy Ivanov pos = phdr[i].p_vaddr;
35258a2b000SEvgeniy Ivanov if (minp > pos)
35358a2b000SEvgeniy Ivanov minp = pos;
35458a2b000SEvgeniy Ivanov pos += phdr[i].p_filesz;
35558a2b000SEvgeniy Ivanov if (maxp < pos)
35658a2b000SEvgeniy Ivanov maxp = pos;
35758a2b000SEvgeniy Ivanov }
35858a2b000SEvgeniy Ivanov
35958a2b000SEvgeniy Ivanov /* Zero out bss. */
36058a2b000SEvgeniy Ivanov if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
36158a2b000SEvgeniy Ivanov PROGRESS(("+%lu",
36258a2b000SEvgeniy Ivanov (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
36358a2b000SEvgeniy Ivanov BZERO((phdr[i].p_vaddr + phdr[i].p_filesz),
36458a2b000SEvgeniy Ivanov phdr[i].p_memsz - phdr[i].p_filesz);
36558a2b000SEvgeniy Ivanov }
36658a2b000SEvgeniy Ivanov if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
36758a2b000SEvgeniy Ivanov pos += phdr[i].p_memsz - phdr[i].p_filesz;
36858a2b000SEvgeniy Ivanov if (maxp < pos)
36958a2b000SEvgeniy Ivanov maxp = pos;
37058a2b000SEvgeniy Ivanov }
37158a2b000SEvgeniy Ivanov }
37258a2b000SEvgeniy Ivanov DEALLOC(phdr, sz);
37358a2b000SEvgeniy Ivanov
37458a2b000SEvgeniy Ivanov /*
37558a2b000SEvgeniy Ivanov * Copy the ELF and section headers.
37658a2b000SEvgeniy Ivanov */
37758a2b000SEvgeniy Ivanov maxp = roundup(maxp, ELFROUND);
37858a2b000SEvgeniy Ivanov if (flags & (LOAD_HDR|COUNT_HDR)) {
37958a2b000SEvgeniy Ivanov elfp = maxp;
38058a2b000SEvgeniy Ivanov maxp += sizeof(Elf_Ehdr);
38158a2b000SEvgeniy Ivanov }
38258a2b000SEvgeniy Ivanov
38358a2b000SEvgeniy Ivanov if (flags & (LOAD_SYM|COUNT_SYM)) {
38458a2b000SEvgeniy Ivanov if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) {
38558a2b000SEvgeniy Ivanov WARN(("lseek section headers"));
38658a2b000SEvgeniy Ivanov return 1;
38758a2b000SEvgeniy Ivanov }
38858a2b000SEvgeniy Ivanov sz = elf->e_shnum * sizeof(Elf_Shdr);
38958a2b000SEvgeniy Ivanov
39058a2b000SEvgeniy Ivanov shp = ALLOC(sz);
39158a2b000SEvgeniy Ivanov
39258a2b000SEvgeniy Ivanov nr = read(fd, shp, sz);
39358a2b000SEvgeniy Ivanov if (nr == -1) {
39458a2b000SEvgeniy Ivanov WARN(("read section headers"));
39558a2b000SEvgeniy Ivanov goto freeshp;
39658a2b000SEvgeniy Ivanov }
39758a2b000SEvgeniy Ivanov if (nr != sz) {
39858a2b000SEvgeniy Ivanov errno = EIO;
39958a2b000SEvgeniy Ivanov WARN(("read section headers"));
40058a2b000SEvgeniy Ivanov goto freeshp;
40158a2b000SEvgeniy Ivanov }
40258a2b000SEvgeniy Ivanov
40358a2b000SEvgeniy Ivanov shpp = maxp;
40458a2b000SEvgeniy Ivanov maxp += roundup(sz, ELFROUND);
40558a2b000SEvgeniy Ivanov
40658a2b000SEvgeniy Ivanov #ifndef _STANDALONE
40758a2b000SEvgeniy Ivanov /* Internalize the section headers. */
40858a2b000SEvgeniy Ivanov for (i = 0; i < elf->e_shnum; i++)
40958a2b000SEvgeniy Ivanov internalize_shdr(elf->e_ident[EI_DATA], &shp[i]);
41058a2b000SEvgeniy Ivanov #endif /* ! _STANDALONE */
41158a2b000SEvgeniy Ivanov
41258a2b000SEvgeniy Ivanov /*
41358a2b000SEvgeniy Ivanov * First load the section names section.
41458a2b000SEvgeniy Ivanov */
41558a2b000SEvgeniy Ivanov if (boot_load_ctf && (elf->e_shstrndx != 0)) {
41658a2b000SEvgeniy Ivanov if (flags & LOAD_SYM) {
41758a2b000SEvgeniy Ivanov if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
41858a2b000SEvgeniy Ivanov SEEK_SET) == -1) {
41958a2b000SEvgeniy Ivanov WARN(("lseek symbols"));
42058a2b000SEvgeniy Ivanov goto freeshp;
42158a2b000SEvgeniy Ivanov }
42258a2b000SEvgeniy Ivanov nr = READ(fd, maxp,
42358a2b000SEvgeniy Ivanov shp[elf->e_shstrndx].sh_size);
42458a2b000SEvgeniy Ivanov if (nr == -1) {
42558a2b000SEvgeniy Ivanov WARN(("read symbols"));
42658a2b000SEvgeniy Ivanov goto freeshp;
42758a2b000SEvgeniy Ivanov }
42858a2b000SEvgeniy Ivanov if (nr !=
42958a2b000SEvgeniy Ivanov (ssize_t)shp[elf->e_shstrndx].sh_size) {
43058a2b000SEvgeniy Ivanov errno = EIO;
43158a2b000SEvgeniy Ivanov WARN(("read symbols"));
43258a2b000SEvgeniy Ivanov goto freeshp;
43358a2b000SEvgeniy Ivanov }
43458a2b000SEvgeniy Ivanov
43558a2b000SEvgeniy Ivanov shstr = ALLOC(shp[elf->e_shstrndx].sh_size);
43684d9c625SLionel Sambuc shstrsz = shp[elf->e_shstrndx].sh_size;
43758a2b000SEvgeniy Ivanov if (lseek(fd, shp[elf->e_shstrndx].sh_offset,
43858a2b000SEvgeniy Ivanov SEEK_SET) == -1) {
43958a2b000SEvgeniy Ivanov WARN(("lseek symbols"));
44058a2b000SEvgeniy Ivanov goto freeshp;
44158a2b000SEvgeniy Ivanov }
44258a2b000SEvgeniy Ivanov nr = read(fd, shstr,
44358a2b000SEvgeniy Ivanov shp[elf->e_shstrndx].sh_size);
44458a2b000SEvgeniy Ivanov if (nr == -1) {
44558a2b000SEvgeniy Ivanov WARN(("read symbols"));
44658a2b000SEvgeniy Ivanov goto freeshp;
44758a2b000SEvgeniy Ivanov }
44858a2b000SEvgeniy Ivanov }
44958a2b000SEvgeniy Ivanov shp[elf->e_shstrndx].sh_offset = maxp - elfp;
45058a2b000SEvgeniy Ivanov maxp += roundup(shp[elf->e_shstrndx].sh_size, ELFROUND);
45158a2b000SEvgeniy Ivanov }
45258a2b000SEvgeniy Ivanov
45358a2b000SEvgeniy Ivanov /*
45458a2b000SEvgeniy Ivanov * Now load the symbol sections themselves. Make sure
45558a2b000SEvgeniy Ivanov * the sections are aligned. Don't bother with any
45658a2b000SEvgeniy Ivanov * string table that isn't referenced by a symbol
45758a2b000SEvgeniy Ivanov * table.
45858a2b000SEvgeniy Ivanov */
45958a2b000SEvgeniy Ivanov for (first = 1, i = 0; i < elf->e_shnum; i++) {
46058a2b000SEvgeniy Ivanov if (i == elf->e_shstrndx) {
46158a2b000SEvgeniy Ivanov /* already loaded this section */
46258a2b000SEvgeniy Ivanov continue;
46358a2b000SEvgeniy Ivanov }
46458a2b000SEvgeniy Ivanov switch (shp[i].sh_type) {
46558a2b000SEvgeniy Ivanov case SHT_PROGBITS:
46658a2b000SEvgeniy Ivanov if (boot_load_ctf && shstr) {
46758a2b000SEvgeniy Ivanov /* got a CTF section? */
46858a2b000SEvgeniy Ivanov if (strncmp(".SUNW_ctf",
46958a2b000SEvgeniy Ivanov &shstr[shp[i].sh_name],
47058a2b000SEvgeniy Ivanov 10) == 0) {
47158a2b000SEvgeniy Ivanov goto havesym;
47258a2b000SEvgeniy Ivanov }
47358a2b000SEvgeniy Ivanov }
47458a2b000SEvgeniy Ivanov
47558a2b000SEvgeniy Ivanov /* Not loading this, so zero out the offset. */
47658a2b000SEvgeniy Ivanov shp[i].sh_offset = 0;
47758a2b000SEvgeniy Ivanov break;
47858a2b000SEvgeniy Ivanov case SHT_STRTAB:
47958a2b000SEvgeniy Ivanov for (j = 0; j < elf->e_shnum; j++)
48058a2b000SEvgeniy Ivanov if (shp[j].sh_type == SHT_SYMTAB &&
48158a2b000SEvgeniy Ivanov shp[j].sh_link == (unsigned int)i)
48258a2b000SEvgeniy Ivanov goto havesym;
48358a2b000SEvgeniy Ivanov /* FALLTHROUGH */
48458a2b000SEvgeniy Ivanov default:
48558a2b000SEvgeniy Ivanov /* Not loading this, so zero out the offset. */
48658a2b000SEvgeniy Ivanov shp[i].sh_offset = 0;
48758a2b000SEvgeniy Ivanov break;
48858a2b000SEvgeniy Ivanov havesym:
48958a2b000SEvgeniy Ivanov case SHT_SYMTAB:
49058a2b000SEvgeniy Ivanov if (flags & LOAD_SYM) {
49158a2b000SEvgeniy Ivanov PROGRESS(("%s%ld", first ? " [" : "+",
49258a2b000SEvgeniy Ivanov (u_long)shp[i].sh_size));
49358a2b000SEvgeniy Ivanov if (lseek(fd, shp[i].sh_offset,
49458a2b000SEvgeniy Ivanov SEEK_SET) == -1) {
49558a2b000SEvgeniy Ivanov WARN(("lseek symbols"));
49658a2b000SEvgeniy Ivanov goto freeshp;
49758a2b000SEvgeniy Ivanov }
49858a2b000SEvgeniy Ivanov nr = READ(fd, maxp, shp[i].sh_size);
49958a2b000SEvgeniy Ivanov if (nr == -1) {
50058a2b000SEvgeniy Ivanov WARN(("read symbols"));
50158a2b000SEvgeniy Ivanov goto freeshp;
50258a2b000SEvgeniy Ivanov }
50358a2b000SEvgeniy Ivanov if (nr != (ssize_t)shp[i].sh_size) {
50458a2b000SEvgeniy Ivanov errno = EIO;
50558a2b000SEvgeniy Ivanov WARN(("read symbols"));
50658a2b000SEvgeniy Ivanov goto freeshp;
50758a2b000SEvgeniy Ivanov }
50858a2b000SEvgeniy Ivanov }
50958a2b000SEvgeniy Ivanov shp[i].sh_offset = maxp - elfp;
51058a2b000SEvgeniy Ivanov maxp += roundup(shp[i].sh_size, ELFROUND);
51158a2b000SEvgeniy Ivanov first = 0;
51258a2b000SEvgeniy Ivanov break;
51358a2b000SEvgeniy Ivanov case SHT_NOTE:
51458a2b000SEvgeniy Ivanov if ((flags & LOAD_NOTE) == 0)
51558a2b000SEvgeniy Ivanov break;
51658a2b000SEvgeniy Ivanov if (shp[i].sh_size < sizeof(note)) {
51758a2b000SEvgeniy Ivanov shp[i].sh_offset = 0;
51858a2b000SEvgeniy Ivanov break;
51958a2b000SEvgeniy Ivanov }
52058a2b000SEvgeniy Ivanov if (lseek(fd, shp[i].sh_offset, SEEK_SET)
52158a2b000SEvgeniy Ivanov == -1) {
52258a2b000SEvgeniy Ivanov WARN(("lseek note"));
52358a2b000SEvgeniy Ivanov goto freeshp;
52458a2b000SEvgeniy Ivanov }
52558a2b000SEvgeniy Ivanov nr = read(fd, ¬e, sizeof(note));
52658a2b000SEvgeniy Ivanov if (nr == -1) {
52758a2b000SEvgeniy Ivanov WARN(("read note"));
52858a2b000SEvgeniy Ivanov goto freeshp;
52958a2b000SEvgeniy Ivanov }
53058a2b000SEvgeniy Ivanov if (note.nh.n_namesz ==
53158a2b000SEvgeniy Ivanov ELF_NOTE_NETBSD_NAMESZ &&
53258a2b000SEvgeniy Ivanov note.nh.n_descsz ==
53358a2b000SEvgeniy Ivanov ELF_NOTE_NETBSD_DESCSZ &&
53458a2b000SEvgeniy Ivanov note.nh.n_type ==
53558a2b000SEvgeniy Ivanov ELF_NOTE_TYPE_NETBSD_TAG &&
53658a2b000SEvgeniy Ivanov memcmp(note.name, ELF_NOTE_NETBSD_NAME,
53758a2b000SEvgeniy Ivanov sizeof(note.name)) == 0) {
53858a2b000SEvgeniy Ivanov memcpy(&netbsd_version, ¬e.desc,
53958a2b000SEvgeniy Ivanov sizeof(netbsd_version));
54058a2b000SEvgeniy Ivanov }
54158a2b000SEvgeniy Ivanov shp[i].sh_offset = 0;
54258a2b000SEvgeniy Ivanov break;
54358a2b000SEvgeniy Ivanov }
54458a2b000SEvgeniy Ivanov }
54558a2b000SEvgeniy Ivanov if (flags & LOAD_SYM) {
54658a2b000SEvgeniy Ivanov #ifndef _STANDALONE
54758a2b000SEvgeniy Ivanov /* Externalize the section headers. */
54858a2b000SEvgeniy Ivanov for (i = 0; i < elf->e_shnum; i++)
54958a2b000SEvgeniy Ivanov externalize_shdr(elf->e_ident[EI_DATA],
55058a2b000SEvgeniy Ivanov &shp[i]);
55158a2b000SEvgeniy Ivanov #endif /* ! _STANDALONE */
55258a2b000SEvgeniy Ivanov BCOPY(shp, shpp, sz);
55358a2b000SEvgeniy Ivanov
55458a2b000SEvgeniy Ivanov if (first == 0)
55558a2b000SEvgeniy Ivanov PROGRESS(("]"));
55658a2b000SEvgeniy Ivanov }
55758a2b000SEvgeniy Ivanov DEALLOC(shp, sz);
55858a2b000SEvgeniy Ivanov }
55958a2b000SEvgeniy Ivanov
56058a2b000SEvgeniy Ivanov if (shstr) {
56184d9c625SLionel Sambuc DEALLOC(shstr, shstrsz);
56258a2b000SEvgeniy Ivanov }
56358a2b000SEvgeniy Ivanov
56458a2b000SEvgeniy Ivanov /*
56558a2b000SEvgeniy Ivanov * Frob the copied ELF header to give information relative
56658a2b000SEvgeniy Ivanov * to elfp.
56758a2b000SEvgeniy Ivanov */
56858a2b000SEvgeniy Ivanov if (flags & LOAD_HDR) {
56958a2b000SEvgeniy Ivanov elf->e_phoff = 0;
57058a2b000SEvgeniy Ivanov elf->e_shoff = sizeof(Elf_Ehdr);
57158a2b000SEvgeniy Ivanov elf->e_phentsize = 0;
57258a2b000SEvgeniy Ivanov elf->e_phnum = 0;
57358a2b000SEvgeniy Ivanov externalize_ehdr(elf->e_ident[EI_DATA], elf);
57458a2b000SEvgeniy Ivanov BCOPY(elf, elfp, sizeof(*elf));
57558a2b000SEvgeniy Ivanov internalize_ehdr(elf->e_ident[EI_DATA], elf);
57658a2b000SEvgeniy Ivanov }
57758a2b000SEvgeniy Ivanov
57858a2b000SEvgeniy Ivanov marks[MARK_START] = LOADADDR(minp);
57958a2b000SEvgeniy Ivanov marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
58058a2b000SEvgeniy Ivanov /*
58158a2b000SEvgeniy Ivanov * Since there can be more than one symbol section in the code
58258a2b000SEvgeniy Ivanov * and we need to find strtab too in order to do anything
58358a2b000SEvgeniy Ivanov * useful with the symbols, we just pass the whole elf
58458a2b000SEvgeniy Ivanov * header back and we let the kernel debugger find the
58558a2b000SEvgeniy Ivanov * location and number of symbols by itself.
58658a2b000SEvgeniy Ivanov */
58758a2b000SEvgeniy Ivanov marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */
58858a2b000SEvgeniy Ivanov marks[MARK_SYM] = LOADADDR(elfp);
58958a2b000SEvgeniy Ivanov marks[MARK_END] = LOADADDR(maxp);
59058a2b000SEvgeniy Ivanov return 0;
59158a2b000SEvgeniy Ivanov freephdr:
59258a2b000SEvgeniy Ivanov DEALLOC(phdr, sz);
59358a2b000SEvgeniy Ivanov return 1;
59458a2b000SEvgeniy Ivanov freeshp:
59558a2b000SEvgeniy Ivanov DEALLOC(shp, sz);
59658a2b000SEvgeniy Ivanov return 1;
59758a2b000SEvgeniy Ivanov }
59858a2b000SEvgeniy Ivanov
59958a2b000SEvgeniy Ivanov #ifdef TEST
60058a2b000SEvgeniy Ivanov #include <stdlib.h>
60158a2b000SEvgeniy Ivanov #include <fcntl.h>
60258a2b000SEvgeniy Ivanov #include <err.h>
60358a2b000SEvgeniy Ivanov #include <stdio.h>
60458a2b000SEvgeniy Ivanov u_int32_t netbsd_version;
60558a2b000SEvgeniy Ivanov int
main(int argc,char * argv[])60658a2b000SEvgeniy Ivanov main(int argc, char *argv[])
60758a2b000SEvgeniy Ivanov {
60858a2b000SEvgeniy Ivanov int fd;
60958a2b000SEvgeniy Ivanov u_long marks[MARK_MAX];
61058a2b000SEvgeniy Ivanov Elf_Ehdr elf;
61158a2b000SEvgeniy Ivanov if (argc != 2) {
61258a2b000SEvgeniy Ivanov (void)fprintf(stderr, "Usage: %s <file>\n", getprogname());
61358a2b000SEvgeniy Ivanov return 1;
61458a2b000SEvgeniy Ivanov }
61558a2b000SEvgeniy Ivanov if ((fd = open(argv[1], O_RDONLY)) == -1)
61658a2b000SEvgeniy Ivanov err(1, "Can't open `%s'", argv[1]);
61758a2b000SEvgeniy Ivanov if (read(fd, &elf, sizeof(elf)) != sizeof(elf))
61858a2b000SEvgeniy Ivanov err(1, "Can't read `%s'", argv[1]);
61958a2b000SEvgeniy Ivanov memset(marks, 0, sizeof(marks));
62058a2b000SEvgeniy Ivanov marks[MARK_START] = (u_long)malloc(2LL * 1024 * 2024 * 1024);
62158a2b000SEvgeniy Ivanov ELFNAMEEND(loadfile)(fd, &elf, marks, LOAD_ALL);
62258a2b000SEvgeniy Ivanov printf("%d\n", netbsd_version);
62358a2b000SEvgeniy Ivanov return 0;
62458a2b000SEvgeniy Ivanov }
62558a2b000SEvgeniy Ivanov #endif
62658a2b000SEvgeniy Ivanov
62758a2b000SEvgeniy Ivanov #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */
628