Ejemplo n.º 1
0
/*
 * Apply any intra-module relocations to the value. p is the load address
 * of the value and val/len is the value to be modified. This does NOT modify
 * the image in-place, because this is done by kern_linker later on.
 *
 * Returns EOPNOTSUPP if no relocation method is supplied.
 */
static int
__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
    Elf_Addr p, void *val, size_t len)
{
	size_t n;
	Elf_Rela a;
	Elf_Rel r;
	int error;

	/*
	 * The kernel is already relocated, but we still want to apply
	 * offset adjustments.
	 */
	if (ef->kernel)
		return (EOPNOTSUPP);

	for (n = 0; n < ef->relsz / sizeof(r); n++) {
		COPYOUT(ef->rel + n, &r, sizeof(r));

		error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL,
		    ef->off, p, val, len);
		if (error != 0)
			return (error);
	}
	for (n = 0; n < ef->relasz / sizeof(a); n++) {
		COPYOUT(ef->rela + n, &a, sizeof(a));

		error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA,
		    ef->off, p, val, len);
		if (error != 0)
			return (error);
	}

	return (0);
}
Ejemplo n.º 2
0
/*
 * Apply any intra-module relocations to the value. p is the load address
 * of the value and val/len is the value to be modified. This does NOT modify
 * the image in-place, because this is done by kern_linker later on.
 */
static int
__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p,
    void *val, size_t len)
{
	Elf_Ehdr *hdr;
	Elf_Shdr *shdr;
	Elf_Addr off = p;
	Elf_Addr base;
	Elf_Rela a, *abase;
	Elf_Rel r, *rbase;
	int error, i, j, nrel, nrela;

	hdr = &ef->hdr;
	shdr = ef->e_shdr;

	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL)
			continue;
		base = shdr[shdr[i].sh_info].sh_addr;
		if (base == 0 || shdr[i].sh_addr == 0)
			continue;
		if (off < base || off + len > base +
		    shdr[shdr[i].sh_info].sh_size)
			continue;

		switch (shdr[i].sh_type) {
		case SHT_RELA:
			abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr;

			nrela = shdr[i].sh_size / sizeof(Elf_Rela);
			for (j = 0; j < nrela; j++) {
				COPYOUT(abase + j, &a, sizeof(a));

				error = __elfN(reloc)(ef, __elfN(obj_symaddr),
				    &a, ELF_RELOC_RELA, base, off, val, len);
				if (error != 0)
					return (error);
			}
			break;
		case SHT_REL:
			rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr;

			nrel = shdr[i].sh_size / sizeof(Elf_Rel);
			for (j = 0; j < nrel; j++) {
				COPYOUT(rbase + j, &r, sizeof(r));

				error = __elfN(reloc)(ef, __elfN(obj_symaddr),
				    &r, ELF_RELOC_REL, base, off, val, len);
				if (error != 0)
					return (error);
			}
			break;
		}
	}
	return (0);
}
Ejemplo n.º 3
0
static int
__elfN(arm_exec)(struct preloaded_file *fp)
{
	struct file_metadata *fmp;
	vm_offset_t modulep, kernend;
	Elf_Ehdr *e;
	int error;
	void (*entry)(void *);

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return (EFTYPE);

	e = (Elf_Ehdr *)&fmp->md_data;

	if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0)
		return (error);

	entry = efi_translate(e->e_entry);
	printf("Kernel entry at 0x%x...\n", (unsigned)entry);
	printf("Kernel args: %s\n", fp->f_args);
	printf("modulep: %#x\n", modulep);
	printf("relocation_offset %llx\n", __elfN(relocation_offset));

	dev_cleanup();

	(*entry)((void *)modulep);
	panic("exec returned");
}
Ejemplo n.º 4
0
static vm_offset_t
md_copymodules(vm_offset_t addr)
{
	struct preloaded_file	*fp;
	struct file_metadata	*md;
	int			c;
	vm_offset_t a;

	c = addr != 0;
	/* start with the first module on the list, should be the kernel */
	for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {

		MOD_NAME(addr, fp->f_name, c);	/* this field must be first */
		MOD_TYPE(addr, fp->f_type, c);
		if (fp->f_args)
			MOD_ARGS(addr, fp->f_args, c);
		a = fp->f_addr - __elfN(relocation_offset);
		MOD_ADDR(addr, a, c);
		MOD_SIZE(addr, fp->f_size, c);
		for (md = fp->f_metadata; md != NULL; md = md->md_next) {
			if (!(md->md_type & MODINFOMD_NOCOPY))
				MOD_METADATA(addr, md, c);
		}
	}
	MOD_END(addr, c);
	return(addr);
}
Ejemplo n.º 5
0
static int
beri_elf64_loadfile(char *filename, uint64_t dest,
    struct preloaded_file **result)
{

	/*
	 * Some platforms require invalidation of instruction caches here; we
	 * don't need that currently.
	 */
	return (__elfN(loadfile)(filename, dest, result));
}
Ejemplo n.º 6
0
static int
__elfN(arm_load)(char *filename, u_int64_t dest,
    struct preloaded_file **result)
{
	int r;

	r = __elfN(loadfile)(filename, dest, result);
	if (r != 0)
		return (r);

	return (0);
}
Ejemplo n.º 7
0
int
__elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name,
		  Elf_Sym *symp)
{
    Elf_Hashelt symnum;
    Elf_Sym sym;
    char *strp;
    unsigned long hash;

    hash = elf_hash(name);
    COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum));

    while (symnum != STN_UNDEF) {
	if (symnum >= ef->nchains) {
	    printf(__elfN(bad_symtable));
	    return ENOENT;
	}

	COPYOUT(ef->symtab + symnum, &sym, sizeof(sym));
	if (sym.st_name == 0) {
	    printf(__elfN(bad_symtable));
	    return ENOENT;
	}

	strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
	if (strcmp(name, strp) == 0) {
	    free(strp);
	    if (sym.st_shndx != SHN_UNDEF ||
		(sym.st_value != 0 &&
		 ELF_ST_TYPE(sym.st_info) == STT_FUNC)) {
		*symp = sym;
		return 0;
	    }
	    return ENOENT;
	}
	free(strp);
	COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum));
    }
    return ENOENT;
}
Ejemplo n.º 8
0
static void
linux_vdso_install(void *param)
{

	linux_szsigcode = (&_binary_linux_locore_o_end - 
	    &_binary_linux_locore_o_start);

	if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
		panic("Linux invalid vdso size\n");

	__elfN(linux_vdso_fixup)(&elf_linux_sysvec);

	linux_shared_page_obj = __elfN(linux_shared_page_init)
	    (&linux_shared_page_mapping);

	__elfN(linux_vdso_reloc)(&elf_linux_sysvec, SHAREDPAGE);

	bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
	    linux_szsigcode);
	elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;

	linux_kplatform = linux_shared_page_mapping +
	    (linux_platform - (caddr_t)SHAREDPAGE);
}
Ejemplo n.º 9
0
int
ppc64_ofw_elf_loadfile(char *filename, u_int64_t dest,
    struct preloaded_file **result)
{
	int	r;

	r = __elfN(loadfile)(filename, dest, result);
	if (r != 0)
		return (r);

	/*
	 * No need to sync the icache for modules: this will
	 * be done by the kernel after relocation.
	 */
	if (!strcmp((*result)->f_type, "elf kernel"))
		__syncicache((void *) (*result)->f_addr, (*result)->f_size);
	return (0);
}
Ejemplo n.º 10
0
int
__elfN(uboot_load)(char *filename, u_int64_t dest,
    struct preloaded_file **result)
{
	int r;

	r = __elfN(loadfile)(filename, dest, result);
	if (r != 0)
		return (r);

#if defined(__powerpc__)
	/*
	 * No need to sync the icache for modules: this will
	 * be done by the kernel after relocation.
	 */
	if (!strcmp((*result)->f_type, "elf kernel"))
		__syncicache((void *) (*result)->f_addr, (*result)->f_size);
#endif
	return (0);
}
Ejemplo n.º 11
0
struct devsw *devsw[] = {
#ifdef LOADER_DISK_SUPPORT
	&ofwdisk,
#endif
#ifdef LOADER_NET_SUPPORT
	&netdev,
#endif
#ifdef LOADER_ZFS_SUPPORT
	&zfs_dev,
#endif
	0
};
struct arch_switch archsw;

