예제 #1
0
/*
 * 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;
}
예제 #2
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;
}
예제 #3
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, &note, 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, &note.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;
}