Example #1
0
static int
dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
{
	dtrace_eprobedesc_t *epd = data->dtpda_edesc, *errepd;
	dtrace_probedesc_t *pd = data->dtpda_pdesc, *errpd;
	dtrace_errdata_t err;
	dtrace_epid_t epid;

	char where[30];
	char details[30];
	char offinfo[30];
	const int slop = 80;
	const char *faultstr;
	char *str;
	int len;

	assert(epd->dtepd_uarg == DT_ECB_ERROR);

	if (epd->dtepd_nrecs != 5 || strcmp(pd->dtpd_provider, "dtrace") != 0 ||
	    strcmp(pd->dtpd_name, "ERROR") != 0)
		return (dt_set_errno(dtp, EDT_BADERROR));

	/*
	 * This is an error.  We have the following items here:  EPID,
	 * faulting action, DIF offset, fault code and faulting address.
	 */
	epid = (uint32_t)DT_REC(uint64_t, 0);

	if (dt_epid_lookup(dtp, epid, &errepd, &errpd) != 0)
		return (dt_set_errno(dtp, EDT_BADERROR));

	err.dteda_edesc = errepd;
	err.dteda_pdesc = errpd;
	err.dteda_cpu = data->dtpda_cpu;
	err.dteda_action = (int)DT_REC(uint64_t, 1);
	err.dteda_offset = (int)DT_REC(uint64_t, 2);
	err.dteda_fault = (int)DT_REC(uint64_t, 3);
	err.dteda_addr = DT_REC(uint64_t, 4);

	faultstr = dtrace_faultstr(dtp, err.dteda_fault);
	len = sizeof (where) + sizeof (offinfo) + strlen(faultstr) +
	    strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) +
	    strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) +
	    slop;

	str = (char *)alloca(len);

	if (err.dteda_action == 0) {
		(void) sprintf(where, "predicate");
	} else {
		(void) sprintf(where, "action #%d", err.dteda_action);
	}

	if (err.dteda_offset != -1) {
		(void) sprintf(offinfo, " at DIF offset %d", err.dteda_offset);
	} else {
		offinfo[0] = 0;
	}

	switch (err.dteda_fault) {
	case DTRACEFLT_BADADDR:
	case DTRACEFLT_BADALIGN:
	case DTRACEFLT_BADSTACK:
		(void) sprintf(details, " (0x%llx)",
		    (u_longlong_t)err.dteda_addr);
		break;

	default:
		details[0] = 0;
	}

	(void) snprintf(str, len, "error on enabled probe ID %u "
	    "(ID %u: %s:%s:%s:%s): %s%s in %s%s\n",
	    epid, errpd->dtpd_id, errpd->dtpd_provider,
	    errpd->dtpd_mod, errpd->dtpd_func,
	    errpd->dtpd_name, dtrace_faultstr(dtp, err.dteda_fault),
	    details, where, offinfo);

	err.dteda_msg = str;

	if (dtp->dt_errhdlr == NULL)
		return (dt_set_errno(dtp, EDT_ERRABORT));

	if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT)
		return (dt_set_errno(dtp, EDT_ERRABORT));

	return (0);
}
Example #2
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));
	}
}
Example #3
0
void *
dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
{
	dt_dof_t *ddo = &dtp->dt_dof;

	const dtrace_ecbdesc_t *edp, *last;
	const dtrace_probedesc_t *pdp;
	const dtrace_actdesc_t *ap;
	const dt_stmt_t *stp;

	uint_t maxacts = 0;
	uint_t maxfmt = 0;

	dt_provider_t *pvp;
	dt_xlator_t *dxp;
	dof_actdesc_t *dofa;
	dof_sec_t *sp;
	size_t ssize, lsize;
	dof_hdr_t h;

	dt_buf_t dof;
	char *fmt;
	uint_t i;

	if (flags & ~DTRACE_D_MASK) {
		(void) dt_set_errno(dtp, EINVAL);
		return (NULL);
	}

	flags |= dtp->dt_dflags;

	if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0)
		return (NULL);

	if (dt_dof_reset(dtp, pgp) != 0)
		return (NULL);

	/*
	 * Iterate through the statement list computing the maximum number of
	 * actions and the maximum format string for allocating local buffers.
	 */
	for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
	    stp != NULL; stp = dt_list_next(stp), last = edp) {

		dtrace_stmtdesc_t *sdp = stp->ds_desc;
		dtrace_actdesc_t *ap = sdp->dtsd_action;

		if (sdp->dtsd_fmtdata != NULL) {
			i = dtrace_printf_format(dtp,
			    sdp->dtsd_fmtdata, NULL, 0);
			maxfmt = MAX(maxfmt, i);
		}

		if ((edp = sdp->dtsd_ecbdesc) == last)
			continue; /* same ecb as previous statement */

		for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next)
			i++;

		maxacts = MAX(maxacts, i);
	}

	dofa = alloca(sizeof (dof_actdesc_t) * maxacts);
	fmt = alloca(maxfmt + 1);

	ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0);
	(void) dof_add_string(ddo, "");

	/*
	 * If there are references to dynamic translators in the program, add
	 * an imported translator table entry for each referenced translator.
	 */
	if (pgp->dp_xrefslen != 0) {
		for (dxp = dt_list_next(&dtp->dt_xlators);
		    dxp != NULL; dxp = dt_list_next(dxp)) {
			if (dxp->dx_id < pgp->dp_xrefslen &&
			    pgp->dp_xrefs[dxp->dx_id] != NULL)
				dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT);
		}
	}

	/*
	 * Now iterate through the statement list, creating the DOF section
	 * headers and data for each one and adding them to our buffers.
	 */
	for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
	    stp != NULL; stp = dt_list_next(stp), last = edp) {

		dof_secidx_t probesec = DOF_SECIDX_NONE;
		dof_secidx_t prdsec = DOF_SECIDX_NONE;
		dof_secidx_t actsec = DOF_SECIDX_NONE;

		const dt_stmt_t *next = stp;
		dtrace_stmtdesc_t *sdp = stp->ds_desc;
		dof_stridx_t strndx = 0;
		dof_probedesc_t dofp;
		dof_ecbdesc_t dofe;
		uint_t i;

		if ((edp = stp->ds_desc->dtsd_ecbdesc) == last)
			continue; /* same ecb as previous statement */

		pdp = &edp->dted_probe;

		/*
		 * Add a DOF_SECT_PROBEDESC for the ECB's probe description,
		 * and copy the probe description strings into the string table.
		 */
		dofp.dofp_strtab = ddo->ddo_strsec;
		dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider);
		dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod);
		dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func);
		dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name);
		dofp.dofp_id = pdp->dtpd_id;

		probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC,
		    sizeof (dof_secidx_t), 0,
		    sizeof (dof_probedesc_t), sizeof (dof_probedesc_t));

		/*
		 * If there is a predicate DIFO associated with the ecbdesc,
		 * write out the DIFO sections and save the DIFO section index.
		 */
		if (edp->dted_pred.dtpdd_difo != NULL)
			prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo);

		/*
		 * Now iterate through the action list generating DIFOs as
		 * referenced therein and adding action descriptions to 'dofa'.
		 */
		for (i = 0, ap = edp->dted_action;
		    ap != NULL; ap = ap->dtad_next, i++) {

			if (ap->dtad_difo != NULL) {
				dofa[i].dofa_difo =
				    dof_add_difo(ddo, ap->dtad_difo);
			} else
				dofa[i].dofa_difo = DOF_SECIDX_NONE;

			/*
			 * If the first action in a statement has string data,
			 * add the string to the global string table.  This can
			 * be due either to a printf() format string
			 * (dtsd_fmtdata) or a print() type string
			 * (dtsd_strdata).
			 */
			if (sdp != NULL && ap == sdp->dtsd_action) {
				if (sdp->dtsd_fmtdata != NULL) {
					(void) dtrace_printf_format(dtp,
					    sdp->dtsd_fmtdata, fmt, maxfmt + 1);
					strndx = dof_add_string(ddo, fmt);
				} else if (sdp->dtsd_strdata != NULL) {
					strndx = dof_add_string(ddo, sdp->dtsd_strdata);
				} else
					strndx = 0; /* use dtad_arg instead */

				if ((next = dt_list_next(next)) != NULL)
					sdp = next->ds_desc;
				else
					sdp = NULL;
			}

			if (strndx != 0) {
				dofa[i].dofa_arg = strndx;
				dofa[i].dofa_strtab = ddo->ddo_strsec;
			} else {
				dofa[i].dofa_arg = ap->dtad_arg;
				dofa[i].dofa_strtab = DOF_SECIDX_NONE;
			}

			dofa[i].dofa_kind = ap->dtad_kind;
			dofa[i].dofa_ntuple = ap->dtad_ntuple;
			dofa[i].dofa_uarg = ap->dtad_uarg;
		}

		if (i > 0) {
			actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC,
			    sizeof (uint64_t), 0, sizeof (dof_actdesc_t),
			    sizeof (dof_actdesc_t) * i);
		}

		/*
		 * Now finally, add the DOF_SECT_ECBDESC referencing all the
		 * previously created sub-sections.
		 */
		dofe.dofe_probes = probesec;
		dofe.dofe_pred = prdsec;
		dofe.dofe_actions = actsec;
		dofe.dofe_pad = 0;
		dofe.dofe_uarg = edp->dted_uarg;

		(void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC,
		    sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t));
	}

	/*
	 * If any providers are user-defined, output DOF sections corresponding
	 * to the providers and the probes and arguments that they define.
	 */
	if (flags & DTRACE_D_PROBES) {
		for (pvp = dt_list_next(&dtp->dt_provlist);
		    pvp != NULL; pvp = dt_list_next(pvp))
			dof_add_provider(ddo, pvp);
	}

	/*
	 * If we're not stripping unloadable sections, generate compiler
	 * comments and any other unloadable miscellany.
	 */
	if (!(flags & DTRACE_D_STRIP)) {
		(void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS,
		    sizeof (char), 0, 0, strlen(_dtrace_version) + 1);
		(void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME,
		    sizeof (char), 0, 0, sizeof (struct utsname));
	}

	/*
	 * Compute and fill in the appropriate values for the dof_hdr_t's
	 * dofh_secnum, dofh_loadsz, and dofh_filez values.
	 */
	h.dofh_secnum = ddo->ddo_nsecs;
	ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs);
	assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);

	h.dofh_loadsz = ssize +
	    dt_buf_len(&ddo->ddo_ldata) +
	    dt_buf_len(&ddo->ddo_strs);

	if (dt_buf_len(&ddo->ddo_udata) != 0) {
		lsize = roundup(h.dofh_loadsz, sizeof (uint64_t));
		h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata);
	} else {
		lsize = h.dofh_loadsz;
		h.dofh_filesz = lsize;
	}

	/*
	 * Set the global DOF_SECT_STRTAB's offset to be after the header,
	 * section headers, and other loadable data.  Since we're going to
	 * iterate over the buffer data directly, we must check for errors.
	 */
	if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) {
		(void) dt_set_errno(dtp, i);
		return (NULL);
	}

	sp = dt_buf_ptr(&ddo->ddo_secs);
	assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB);

	sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata);
	sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs);

	/*
	 * Now relocate all the other section headers by adding the appropriate
	 * delta to their respective dofs_offset values.
	 */
	for (i = 0; i < ddo->ddo_nsecs; i++, sp++) {
		if (i == ddo->ddo_strsec)
			continue; /* already relocated above */

		if (sp->dofs_flags & DOF_SECF_LOAD)
			sp->dofs_offset += ssize;
		else
			sp->dofs_offset += lsize;
	}

	/*
	 * Finally, assemble the complete in-memory DOF buffer by writing the
	 * header and then concatenating all our buffers.  dt_buf_concat() will
	 * propagate any errors and cause dt_buf_claim() to return NULL.
	 */
	dt_buf_create(dtp, &dof, "dof", h.dofh_filesz);

	dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t));
	dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t));
	dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t));
	dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char));
	dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t));

	return (dt_buf_claim(dtp, &dof));
}
Example #4
0
int
dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
    const char *fname, const char *rname, uint32_t offset, int isenabled)
{
	dtrace_hdl_t *dtp = pvp->pv_hdl;
	dt_probe_instance_t *pip;
	uint32_t **offs;
	uint_t *noffs, *maxoffs;

	assert(fname != NULL);

	for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
		if (strcmp(pip->pi_fname, fname) == 0 &&
		    ((rname == NULL && pip->pi_rname[0] == '\0') ||
		    (rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
			break;
	}

	if (pip == NULL) {
		if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL)
			return (-1);

		if ((pip->pi_offs = dt_zalloc(dtp,
		    sizeof (uint32_t))) == NULL) {
			dt_free(dtp, pip);
			return (-1);
		}

		if ((pip->pi_enoffs = dt_zalloc(dtp,
		    sizeof (uint32_t))) == NULL) {
			dt_free(dtp, pip->pi_offs);
			dt_free(dtp, pip);
			return (-1);
		}

		(void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname));
		if (rname != NULL) {
			if (strlen(rname) + 1 > sizeof (pip->pi_rname)) {
				dt_free(dtp, pip->pi_offs);
				dt_free(dtp, pip);
				return (dt_set_errno(dtp, EDT_COMPILER));
			}
			(void) strcpy(pip->pi_rname, rname);
		}

		pip->pi_noffs = 0;
		pip->pi_maxoffs = 1;
		pip->pi_nenoffs = 0;
		pip->pi_maxenoffs = 1;

		pip->pi_next = prp->pr_inst;

		prp->pr_inst = pip;
	}

	if (isenabled) {
		offs = &pip->pi_enoffs;
		noffs = &pip->pi_nenoffs;
		maxoffs = &pip->pi_maxenoffs;
	} else {
		offs = &pip->pi_offs;
		noffs = &pip->pi_noffs;
		maxoffs = &pip->pi_maxoffs;
	}

	if (*noffs == *maxoffs) {
		uint_t new_max = *maxoffs * 2;
		uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max);

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

		bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs);

		dt_free(dtp, *offs);
		*maxoffs = new_max;
		*offs = new_offs;
	}

	dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n",
	    isenabled ? "(is-enabled)" : "",
	    pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset,
	    rname != NULL ? rname : fname);

	assert(*noffs < *maxoffs);
	(*offs)[(*noffs)++] = offset;

	return (0);
}
Example #5
0
dt_probe_t *
dt_probe_info(dtrace_hdl_t *dtp,
    const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
{
	int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
	int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
	int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);

	dt_probe_t *prp = NULL;
	const dtrace_pattr_t *pap;
	dt_provider_t *pvp;
	dt_ident_t *idp;

	/*
	 * Attempt to lookup the probe in our existing cache for this provider.
	 * If none is found and an explicit probe ID was specified, discover
	 * that specific probe and cache its description and arguments.
	 */
	if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
		size_t keylen = dt_probe_keylen(pdp);
		char *key = dt_probe_key(pdp, alloca(keylen));

		if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
			prp = idp->di_data;
		else if (pdp->dtpd_id != DTRACE_IDNONE)
			prp = dt_probe_discover(pvp, pdp);
	}

	/*
	 * If no probe was found in our cache, convert the caller's partial
	 * probe description into a fully-formed matching probe description by
	 * iterating over up to at most two probes that match 'pdp'.  We then
	 * call dt_probe_discover() on the resulting probe identifier.
	 */
	if (prp == NULL) {
		dtrace_probedesc_t pd;
		int m;

		bzero(&pd, sizeof (pd));
		pd.dtpd_id = DTRACE_IDNONE;

		/*
		 * Call dtrace_probe_iter() to find matching probes.  Our
		 * dt_probe_desc() callback will produce the following results:
		 *
		 * m < 0 dtrace_probe_iter() found zero matches (or failed).
		 * m > 0 dtrace_probe_iter() found more than one match.
		 * m = 0 dtrace_probe_iter() found exactly one match.
		 */
		if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
			return (NULL); /* dt_errno is set for us */

		if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
			return (NULL); /* dt_errno is set for us */

		/*
		 * If more than one probe was matched, then do not report probe
		 * information if either of the following conditions is true:
		 *
		 * (a) The Arguments Data stability of the matched provider is
		 *	less than Evolving.
		 *
		 * (b) Any description component that is at least Evolving is
		 *	empty or is specified using a globbing expression.
		 *
		 * These conditions imply that providers that provide Evolving
		 * or better Arguments Data stability must guarantee that all
		 * probes with identical field names in a field of Evolving or
		 * better Name stability have identical argument signatures.
		 */
		if (m > 0) {
			if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
			    DTRACE_STABILITY_EVOLVING) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}


			if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && m_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}

			if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && f_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}

			if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && n_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}
		}

		/*
		 * If we matched a probe exported by dtrace(7D), then discover
		 * the real attributes.  Otherwise grab the static declaration.
		 */
		if (pd.dtpd_id != DTRACE_IDNONE)
			prp = dt_probe_discover(pvp, &pd);
		else
			prp = dt_probe_lookup(pvp, pd.dtpd_name);

		if (prp == NULL)
			return (NULL); /* dt_errno is set for us */
	}

	assert(pvp != NULL && prp != NULL);

	/*
	 * Compute the probe description attributes by taking the minimum of
	 * the attributes of the specified fields.  If no provider is specified
	 * or a glob pattern is used for the provider, use Unstable attributes.
	 */
	if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
		pap = &_dtrace_prvdesc;
	else
		pap = &pvp->pv_desc.dtvd_attr;

	pip->dtp_attr = pap->dtpa_provider;

	if (!m_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
	if (!f_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
	if (!n_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);

	pip->dtp_arga = pap->dtpa_args;
	pip->dtp_argv = prp->pr_argv;
	pip->dtp_argc = prp->pr_argc;

	return (prp);
}
Example #6
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++;

	/*
	 * 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);
		}

		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);
		}

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

	return (prp);
}
Example #7
0
/*ARGSUSED*/
int
dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
{
	uint8_t *text;
	int size;
	ulong_t i, end = symp->st_size;
#if defined(sun)
	pid_t pid = Pstatus(P)->pr_pid;
	char dmodel = Pstatus(P)->pr_dmodel;
#else
	pid_t pid = proc_getpid(P);
#if __i386__
	char dmodel = PR_MODEL_ILP32;
#elif __amd64__
	char dmodel = PR_MODEL_LP64;
#endif
#endif

	ftp->ftps_type = DTFTP_OFFSETS;
	ftp->ftps_pc = (uintptr_t)symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 0;

	if ((text = malloc(symp->st_size)) == NULL) {
		dt_dprintf("mr sparkle: malloc() failed\n");
		return (DT_PROC_ERR);
	}

	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
		dt_dprintf("mr sparkle: Pread() failed\n");
		free(text);
		return (DT_PROC_ERR);
	}

	/*
	 * We can't instrument offsets in functions with jump tables as
	 * we might interpret a jump table offset as an instruction.
	 */
	if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
		free(text);
		return (0);
	}

	if (strcmp("*", pattern) == 0) {
		for (i = 0; i < end; i += size) {
			ftp->ftps_offs[ftp->ftps_noffs++] = i;

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;
		}
	} else {
		char name[sizeof (i) * 2 + 1];

		for (i = 0; i < end; i += size) {
			(void) snprintf(name, sizeof (name), "%lx", i);
			if (gmatch(name, pattern))
				ftp->ftps_offs[ftp->ftps_noffs++] = i;

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;
		}
	}

	free(text);
	if (ftp->ftps_noffs > 0) {
		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
			    strerror(errno));
			return (dt_set_errno(dtp, errno));
		}
	}

	return (ftp->ftps_noffs);
}
Example #8
0
/*ARGSUSED*/
int
dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
{
	ftp->ftps_type = DTFTP_OFFSETS;
	ftp->ftps_pc = (uintptr_t)symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 1;

	if (strcmp("-", ftp->ftps_func) == 0) {
		ftp->ftps_offs[0] = off;
	} else {
		uint8_t *text;
		ulong_t i;
		int size;
#if defined(sun)
		pid_t pid = Pstatus(P)->pr_pid;
		char dmodel = Pstatus(P)->pr_dmodel;
#else
		pid_t pid = proc_getpid(P);
#if __i386__
		char dmodel = PR_MODEL_ILP32;
#elif __amd64__
		char dmodel = PR_MODEL_LP64;
#endif
#endif

		if ((text = malloc(symp->st_size)) == NULL) {
			dt_dprintf("mr sparkle: malloc() failed\n");
			return (DT_PROC_ERR);
		}

		if (Pread(P, text, symp->st_size, symp->st_value) !=
		    symp->st_size) {
			dt_dprintf("mr sparkle: Pread() failed\n");
			free(text);
			return (DT_PROC_ERR);
		}

		/*
		 * We can't instrument offsets in functions with jump tables
		 * as we might interpret a jump table offset as an
		 * instruction.
		 */
		if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
			free(text);
			return (0);
		}

		for (i = 0; i < symp->st_size; i += size) {
			if (i == off) {
				ftp->ftps_offs[0] = i;
				break;
			}

			/*
			 * If we've passed the desired offset without a
			 * match, then the given offset must not lie on a
			 * instruction boundary.
			 */
			if (i > off) {
				free(text);
				return (DT_PROC_ALIGN);
			}

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/*
			 * If we hit an invalid instruction, bail as if we
			 * couldn't find the offset.
			 */
			if (size <= 0) {
				free(text);
				return (DT_PROC_ALIGN);
			}
		}

		free(text);
	}

	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
		    strerror(errno));
		return (dt_set_errno(dtp, errno));
	}

	return (ftp->ftps_noffs);
}
Example #9
0
/*ARGSUSED*/
int
dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
{
	uint8_t *text;
	ulong_t i, end;
	int size;
#if defined(sun)
	pid_t pid = Pstatus(P)->pr_pid;
	char dmodel = Pstatus(P)->pr_dmodel;
#else
	pid_t pid = proc_getpid(P);
#if __i386__
	char dmodel = PR_MODEL_ILP32;
#elif __amd64__
	char dmodel = PR_MODEL_LP64;
#endif
#endif

	/*
	 * We allocate a few extra bytes at the end so we don't have to check
	 * for overrunning the buffer.
	 */
	if ((text = calloc(1, symp->st_size + 4)) == NULL) {
		dt_dprintf("mr sparkle: malloc() failed\n");
		return (DT_PROC_ERR);
	}

	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
		dt_dprintf("mr sparkle: Pread() failed\n");
		free(text);
		return (DT_PROC_ERR);
	}

	ftp->ftps_type = DTFTP_RETURN;
	ftp->ftps_pc = (uintptr_t)symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 0;

	/*
	 * If there's a jump table in the function we're only willing to
	 * instrument these specific (and equivalent) instruction sequences:
	 *	leave
	 *	[rep] ret
	 * and
	 *	movl	%ebp,%esp
	 *	popl	%ebp
	 *	[rep] ret
	 *
	 * We do this to avoid accidentally interpreting jump table
	 * offsets as actual instructions.
	 */
	if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
		for (i = 0, end = ftp->ftps_size; i < end; i += size) {
			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;

			if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) {
				dt_dprintf("leave/ret at %lx\n", i + 1);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
				size = 2;
			} else if (text[i] == DT_LEAVE &&
			    text[i + 1] == DT_REP && text[i + 2] == DT_RET) {
				dt_dprintf("leave/rep ret at %lx\n", i + 1);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
				size = 3;
			} else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
			    text[i + 2] == DT_POPL_EBP &&
			    text[i + 3] == DT_RET) {
				dt_dprintf("movl/popl/ret at %lx\n", i + 3);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
				size = 4;
			} else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
			    text[i + 2] == DT_POPL_EBP &&
			    text[i + 3] == DT_REP &&
			    text[i + 4] == DT_RET) {
				dt_dprintf("movl/popl/rep ret at %lx\n", i + 3);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
				size = 5;
			}
		}
	} else {
		for (i = 0, end = ftp->ftps_size; i < end; i += size) {
			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;

			/* ordinary ret */
			if (size == 1 && text[i] == DT_RET)
				goto is_ret;

			/* two-byte ret */
			if (size == 2 && text[i] == DT_REP &&
			    text[i + 1] == DT_RET)
				goto is_ret;

			/* ret <imm16> */
			if (size == 3 && text[i] == DT_RET16)
				goto is_ret;

			/* two-byte ret <imm16> */
			if (size == 4 && text[i] == DT_REP &&
			    text[i + 1] == DT_RET16)
				goto is_ret;

			/* 32-bit displacement jmp outside of the function */
			if (size == 5 && text[i] == DT_JMP32 && symp->st_size <=
			    (uintptr_t)(i + size + *(int32_t *)&text[i + 1]))
				goto is_ret;

			/* 8-bit displacement jmp outside of the function */
			if (size == 2 && text[i] == DT_JMP8 && symp->st_size <=
			    (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
				goto is_ret;

			/* 32-bit disp. conditional jmp outside of the func. */
			if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) &&
			    symp->st_size <=
			    (uintptr_t)(i + size + *(int32_t *)&text[i + 2]))
				goto is_ret;

			/* 8-bit disp. conditional jmp outside of the func. */
			if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <=
			    (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
				goto is_ret;

			continue;
is_ret:
			dt_dprintf("return at offset %lx\n", i);
			ftp->ftps_offs[ftp->ftps_noffs++] = i;
		}
	}

	free(text);
	if (ftp->ftps_noffs > 0) {
		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
			    strerror(errno));
			return (dt_set_errno(dtp, errno));
		}
	}

	return (ftp->ftps_noffs);
}
Example #10
0
static int
dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
	char *end;
	int i;
	dtrace_optval_t mul = 1, val = 0;

	const struct {
		char *name;
		hrtime_t mul;
	} suffix[] = {
		{ "ns", 	NANOSEC / NANOSEC },
		{ "nsec",	NANOSEC / NANOSEC },
		{ "us",		NANOSEC / MICROSEC },
		{ "usec",	NANOSEC / MICROSEC },
		{ "ms",		NANOSEC / MILLISEC },
		{ "msec",	NANOSEC / MILLISEC },
		{ "s",		NANOSEC / SEC },
		{ "sec",	NANOSEC / SEC },
		{ "m",		NANOSEC * (hrtime_t)60 },
		{ "min",	NANOSEC * (hrtime_t)60 },
		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
		{ "hz",		0 },
		{ NULL }
	};

	if (arg != NULL) {
#ifndef VBOX
		errno = 0;
		val = strtoull(arg, &end, 0);
#else
		int rc = RTStrToInt64Ex(arg, &end, 0, &val);
		if (rc != VWRN_TRAILING_CHARS)
			return (dt_set_errno(dtp, EDT_BADOPTVAL));
#endif

		for (i = 0; suffix[i].name != NULL; i++) {
			if (strcasecmp(suffix[i].name, end) == 0) {
				mul = suffix[i].mul;
				break;
			}
		}

		if (suffix[i].name == NULL && *end != '\0' || val < 0)
			return (dt_set_errno(dtp, EDT_BADOPTVAL));

		if (mul == 0) {
			/*
			 * The rate has been specified in frequency-per-second.
			 */
			if (val != 0)
				val = NANOSEC / val;
		} else {
			val *= mul;
		}
	}

	dtp->dt_options[option] = val;
	return (0);
}