Example #1
0
static int
__elfN(obj_lookup_set)(struct preloaded_file *fp, elf_file_t ef,
    const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp)
{
	Elf_Ehdr *hdr;
	Elf_Shdr *shdr;
	char *p;
	vm_offset_t shstrtab;
	int i;

	hdr = &ef->hdr;
	shdr = ef->e_shdr;
	shstrtab = shdr[ef->shstrindex].sh_addr;

	for (i = 0; i < hdr->e_shnum; i++) {
		if (shdr[i].sh_type != SHT_PROGBITS)
			continue;
		if (shdr[i].sh_name == 0)
			continue;
		p = strdupout(shstrtab + shdr[i].sh_name);
		if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) {
			*startp = shdr[i].sh_addr;
			*stopp = shdr[i].sh_addr +  shdr[i].sh_size;
			*countp = (*stopp - *startp) / sizeof(Elf_Addr);
			free(p);
			return (0);
		}
		free(p);
	}

	return (ESRCH);
}
Example #2
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;
}
Example #3
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;
}
Example #4
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);
}
Example #5
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;
}
Example #6
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);
}