Esempio n. 1
0
int
dtrace_stop(dtrace_hdl_t *dtp)
{
	int gen = dtp->dt_statusgen;

	if (dtp->dt_stopped)
		return (0);

	if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1)
		return (dt_set_errno(dtp, errno));

	dtp->dt_stopped = 1;

	/*
	 * Now that we're stopped, we're going to get status one final time.
	 */
	if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
		return (dt_set_errno(dtp, errno));

	if (dt_handle_status(dtp, &dtp->dt_status[gen ^ 1],
	    &dtp->dt_status[gen]) == -1)
		return (-1);

	return (0);
}
Esempio n. 2
0
int
dtrace_go(dtrace_hdl_t *dtp)
{
	dtrace_enable_io_t args;
	void *dof;
	int error, r;

	if (dtp->dt_active)
		return (dt_set_errno(dtp, EINVAL));

	/*
	 * If a dtrace:::ERROR program and callback are registered, enable the
	 * program before we start tracing.  If this fails for a vector open
	 * with ENOTTY, we permit dtrace_go() to succeed so that vector clients
	 * such as mdb's dtrace module can execute the rest of dtrace_go() even
	 * though they do not provide support for the DTRACEIOC_ENABLE ioctl.
	 */
	if (dtp->dt_errprog != NULL &&
	    dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
	    dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
		return (-1); /* dt_errno has been set for us */

	if ((dof = dtrace_getopt_dof(dtp)) == NULL)
		return (-1); /* dt_errno has been set for us */

	args.dof = dof;
	args.n_matched = 0;
	r = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
	error = errno;
	dtrace_dof_destroy(dtp, dof);

	if (r == -1 && (error != ENOTTY || dtp->dt_vector == NULL))
		return (dt_set_errno(dtp, error));

	if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
		if (errno == EACCES)
			return (dt_set_errno(dtp, EDT_DESTRUCTIVE));

		if (errno == EALREADY)
			return (dt_set_errno(dtp, EDT_ISANON));

		if (errno == ENOENT)
			return (dt_set_errno(dtp, EDT_NOANON));

		if (errno == E2BIG)
			return (dt_set_errno(dtp, EDT_ENDTOOBIG));

		if (errno == ENOSPC)
			return (dt_set_errno(dtp, EDT_BUFTOOSMALL));

		return (dt_set_errno(dtp, errno));
	}

	dtp->dt_active = 1;

	if (dt_options_load(dtp) == -1)
		return (dt_set_errno(dtp, errno));

	return (dt_aggregate_go(dtp));
}
Esempio n. 3
0
int
dt_options_load(dtrace_hdl_t *dtp)
{
	dof_hdr_t hdr, *dof;
	dof_sec_t *sec;
	size_t offs;
	int i;

	/*
	 * To load the option values, we need to ask the kernel to provide its
	 * DOF, which we'll sift through to look for OPTDESC sections.
	 */
	bzero(&hdr, sizeof (dof_hdr_t));
	hdr.dofh_loadsz = sizeof (dof_hdr_t);


	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
		return (dt_set_errno(dtp, errno));

	if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
		return (dt_set_errno(dtp, EINVAL));

	dof = alloca(hdr.dofh_loadsz);
	bzero(dof, sizeof (dof_hdr_t));
	dof->dofh_loadsz = hdr.dofh_loadsz;

	for (i = 0; i < DTRACEOPT_MAX; i++)
		dtp->dt_options[i] = DTRACEOPT_UNSET;


	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
		return (dt_set_errno(dtp, errno));

	for (i = 0; i < dof->dofh_secnum; i++) {
		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
		    dof->dofh_secoff + i * dof->dofh_secsize);

		if (sec->dofs_type != DOF_SECT_OPTDESC)
			continue;

		break;
	}

	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
		    ((uintptr_t)dof + sec->dofs_offset + offs);

		if (opt->dofo_strtab != DOF_SECIDX_NONE)
			continue;

		if (opt->dofo_option >= DTRACEOPT_MAX)
			continue;

		dtp->dt_options[opt->dofo_option] = opt->dofo_value;
	}

	return (0);
}
Esempio n. 4
0
dt_provider_t *
dt_provider_lookup(dtrace_hdl_t *dtp, const char *name)
{
	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets;
	dtrace_providerdesc_t desc;
	dt_provider_t *pvp;

	for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) {
		if (strcmp(pvp->pv_desc.dtvd_name, name) == 0)
			return (pvp);
	}

	if (strisglob(name) || name[0] == '\0') {
		(void) dt_set_errno(dtp, EDT_NOPROV);
		return (NULL);
	}

	bzero(&desc, sizeof (desc));
	(void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN);

	if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) {
		(void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno);
		return (NULL);
	}

	if ((pvp = dt_provider_create(dtp, name)) == NULL)
		return (NULL); /* dt_errno is set for us */

	bcopy(&desc, &pvp->pv_desc, sizeof (desc));
	pvp->pv_flags |= DT_PROVIDER_IMPL;
	return (pvp);
}
Esempio n. 5
0
int
dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
	dtrace_prog_t *pgp;
	dt_stmt_t *stp;
	dtrace_probedesc_t *pdp, pd;
	pid_t pid;
	int ret = 0, found = B_FALSE;
	char provname[DTRACE_PROVNAMELEN];

	(void) snprintf(provname, sizeof (provname), "pid%d",
	    (int)dpr->dpr_pid);

	for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL;
	    pgp = dt_list_next(pgp)) {

		for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL;
		    stp = dt_list_next(stp)) {

			pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe;
			pid = dt_pid_get_pid(pdp, dtp, NULL, dpr);
			if (pid != dpr->dpr_pid)
				continue;

			found = B_TRUE;

			pd = *pdp;

			if (gmatch(provname, pdp->dtpd_provider) != 0 &&
			    dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0)
				ret = 1;

			/*
			 * If it's not strictly a pid provider, we might match
			 * a USDT provider.
			 */
			if (strcmp(provname, pdp->dtpd_provider) != 0 &&
			    dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0)
				ret = 1;
		}
	}

	if (found) {
		/*
		 * Give DTrace a shot to the ribs to get it to check
		 * out the newly created probes.
		 */
		(void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
	}

	return (ret);
}
Esempio n. 6
0
int
dtrace_status(dtrace_hdl_t *dtp)
{
	int gen = dtp->dt_statusgen;
	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_STATUSRATE];
	hrtime_t now = gethrtime();

	if (!dtp->dt_active)
		return (DTRACE_STATUS_NONE);

	if (dtp->dt_stopped)
		return (DTRACE_STATUS_STOPPED);

	if (dtp->dt_laststatus != 0) {
		if (now - dtp->dt_laststatus < interval)
			return (DTRACE_STATUS_NONE);

		dtp->dt_laststatus += interval;
	} else {
		dtp->dt_laststatus = now;
	}

	if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
		return (dt_set_errno(dtp, errno));

	dtp->dt_statusgen ^= 1;

	if (dt_handle_status(dtp, &dtp->dt_status[dtp->dt_statusgen],
	    &dtp->dt_status[gen]) == -1)
		return (-1);

	if (dtp->dt_status[gen].dtst_exiting) {
		if (!dtp->dt_stopped)
			(void) dtrace_stop(dtp);

		return (DTRACE_STATUS_EXITED);
	}

	if (dtp->dt_status[gen].dtst_filled == 0)
		return (DTRACE_STATUS_OKAY);

	if (dtp->dt_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL)
		return (DTRACE_STATUS_OKAY);

	if (!dtp->dt_stopped) {
		if (dtrace_stop(dtp) == -1)
			return (-1);
	}

	return (DTRACE_STATUS_FILLED);
}
Esempio n. 7
0
struct ps_prochandle *
dtrace_proc_waitfor(dtrace_hdl_t *dtp, char const *pname)
{
	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
	struct ps_prochandle *P = NULL;
	int err;

	dtrace_procdesc_t pdesc;

	assert(dtp);
	assert(pname);
	assert(*pname != '\0');

	size_t max_len = sizeof(pdesc.p_comm);
	if (strlcpy(pdesc.p_comm, pname, max_len) >= max_len) {
		fprintf(stderr, "Error, the process name (%s) exceeded the %lu characters limit\n",
		       pname, sizeof(pdesc.p_comm) - 1);
		return NULL;
	}

	if ((err = dt_ioctl(dtp, DTRACEIOC_PROCWAITFOR, &pdesc)) != 0) {
		fprintf(stderr, "Error, dt_ioctl() failed (%s)\n", strerror(errno));
		return NULL;
	}

	assert(pdesc.p_pid != -1);

	/*
 	 * The process is already stopped by the previous ioctl call.
	 * The function dt_proc_grab() will stop and resume the process,
	 * but the process will remain stopped until we call pid_resume().
	 */
	P = dt_proc_grab(dtp, pdesc.p_pid, 0, 0);

	/* Waking-up a process can fail if there is another client waiting for the same process. */
	if ((err = pid_resume(pdesc.p_pid)) != 0) {
		dt_dprintf("Unable to resume the process (pid=%d), the process is still suspended\n",
		           pdesc.p_pid);
	}

	if (P != NULL && idp != NULL && idp->di_id == 0)
		idp->di_id = pdesc.p_pid; /* $target = grabbed pid */

	return P;
}
Esempio n. 8
0
int
dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
    dtrace_proginfo_t *pip)
{
	void *dof;
	int n, err;

	dtrace_program_info(dtp, pgp, pip);

	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
		return (-1);

	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
#if defined(__APPLE__)
        if (n == -1 && (errno & 0xfffff000))
                n = (((unsigned int)errno) >> 12); /* Darwin's ioctls only return -1 or zero. Overload errno to mimic Solaris. */
#endif /* __APPLE__ */	
	dtrace_dof_destroy(dtp, dof);

	if (n == -1) {
		switch (errno) {
		case EINVAL:
			err = EDT_DIFINVAL;
			break;
		case EFAULT:
			err = EDT_DIFFAULT;
			break;
		case E2BIG:
			err = EDT_DIFSIZE;
			break;
		case EBUSY:
			err = EDT_ENABLING_ERR;
			break;
		default:
			err = errno;
		}

		return (dt_set_errno(dtp, err));
	}

	if (pip != NULL)
		pip->dpi_matches += n;

	return (0);
}
Esempio n. 9
0
int
dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
    dtrace_proginfo_t *pip)
{
	dtrace_enable_io_t args;
	void *dof;
	int n, err;

	dtrace_program_info(dtp, pgp, pip);

	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
		return (-1);

	args.dof = dof;
	args.n_matched = 0;
	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
	dtrace_dof_destroy(dtp, dof);

	if (n == -1) {
		switch (errno) {
		case EINVAL:
			err = EDT_DIFINVAL;
			break;
		case EFAULT:
			err = EDT_DIFFAULT;
			break;
		case E2BIG:
			err = EDT_DIFSIZE;
			break;
		case EBUSY:
			err = EDT_ENABLING_ERR;
			break;
		default:
			err = errno;
		}

		return (dt_set_errno(dtp, err));
	}

	if (pip != NULL)
		pip->dpi_matches += args.n_matched;

	return (0);
}
Esempio n. 10
0
/*
 * Lookup a probe declaration based on a known provider and full or partially
 * specified module, function, and name.  If the probe is not known to us yet,
 * ask dtrace(7D) to match the description and then cache any useful results.
 */