static struct file_format sparc64_elf = {
	__elfN(loadfile),
	__elfN(exec)
};
struct file_format *file_formats[] = {
	&sparc64_elf,
	0
};

struct fs_ops *file_system[] = {
#ifdef LOADER_UFS_SUPPORT
	&ufs_fsops,
#endif
#ifdef LOADER_CD9660_SUPPORT
	&cd9660_fsops,
#endif
#ifdef LOADER_ZFS_SUPPORT
Ejemplo n.º 12
0
/*
 * Attempt to load the file (file) as an ELF module.  It will be stored at
 * (dest), and a pointer to a module structure describing the loaded object
 * will be saved in (result).
 */
int
__elfN(obj_loadfile)(char *filename, u_int64_t dest,
    struct preloaded_file **result)
{
	struct preloaded_file *fp, *kfp;
	struct elf_file	ef;
	Elf_Ehdr *hdr;
	int err;
	ssize_t bytes_read;

	fp = NULL;
	bzero(&ef, sizeof(struct elf_file));

	/*
	 * Open the image, read and validate the ELF header
	 */
	if (filename == NULL)	/* can't handle nameless */
		return(EFTYPE);
	if ((ef.fd = open(filename, O_RDONLY)) == -1)
		return(errno);

	hdr = &ef.hdr;
	bytes_read = read(ef.fd, hdr, sizeof(*hdr));
	if (bytes_read != sizeof(*hdr)) {
		err = EFTYPE;	/* could be EIO, but may be small file */
		goto oerr;
	}

	/* Is it ELF? */
	if (!IS_ELF(*hdr)) {
		err = EFTYPE;
		goto oerr;
	}
	if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	    hdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
	    hdr->e_version != EV_CURRENT ||
	    hdr->e_machine != ELF_TARG_MACH ||		/* Machine ? */
	    hdr->e_type != ET_REL) {
		err = EFTYPE;
		goto oerr;
	}

	if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 ||
	    hdr->e_shentsize != sizeof(Elf_Shdr)) {
		err = EFTYPE;
		goto oerr;
	}

	kfp = file_findfile(NULL, NULL);
	if (kfp == NULL) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: can't load module before kernel\n");
		err = EPERM;
		goto oerr;
	}
	if (strcmp(__elfN(obj_kerneltype), kfp->f_type)) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: can't load module with kernel type '%s'\n",
		    kfp->f_type);
		err = EPERM;
		goto oerr;
	}

	if (archsw.arch_loadaddr != NULL)
		dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
	else
		dest = roundup(dest, PAGE_SIZE);

	/*
	 * Ok, we think we should handle this.
	 */
	fp = file_alloc();
	if (fp == NULL) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadfile: cannot allocate module info\n");
		err = EPERM;
		goto out;
	}
	fp->f_name = strdup(filename);
	fp->f_type = strdup(__elfN(obj_moduletype));

	printf("%s ", filename);

	fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest);
	if (fp->f_size == 0 || fp->f_addr == 0)
		goto ioerr;

	/* save exec header as metadata */
	file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr);

	/* Load OK, return module pointer */
	*result = (struct preloaded_file *)fp;
	err = 0;
	goto out;

ioerr:
	err = EIO;
oerr:
	file_discard(fp);
out:
	close(ef.fd);
	if (ef.e_shdr != NULL)
		free(ef.e_shdr);

	return(err);
}
Ejemplo n.º 13
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
    int 	i;
    u_int	j;
    Elf_Ehdr	*ehdr;
    Elf_Phdr	*phdr, *php;
    Elf_Shdr	*shdr;
    int		ret;
    vm_offset_t firstaddr;
    vm_offset_t lastaddr;
    size_t	chunk;
    ssize_t	result;
    Elf_Addr	ssym, esym;
    Elf_Dyn	*dp;
    Elf_Addr	adp;
    int		ndp;
    int		symstrindex;
    int		symtabindex;
    Elf_Size	size;
    u_int	fpcopy;

    dp = NULL;
    shdr = NULL;
    ret = 0;
    firstaddr = lastaddr = 0;
    ehdr = ef->ehdr;
    if (ef->kernel) {
#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
	off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
#else
	off = - (off & 0xff000000u);	/* i386 relocates after locore */
#endif
#elif defined(__powerpc__)
	/*
	 * On the purely virtual memory machines like e500, the kernel is
	 * linked against its final VA range, which is most often not
	 * available at the loader stage, but only after kernel initializes
	 * and completes its VM settings. In such cases we cannot use p_vaddr
	 * field directly to load ELF segments, but put them at some
	 * 'load-time' locations.
	 */
	if (off & 0xf0000000u) {
	    off = -(off & 0xf0000000u);
	    /*
	     * XXX the physical load address should not be hardcoded. Note
	     * that the Book-E kernel assumes that it's loaded at a 16MB
	     * boundary for now...
	     */
	    off += 0x01000000;
	    ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	    printf("Converted entry 0x%08x\n", ehdr->e_entry);
#endif
	} else
	    off = 0;
#elif defined(__arm__)
	/*
	 * The elf headers in some kernels specify virtual addresses in all
	 * header fields.  More recently, the e_entry and p_paddr fields are the
	 * proper physical addresses.  Even when the p_paddr fields are correct,
	 * the MI code below uses the p_vaddr fields with an offset added for
	 * loading (doing so is arguably wrong).  To make loading work, we need
	 * an offset that represents the difference between physical and virtual
	 * addressing.  ARM kernels are always linked at 0xCnnnnnnn.  Depending
	 * on the headers, the offset value passed in may be physical or virtual
	 * (because it typically comes from e_entry), but we always replace
	 * whatever is passed in with the va<->pa offset.  On the other hand, we
	 * always remove the high-order part of the entry address whether it's
	 * physical or virtual, because it will be adjusted later for the actual
	 * physical entry point based on where the image gets loaded.
	 */
	off = -0xc0000000;
	ehdr->e_entry &= ~0xf0000000;
#ifdef ELF_VERBOSE
	printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off);
#endif
#else
	off = 0;		/* other archs use direct mapped kernels */
#endif
	__elfN(relocation_offset) = off;
    }
    ef->off = off;

    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
	printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
	goto out;
    }
    phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);

    for (i = 0; i < ehdr->e_phnum; i++) {
	/* We want to load PT_LOAD segments only.. */
	if (phdr[i].p_type != PT_LOAD)
	    continue;

#ifdef ELF_VERBOSE
	printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
	    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
	    (long)(phdr[i].p_vaddr + off),
	    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
#else
	if ((phdr[i].p_flags & PF_W) == 0) {
	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
	} else {
	    printf("data=0x%lx", (long)phdr[i].p_filesz);
	    if (phdr[i].p_filesz < phdr[i].p_memsz)
		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
	    printf(" ");
	}
#endif
	fpcopy = 0;
	if (ef->firstlen > phdr[i].p_offset) {
	    fpcopy = ef->firstlen - phdr[i].p_offset;
	    archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
			       phdr[i].p_vaddr + off, fpcopy);
	}
	if (phdr[i].p_filesz > fpcopy) {
	    if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy,
		phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_loadimage: read failed\n");
		goto out;
	    }
	}
	/* clear space from oversized segments; eg: bss */
	if (phdr[i].p_filesz < phdr[i].p_memsz) {
#ifdef ELF_VERBOSE
	    printf(" (bss: 0x%lx-0x%lx)",
		(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
#endif

	    kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz,
		phdr[i].p_memsz - phdr[i].p_filesz);
	}
#ifdef ELF_VERBOSE
	printf("\n");
#endif

	if (archsw.arch_loadseg != NULL)
	    archsw.arch_loadseg(ehdr, phdr + i, off);

	if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
	    firstaddr = phdr[i].p_vaddr + off;
	if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
	    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
    }
    lastaddr = roundup(lastaddr, sizeof(long));

    /*
     * Now grab the symbol tables.  This isn't easy if we're reading a
     * .gz file.  I think the rule is going to have to be that you must
     * strip a file to remove symbols before gzipping it so that we do not
     * try to lseek() on it.
     */
    chunk = ehdr->e_shnum * ehdr->e_shentsize;
    if (chunk == 0 || ehdr->e_shoff == 0)
	goto nosyms;
    shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
    if (shdr == NULL) {
	printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
	    "_loadimage: failed to read section headers");
	goto nosyms;
    }
    file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);

    symtabindex = -1;
    symstrindex = -1;
    for (i = 0; i < ehdr->e_shnum; i++) {
	if (shdr[i].sh_type != SHT_SYMTAB)
	    continue;
	for (j = 0; j < ehdr->e_phnum; j++) {
	    if (phdr[j].p_type != PT_LOAD)
		continue;
	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
		(shdr[i].sh_offset + shdr[i].sh_size <=
		 phdr[j].p_offset + phdr[j].p_filesz)) {
		shdr[i].sh_offset = 0;
		shdr[i].sh_size = 0;
		break;
	    }
	}
	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
	    continue;		/* alread loaded in a PT_LOAD above */
	/* Save it for loading below */
	symtabindex = i;
	symstrindex = shdr[i].sh_link;
    }
    if (symtabindex < 0 || symstrindex < 0)
	goto nosyms;

    /* Ok, committed to a load. */
