Пример #1
0
void
dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
	dt_module_t **dmpp = &dtp->dt_mods[h];

	dt_list_delete(&dtp->dt_modlist, dmp);
	assert(dtp->dt_nmods != 0);
	dtp->dt_nmods--;

	/*
	 * Now remove this module from its hash chain.  We expect to always
	 * find the module on its hash chain, so in this loop we assert that
	 * we don't run off the end of the list.
	 */
	while (*dmpp != dmp) {
		dmpp = &((*dmpp)->dm_next);
		assert(*dmpp != NULL);
	}

	*dmpp = dmp->dm_next;

	dt_module_unload(dtp, dmp);
	free(dmp);
}
Пример #2
0
void
dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	dt_list_delete(&dtp->dt_modlist, dmp);
	assert(dtp->dt_nmods != 0);
	dtp->dt_nmods--;

	dt_module_unload(dtp, dmp);
	free(dmp);
}
Пример #3
0
/*
 * Unload all the loaded modules and then refresh the module cache with the
 * latest list of loaded modules and their address ranges.
 */
void
dtrace_update(dtrace_hdl_t *dtp)
{
	dt_module_t *dmp;
	DIR *dirp;

	for (dmp = dt_list_next(&dtp->dt_modlist);
	    dmp != NULL; dmp = dt_list_next(dmp))
		dt_module_unload(dtp, dmp);

	if (!(dtp->dt_oflags & DTRACE_O_NOSYS)) {
		dt_module_update(dtp, "mach_kernel");
	}

	/*
	 * Look up all the macro identifiers and set di_id to the latest value.
	 * This code collaborates with dt_lex.l on the use of di_id.  We will
	 * need to implement something fancier if we need to support non-ints.
	 */
	dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
	dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
	dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
	dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
	dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
	dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
	dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
	dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
	dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
	dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();

	/*
	 * Cache the pointers to the modules representing the base executable
	 * and the run-time linker in the dtrace client handle. Note that on
	 * x86 krtld is folded into unix, so if we don't find it, use unix
	 * instead.
	 */
	dtp->dt_exec = dt_module_lookup_by_name(dtp, "mach_kernel");
	dtp->dt_rtld = dt_module_lookup_by_name(dtp, "dyld"); /* XXX to what purpose? */

	/*
	 * If this is the first time we are initializing the module list,
	 * remove the module for genunix from the module list and then move it
	 * to the front of the module list.  We do this so that type and symbol
	 * queries encounter genunix and thereby optimize for the common case
	 * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
	 */
	if (dtp->dt_exec != NULL &&
	    dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
		dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
		dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
	}
}
Пример #4
0
int
dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	if (dmp->dm_flags & DT_DM_LOADED)
		return (0); /* module is already loaded */

	if (dmp->dm_pid != 0)
		return (dt_module_load_proc(dtp, dmp));

	dmp->dm_ctdata.cts_name = ".SUNW_ctf";
	dmp->dm_ctdata.cts_type = SHT_PROGBITS;
	dmp->dm_ctdata.cts_flags = 0;
	dmp->dm_ctdata.cts_data = NULL;
	dmp->dm_ctdata.cts_size = 0;
	dmp->dm_ctdata.cts_entsize = 0;
	dmp->dm_ctdata.cts_offset = 0;

	dmp->dm_symtab.cts_name = ".symtab";
	dmp->dm_symtab.cts_type = SHT_SYMTAB;
	dmp->dm_symtab.cts_flags = 0;
	dmp->dm_symtab.cts_data = NULL;
	dmp->dm_symtab.cts_size = 0;
	dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ?
	    sizeof (Elf64_Sym) : sizeof (Elf32_Sym);
	dmp->dm_symtab.cts_offset = 0;

	dmp->dm_strtab.cts_name = ".strtab";
	dmp->dm_strtab.cts_type = SHT_STRTAB;
	dmp->dm_strtab.cts_flags = 0;
	dmp->dm_strtab.cts_data = NULL;
	dmp->dm_strtab.cts_size = 0;
	dmp->dm_strtab.cts_entsize = 0;
	dmp->dm_strtab.cts_offset = 0;

	/*
	 * Attempt to load the module's CTF section, symbol table section, and
	 * string table section.  Note that modules may not contain CTF data:
	 * this will result in a successful load_sect but data of size zero.
	 * We will then fail if dt_module_getctf() is called, as shown below.
	 */
	if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 ||
	    dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
	    dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
		dt_module_unload(dtp, dmp);
		return (-1); /* dt_errno is set for us */
	}

	/*
	 * Allocate the hash chains and hash buckets for symbol name lookup.
	 * This is relatively simple since the symbol table is of fixed size
	 * and is known in advance.  We allocate one extra element since we
	 * use element indices instead of pointers and zero is our sentinel.
	 */
	dmp->dm_nsymelems =
	    dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize;

	dmp->dm_nsymbuckets = _dtrace_strbuckets;
	dmp->dm_symfree = 1;		/* first free element is index 1 */

	dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets);
	dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);

	if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
		dt_module_unload(dtp, dmp);
		return (dt_set_errno(dtp, EDT_NOMEM));
	}

	bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets);
	bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);

	/*
	 * Iterate over the symbol table data buffer and insert each symbol
	 * name into the name hash if the name and type are valid.  Then
	 * allocate the address map, fill it in, and sort it.
	 */
	dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp);

	dt_dprintf("hashed %s [%s] (%u symbols)\n",
	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1);

	if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) {
		dt_module_unload(dtp, dmp);
		return (dt_set_errno(dtp, EDT_NOMEM));
	}

	dmp->dm_ops->do_symsort(dmp);

	dt_dprintf("sorted %s [%s] (%u symbols)\n",
	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen);

	dmp->dm_flags |= DT_DM_LOADED;
	return (0);
}
Пример #5
0
/*
 * We've been asked to load data that belongs to another process. As such we're
 * going to pgrab it at this instant, load everything that we might ever care
 * about, and then drive on. The reason for this is that the process that we're
 * interested in might be changing. As long as we have grabbed it, then this
 * can't be a problem for us.
 *
 * For now, we're actually going to punt on most things and just try to get CTF
 * data, nothing else. Basically this is only useful as a source of type
 * information, we can't go and do the stacktrace lookups, etc.
 */