dt_probe_t *
dt_probe_lookup(dt_provider_t *pvp, const char *s)
{
	dtrace_hdl_t *dtp = pvp->pv_hdl;
	dtrace_probedesc_t pd;
	dt_ident_t *idp;
	size_t keylen;
	char *key;

	if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
		return (NULL); /* dt_errno is set for us */

	keylen = dt_probe_keylen(&pd);
	key = dt_probe_key(&pd, alloca(keylen));

	/*
	 * If the probe is already declared, then return the dt_probe_t from
	 * the existing identifier.  This could come from a static declaration
	 * or it could have been cached from an earlier call to this function.
	 */
	if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
		return (idp->di_data);

	/*
	 * If the probe isn't known, use the probe description computed above
	 * to ask dtrace(7D) to find the first matching probe.
	 */
	if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0)
		return (dt_probe_discover(pvp, &pd));

	if (errno == ESRCH || errno == EBADF)
		(void) dt_set_errno(dtp, EDT_NOPROBE);
	else
		(void) dt_set_errno(dtp, errno);

	return (NULL);
}
Esempio n. 11
0
int
dtrace_probe_iter(dtrace_hdl_t *dtp,
    const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg)
{
	const char *provider = pdp ? pdp->dtpd_provider : NULL;
	dtrace_id_t id = DTRACE_IDNONE;

	dtrace_probedesc_t pd;
	dt_probe_iter_t pit;
	int cmd, rv;

	bzero(&pit, sizeof (pit));
	pit.pit_hdl = dtp;
	pit.pit_func = func;
	pit.pit_arg = arg;
	pit.pit_pat = pdp ? pdp->dtpd_name : NULL;

	for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist);
	    pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) {

		if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL)
			continue; /* we'll get these later using dt_ioctl() */

		if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider))
			continue;

		(void) strlcpy(pit.pit_desc.dtpd_provider,
		    pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN);

		if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes,
		    (dt_idhash_f *)dt_probe_iter, &pit)) != 0)
			return (rv);
	}

	if (pdp != NULL)
		cmd = DTRACEIOC_PROBEMATCH;
	else
		cmd = DTRACEIOC_PROBES;

	for (;;) {
		if (pdp != NULL)
			bcopy(pdp, &pd, sizeof (pd));

		pd.dtpd_id = id;

		if (dt_ioctl(dtp, cmd, &pd) != 0)
			break;
		else if ((rv = func(dtp, &pd, arg)) != 0)
			return (rv);

		pit.pit_matches++;
		id = pd.dtpd_id + 1;
	}

	switch (errno) {
	case ESRCH:
	case EBADF:
		return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE));
	case EINVAL:
		return (dt_set_errno(dtp, EDT_BADPGLOB));
	default:
		return (dt_set_errno(dtp, errno));
	}
}
Esempio n. 12
0
/*
 * If a probe was discovered from the kernel, ask dtrace(7D) for a description
 * of each of its arguments, including native and translated types.
 */