#ifndef ELF_VERBOSE
    printf("syms=[");
#endif
    ssym = lastaddr;
    for (i = symtabindex; i >= 0; i = symstrindex) {
#ifdef ELF_VERBOSE
	char	*secname;

	switch(shdr[i].sh_type) {
	    case SHT_SYMTAB:		/* Symbol table */
		secname = "symtab";
		break;
	    case SHT_STRTAB:		/* String table */
		secname = "strtab";
		break;
	    default:
		secname = "WHOA!!";
		break;
	}
#endif

	size = shdr[i].sh_size;
	archsw.arch_copyin(&size, lastaddr, sizeof(size));
	lastaddr += sizeof(size);

#ifdef ELF_VERBOSE
	printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
	    (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
	    (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size));
#else
	if (i == symstrindex)
	    printf("+");
	printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
#endif

	if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
	if (result < 0 || (size_t)result != shdr[i].sh_size) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result,
		(uintmax_t)shdr[i].sh_size);
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	/* Reset offsets relative to ssym */
	lastaddr += shdr[i].sh_size;
	lastaddr = roundup(lastaddr, sizeof(size));
	if (i == symtabindex)
	    symtabindex = -1;
	else if (i == symstrindex)
	    symstrindex = -1;
    }
    esym = lastaddr;
#ifndef ELF_VERBOSE
    printf("]");
#endif

    file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
    file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);

nosyms:
    printf("\n");

    ret = lastaddr - firstaddr;
    fp->f_addr = firstaddr;

    php = NULL;
    for (i = 0; i < ehdr->e_phnum; i++) {
	if (phdr[i].p_type == PT_DYNAMIC) {
	    php = phdr + i;
	    adp = php->p_vaddr;
	    file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
	    break;
	}
    }

    if (php == NULL)	/* this is bad, we cannot get to symbols or _DYNAMIC */
	goto out;

    ndp = php->p_filesz / sizeof(Elf_Dyn);
    if (ndp == 0)
	goto out;
    dp = malloc(php->p_filesz);
    if (dp == NULL)
	goto out;
    archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);

    ef->strsz = 0;
    for (i = 0; i < ndp; i++) {
	if (dp[i].d_tag == 0)
	    break;
	switch (dp[i].d_tag) {
	case DT_HASH:
	    ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRTAB:
	    ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRSZ:
	    ef->strsz = dp[i].d_un.d_val;
	    break;
	case DT_SYMTAB:
	    ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_REL:
	    ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELSZ:
	    ef->relsz = dp[i].d_un.d_val;
	    break;
	case DT_RELA:
	    ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELASZ:
	    ef->relasz = dp[i].d_un.d_val;
	    break;
	default:
	    break;
	}
    }
    if (ef->hashtab == NULL || ef->symtab == NULL ||
	ef->strtab == NULL || ef->strsz == 0)
	goto out;
    COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
    COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
    ef->buckets = ef->hashtab + 2;
    ef->chains = ef->buckets + ef->nbuckets;
    if (__elfN(parse_modmetadata)(fp, ef) == 0)
	goto out;

    if (ef->kernel)			/* kernel must not depend on anything */
	goto out;

out:
    if (dp)
	free(dp);
    if (shdr)
	free(shdr);
    return ret;
}
Ejemplo n.º 14
0
int
__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
{
	struct mod_metadata md;
#if defined(__i386__) && __ELF_WORD_SIZE == 64
	struct mod_metadata64 md64;
#endif
	struct mod_depend *mdepend;
	struct mod_version mver;
	char *s;
	int error, modcnt, minfolen;
	Elf_Addr v, p, p_stop;

	if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
	    &modcnt) != 0)
		return 0;

	modcnt = 0;
	while (p < p_stop) {
		COPYOUT(p, &v, sizeof(v));
		error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v));
		if (error != 0)
			return (error);
#if defined(__i386__) && __ELF_WORD_SIZE == 64
		COPYOUT(v, &md64, sizeof(md64));
		error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
		if (error != 0)
			return (error);
		md.md_version = md64.md_version;
		md.md_type = md64.md_type;
		md.md_cval = (const char *)(uintptr_t)md64.md_cval;
		md.md_data = (void *)(uintptr_t)md64.md_data;
#else
		COPYOUT(v, &md, sizeof(md));
		error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md));
		if (error != 0)
			return (error);
#endif
		p += sizeof(Elf_Addr);
		switch(md.md_type) {
		case MDT_DEPEND:
			s = strdupout((vm_offset_t)md.md_cval);
			minfolen = sizeof(*mdepend) + strlen(s) + 1;
			mdepend = malloc(minfolen);
			if (mdepend == NULL)
				return ENOMEM;
			COPYOUT((vm_offset_t)md.md_data, mdepend,
			    sizeof(*mdepend));
			strcpy((char*)(mdepend + 1), s);
			free(s);
			file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
			    mdepend);
			free(mdepend);
			break;
		case MDT_VERSION:
			s = strdupout((vm_offset_t)md.md_cval);
			COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
			file_addmodule(fp, s, mver.mv_version, NULL);
			free(s);
			modcnt++;
			break;
		case MDT_MODULE:
			break;
		default:
			printf("unknown type %d\n", md.md_type);
			break;
		}
	}
	return 0;
}
Ejemplo n.º 15
0
/*
 * Attempt to load the file (file) as an ELF module.  It will be stored at
 * (dest), and a pointer to a module structure describing the loaded object
 * will be saved in (result).
 */
int
__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
{
    struct preloaded_file	*fp, *kfp;
    struct elf_file		ef;
    Elf_Ehdr 			*ehdr;
    int				err;
    ssize_t			bytes_read;

    fp = NULL;
    bzero(&ef, sizeof(struct elf_file));

    /*
     * Open the image, read and validate the ELF header 
     */
    if (filename == NULL)	/* can't handle nameless */
	return(EFTYPE);
    if ((ef.fd = open(filename, O_RDONLY)) == -1)
	return(errno);
    ef.firstpage = malloc(PAGE_SIZE);
    if (ef.firstpage == NULL) {
	close(ef.fd);
	return(ENOMEM);
    }
    bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE);
    ef.firstlen = (size_t)bytes_read;
    if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) {
	err = EFTYPE;		/* could be EIO, but may be small file */
	goto oerr;
    }
    ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;

    /* Is it ELF? */
    if (!IS_ELF(*ehdr)) {
	err = EFTYPE;
	goto oerr;
    }
    if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
	ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
	ehdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
	ehdr->e_version != EV_CURRENT ||
	ehdr->e_machine != ELF_TARG_MACH) {		/* Machine ? */
	err = EFTYPE;
	goto oerr;
    }


    /*
     * Check to see what sort of module we are.
     */
    kfp = file_findfile(NULL, NULL);
    if (ehdr->e_type == ET_DYN) {
	/* Looks like a kld module */
	if (kfp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
	    err = EPERM;
	    goto oerr;
	}
	if (strcmp(__elfN(kerneltype), kfp->f_type)) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
	    err = EPERM;
	    goto oerr;
	}
	/* Looks OK, got ahead */
	ef.kernel = 0;

    } else if (ehdr->e_type == ET_EXEC) {
	/* Looks like a kernel */
	if (kfp != NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
	    err = EPERM;
	    goto oerr;
	}
	/* 
	 * Calculate destination address based on kernel entrypoint 	
	 */
	dest = (ehdr->e_entry & ~PAGE_MASK);
	if (dest == 0) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
	    err = EPERM;
	    goto oerr;
	}
	ef.kernel = 1;

    } else {
	err = EFTYPE;
	goto oerr;
    }

    if (archsw.arch_loadaddr != NULL)
	dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest);
    else
	dest = roundup(dest, PAGE_SIZE);

    /* 
     * Ok, we think we should handle this.
     */
    fp = file_alloc();
    if (fp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
	    err = EPERM;
	    goto out;
    }
    if (ef.kernel)
	setenv("kernelname", filename, 1);
    fp->f_name = strdup(filename);
    fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype));

