Beispiel #1
0
dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
#endif
{
	char fname[MAXPATHLEN];
	struct stat64 st;
	int fd, err, bits;

	dt_module_t *dmp;
	const char *s;
	size_t shstrs;
	GElf_Shdr sh;
	Elf_Data *dp;
	Elf_Scn *sp;

#if defined(sun)
	(void) snprintf(fname, sizeof (fname),
	    "%s/%s/object", OBJFS_ROOT, name);
#else
	GElf_Ehdr ehdr;
	GElf_Phdr ph;
	char name[MAXPATHLEN];
	uintptr_t mapbase, alignmask;
	int i = 0;
	int is_elf_obj;

	(void) strlcpy(name, k_stat->name, sizeof(name));
	(void) strlcpy(fname, k_stat->pathname, sizeof(fname));
#endif

	if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
	    (dmp = dt_module_create(dtp, name)) == NULL) {
		dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
		(void) close(fd);
		return;
	}

	/*
	 * Since the module can unload out from under us (and /system/object
	 * will return ENOENT), tell libelf to cook the entire file now and
	 * then close the underlying file descriptor immediately.  If this
	 * succeeds, we know that we can continue safely using dmp->dm_elf.
	 */
	dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL);
	err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
	(void) close(fd);

	if (dmp->dm_elf == NULL || err == -1 ||
	    elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
		dt_dprintf("failed to load %s: %s\n",
		    fname, elf_errmsg(elf_errno()));
		dt_module_destroy(dtp, dmp);
		return;
	}

	switch (gelf_getclass(dmp->dm_elf)) {
	case ELFCLASS32:
		dmp->dm_ops = &dt_modops_32;
		bits = 32;
		break;
	case ELFCLASS64:
		dmp->dm_ops = &dt_modops_64;
		bits = 64;
		break;
	default:
		dt_dprintf("failed to load %s: unknown ELF class\n", fname);
		dt_module_destroy(dtp, dmp);
		return;
	}
#if defined(__FreeBSD__)
	mapbase = (uintptr_t)k_stat->address;
	gelf_getehdr(dmp->dm_elf, &ehdr);
	is_elf_obj = (ehdr.e_type == ET_REL);
	if (is_elf_obj) {
		dmp->dm_sec_offsets =
		    malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets));
		if (dmp->dm_sec_offsets == NULL) {
			dt_dprintf("failed to allocate memory\n");
			dt_module_destroy(dtp, dmp);
			return;
		}
	}
#endif
	/*
	 * Iterate over the section headers locating various sections of
	 * interest and use their attributes to flesh out the dt_module_t.
	 */
	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
			continue; /* skip any malformed sections */
#if defined(__FreeBSD__)
		if (sh.sh_size == 0)
			continue;
		if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
			alignmask = sh.sh_addralign - 1;
			mapbase += alignmask;
			mapbase &= ~alignmask;
			sh.sh_addr = mapbase;
			if (is_elf_obj)
				dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
			mapbase += sh.sh_size;
		}
#endif
		if (strcmp(s, ".text") == 0) {
			dmp->dm_text_size = sh.sh_size;
			dmp->dm_text_va = sh.sh_addr;
		} else if (strcmp(s, ".data") == 0) {
			dmp->dm_data_size = sh.sh_size;
			dmp->dm_data_va = sh.sh_addr;
		} else if (strcmp(s, ".bss") == 0) {
			dmp->dm_bss_size = sh.sh_size;
			dmp->dm_bss_va = sh.sh_addr;
		} else if (strcmp(s, ".info") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			bcopy(dp->d_buf, &dmp->dm_info,
			    MIN(sh.sh_size, sizeof (dmp->dm_info)));
		} else if (strcmp(s, ".filename") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			(void) strlcpy(dmp->dm_file,
			    dp->d_buf, sizeof (dmp->dm_file));
		}
	}

	dmp->dm_flags |= DT_DM_KERNEL;
#if defined(sun)
	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
#else
	/*
	 * Include .rodata and special sections into .text.
	 * This depends on default section layout produced by GNU ld
	 * for ELF objects and libraries:
	 * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable]
	 */
	dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va;