static dt_probe_t *
dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
{
	dtrace_hdl_t *dtp = pvp->pv_hdl;
	char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));

	dt_node_t *xargs, *nargs;
	dt_ident_t *idp;
	dt_probe_t *prp;

	dtrace_typeinfo_t dtt;
	int i, nc, xc;

	int adc = _dtrace_argmax;
	dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
	dtrace_argdesc_t *adp = adv;

	assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
	assert(pdp->dtpd_id != DTRACE_IDNONE);

	dt_dprintf("discovering probe %s:%s id=%d\n",
	    pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);

	for (nc = -1, i = 0; i < adc; i++, adp++) {
		bzero(adp, sizeof (dtrace_argdesc_t));
		adp->dtargd_ndx = i;
		adp->dtargd_id = pdp->dtpd_id;

		if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
			(void) dt_set_errno(dtp, errno);
			return (NULL);
		}

		if (adp->dtargd_ndx == DTRACE_ARGNONE)
			break; /* all argument descs have been retrieved */

		nc = MAX(nc, adp->dtargd_mapping);
	}

	xc = i;
	nc++;

	/*
	 * The pid provider believes in giving the kernel a break. No reason to
	 * give the kernel all the ctf containers that we're keeping ourselves
	 * just to get it back from it. So if we're coming from a pid provider
	 * probe and the kernel gave us no argument information we'll get some
	 * here. If for some crazy reason the kernel knows about our userland
	 * types then we just ignore this.
	 */
	if (xc == 0 && nc == 0 &&
	    strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
		nc = adc;
		dt_pid_get_types(dtp, pdp, adv, &nc);
		xc = nc;
	}

	/*
	 * Now that we have discovered the number of native and translated
	 * arguments from the argument descriptions, allocate a new probe ident
	 * and corresponding dt_probe_t and hash it into the provider.
	 */
	xargs = dt_probe_alloc_args(pvp, xc);
	nargs = dt_probe_alloc_args(pvp, nc);

	if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
		return (NULL); /* dt_errno is set for us */

	idp = dt_ident_create(name, DT_IDENT_PROBE,
	    DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
	    &dt_idops_probe, NULL, dtp->dt_gen);

	if (idp == NULL) {
		(void) dt_set_errno(dtp, EDT_NOMEM);
		return (NULL);
	}

	if ((prp = dt_probe_create(dtp, idp, 2,
	    nargs, nc, xargs, xc)) == NULL) {
		dt_ident_destroy(idp);
		return (NULL);
	}

	dt_probe_declare(pvp, prp);

	/*
	 * Once our new dt_probe_t is fully constructed, iterate over the
	 * cached argument descriptions and assign types to prp->pr_nargv[]
	 * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
	 */
	for (adp = adv, i = 0; i < xc; i++, adp++) {
		if (dtrace_type_strcompile(dtp,
		    adp->dtargd_native, &dtt) != 0) {
			dt_dprintf("failed to resolve input type %s "
			    "for %s:%s arg #%d: %s\n", adp->dtargd_native,
			    pvp->pv_desc.dtvd_name, name, i + 1,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));

			dtt.dtt_object = NULL;
			dtt.dtt_ctfp = NULL;
			dtt.dtt_type = CTF_ERR;
		} else {
			dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
			    dtt.dtt_ctfp, dtt.dtt_type,
			    dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
		}

		if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
		    strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
			dt_node_type_propagate(prp->pr_nargv[
			    adp->dtargd_mapping], prp->pr_xargv[i]);
		} else if (dtrace_type_strcompile(dtp,
		    adp->dtargd_xlate, &dtt) != 0) {
			dt_dprintf("failed to resolve output type %s "
			    "for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
			    pvp->pv_desc.dtvd_name, name, i + 1,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));

			dtt.dtt_object = NULL;
			dtt.dtt_ctfp = NULL;
			dtt.dtt_type = CTF_ERR;
		} else {
			dt_node_type_assign(prp->pr_xargv[i],
			    dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
		}

		prp->pr_mapping[i] = adp->dtargd_mapping;
		prp->pr_argv[i] = dtt;
	}

	return (prp);
}
Esempio n. 13
0
static int
dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
{
	dtrace_id_t max;
	int rval, i;
	dtrace_eprobedesc_t *enabled, *nenabled;
	dtrace_probedesc_t *probe;

	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
		dtrace_id_t new_max = max ? (max << 1) : 1;
		size_t nsize = new_max * sizeof (void *);
		dtrace_probedesc_t **new_pdesc;
		dtrace_eprobedesc_t **new_edesc;

		if ((new_pdesc = malloc(nsize)) == NULL ||
		    (new_edesc = malloc(nsize)) == NULL) {
			free(new_pdesc);
			return (dt_set_errno(dtp, EDT_NOMEM));
		}

		bzero(new_pdesc, nsize);
		bzero(new_edesc, nsize);

		if (dtp->dt_pdesc != NULL) {
			size_t osize = max * sizeof (void *);

			bcopy(dtp->dt_pdesc, new_pdesc, osize);
			free(dtp->dt_pdesc);

			bcopy(dtp->dt_edesc, new_edesc, osize);
			free(dtp->dt_edesc);
		}

		dtp->dt_pdesc = new_pdesc;
		dtp->dt_edesc = new_edesc;
		dtp->dt_maxprobe = new_max;
	}

	if (dtp->dt_pdesc[id] != NULL)
		return (0);

	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
		return (dt_set_errno(dtp, EDT_NOMEM));

	bzero(enabled, sizeof (dtrace_eprobedesc_t));
	enabled->dtepd_epid = id;
	enabled->dtepd_nrecs = 1;