#ifdef ELF_VERBOSE
    if (ef.kernel)
	printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry);
#else
    printf("%s ", filename);
#endif

    fp->f_size = __elfN(loadimage)(fp, &ef, dest);
    if (fp->f_size == 0 || fp->f_addr == 0)
	goto ioerr;

    /* save exec header as metadata */
    file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);

    /* Load OK, return module pointer */
    *result = (struct preloaded_file *)fp;
    err = 0;
    goto out;
    
 ioerr:
    err = EIO;
 oerr:
    file_discard(fp);
 out:
    if (ef.firstpage)
	free(ef.firstpage);
    close(ef.fd);
    return(err);
}
Ejemplo n.º 16
0
int
__elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest)
{
	struct elf_file		 ef;
	int			 err, i, j;
	Elf_Shdr		*sh_meta, *shdr = NULL;
	Elf_Shdr		*sh_data[2];
	char			*shstrtab = NULL;
	size_t			 size;
	Elf_Addr		 p_start, p_end;

	bzero(&ef, sizeof(struct elf_file));
	ef.fd = -1;

	err = __elfN(load_elf_header)(fp->f_name, &ef);
	if (err != 0)
		goto out;

	if (ef.kernel == 1 || ef.ehdr->e_type == ET_EXEC) {
		ef.kernel = 1;
	} else if (ef.ehdr->e_type != ET_DYN) {
		err = EFTYPE;
		goto out;
	}

	size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize;
	shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size);
	if (shdr == NULL) {
		err = ENOMEM;
		goto out;
	}

	/* Load shstrtab. */
	shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset,
	    shdr[ef.ehdr->e_shstrndx].sh_size);
	if (shstrtab == NULL) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "load_modmetadata: unable to load shstrtab\n");
		err = EFTYPE;
		goto out;
	}

	/* Find set_modmetadata_set and data sections. */
	sh_data[0] = sh_data[1] = sh_meta = NULL;
	for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) {
		if (strcmp(&shstrtab[shdr[i].sh_name],
		    "set_modmetadata_set") == 0) {
			sh_meta = &shdr[i];
		}
		if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) ||
		    (strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) {
			sh_data[j++] = &shdr[i];
		}
	}
	if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
    "load_modmetadata: unable to find set_modmetadata_set or data sections\n");
		err = EFTYPE;
		goto out;
	}

	/* Load set_modmetadata_set into memory */
	err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset);
	if (err != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
    "load_modmetadata: unable to load set_modmetadata_set: %d\n", err);
		goto out;
	}
	p_start = dest;
	p_end = dest + sh_meta->sh_size;
	dest += sh_meta->sh_size;

	/* Load data sections into memory. */
	err = kern_pread(ef.fd, dest, sh_data[0]->sh_size,
	    sh_data[0]->sh_offset);
	if (err != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "load_modmetadata: unable to load data: %d\n", err);
		goto out;
	}

	/*
	 * We have to increment the dest, so that the offset is the same into
	 * both the .rodata and .data sections.
	 */
	ef.off = -(sh_data[0]->sh_addr - dest);
	dest +=	(sh_data[1]->sh_addr - sh_data[0]->sh_addr);

	err = kern_pread(ef.fd, dest, sh_data[1]->sh_size,
	    sh_data[1]->sh_offset);
	if (err != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "load_modmetadata: unable to load data: %d\n", err);
		goto out;
	}

	err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end);
	if (err != 0) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "load_modmetadata: unable to parse metadata: %d\n", err);
		goto out;
	}

out:
	if (shstrtab != NULL)
		free(shstrtab);
	if (shdr != NULL)
		free(shdr);
	if (ef.firstpage != NULL)
		free(ef.firstpage);
	if (ef.fd != -1)
		close(ef.fd);
	return (err);
}
Ejemplo n.º 17
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
	Elf_Ehdr *hdr;
	Elf_Shdr *shdr, *cshdr, *lshdr;
	vm_offset_t firstaddr, lastaddr;
	int i, nsym, res, ret, shdrbytes, symstrindex;

	ret = 0;
	firstaddr = lastaddr = (vm_offset_t)off;
	hdr = &ef->hdr;
	ef->off = (vm_offset_t)off;

	/* Read in the section headers. */
	shdrbytes = hdr->e_shnum * hdr->e_shentsize;
	shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes);
	if (shdr == NULL) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: read section headers failed\n");
		goto out;
	}
	ef->e_shdr = shdr;

	/*
	 * Decide where to load everything, but don't read it yet.
	 * We store the load address as a non-zero sh_addr value.
	 * Start with the code/data and bss.
	 */
	for (i = 0; i < hdr->e_shnum; i++)
		shdr[i].sh_addr = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_size == 0)
			continue;
		switch (shdr[i].sh_type) {
		case SHT_PROGBITS:
		case SHT_NOBITS:
			lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}

	/* Symbols. */
	nsym = 0;
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_SYMTAB:
			nsym++;
			ef->symtabindex = i;
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}
	if (nsym != 1) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has no valid symbol table\n");
		goto out;
	}
	lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign);
	shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[ef->symtabindex].sh_size;

	symstrindex = shdr[ef->symtabindex].sh_link;
	if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
	    shdr[symstrindex].sh_type != SHT_STRTAB) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has invalid symbol strings\n");
		goto out;
	}
	lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign);
	shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[symstrindex].sh_size;

	/* Section names. */
	if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
	    shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
		printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
		    "_obj_loadimage: file has no section names\n");
		goto out;
	}
	ef->shstrindex = hdr->e_shstrndx;
	lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign);
	shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr;
	lastaddr += shdr[ef->shstrindex].sh_size;

	/* Relocation tables. */
	for (i = 0; i < hdr->e_shnum; i++) {
		switch (shdr[i].sh_type) {
		case SHT_REL:
		case SHT_RELA:
			lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
			shdr[i].sh_addr = (Elf_Addr)lastaddr;
			lastaddr += shdr[i].sh_size;
			break;
		}
	}

	/* Clear the whole area, including bss regions. */
	kern_bzero(firstaddr, lastaddr - firstaddr);

	/* Figure section with the lowest file offset we haven't loaded yet. */
	for (cshdr = NULL; /* none */; /* none */)
	{
		/*
		 * Find next section to load. The complexity of this loop is
		 * O(n^2), but with  the number of sections being typically
		 * small, we do not care.
		 */
		lshdr = cshdr;

		for (i = 0; i < hdr->e_shnum; i++) {
			if (shdr[i].sh_addr == 0 ||
			    shdr[i].sh_type == SHT_NOBITS)
				continue;
			/* Skip sections that were loaded already. */
			if (lshdr != NULL &&
			    lshdr->sh_offset >= shdr[i].sh_offset)
				continue;
			/* Find section with smallest offset. */
			if (cshdr == lshdr ||
			    cshdr->sh_offset > shdr[i].sh_offset)
				cshdr = &shdr[i];
		}

		if (cshdr == lshdr)
			break;

		if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr,
		    cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_obj_loadimage: read failed\n");
			goto out;
		}
	}

	file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr);

	res = __elfN(obj_parse_modmetadata)(fp, ef);
	if (res != 0)
		goto out;

	ret = lastaddr - firstaddr;
	fp->f_addr = firstaddr;

	printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr);

out:
	printf("\n");
	return ret;
}
Ejemplo n.º 18
0
/*
 * Attempt to load the file (file) as an ELF module.  It will be stored at
 * (dest), and a pointer to a module structure describing the loaded object
 * will be saved in (result).
 */
