/* * elf32_exec * * Load the kernel indicated by 'fd' into the guest physical memory * space, at the addresses defined in the ELF header. * * This function is used for 32 bit kernels. * * Parameters: * fd: file descriptor of the kernel to load * elf: ELF header of the kernel * marks: array to store the offsets of various kernel structures * (start, bss, etc) * flags: flag value to indicate which section(s) to load (usually * LOAD_ALL) * * Return values: * 0 if successful * 1 if unsuccessful */ static int elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) { Elf32_Shdr *shp; Elf32_Phdr *phdr; Elf32_Off off; int i; ssize_t sz; int first; int havesyms, havelines; paddr_t minp = ~0, maxp = 0, pos = 0; paddr_t offset = marks[MARK_START], shpp, elfp; sz = elf->e_phnum * sizeof(Elf32_Phdr); phdr = malloc(sz); if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1) { free(phdr); return 1; } if (read(fd, phdr, sz) != sz) { free(phdr); return 1; } for (first = 1, i = 0; i < elf->e_phnum; i++) { if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) { int m; /* Fill segment if asked for. */ if (flags & LOAD_RANDOM) { for (pos = 0; pos < phdr[i].p_filesz; pos += m) { m = phdr[i].p_filesz - pos; marc4random_buf(phdr[i].p_paddr + pos, m); } } if (flags & (LOAD_RANDOM | COUNT_RANDOM)) { marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr); marks[MARK_ERANDOM] = marks[MARK_RANDOM] + phdr[i].p_filesz; } continue; } if (phdr[i].p_type != PT_LOAD || (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) continue; #define IS_TEXT(p) (p.p_flags & PF_X) #define IS_DATA(p) ((p.p_flags & PF_X) == 0) #define IS_BSS(p) (p.p_filesz < p.p_memsz) /* * XXX: Assume first address is lowest */ if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) || (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1) { free(phdr); return 1; } if (mread(fd, phdr[i].p_paddr, phdr[i].p_filesz) != phdr[i].p_filesz) { free(phdr); return 1; } first = 0; } if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) || (IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) { pos = phdr[i].p_paddr; if (minp > pos) minp = pos; pos += phdr[i].p_filesz; if (maxp < pos) maxp = pos; } /* Zero out BSS. */ if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) { mbzero((phdr[i].p_paddr + phdr[i].p_filesz), phdr[i].p_memsz - phdr[i].p_filesz); } if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) { pos += phdr[i].p_memsz - phdr[i].p_filesz; if (maxp < pos) maxp = pos; } } free(phdr); /* * Copy the ELF and section headers. */ elfp = maxp = roundup(maxp, sizeof(Elf32_Addr)); if (flags & (LOAD_HDR | COUNT_HDR)) maxp += sizeof(Elf32_Ehdr); if (flags & (LOAD_SYM | COUNT_SYM)) { if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf32_Shdr); shp = malloc(sz); if (read(fd, shp, sz) != sz) { free(shp); return 1; } shpp = maxp; maxp += roundup(sz, sizeof(Elf32_Addr)); ssize_t shstrsz = shp[elf->e_shstrndx].sh_size; char *shstr = malloc(shstrsz); if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } if (read(fd, shstr, shstrsz) != shstrsz) { free(shstr); free(shp); return 1; } /* * Now load the symbol sections themselves. Make sure the * sections are aligned. Don't bother with string tables if * there are no symbol sections. */ off = roundup((sizeof(Elf32_Ehdr) + sz), sizeof(Elf32_Addr)); for (havesyms = havelines = i = 0; i < elf->e_shnum; i++) if (shp[i].sh_type == SHT_SYMTAB) havesyms = 1; for (first = 1, i = 0; i < elf->e_shnum; i++) { if (shp[i].sh_type == SHT_SYMTAB || shp[i].sh_type == SHT_STRTAB || !strcmp(shstr + shp[i].sh_name, ".debug_line")) { if (havesyms && (flags & LOAD_SYM)) { if (lseek(fd, (off_t)shp[i].sh_offset, SEEK_SET) == -1) { free(shstr); free(shp); return 1; } if (mread(fd, maxp, shp[i].sh_size) != shp[i].sh_size) { free(shstr); free(shp); return 1; } } maxp += roundup(shp[i].sh_size, sizeof(Elf32_Addr)); shp[i].sh_offset = off; shp[i].sh_flags |= SHF_ALLOC; off += roundup(shp[i].sh_size, sizeof(Elf32_Addr)); first = 0; } } if (flags & LOAD_SYM) { mbcopy(shp, shpp, sz); } free(shstr); free(shp); } /* * Frob the copied ELF header to give information relative * to elfp. */ if (flags & LOAD_HDR) { elf->e_phoff = 0; elf->e_shoff = sizeof(Elf32_Ehdr); elf->e_phentsize = 0; elf->e_phnum = 0; mbcopy(elf, elfp, sizeof(*elf)); } marks[MARK_START] = LOADADDR(minp); marks[MARK_ENTRY] = LOADADDR(elf->e_entry); marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ marks[MARK_SYM] = LOADADDR(elfp); marks[MARK_END] = LOADADDR(maxp); return 0; }
static int elf_exec(int fd, Elf_Ehdr *elf, u_long *marks, int flags) { Elf_Shdr *shp; Elf_Phdr *phdr; Elf_Off off; int i; size_t sz; int first; int havesyms; paddr_t minp = ~0, maxp = 0, pos = 0; paddr_t offset = marks[MARK_START], shpp, elfp; sz = elf->e_phnum * sizeof(Elf_Phdr); phdr = ALLOC(sz); if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) { WARN(("lseek phdr")); FREE(phdr, sz); return 1; } if (read(fd, phdr, sz) != sz) { WARN(("read program headers")); FREE(phdr, sz); return 1; } for (first = 1, i = 0; i < elf->e_phnum; i++) { if (phdr[i].p_type != PT_LOAD || (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) continue; #define IS_TEXT(p) (p.p_flags & PF_X) #define IS_DATA(p) ((p.p_flags & PF_X) == 0) #define IS_BSS(p) (p.p_filesz < p.p_memsz) /* * XXX: Assume first address is lowest */ if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) || (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { /* Read in segment. */ PROGRESS(("%s%lu", first ? "" : "+", (u_long)phdr[i].p_filesz)); if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) { WARN(("lseek text")); FREE(phdr, sz); return 1; } if (READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz) != phdr[i].p_filesz) { WARN(("read text")); FREE(phdr, sz); return 1; } first = 0; } if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) || (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) { pos = phdr[i].p_vaddr; if (minp > pos) minp = pos; pos += phdr[i].p_filesz; if (maxp < pos) maxp = pos; } /* Zero out bss. */ if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) { PROGRESS(("+%lu", (u_long)(phdr[i].p_memsz - phdr[i].p_filesz))); BZERO((phdr[i].p_vaddr + phdr[i].p_filesz), phdr[i].p_memsz - phdr[i].p_filesz); } if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) { pos += phdr[i].p_memsz - phdr[i].p_filesz; if (maxp < pos) maxp = pos; } } FREE(phdr, sz); /* * Copy the ELF and section headers. */ elfp = maxp = roundup(maxp, sizeof(long)); if (flags & (LOAD_HDR|COUNT_HDR)) maxp += sizeof(Elf_Ehdr); if (flags & (LOAD_SYM|COUNT_SYM)) { if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf_Shdr); shp = ALLOC(sz); if (read(fd, shp, sz) != sz) { WARN(("read section headers")); return 1; } shpp = maxp; maxp += roundup(sz, sizeof(long)); /* * Now load the symbol sections themselves. Make sure the * sections are aligned. Don't bother with string tables if * there are no symbol sections. */ off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); for (havesyms = i = 0; i < elf->e_shnum; i++) if (shp[i].sh_type == SHT_SYMTAB) havesyms = 1; for (first = 1, i = 0; i < elf->e_shnum; i++) { if (shp[i].sh_type == SHT_SYMTAB || shp[i].sh_type == SHT_STRTAB) { if (havesyms && (flags & LOAD_SYM)) { PROGRESS(("%s%ld", first ? " [" : "+", (u_long)shp[i].sh_size)); if (lseek(fd, shp[i].sh_offset, SEEK_SET) == -1) { WARN(("lseek symbols")); FREE(shp, sz); return 1; } if (READ(fd, maxp, shp[i].sh_size) != shp[i].sh_size) { WARN(("read symbols")); FREE(shp, sz); return 1; } } maxp += roundup(shp[i].sh_size, sizeof(long)); shp[i].sh_offset = off; off += roundup(shp[i].sh_size, sizeof(long)); first = 0; } } if (flags & LOAD_SYM) { BCOPY(shp, shpp, sz); if (havesyms && first == 0) PROGRESS(("]")); } FREE(shp, sz); } /* * Frob the copied ELF header to give information relative * to elfp. */ if (flags & LOAD_HDR) { elf->e_phoff = 0; elf->e_shoff = sizeof(Elf_Ehdr); elf->e_phentsize = 0; elf->e_phnum = 0; BCOPY(elf, elfp, sizeof(*elf)); } marks[MARK_START] = LOADADDR(minp); marks[MARK_ENTRY] = LOADADDR(elf->e_entry); marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ marks[MARK_SYM] = LOADADDR(elfp); marks[MARK_END] = LOADADDR(maxp); return 0; }
int ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags) { Elf_Shdr *shp; Elf_Phdr *phdr; int i, j; ssize_t sz; int first; Elf_Addr shpp; Elf_Addr minp = ~0, maxp = 0, pos = 0, elfp = 0; u_long offset = marks[MARK_START]; ssize_t nr; struct __packed { Elf_Nhdr nh; uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1]; uint8_t desc[ELF_NOTE_NETBSD_DESCSZ]; } note; char *shstr = NULL; int boot_load_ctf = 1; /* some ports dont use the offset */ (void)&offset; internalize_ehdr(elf->e_ident[EI_DATA], elf); sz = elf->e_phnum * sizeof(Elf_Phdr); phdr = ALLOC(sz); if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) { WARN(("lseek phdr")); goto freephdr; } nr = read(fd, phdr, sz); if (nr == -1) { WARN(("read program headers")); goto freephdr; } if (nr != sz) { errno = EIO; WARN(("read program headers")); goto freephdr; } for (first = 1, i = 0; i < elf->e_phnum; i++) { internalize_phdr(elf->e_ident[EI_DATA], &phdr[i]); #ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */ #define MD_LOADSEG(a) /*CONSTCOND*/0 #endif if (MD_LOADSEG(&phdr[i])) goto loadseg; if (phdr[i].p_type != PT_LOAD || (phdr[i].p_flags & (PF_W|PF_X)) == 0) continue; #define IS_TEXT(p) (p.p_flags & PF_X) #define IS_DATA(p) (p.p_flags & PF_W) #define IS_BSS(p) (p.p_filesz < p.p_memsz) /* * XXX: Assume first address is lowest */ if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) || (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) { loadseg: if (marks[MARK_DATA] == 0 && IS_DATA(phdr[i])) marks[MARK_DATA] = LOADADDR(phdr[i].p_vaddr); /* Read in segment. */ PROGRESS(("%s%lu", first ? "" : "+", (u_long)phdr[i].p_filesz)); if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) { WARN(("lseek text")); goto freephdr; } nr = READ(fd, phdr[i].p_vaddr, phdr[i].p_filesz); if (nr == -1) { WARN(("read text error")); goto freephdr; } if (nr != (ssize_t)phdr[i].p_filesz) { errno = EIO; WARN(("read text")); goto freephdr; } first = 0; } if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT|COUNT_TEXT))) || (IS_DATA(phdr[i]) && (flags & (LOAD_DATA|COUNT_TEXT)))) { pos = phdr[i].p_vaddr; if (minp > pos) minp = pos; pos += phdr[i].p_filesz; if (maxp < pos) maxp = pos; } /* Zero out bss. */ if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) { PROGRESS(("+%lu", (u_long)(phdr[i].p_memsz - phdr[i].p_filesz))); BZERO((phdr[i].p_vaddr + phdr[i].p_filesz), phdr[i].p_memsz - phdr[i].p_filesz); } if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) { pos += phdr[i].p_memsz - phdr[i].p_filesz; if (maxp < pos) maxp = pos; } } DEALLOC(phdr, sz); /* * Copy the ELF and section headers. */ maxp = roundup(maxp, ELFROUND); if (flags & (LOAD_HDR|COUNT_HDR)) { elfp = maxp; maxp += sizeof(Elf_Ehdr); } if (flags & (LOAD_SYM|COUNT_SYM)) { if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { WARN(("lseek section headers")); return 1; } sz = elf->e_shnum * sizeof(Elf_Shdr); shp = ALLOC(sz); nr = read(fd, shp, sz); if (nr == -1) { WARN(("read section headers")); goto freeshp; } if (nr != sz) { errno = EIO; WARN(("read section headers")); goto freeshp; } shpp = maxp; maxp += roundup(sz, ELFROUND); #ifndef _STANDALONE /* Internalize the section headers. */ for (i = 0; i < elf->e_shnum; i++) internalize_shdr(elf->e_ident[EI_DATA], &shp[i]); #endif /* ! _STANDALONE */ /* * First load the section names section. */ if (boot_load_ctf && (elf->e_shstrndx != 0)) { if (flags & LOAD_SYM) { if (lseek(fd, shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { WARN(("lseek symbols")); goto freeshp; } nr = READ(fd, maxp, shp[elf->e_shstrndx].sh_size); if (nr == -1) { WARN(("read symbols")); goto freeshp; } if (nr != (ssize_t)shp[elf->e_shstrndx].sh_size) { errno = EIO; WARN(("read symbols")); goto freeshp; } shstr = ALLOC(shp[elf->e_shstrndx].sh_size); if (lseek(fd, shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) { WARN(("lseek symbols")); goto freeshp; } nr = read(fd, shstr, shp[elf->e_shstrndx].sh_size); if (nr == -1) { WARN(("read symbols")); goto freeshp; } } shp[elf->e_shstrndx].sh_offset = maxp - elfp; maxp += roundup(shp[elf->e_shstrndx].sh_size, ELFROUND); } /* * Now load the symbol sections themselves. Make sure * the sections are aligned. Don't bother with any * string table that isn't referenced by a symbol * table. */ for (first = 1, i = 0; i < elf->e_shnum; i++) { if (i == elf->e_shstrndx) { /* already loaded this section */ continue; } switch (shp[i].sh_type) { case SHT_PROGBITS: if (boot_load_ctf && shstr) { /* got a CTF section? */ if (strncmp(".SUNW_ctf", &shstr[shp[i].sh_name], 10) == 0) { goto havesym; } } /* Not loading this, so zero out the offset. */ shp[i].sh_offset = 0; break; case SHT_STRTAB: for (j = 0; j < elf->e_shnum; j++) if (shp[j].sh_type == SHT_SYMTAB && shp[j].sh_link == (unsigned int)i) goto havesym; /* FALLTHROUGH */ default: /* Not loading this, so zero out the offset. */ shp[i].sh_offset = 0; break; havesym: case SHT_SYMTAB: if (flags & LOAD_SYM) { PROGRESS(("%s%ld", first ? " [" : "+", (u_long)shp[i].sh_size)); if (lseek(fd, shp[i].sh_offset, SEEK_SET) == -1) { WARN(("lseek symbols")); goto freeshp; } nr = READ(fd, maxp, shp[i].sh_size); if (nr == -1) { WARN(("read symbols")); goto freeshp; } if (nr != (ssize_t)shp[i].sh_size) { errno = EIO; WARN(("read symbols")); goto freeshp; } } shp[i].sh_offset = maxp - elfp; maxp += roundup(shp[i].sh_size, ELFROUND); first = 0; break; case SHT_NOTE: if ((flags & LOAD_NOTE) == 0) break; if (shp[i].sh_size < sizeof(note)) { shp[i].sh_offset = 0; break; } if (lseek(fd, shp[i].sh_offset, SEEK_SET) == -1) { WARN(("lseek note")); goto freeshp; } nr = read(fd, ¬e, sizeof(note)); if (nr == -1) { WARN(("read note")); goto freeshp; } if (note.nh.n_namesz == ELF_NOTE_NETBSD_NAMESZ && note.nh.n_descsz == ELF_NOTE_NETBSD_DESCSZ && note.nh.n_type == ELF_NOTE_TYPE_NETBSD_TAG && memcmp(note.name, ELF_NOTE_NETBSD_NAME, sizeof(note.name)) == 0) { memcpy(&netbsd_version, ¬e.desc, sizeof(netbsd_version)); } shp[i].sh_offset = 0; break; } } if (flags & LOAD_SYM) { #ifndef _STANDALONE /* Externalize the section headers. */ for (i = 0; i < elf->e_shnum; i++) externalize_shdr(elf->e_ident[EI_DATA], &shp[i]); #endif /* ! _STANDALONE */ BCOPY(shp, shpp, sz); if (first == 0) PROGRESS(("]")); } DEALLOC(shp, sz); } if (shstr) { DEALLOC(shstr, shp[elf->e_shstrndx].sh_size); } /* * Frob the copied ELF header to give information relative * to elfp. */ if (flags & LOAD_HDR) { elf->e_phoff = 0; elf->e_shoff = sizeof(Elf_Ehdr); elf->e_phentsize = 0; elf->e_phnum = 0; externalize_ehdr(elf->e_ident[EI_DATA], elf); BCOPY(elf, elfp, sizeof(*elf)); internalize_ehdr(elf->e_ident[EI_DATA], elf); } marks[MARK_START] = LOADADDR(minp); marks[MARK_ENTRY] = LOADADDR(elf->e_entry); /* * Since there can be more than one symbol section in the code * and we need to find strtab too in order to do anything * useful with the symbols, we just pass the whole elf * header back and we let the kernel debugger find the * location and number of symbols by itself. */ marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */ marks[MARK_SYM] = LOADADDR(elfp); marks[MARK_END] = LOADADDR(maxp); return 0; freephdr: DEALLOC(phdr, sz); return 1; freeshp: DEALLOC(shp, sz); return 1; }