#if defined(sun)
	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
#else
	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
#endif
		rval = dt_set_errno(dtp, errno);
		free(enabled);
		return (rval);
	}

	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
		/*
		 * There must be more than one action.  Allocate the
		 * appropriate amount of space and try again.
		 */
		if ((nenabled =
		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
			bcopy(enabled, nenabled, sizeof (*enabled));

		free(enabled);

		if ((enabled = nenabled) == NULL)
			return (dt_set_errno(dtp, EDT_NOMEM));

#if defined(sun)
		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
#else
		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
#endif

		if (rval == -1) {
			rval = dt_set_errno(dtp, errno);
			free(enabled);
			return (rval);
		}
	}

	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
		free(enabled);
		return (dt_set_errno(dtp, EDT_NOMEM));
	}

	probe->dtpd_id = enabled->dtepd_probeid;

	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
		rval = dt_set_errno(dtp, errno);
		goto err;
	}

	for (i = 0; i < enabled->dtepd_nrecs; i++) {
		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];

		if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
			if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
			    &dtp->dt_maxformat) != 0) {
				rval = -1;
				goto err;
			}
		} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
			if (dt_strdata_add(dtp, rec,
			    (void ***)&dtp->dt_strdata,
			    &dtp->dt_maxstrdata) != 0) {
				rval = -1;
				goto err;
			}
		}

	}

	dtp->dt_pdesc[id] = probe;
	dtp->dt_edesc[id] = enabled;

	return (0);