static int
dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	struct ps_prochandle *p;
	dt_module_cb_arg_t arg;

	/*
	 * Note that on success we do not release this hold. We must hold this
	 * for our life time.
	 */
	p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
	if (p == NULL) {
		dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid);
		return (dt_set_errno(dtp, EDT_CANTLOAD));
	}
	dt_proc_lock(dtp, p);

	arg.dpa_proc = p;
	arg.dpa_dtp = dtp;
	arg.dpa_dmp = dmp;
	arg.dpa_count = 0;
	if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) {
		dt_dprintf("failed to iterate objects\n");
		dt_proc_release(dtp, p);
		return (dt_set_errno(dtp, EDT_CANTLOAD));
	}

	if (arg.dpa_count == 0) {
		dt_dprintf("no ctf data present\n");
		dt_proc_unlock(dtp, p);
		dt_proc_release(dtp, p);
		return (dt_set_errno(dtp, EDT_CANTLOAD));
	}

	dmp->dm_libctfp = malloc(sizeof (ctf_file_t *) * arg.dpa_count);
	if (dmp->dm_libctfp == NULL) {
		dt_proc_unlock(dtp, p);
		dt_proc_release(dtp, p);
		return (dt_set_errno(dtp, EDT_NOMEM));
	}
	bzero(dmp->dm_libctfp, sizeof (ctf_file_t *) * arg.dpa_count);

	dmp->dm_libctfn = malloc(sizeof (char *) * arg.dpa_count);
	if (dmp->dm_libctfn == NULL) {
		free(dmp->dm_libctfp);
		dt_proc_unlock(dtp, p);
		dt_proc_release(dtp, p);
		return (dt_set_errno(dtp, EDT_NOMEM));
	}
	bzero(dmp->dm_libctfn, sizeof (char *) * arg.dpa_count);

	dmp->dm_nctflibs = arg.dpa_count;

	arg.dpa_count = 0;
	if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) {
		dt_proc_unlock(dtp, p);
		dt_module_unload(dtp, dmp);
		dt_proc_release(dtp, p);
		return (dt_set_errno(dtp, EDT_CANTLOAD));
	}
	assert(arg.dpa_count == dmp->dm_nctflibs);
	dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count,
	    (int)dmp->dm_pid);

	dt_proc_unlock(dtp, p);
	dt_proc_release(dtp, p);
	dmp->dm_flags |= DT_DM_LOADED;

	return (0);
}
Пример #6
0
/*
 * Unload all the loaded modules and then refresh the module cache with the
 * latest list of loaded modules and their address ranges.
 */
void
dtrace_update(dtrace_hdl_t *dtp)
{
	dt_module_t *dmp;
	DIR *dirp;
#if defined(__FreeBSD__)
	int fileid;
#endif

	for (dmp = dt_list_next(&dtp->dt_modlist);
	    dmp != NULL; dmp = dt_list_next(dmp))
		dt_module_unload(dtp, dmp);

#if defined(sun)
	/*
	 * Open /system/object and attempt to create a libdtrace module for
	 * each kernel module that is loaded on the current system.
	 */
	if (!(dtp->dt_oflags & DTRACE_O_NOSYS) &&
	    (dirp = opendir(OBJFS_ROOT)) != NULL) {
		struct dirent *dp;

		while ((dp = readdir(dirp)) != NULL) {
			if (dp->d_name[0] != '.')
				dt_module_update(dtp, dp->d_name);
		}

		(void) closedir(dirp);
	}
#elif defined(__FreeBSD__)
	/*
	 * Use FreeBSD's kernel loader interface to discover what kernel
	 * modules are loaded and create a libdtrace module for each one.
	 */
	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
		struct kld_file_stat k_stat;
		k_stat.version = sizeof(k_stat);
		if (kldstat(fileid, &k_stat) == 0)
			dt_module_update(dtp, &k_stat);
	}
#endif

	/*
	 * Look up all the macro identifiers and set di_id to the latest value.
	 * This code collaborates with dt_lex.l on the use of di_id.  We will
	 * need to implement something fancier if we need to support non-ints.
	 */
	dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
	dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
	dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
	dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
	dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
	dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
#if defined(sun)
	dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
#endif
	dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
#if defined(sun)
	dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
#endif
	dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();

	/*
	 * Cache the pointers to the modules representing the base executable
	 * and the run-time linker in the dtrace client handle. Note that on
	 * x86 krtld is folded into unix, so if we don't find it, use unix
	 * instead.
	 */
	dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix");
	dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld");
	if (dtp->dt_rtld == NULL)
		dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix");

	/*
	 * If this is the first time we are initializing the module list,
	 * remove the module for genunix from the module list and then move it
	 * to the front of the module list.  We do this so that type and symbol
	 * queries encounter genunix and thereby optimize for the common case
	 * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
	 */
	if (dtp->dt_exec != NULL &&
	    dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
		dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
		dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
	}
}