Module Name: src Committed By: maxv Date: Mon Sep 25 20:39:21 UTC 2017
Modified Files: src/sys/lib/libsa: loadfile_elf32.c Log Message: Clean up and split loadfile, reduces a patch I have. To generate a diff of this commit: cvs rdiff -u -r1.40 -r1.41 src/sys/lib/libsa/loadfile_elf32.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/lib/libsa/loadfile_elf32.c diff -u src/sys/lib/libsa/loadfile_elf32.c:1.40 src/sys/lib/libsa/loadfile_elf32.c:1.41 --- src/sys/lib/libsa/loadfile_elf32.c:1.40 Tue Apr 18 07:44:20 2017 +++ src/sys/lib/libsa/loadfile_elf32.c Mon Sep 25 20:39:21 2017 @@ -1,12 +1,12 @@ -/* $NetBSD: loadfile_elf32.c,v 1.40 2017/04/18 07:44:20 uwe Exp $ */ +/* $NetBSD: loadfile_elf32.c,v 1.41 2017/09/25 20:39:21 maxv Exp $ */ /* - * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. + * Copyright (c) 1997, 2008, 2017 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, - * NASA Ames Research Center and by Christos Zoulas. + * NASA Ames Research Center, by Christos Zoulas, and by Maxime Villard. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -259,8 +259,220 @@ externalize_shdr(Elf_Byte bo, Elf_Shdr * #define IS_DATA(p) (p.p_flags & PF_W) #define IS_BSS(p) (p.p_filesz < p.p_memsz) +#ifndef MD_LOADSEG /* Allow processor ABI specific segment loads */ +#define MD_LOADSEG(a) /*CONSTCOND*/0 +#endif + +/* -------------------------------------------------------------------------- */ + /* - * Load the ELF binary into memory. Layout of the memory: + * See comment below. This function is in charge of loading the SECTION HEADERS. + */ +static int +ELFNAMEEND(loadsym)(int fd, Elf_Ehdr *elf, Elf_Addr maxp, Elf_Addr elfp, + u_long *marks, int flags, Elf_Addr *nmaxp) +{ + int boot_load_ctf = 1; + Elf_Shdr *shp; + Elf_Addr shpp; + char *shstr = NULL; + ssize_t nr, sz; + size_t i, j, shstrsz = 0; + u_long offset = marks[MARK_START]; + struct __packed { + Elf_Nhdr nh; + uint8_t name[ELF_NOTE_NETBSD_NAMESZ + 1]; + uint8_t desc[ELF_NOTE_NETBSD_DESCSZ]; + } note; + int first; + + /* some ports dont use the offset */ + (void)&offset; + + 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 out; + } + if (nr != sz) { + errno = EIO; + WARN(("read section headers")); + goto out; + } + + shpp = maxp; + maxp += roundup(sz, ELFROUND); + +#ifndef _STANDALONE + for (i = 0; i < elf->e_shnum; i++) + internalize_shdr(elf->e_ident[EI_DATA], &shp[i]); +#endif + + /* + * First load the section names section. Only useful for CTF. + */ + if (boot_load_ctf && (elf->e_shstrndx != SHN_UNDEF)) { + Elf_Off shstroff = shp[elf->e_shstrndx].sh_offset; + shstrsz = shp[elf->e_shstrndx].sh_size; + if (flags & LOAD_SYM) { + if (lseek(fd, shstroff, SEEK_SET) == -1) { + WARN(("lseek symbols")); + goto out; + } + nr = READ(fd, maxp, shstrsz); + if (nr == -1) { + WARN(("read symbols")); + goto out; + } + if (nr != (ssize_t)shstrsz) { + errno = EIO; + WARN(("read symbols")); + goto out; + } + } + + /* Create a local copy */ + shstr = ALLOC(shstrsz); + if (lseek(fd, shstroff, SEEK_SET) == -1) { + WARN(("lseek symbols")); + goto out; + } + nr = read(fd, shstr, shstrsz); + if (nr == -1) { + WARN(("read symbols")); + goto out; + } + shp[elf->e_shstrndx].sh_offset = maxp - elfp; + maxp += roundup(shstrsz, ELFROUND); + } + + /* + * Now load the symbol sections themselves. Make sure the sections are + * ELFROUND-aligned. Update sh_offset to be relative to elfp. Set it to + * zero when we don't want the sections to be taken care of, the kernel + * will properly skip them. + */ + first = 1; + for (i = 1; 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(&shstr[shp[i].sh_name], + ".SUNW_ctf", 10) == 0) { + goto havesym; + } + } + + shp[i].sh_offset = 0; + break; + case SHT_STRTAB: + for (j = 1; j < elf->e_shnum; j++) + if (shp[j].sh_type == SHT_SYMTAB && + shp[j].sh_link == (unsigned int)i) + goto havesym; + /* + * Don't bother with any string table that isn't + * referenced by a symbol table. + */ + 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 out; + } + nr = READ(fd, maxp, shp[i].sh_size); + if (nr == -1) { + WARN(("read symbols")); + goto out; + } + if (nr != (ssize_t)shp[i].sh_size) { + errno = EIO; + WARN(("read symbols")); + goto out; + } + } + 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 out; + } + nr = read(fd, ¬e, sizeof(note)); + if (nr == -1) { + WARN(("read note")); + goto out; + } + 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; + default: + shp[i].sh_offset = 0; + break; + } + } + if (flags & LOAD_SYM) { +#ifndef _STANDALONE + for (i = 0; i < elf->e_shnum; i++) + externalize_shdr(elf->e_ident[EI_DATA], &shp[i]); +#endif + BCOPY(shp, shpp, sz); + + if (first == 0) + PROGRESS(("]")); + } + + *nmaxp = maxp; + DEALLOC(shp, sz); + if (shstr != NULL) + DEALLOC(shstr, shstrsz); + return 0; + +out: + DEALLOC(shp, sz); + if (shstr != NULL) + DEALLOC(shstr, shstrsz); + return -1; +} + +/* -------------------------------------------------------------------------- */ + +/* + * Load a static ELF binary into memory. Layout of the memory: * +-----------------+------------+-----------------+-----------------+ * | KERNEL SEGMENTS | ELF HEADER | SECTION HEADERS | SYMBOL SECTIONS | * +-----------------+------------+-----------------+-----------------+ @@ -273,27 +485,15 @@ externalize_shdr(Elf_Byte bo, Elf_Shdr * * We just give the kernel a pointer to the ELF HEADER, which is enough for it * to find the location and number of symbols by itself later. */ - int ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *elf, u_long *marks, int flags) { - Elf_Shdr *shp; Elf_Phdr *phdr; - int i, j; + int i, first; 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; - size_t shstrsz = 0; - int boot_load_ctf = 1; /* some ports dont use the offset */ (void)&offset; @@ -325,9 +525,6 @@ ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *e for (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; @@ -390,194 +587,25 @@ ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *e } } DEALLOC(phdr, sz); + maxp = roundup(maxp, ELFROUND); /* - * Copy the ELF and section headers. + * Load the ELF HEADER, SECTION HEADERS and possibly the SYMBOL + * SECTIONS. */ - 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 - - /* - * First load the section names section. - */ - if (boot_load_ctf && (elf->e_shstrndx != SHN_UNDEF)) { - Elf_Off shstroff = shp[elf->e_shstrndx].sh_offset; - shstrsz = shp[elf->e_shstrndx].sh_size; - if (flags & LOAD_SYM) { - if (lseek(fd, shstroff, SEEK_SET) == -1) { - WARN(("lseek symbols")); - goto freeshp; - } - nr = READ(fd, maxp, shstrsz); - if (nr == -1) { - WARN(("read symbols")); - goto freeshp; - } - if (nr != (ssize_t)shstrsz) { - errno = EIO; - WARN(("read symbols")); - goto freeshp; - } - } - - shstr = ALLOC(shstrsz); - if (lseek(fd, shstroff, SEEK_SET) == -1) { - WARN(("lseek symbols")); - goto freeshp; - } - nr = read(fd, shstr, shstrsz); - if (nr == -1) { - WARN(("read symbols")); - goto freeshp; - } - shp[elf->e_shstrndx].sh_offset = maxp - elfp; - maxp += roundup(shstrsz, ELFROUND); + if (ELFNAMEEND(loadsym)(fd, elf, maxp, elfp, marks, flags, + &maxp) == -1) { + return 1; } - - /* - * 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. - */ - first = 1; - for (i = 1; 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(&shstr[shp[i].sh_name], - ".SUNW_ctf", 10) == 0) { - goto havesym; - } - } - - /* Not loading this, so zero out the offset. */ - shp[i].sh_offset = 0; - break; - case SHT_STRTAB: - for (j = 1; 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 - BCOPY(shp, shpp, sz); - - if (first == 0) - PROGRESS(("]")); - } - DEALLOC(shp, sz); - if (shstr) - DEALLOC(shstr, shstrsz); } /* - * Frob the copied ELF header to give information relative - * to elfp. + * Update the ELF HEADER to give information relative to elfp. */ if (flags & LOAD_HDR) { elf->e_phoff = 0; @@ -591,13 +619,6 @@ ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *e 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); @@ -606,38 +627,6 @@ ELFNAMEEND(loadfile)(int fd, Elf_Ehdr *e freephdr: DEALLOC(phdr, sz); return 1; - -freeshp: - DEALLOC(shp, sz); - return 1; } -#ifdef TEST -#include <stdlib.h> -#include <fcntl.h> -#include <err.h> -#include <stdio.h> -u_int32_t netbsd_version; -int -main(int argc, char *argv[]) -{ - int fd; - u_long marks[MARK_MAX]; - Elf_Ehdr elf; - if (argc != 2) { - (void)fprintf(stderr, "Usage: %s <file>\n", getprogname()); - return 1; - } - if ((fd = open(argv[1], O_RDONLY)) == -1) - err(1, "Can't open `%s'", argv[1]); - if (read(fd, &elf, sizeof(elf)) != sizeof(elf)) - err(1, "Can't read `%s'", argv[1]); - memset(marks, 0, sizeof(marks)); - marks[MARK_START] = (u_long)malloc(2LL * 1024 * 2024 * 1024); - ELFNAMEEND(loadfile)(fd, &elf, marks, LOAD_ALL); - printf("%d\n", netbsd_version); - return 0; -} -#endif - #endif /* (ELFSIZE == 32 && BOOT_ELF32) || (ELFSIZE == 64 && BOOT_ELF64) */