err:
	/*
	 * If we failed, free our allocated probes.  Note that if we failed
	 * while allocating formats, we aren't going to free formats that
	 * we have already allocated.  This is okay; these formats are
	 * hanging off of dt_formats and will therefore not be leaked.
	 */
	free(enabled);
	free(probe);
	return (rval);
}

int
dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
    dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
{
	int rval;

	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
		if ((rval = dt_epid_add(dtp, epid)) != 0)
			return (rval);
	}

	assert(epid < dtp->dt_maxprobe);
	assert(dtp->dt_edesc[epid] != NULL);
	assert(dtp->dt_pdesc[epid] != NULL);
	*epdp = dtp->dt_edesc[epid];
	*pdp = dtp->dt_pdesc[epid];

	return (0);
}
Esempio n. 14
0
static int
dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
{
	dtrace_id_t max;
	dtrace_epid_t epid;
	int rval;

	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
		dtrace_id_t new_max = max ? (max << 1) : 1;
		size_t nsize = new_max * sizeof (void *);
		dtrace_aggdesc_t **new_aggdesc;

		if ((new_aggdesc = malloc(nsize)) == NULL)
			return (dt_set_errno(dtp, EDT_NOMEM));

		bzero(new_aggdesc, nsize);

		if (dtp->dt_aggdesc != NULL) {
			bcopy(dtp->dt_aggdesc, new_aggdesc,
			    max * sizeof (void *));
			free(dtp->dt_aggdesc);
		}

		dtp->dt_aggdesc = new_aggdesc;
		dtp->dt_maxagg = new_max;
	}

	if (dtp->dt_aggdesc[id] == NULL) {
		dtrace_aggdesc_t *agg, *nagg;

		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
			return (dt_set_errno(dtp, EDT_NOMEM));

		bzero(agg, sizeof (dtrace_aggdesc_t));
		agg->dtagd_id = id;
		agg->dtagd_nrecs = 1;

#if defined(sun)
		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
#else
		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
#endif
			rval = dt_set_errno(dtp, errno);
			free(agg);
			return (rval);
		}

		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
			/*
			 * There must be more than one action.  Allocate the
			 * appropriate amount of space and try again.
			 */
			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
				bcopy(agg, nagg, sizeof (*agg));

			free(agg);

			if ((agg = nagg) == NULL)
				return (dt_set_errno(dtp, EDT_NOMEM));