int
__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
{
	return (__elfN(loadfile_raw)(filename, dest, result, 0));
}
Ejemplo n.º 19
0
static vm_offset_t
fdt_find_static_dtb()
{
	Elf_Ehdr *ehdr;
	Elf_Shdr *shdr;
	Elf_Sym sym;
	vm_offset_t strtab, symtab, fdt_start;
	uint64_t offs;
	struct preloaded_file *kfp;
	struct file_metadata *md;
	char *strp;
	int i, sym_count;

	debugf("fdt_find_static_dtb()\n");

	sym_count = symtab = strtab = 0;
	strp = NULL;

	offs = __elfN(relocation_offset);

	kfp = file_findfile(NULL, NULL);
	if (kfp == NULL)
		return (0);

	/* Locate the dynamic symbols and strtab. */
	md = file_findmetadata(kfp, MODINFOMD_ELFHDR);
	if (md == NULL)
		return (0);
	ehdr = (Elf_Ehdr *)md->md_data;

	md = file_findmetadata(kfp, MODINFOMD_SHDR);
	if (md == NULL)
		return (0);
	shdr = (Elf_Shdr *)md->md_data;

	for (i = 0; i < ehdr->e_shnum; ++i) {
		if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) {
			symtab = shdr[i].sh_addr + offs;
			sym_count = shdr[i].sh_size / sizeof(Elf_Sym);
		} else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) {
			strtab = shdr[i].sh_addr + offs;
		}
	}

	/*
	 * The most efficent way to find a symbol would be to calculate a
	 * hash, find proper bucket and chain, and thus find a symbol.
	 * However, that would involve code duplication (e.g. for hash
	 * function). So we're using simpler and a bit slower way: we're
	 * iterating through symbols, searching for the one which name is
	 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
	 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
	 * those which binding attribute is not STB_GLOBAL.
	 */
	fdt_start = 0;
	while (sym_count > 0 && fdt_start == 0) {
		COPYOUT(symtab, &sym, sizeof(sym));
		symtab += sizeof(sym);
		--sym_count;
		if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
		    ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
			continue;
		strp = strdupout(strtab + sym.st_name);
		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0)
			fdt_start = (vm_offset_t)sym.st_value + offs;
		free(strp);
	}
	return (fdt_start);
}
Ejemplo n.º 20
0
int
__elfN(loadfile_raw)(char *filename, u_int64_t dest,
    struct preloaded_file **result, int multiboot)
{
    struct preloaded_file	*fp, *kfp;
    struct elf_file		ef;
    Elf_Ehdr 			*ehdr;
    int				err;

    fp = NULL;
    bzero(&ef, sizeof(struct elf_file));
    ef.fd = -1;

    err = __elfN(load_elf_header)(filename, &ef);
    if (err != 0)
    	return (err);

    ehdr = ef.ehdr;

    /*
     * Check to see what sort of module we are.
     */
    kfp = file_findfile(NULL, __elfN(kerneltype));
#ifdef __powerpc__
    /*
     * Kernels can be ET_DYN, so just assume the first loaded object is the
     * kernel. This assumption will be checked later.
     */
    if (kfp == NULL)
        ef.kernel = 1;
#endif
    if (ef.kernel || ehdr->e_type == ET_EXEC) {
	/* Looks like a kernel */
	if (kfp != NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
	    err = EPERM;
	    goto oerr;
	}
	/* 
	 * Calculate destination address based on kernel entrypoint.
	 *
	 * For ARM, the destination address is independent of any values in the
	 * elf header (an ARM kernel can be loaded at any 2MB boundary), so we
	 * leave dest set to the value calculated by archsw.arch_loadaddr() and
	 * passed in to this function.
	 */
#ifndef __arm__
        if (ehdr->e_type == ET_EXEC)
	    dest = (ehdr->e_entry & ~PAGE_MASK);
#endif
	if ((ehdr->e_entry & ~PAGE_MASK) == 0) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
	    err = EPERM;
	    goto oerr;
	}
	ef.kernel = 1;

    } else if (ehdr->e_type == ET_DYN) {
	/* Looks like a kld module */
	if (multiboot != 0) {
		printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n");
		err = EPERM;
		goto oerr;
	}
	if (kfp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
	    err = EPERM;
	    goto oerr;
	}
	if (strcmp(__elfN(kerneltype), kfp->f_type)) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
	    err = EPERM;
	    goto oerr;
	}
	/* Looks OK, got ahead */
	ef.kernel = 0;

    } else {
	err = EFTYPE;
	goto oerr;
    }

    if (archsw.arch_loadaddr != NULL)
	dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest);
    else
	dest = roundup(dest, PAGE_SIZE);

    /* 
     * Ok, we think we should handle this.
     */
    fp = file_alloc();
    if (fp == NULL) {
	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
	    err = EPERM;
	    goto out;
    }
    if (ef.kernel == 1 && multiboot == 0)
	setenv("kernelname", filename, 1);
    fp->f_name = strdup(filename);
    if (multiboot == 0)
    	fp->f_type = strdup(ef.kernel ?
    	    __elfN(kerneltype) : __elfN(moduletype));
    else
    	fp->f_type = strdup("elf multiboot kernel");

#ifdef ELF_VERBOSE
    if (ef.kernel)
	printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry);
#else
    printf("%s ", filename);
#endif

    fp->f_size = __elfN(loadimage)(fp, &ef, dest);
    if (fp->f_size == 0 || fp->f_addr == 0)
	goto ioerr;

    /* save exec header as metadata */
    file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);

    /* Load OK, return module pointer */
    *result = (struct preloaded_file *)fp;
    err = 0;
    goto out;
    
 ioerr:
    err = EIO;
 oerr:
    file_discard(fp);
 out:
    if (ef.firstpage)
	free(ef.firstpage);
    if (ef.fd != -1)
    	close(ef.fd);
    return(err);
}
Ejemplo n.º 21
0
static vm_offset_t
fdt_find_static_dtb(void)
{
	Elf_Sym sym;
	vm_offset_t dyntab, esym;
	uint64_t offs;
	struct preloaded_file *kfp;
	struct file_metadata *md;
	Elf_Sym *symtab;
	Elf_Dyn *dyn;
	char *strtab, *strp;
	int i, sym_count;

	symtab = NULL;
	dyntab = esym = 0;
	strtab = strp = NULL;

	offs = __elfN(relocation_offset);

	kfp = file_findfile(NULL, NULL);
	if (kfp == NULL)
		return (0);

	md = file_findmetadata(kfp, MODINFOMD_ESYM);
	if (md == NULL)
		return (0);
	COPYOUT(md->md_data, &esym, sizeof(esym));

	md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
	if (md == NULL)
		return (0);
	COPYOUT(md->md_data, &dyntab, sizeof(dyntab));

	dyntab += offs;

	/* Locate STRTAB and DYNTAB */
	for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) {
		if (dyn->d_tag == DT_STRTAB) {
			strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs);
			continue;
		} else if (dyn->d_tag == DT_SYMTAB) {
			symtab = (Elf_Sym *)(uintptr_t)
			    (dyn->d_un.d_ptr + offs);
			continue;
		}
	}

	if (symtab == NULL || strtab == NULL) {
		/*
		 * No symtab? No strtab? That should not happen here,
		 * and should have been verified during __elfN(loadimage).
		 * This must be some kind of a bug.
		 */
		return (0);
	}

	sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym);

	/*
	 * The most efficent way to find a symbol would be to calculate a
	 * hash, find proper bucket and chain, and thus find a symbol.
	 * However, that would involve code duplication (e.g. for hash
	 * function). So we're using simpler and a bit slower way: we're
	 * iterating through symbols, searching for the one which name is
	 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
	 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
	 * those which binding attribute is not STB_GLOBAL.
	 */
	for (i = 0; i < sym_count; i++) {
		COPYOUT(symtab + i, &sym, sizeof(sym));
		if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
		    ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
			continue;

		strp = strdupout((vm_offset_t)(strtab + sym.st_name));
		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) {
			/* Found a match ! */
			free(strp);
			return ((vm_offset_t)(sym.st_value + offs));
		}
		free(strp);
	}
	return (0);
}
Ejemplo n.º 22
0
	struct file_metadata	*fmp;
	vm_offset_t		mdp;
	Elf_Ehdr		*e;
	int			error;
	intptr_t		entry;

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
		return(EFTYPE);
	}
	e = (Elf_Ehdr *)&fmp->md_data;
	entry = e->e_entry;

	if ((error = md_load(fp->f_args, &mdp)) != 0)
		return (error);

	printf("Kernel entry at 0x%lx ...\n", e->e_entry);

	dev_cleanup();
	ofw_release_heap();
	OF_chain((void *)reloc, end - (char *)reloc, (void *)entry,
	    (void *)mdp, sizeof(mdp));

	panic("exec returned");
}