#if defined(__i386__)
	/*
	 * Find the first load section and figure out the relocation
	 * offset for the symbols. The kernel module will not need
	 * relocation, but the kernel linker modules will.
	 */
	for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) {
		if (ph.p_type == PT_LOAD) {
			dmp->dm_reloc_offset = k_stat->address - ph.p_vaddr;
			break;
		}
	}
#endif
#endif

	if (dmp->dm_info.objfs_info_primary)
		dmp->dm_flags |= DT_DM_PRIMARY;

	dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
	    bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
}
Beispiel #2
0
/*
 * Update our module cache by adding an entry for the specified module 'name'.
 * We create the dt_module_t and populate it using /system/object/<name>/.
 */
static void
dt_module_update(dtrace_hdl_t *dtp, const char *name)
{
	char fname[MAXPATHLEN];
	struct stat64 st;
	int fd, err, bits;

	dt_module_t *dmp;
	const char *s;
	size_t shstrs;
	GElf_Shdr sh;
	Elf_Data *dp;
	Elf_Scn *sp;

	unsigned read_cmd = ELF_C_READ;

	if (0 == strcmp("mach_kernel", name)) {
		if (dtrace_kernel_path(fname, sizeof(fname)) != 0) {
			dt_dprintf("failed to retrieve the kernel binary, the module cache will not be updated\n");
			return;
		}

		read_cmd = ELF_C_RDKERNTYPE;
	}

	if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
	    (dmp = dt_module_create(dtp, name)) == NULL) {
		dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
		(void) close(fd);
		return;
	}

	/*
	 * Since the module can unload out from under us (and /system/object
	 * will return ENOENT), tell libelf to cook the entire file now and
	 * then close the underlying file descriptor immediately.  If this
	 * succeeds, we know that we can continue safely using dmp->dm_elf.
	 */
	dmp->dm_elf = elf_begin(fd, read_cmd, NULL);
	err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
	(void) close(fd);

	if (dmp->dm_elf == NULL || err == -1 ||
	    elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) {
		dt_dprintf("failed to load %s: %s\n",
		    fname, elf_errmsg(elf_errno()));
		dt_module_destroy(dtp, dmp);
		return;
	}

	switch (gelf_getclass(dmp->dm_elf)) {
	case ELFCLASS32:
		dmp->dm_ops = (dmp->dm_elf->ed_kind == ELF_K_MACHO ? &dt_modops_macho_32 : &dt_modops_32);
		bits = 32;
		break;
	case ELFCLASS64:
		dmp->dm_ops = (dmp->dm_elf->ed_kind == ELF_K_MACHO ? &dt_modops_macho_64 : &dt_modops_64);
		bits = 64;
		break;
	default:
		dt_dprintf("failed to load %s: unknown ELF class\n", fname);
		dt_module_destroy(dtp, dmp);
		return;
	}

	/*
	 * Iterate over the section headers locating various sections of
	 * interest and use their attributes to flesh out the dt_module_t.
	 */
	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
			continue; /* skip any malformed sections */

		if (strcmp(s, ".text") == 0) {
			dmp->dm_text_size = sh.sh_size;
			dmp->dm_text_va = sh.sh_addr;
		} else if (strcmp(s, ".data") == 0) {
			dmp->dm_data_size = sh.sh_size;
			dmp->dm_data_va = sh.sh_addr;
		} else if (strcmp(s, ".bss") == 0) {
			dmp->dm_bss_size = sh.sh_size;
			dmp->dm_bss_va = sh.sh_addr;
		} else if (strcmp(s, ".info") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			bcopy(dp->d_buf, &dmp->dm_info,
			    MIN(sh.sh_size, sizeof (dmp->dm_info)));
		} else if (strcmp(s, ".filename") == 0 &&
		    (dp = elf_getdata(sp, NULL)) != NULL) {
			(void) strlcpy(dmp->dm_file,
			    dp->d_buf, sizeof (dmp->dm_file));
		}
	}

	dmp->dm_flags |= DT_DM_KERNEL;
	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);

	if (dmp->dm_info.objfs_info_primary)
		dmp->dm_flags |= DT_DM_PRIMARY;

	dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
	    bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
}