#if defined(sun)
			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
#else
			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
#endif

			if (rval == -1) {
				rval = dt_set_errno(dtp, errno);
				free(agg);
				return (rval);
			}
		}

		/*
		 * If we have a uarg, it's a pointer to the compiler-generated
		 * statement; we'll use this value to get the name and
		 * compiler-generated variable ID for the aggregation.  If
		 * we're grabbing an anonymous enabling, this pointer value
		 * is obviously meaningless -- and in this case, we can't
		 * provide the compiler-generated aggregation information.
		 */
		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
		    agg->dtagd_rec[0].dtrd_uarg != 0) {
			dtrace_stmtdesc_t *sdp;
			dt_ident_t *aid;

			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
			    agg->dtagd_rec[0].dtrd_uarg;
			aid = sdp->dtsd_aggdata;
			agg->dtagd_name = aid->di_name;
			agg->dtagd_varid = aid->di_id;
		} else {
			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
		}

		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
		    dtp->dt_pdesc[epid] == NULL) {
			if ((rval = dt_epid_add(dtp, epid)) != 0) {
				free(agg);
				return (rval);
			}
		}

		dtp->dt_aggdesc[id] = agg;
	}

	return (0);
}

int
dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
    dtrace_aggdesc_t **adp)
{
	int rval;

	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
			return (rval);
	}

	assert(aggid < dtp->dt_maxagg);
	assert(dtp->dt_aggdesc[aggid] != NULL);
	*adp = dtp->dt_aggdesc[aggid];

	return (0);
}
Esempio n. 15
0
static int
dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
{
	int maxformat;
	dtrace_fmtdesc_t fmt;
	void *result;

	if (rec->dtrd_format == 0)
		return (0);

	if (rec->dtrd_format <= *max &&
	    (*data)[rec->dtrd_format - 1] != NULL) {
		return (0);
	}

	bzero(&fmt, sizeof (fmt));
	fmt.dtfd_format = rec->dtrd_format;
	fmt.dtfd_string = NULL;
	fmt.dtfd_length = 0;

	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
		return (dt_set_errno(dtp, errno));

	if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
		return (dt_set_errno(dtp, EDT_NOMEM));

	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
		free(fmt.dtfd_string);
		return (dt_set_errno(dtp, errno));
	}

	while (rec->dtrd_format > (maxformat = *max)) {
		int new_max = maxformat ? (maxformat << 1) : 1;
		size_t nsize = new_max * sizeof (void *);
		size_t osize = maxformat * sizeof (void *);
		void **new_data = dt_zalloc(dtp, nsize);

		if (new_data == NULL) {
			dt_free(dtp, fmt.dtfd_string);
			return (dt_set_errno(dtp, EDT_NOMEM));
		}

		bcopy(*data, new_data, osize);
		free(*data);

		*data = new_data;
		*max = new_max;
	}

	switch (rec->dtrd_action) {
	case DTRACEACT_DIFEXPR:
		result = fmt.dtfd_string;
		break;
	case DTRACEACT_PRINTA:
		result = dtrace_printa_create(dtp, fmt.dtfd_string);
		dt_free(dtp, fmt.dtfd_string);
		break;
	default:
		result = dtrace_printf_create(dtp, fmt.dtfd_string);
		dt_free(dtp, fmt.dtfd_string);
		break;
	}

	if (result == NULL)
		return (-1);

	(*data)[rec->dtrd_format - 1] = result;

	return (0);
}
Esempio n. 16
0
int
dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
	char provname[DTRACE_PROVNAMELEN];
	struct ps_prochandle *P;
	dt_proc_t *dpr;
	pid_t pid;
	int err = 0;

	assert(pcb != NULL);

	if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
		return (-1);

	if (dtp->dt_ftfd == -1) {
		if (dtp->dt_fterr == ENOENT) {
			(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
			    "pid provider is not installed on this system");
		} else {
			(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
			    "pid provider is not available: %s",
			    strerror(dtp->dt_fterr));
		}

		return (-1);
	}

	(void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);

	if (gmatch(provname, pdp->dtpd_provider) != 0) {
		if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
		    0)) == NULL) {
			(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
			    "failed to grab process %d", (int)pid);
			return (-1);
		}

		dpr = dt_proc_lookup(dtp, P, 0);
		assert(dpr != NULL);
		(void) pthread_mutex_lock(&dpr->dpr_lock);

		if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) {
			/*
			 * Alert other retained enablings which may match
			 * against the newly created probes.
			 */
			(void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
		dt_proc_release(dtp, P);
	}

	/*
	 * If it's not strictly a pid provider, we might match a USDT provider.
	 */
	if (strcmp(provname, pdp->dtpd_provider) != 0) {
		if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) {
			(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
			    "failed to grab process %d", (int)pid);
			return (-1);
		}

		dpr = dt_proc_lookup(dtp, P, 0);
		assert(dpr != NULL);
		(void) pthread_mutex_lock(&dpr->dpr_lock);

		if (!dpr->dpr_usdt) {
			err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr);
			dpr->dpr_usdt = B_TRUE;
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
		dt_proc_release(dtp, P);
	}

	return (err ? -1 : 0);
}