struct file_format	ofw_elf =
{
	__elfN(ofw_loadfile),
	__elfN(ofw_exec)
};
Ejemplo n.º 23
0
    Elf_Brandnote *checknote, int32_t *osrel);
static vm_prot_t __elfN(trans_prot)(Elf_Word);
static Elf_Word __elfN(untrans_prot)(vm_prot_t);

SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(elf, __ELF_WORD_SIZE), CTLFLAG_RW, 0,
    "");

#ifdef COMPRESS_USER_CORES
static int compress_core(gzFile, char *, char *, unsigned int,
    struct thread * td);
#define CORE_BUF_SIZE	(16 * 1024)
#endif

int __elfN(fallback_brand) = -1;
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
    fallback_brand, CTLFLAG_RW, &__elfN(fallback_brand), 0,
    __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) " brand of last resort");
TUNABLE_INT("kern.elf" __XSTRING(__ELF_WORD_SIZE) ".fallback_brand",
    &__elfN(fallback_brand));

static int elf_legacy_coredump = 0;
SYSCTL_INT(_debug, OID_AUTO, __elfN(legacy_coredump), CTLFLAG_RW, 
    &elf_legacy_coredump, 0, "");

int __elfN(nxstack) =
#if defined(__amd64__) || defined(__powerpc64__) /* both 64 and 32 bit */
	1;
#else
	0;
#endif
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
Ejemplo n.º 24
0
int
__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef,
    Elf_Addr p_start, Elf_Addr p_end)
{
    struct mod_metadata md;
#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
    struct mod_metadata64 md64;
#elif defined(__amd64__) && __ELF_WORD_SIZE == 32
    struct mod_metadata32 md32;
#endif
    struct mod_depend *mdepend;
    struct mod_version mver;
    char *s;
    int error, modcnt, minfolen;
    Elf_Addr v, p;

    modcnt = 0;
    p = p_start;
    while (p < p_end) {
	COPYOUT(p, &v, sizeof(v));
	error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v));
	if (error == EOPNOTSUPP)
	    v += ef->off;
	else if (error != 0)
	    return (error);
#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
	COPYOUT(v, &md64, sizeof(md64));
	error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
	if (error == EOPNOTSUPP) {
	    md64.md_cval += ef->off;
	    md64.md_data += ef->off;
	} else if (error != 0)
	    return (error);
	md.md_version = md64.md_version;
	md.md_type = md64.md_type;
	md.md_cval = (const char *)(uintptr_t)md64.md_cval;
	md.md_data = (void *)(uintptr_t)md64.md_data;
#elif defined(__amd64__) && __ELF_WORD_SIZE == 32
	COPYOUT(v, &md32, sizeof(md32));
	error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof(md32));
	if (error == EOPNOTSUPP) {
	    md32.md_cval += ef->off;
	    md32.md_data += ef->off;
	} else if (error != 0)
	    return (error);
	md.md_version = md32.md_version;
	md.md_type = md32.md_type;
	md.md_cval = (const char *)(uintptr_t)md32.md_cval;
	md.md_data = (void *)(uintptr_t)md32.md_data;
#else
	COPYOUT(v, &md, sizeof(md));
	error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md));
	if (error == EOPNOTSUPP) {
	    md.md_cval += ef->off;
	    md.md_data = (void *)((uintptr_t)md.md_data + (uintptr_t)ef->off);
	} else if (error != 0)
	    return (error);
#endif
	p += sizeof(Elf_Addr);
	switch(md.md_type) {
	  case MDT_DEPEND:
	    if (ef->kernel)		/* kernel must not depend on anything */
	      break;
	    s = strdupout((vm_offset_t)md.md_cval);
	    minfolen = sizeof(*mdepend) + strlen(s) + 1;
	    mdepend = malloc(minfolen);
	    if (mdepend == NULL)
		return ENOMEM;
	    COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend));
	    strcpy((char*)(mdepend + 1), s);
	    free(s);
	    file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend);
	    free(mdepend);
	    break;
	  case MDT_VERSION:
	    s = strdupout((vm_offset_t)md.md_cval);
	    COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
	    file_addmodule(fp, s, mver.mv_version, NULL);
	    free(s);
	    modcnt++;
	    break;
	}
    }
    if (modcnt == 0) {
	s = fake_modname(fp->f_name);
	file_addmodule(fp, s, 1, NULL);
	free(s);
    }
    return 0;
}
Ejemplo n.º 25
0
}

int
__elfN(uboot_exec)(struct preloaded_file *fp)
{
	struct file_metadata *fmp;
	vm_offset_t mdp;
	Elf_Ehdr *e;
	int error;

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return (EFTYPE);

	e = (Elf_Ehdr *)&fmp->md_data;

	if ((error = md_load(fp->f_args, &mdp)) != 0)
		return (error);

	printf("Kernel entry at 0x%x ...\n", e->e_entry);

	dev_cleanup();

	(*(void (*)())e->e_entry)((void *)mdp);
	panic("exec returned");
}

struct file_format uboot_elf = {
	__elfN(uboot_load),
	__elfN(uboot_exec)
};
Ejemplo n.º 26
0
static void
linux_vdso_deinstall(void *param)
{

	__elfN(linux_shared_page_fini)(linux_shared_page_obj);
};
Ejemplo n.º 27
0
int read_header_elf(
  const char *exec_hdr,		/* executable header */
  vir_bytes *text_addr,		/* text virtual address */
  vir_bytes *text_filebytes,	/* text segment size (in the file) */
  vir_bytes *text_membytes,	/* text segment size (in memory) */
  vir_bytes *data_addr,		/* data virtual address */
  vir_bytes *data_filebytes,	/* data segment size (in the file) */
  vir_bytes *data_membytes,	/* data segment size (in memory) */
  phys_bytes *tot_bytes,	/* total size */
  vir_bytes *pc,		/* program entry point (initial PC) */
  off_t *text_offset,		/* file offset to text segment */
  off_t *data_offset		/* file offset to data segment */
)
{
  const Elf_Ehdr *hdr = NULL;
  const Elf_Phdr *phdr = NULL;
  unsigned long seg_filebytes, seg_membytes, seg_addr;
  int i = 0;

  assert(exec_hdr != NULL);

  *text_addr = *text_filebytes = *text_membytes = 0;
  *data_addr = *data_filebytes = *data_membytes = 0;
  *tot_bytes = *pc = *text_offset = *data_offset = 0;

  hdr = (const Elf_Ehdr *)exec_hdr;
  if (__elfN(check_header)(hdr) != OK || (hdr->e_type != ET_EXEC))
  {
     return ENOEXEC;
  }

  if ((hdr->e_phoff > PAGE_SIZE) ||
      (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
     return ENOEXEC;
  }

  phdr = (const Elf_Phdr *)(exec_hdr + hdr->e_phoff);
  if (!aligned(phdr, Elf_Addr)) {
     return ENOEXEC;
  }

#if ELF_DEBUG
  printf("Program header file offset (phoff): %d\n", hdr->e_phoff);
  printf("Section header file offset (shoff): %d\n", hdr->e_shoff);
  printf("Program header entry size (phentsize): %d\n", hdr->e_phentsize);
  printf("Program header entry num (phnum): %d\n", hdr->e_phnum);
  printf("Section header entry size (shentsize): %d\n", hdr->e_shentsize);
  printf("Section header entry num (shnum): %d\n", hdr->e_shnum);
  printf("Section name strings index (shstrndx): %d\n", hdr->e_shstrndx);
  printf("Entry Point: 0x%x\n", hdr->e_entry);
#endif

  for (i = 0; i < hdr->e_phnum; i++) {
      switch (phdr[i].p_type) {
      case PT_LOAD:
	  if (phdr[i].p_memsz == 0)
	      break;
	  seg_addr = phdr[i].p_vaddr;
	  seg_filebytes = phdr[i].p_filesz;
	  seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr -
				    trunc_page(phdr[i].p_vaddr));

	  if (hdr->e_entry >= phdr[i].p_vaddr &&
	      hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) {
	      *text_addr = seg_addr;
	      *text_filebytes = seg_filebytes;
	      *text_membytes = seg_membytes;
	      *pc = (vir_bytes)hdr->e_entry;
	      *text_offset = phdr[i].p_offset;
	  } else {
	      *data_addr = seg_addr;
	      *data_filebytes = seg_filebytes;
	      *data_membytes = seg_membytes;
	      *data_offset = phdr[i].p_offset;
	  }
	  break;
      default:
	  break;
      }
  }

  *tot_bytes = 0; /* Use default stack size */

#if ELF_DEBUG
  printf("Text addr:      0x%x\n", *text_addr);
  printf("Text filebytes: 0x%x\n", *text_filebytes);
  printf("Text membytes:  0x%x\n", *text_membytes);
  printf("Data addr:      0x%x\n", *data_addr);
  printf("Data filebyte:  0x%x\n", *data_filebytes);
  printf("Data membytes:  0x%x\n", *data_membytes);
  printf("Tot bytes:      0x%x\n", *tot_bytes);
  printf("PC:             0x%x\n", *pc);
  printf("Text offset:    0x%x\n", *text_offset);
  printf("Data offset:    0x%x\n", *data_offset);
#endif

  return OK;
}
Ejemplo n.º 28
0
/*
 * With the file (fd) open on the image, and (ehdr) containing
 * the Elf header, load the image at (off)
 */
static int
__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
{
    int 	i;
    u_int	j;
    Elf_Ehdr	*ehdr;
    Elf_Phdr	*phdr, *php;
    Elf_Shdr	*shdr;
    char	*shstr;
    int		ret;
    vm_offset_t firstaddr;
    vm_offset_t lastaddr;
    size_t	chunk;
    ssize_t	result;
    Elf_Addr	ssym, esym;
    Elf_Dyn	*dp;
    Elf_Addr	adp;
    Elf_Addr	ctors;
    int		ndp;
    int		symstrindex;
    int		symtabindex;
    Elf_Size	size;
    u_int	fpcopy;
    Elf_Sym	sym;
    Elf_Addr	p_start, p_end;

    dp = NULL;
    shdr = NULL;
    ret = 0;
    firstaddr = lastaddr = 0;
    ehdr = ef->ehdr;
    if (ehdr->e_type == ET_EXEC) {
#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
	off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
#else
	off = - (off & 0xff000000u);	/* i386 relocates after locore */
#endif
#elif defined(__powerpc__)
	/*
	 * On the purely virtual memory machines like e500, the kernel is
	 * linked against its final VA range, which is most often not
	 * available at the loader stage, but only after kernel initializes
	 * and completes its VM settings. In such cases we cannot use p_vaddr
	 * field directly to load ELF segments, but put them at some
	 * 'load-time' locations.
	 */
	if (off & 0xf0000000u) {
	    off = -(off & 0xf0000000u);
	    /*
	     * XXX the physical load address should not be hardcoded. Note
	     * that the Book-E kernel assumes that it's loaded at a 16MB
	     * boundary for now...
	     */
	    off += 0x01000000;
	    ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	    printf("Converted entry 0x%08x\n", ehdr->e_entry);
#endif
	} else
	    off = 0;
#elif defined(__arm__) && !defined(EFI)
	/*
	 * The elf headers in arm kernels specify virtual addresses in all
	 * header fields, even the ones that should be physical addresses.
	 * We assume the entry point is in the first page, and masking the page
	 * offset will leave us with the virtual address the kernel was linked
	 * at.  We subtract that from the load offset, making 'off' into the
	 * value which, when added to a virtual address in an elf header,
	 * translates it to a physical address.  We do the va->pa conversion on
	 * the entry point address in the header now, so that later we can
	 * launch the kernel by just jumping to that address.
	 *
	 * When booting from UEFI the copyin and copyout functions handle
	 * adjusting the location relative to the first virtual address.
	 * Because of this there is no need to adjust the offset or entry
	 * point address as these will both be handled by the efi code.
	 */
	off -= ehdr->e_entry & ~PAGE_MASK;
	ehdr->e_entry += off;
#ifdef ELF_VERBOSE
	printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off);
#endif
#else
	off = 0;		/* other archs use direct mapped kernels */
#endif
    }
    ef->off = off;

    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
	/* use entry address from header */
	fp->f_addr = ehdr->e_entry;
    }

    if (ef->kernel)
	__elfN(relocation_offset) = off;

    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
	printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
	goto out;
    }
    phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);

    for (i = 0; i < ehdr->e_phnum; i++) {
	/* We want to load PT_LOAD segments only.. */
	if (phdr[i].p_type != PT_LOAD)
	    continue;

#ifdef ELF_VERBOSE
	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
	    printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
		(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
		(long)(phdr[i].p_paddr + off),
		(long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1));
	} else {
	    printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
		(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
		(long)(phdr[i].p_vaddr + off),
		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
	}
#else
	if ((phdr[i].p_flags & PF_W) == 0) {
	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
	} else {
	    printf("data=0x%lx", (long)phdr[i].p_filesz);
	    if (phdr[i].p_filesz < phdr[i].p_memsz)
		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
	    printf(" ");
	}
#endif
	fpcopy = 0;
	if (ef->firstlen > phdr[i].p_offset) {
	    fpcopy = ef->firstlen - phdr[i].p_offset;
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
		    phdr[i].p_paddr + off, fpcopy);
	    } else {
		archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
		    phdr[i].p_vaddr + off, fpcopy);
	    }
	}
	if (phdr[i].p_filesz > fpcopy) {
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		if (kern_pread(ef->fd, phdr[i].p_paddr + off + fpcopy,
		    phdr[i].p_filesz - fpcopy,
		    phdr[i].p_offset + fpcopy) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_loadimage: read failed\n");
			goto out;
		}
	    } else {
		if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy,
		    phdr[i].p_filesz - fpcopy,
		    phdr[i].p_offset + fpcopy) != 0) {
			printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
			    "_loadimage: read failed\n");
			goto out;
		}
	    }
	}
	/* clear space from oversized segments; eg: bss */
	if (phdr[i].p_filesz < phdr[i].p_memsz) {
#ifdef ELF_VERBOSE
	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		printf(" (bss: 0x%lx-0x%lx)",
		    (long)(phdr[i].p_paddr + off + phdr[i].p_filesz),
		    (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1));
	    } else {
		printf(" (bss: 0x%lx-0x%lx)",
		    (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
		    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
	    }
#endif

	    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		kern_bzero(phdr[i].p_paddr + off + phdr[i].p_filesz,
		    phdr[i].p_memsz - phdr[i].p_filesz);
	    } else {
		kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz,
		    phdr[i].p_memsz - phdr[i].p_filesz);
	    }
	}
#ifdef ELF_VERBOSE
	printf("\n");
#endif

	if (archsw.arch_loadseg != NULL)
	    archsw.arch_loadseg(ehdr, phdr + i, off);

	if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) {
		if (firstaddr == 0 || firstaddr > (phdr[i].p_paddr + off))
		    firstaddr = phdr[i].p_paddr + off;
		if (lastaddr == 0 ||
		    lastaddr < (phdr[i].p_paddr + off + phdr[i].p_memsz))
		    lastaddr = phdr[i].p_paddr + off + phdr[i].p_memsz;
	} else {
		if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
		    firstaddr = phdr[i].p_vaddr + off;
		if (lastaddr == 0 ||
		    lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
		    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
	}
    }
    lastaddr = roundup(lastaddr, sizeof(long));

    /*
     * Get the section headers.  We need this for finding the .ctors
     * section as well as for loading any symbols.  Both may be hard
     * to do if reading from a .gz file as it involves seeking.  I
     * think the rule is going to have to be that you must strip a
     * file to remove symbols before gzipping it.
     */
    chunk = ehdr->e_shnum * ehdr->e_shentsize;
    if (chunk == 0 || ehdr->e_shoff == 0)
	goto nosyms;
    shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk);
    if (shdr == NULL) {
	printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
	    "_loadimage: failed to read section headers");
	goto nosyms;
    }
    file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);

    /*
     * Read the section string table and look for the .ctors section.
     * We need to tell the kernel where it is so that it can call the
     * ctors.
     */
    chunk = shdr[ehdr->e_shstrndx].sh_size;
    if (chunk) {
	shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset, chunk);
	if (shstr) {
	    for (i = 0; i < ehdr->e_shnum; i++) {
		if (strcmp(shstr + shdr[i].sh_name, ".ctors") != 0)
		    continue;
		ctors = shdr[i].sh_addr;
		file_addmetadata(fp, MODINFOMD_CTORS_ADDR, sizeof(ctors),
		    &ctors);
		size = shdr[i].sh_size;
		file_addmetadata(fp, MODINFOMD_CTORS_SIZE, sizeof(size),
		    &size);
		break;
	    }
	    free(shstr);
	}
    }

    /*
     * Now load any symbols.
     */
    symtabindex = -1;
    symstrindex = -1;
    for (i = 0; i < ehdr->e_shnum; i++) {
	if (shdr[i].sh_type != SHT_SYMTAB)
	    continue;
	for (j = 0; j < ehdr->e_phnum; j++) {
	    if (phdr[j].p_type != PT_LOAD)
		continue;
	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
		(shdr[i].sh_offset + shdr[i].sh_size <=
		 phdr[j].p_offset + phdr[j].p_filesz)) {
		shdr[i].sh_offset = 0;
		shdr[i].sh_size = 0;
		break;
	    }
	}
	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
	    continue;		/* alread loaded in a PT_LOAD above */
	/* Save it for loading below */
	symtabindex = i;
	symstrindex = shdr[i].sh_link;
    }
    if (symtabindex < 0 || symstrindex < 0)
	goto nosyms;

    /* Ok, committed to a load. */
#ifndef ELF_VERBOSE
    printf("syms=[");
#endif
    ssym = lastaddr;
    for (i = symtabindex; i >= 0; i = symstrindex) {
#ifdef ELF_VERBOSE
	char	*secname;

	switch(shdr[i].sh_type) {
	    case SHT_SYMTAB:		/* Symbol table */
		secname = "symtab";
		break;
	    case SHT_STRTAB:		/* String table */
		secname = "strtab";
		break;
	    default:
		secname = "WHOA!!";
		break;
	}
#endif

	size = shdr[i].sh_size;
	archsw.arch_copyin(&size, lastaddr, sizeof(size));
	lastaddr += sizeof(size);

#ifdef ELF_VERBOSE
	printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname,
	    (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset,
	    (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size));
#else
	if (i == symstrindex)
	    printf("+");
	printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
#endif

	if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
	if (result < 0 || (size_t)result != shdr[i].sh_size) {
	    printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result,
		(uintmax_t)shdr[i].sh_size);
	    lastaddr = ssym;
	    ssym = 0;
	    goto nosyms;
	}
	/* Reset offsets relative to ssym */
	lastaddr += shdr[i].sh_size;
	lastaddr = roundup(lastaddr, sizeof(size));
	if (i == symtabindex)
	    symtabindex = -1;
	else if (i == symstrindex)
	    symstrindex = -1;
    }
    esym = lastaddr;
#ifndef ELF_VERBOSE
    printf("]");
#endif

    file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
    file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);

nosyms:
    printf("\n");

    ret = lastaddr - firstaddr;
    if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS)
	fp->f_addr = firstaddr;

    php = NULL;
    for (i = 0; i < ehdr->e_phnum; i++) {
	if (phdr[i].p_type == PT_DYNAMIC) {
	    php = phdr + i;
	    adp = php->p_vaddr;
	    file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
	    break;
	}
    }

    if (php == NULL)	/* this is bad, we cannot get to symbols or _DYNAMIC */
	goto out;

    ndp = php->p_filesz / sizeof(Elf_Dyn);
    if (ndp == 0)
	goto out;
    dp = malloc(php->p_filesz);
    if (dp == NULL)
	goto out;
    if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
	archsw.arch_copyout(php->p_paddr + off, dp, php->p_filesz);
    else
	archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);

    ef->strsz = 0;
    for (i = 0; i < ndp; i++) {
	if (dp[i].d_tag == 0)
	    break;
	switch (dp[i].d_tag) {
	case DT_HASH:
	    ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRTAB:
	    ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_STRSZ:
	    ef->strsz = dp[i].d_un.d_val;
	    break;
	case DT_SYMTAB:
	    ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_REL:
	    ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELSZ:
	    ef->relsz = dp[i].d_un.d_val;
	    break;
	case DT_RELA:
	    ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
	    break;
	case DT_RELASZ:
	    ef->relasz = dp[i].d_un.d_val;
	    break;
	default:
	    break;
	}
    }
    if (ef->hashtab == NULL || ef->symtab == NULL ||
	ef->strtab == NULL || ef->strsz == 0)
	goto out;
    COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
    COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
    ef->buckets = ef->hashtab + 2;
    ef->chains = ef->buckets + ef->nbuckets;

    if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
	return 0;
    p_start = sym.st_value + ef->off;
    if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
	return ENOENT;
    p_end = sym.st_value + ef->off;

    if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0)
	goto out;

    if (ef->kernel)			/* kernel must not depend on anything */
	goto out;

out:
    if (dp)
	free(dp);
    if (shdr)
	free(shdr);
    return ret;
}
Ejemplo n.º 29
0
#include <vm/vm_param.h>

#include <machine/acle-compat.h>
#include <machine/elf.h>
#include <machine/md_var.h>

static boolean_t elf32_arm_abi_supported(struct image_params *);

struct sysentvec elf32_freebsd_sysvec = {
	.sv_size	= SYS_MAXSYSCALL,
	.sv_table	= sysent,
	.sv_mask	= 0,
	.sv_errsize	= 0,
	.sv_errtbl	= NULL,
	.sv_transtrap	= NULL,
	.sv_fixup	= __elfN(freebsd_fixup),
	.sv_sendsig	= sendsig,
	.sv_sigcode	= sigcode,
	.sv_szsigcode	= &szsigcode,
	.sv_name	= "FreeBSD ELF32",
	.sv_coredump	= __elfN(coredump),
	.sv_imgact_try	= NULL,
	.sv_minsigstksz	= MINSIGSTKSZ,
	.sv_pagesize	= PAGE_SIZE,
	.sv_minuser	= VM_MIN_ADDRESS,
	.sv_maxuser	= VM_MAXUSER_ADDRESS,
	.sv_usrstack	= USRSTACK,
	.sv_psstrings	= PS_STRINGS,
	.sv_stackprot	= VM_PROT_ALL,
	.sv_copyout_strings = exec_copyout_strings,
	.sv_setregs	= exec_setregs,
Ejemplo n.º 30
0
		    u_long);

extern const char *cheriabi_syscallnames[];

struct sysentvec elf_freebsd_cheriabi_sysvec = {
	.sv_size	= CHERIABI_SYS_MAXSYSCALL,
	.sv_table	= cheriabi_sysent,
	.sv_mask	= 0,
	.sv_errsize	= 0,
	.sv_errtbl	= NULL,
	.sv_fixup	= cheriabi_elf_fixup,
	.sv_sendsig	= cheriabi_sendsig,
	.sv_sigcode	= cheri_sigcode,
	.sv_szsigcode	= &szcheri_sigcode,
	.sv_name	= "FreeBSD-CHERI ELF64",
	.sv_coredump	= __elfN(coredump),
	.sv_imgact_try	= NULL,
	.sv_minsigstksz	= MINSIGSTKSZ,	/* XXXBD: or something bigger? */
	.sv_pagesize	= PAGE_SIZE,
	.sv_minuser	= VM_MIN_ADDRESS,
	.sv_maxuser	= VM_MAXUSER_ADDRESS,
	.sv_usrstack	= USRSTACK,
	.sv_psstrings	= CHERIABI_PS_STRINGS,
	.sv_stackprot	= VM_PROT_ALL,
	.sv_copyout_strings = cheriabi_copyout_strings,
	.sv_setregs	= cheriabi_exec_setregs,
	.sv_fixlimit	= NULL,
	.sv_maxssiz	= NULL,
	.sv_flags	= SV_ABI_FREEBSD | SV_LP64 | SV_CHERI,
	.sv_set_syscall_retval = cheriabi_set_syscall_retval,
	.sv_fetch_syscall_args = cheriabi_fetch_syscall_args,