Home | History | Annotate | Line # | Download | only in dtrace
dtrace_ioctl.c revision 1.6
      1  1.6  christos /*	$NetBSD: dtrace_ioctl.c,v 1.6 2015/09/30 20:59:13 christos Exp $	*/
      2  1.2    darran 
      3  1.1    darran /*
      4  1.1    darran  * CDDL HEADER START
      5  1.1    darran  *
      6  1.1    darran  * The contents of this file are subject to the terms of the
      7  1.1    darran  * Common Development and Distribution License (the "License").
      8  1.1    darran  * You may not use this file except in compliance with the License.
      9  1.1    darran  *
     10  1.1    darran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11  1.1    darran  * or http://www.opensolaris.org/os/licensing.
     12  1.1    darran  * See the License for the specific language governing permissions
     13  1.1    darran  * and limitations under the License.
     14  1.1    darran  *
     15  1.1    darran  * When distributing Covered Code, include this CDDL HEADER in each
     16  1.1    darran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17  1.1    darran  * If applicable, add the following below this CDDL HEADER, with the
     18  1.1    darran  * fields enclosed by brackets "[]" replaced with your own identifying
     19  1.1    darran  * information: Portions Copyright [yyyy] [name of copyright owner]
     20  1.1    darran  *
     21  1.1    darran  * CDDL HEADER END
     22  1.1    darran  *
     23  1.1    darran  * $FreeBSD: src/sys/cddl/dev/dtrace/dtrace_ioctl.c,v 1.2.2.1 2009/08/03 08:13:06 kensmith Exp $
     24  1.1    darran  *
     25  1.1    darran  */
     26  1.1    darran 
     27  1.2    darran static int dtrace_verbose_ioctl=0;
     28  1.2    darran //SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW, &dtrace_verbose_ioctl, 0, "");
     29  1.1    darran 
     30  1.1    darran #define DTRACE_IOCTL_PRINTF(fmt, ...)	if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ )
     31  1.1    darran 
     32  1.1    darran /* ARGSUSED */
     33  1.1    darran static int
     34  1.2    darran dtrace_ioctl(struct file *fp, u_long cmd, void *addr)
     35  1.1    darran {
     36  1.2    darran 	dtrace_state_t *state = (dtrace_state_t *)fp->f_data;
     37  1.1    darran 	int error = 0;
     38  1.2    darran 
     39  1.1    darran 	if (state == NULL)
     40  1.1    darran 		return (EINVAL);
     41  1.1    darran 
     42  1.1    darran 	if (state->dts_anon) {
     43  1.1    darran 		ASSERT(dtrace_anon.dta_state == NULL);
     44  1.1    darran 		state = state->dts_anon;
     45  1.1    darran 	}
     46  1.1    darran 
     47  1.1    darran 	switch (cmd) {
     48  1.1    darran 	case DTRACEIOC_AGGDESC: {
     49  1.1    darran 		dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr;
     50  1.1    darran 		dtrace_aggdesc_t aggdesc;
     51  1.1    darran 		dtrace_action_t *act;
     52  1.1    darran 		dtrace_aggregation_t *agg;
     53  1.1    darran 		int nrecs;
     54  1.1    darran 		uint32_t offs;
     55  1.1    darran 		dtrace_recdesc_t *lrec;
     56  1.1    darran 		void *buf;
     57  1.1    darran 		size_t size;
     58  1.1    darran 		uintptr_t dest;
     59  1.1    darran 
     60  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__);
     61  1.1    darran 
     62  1.1    darran 		if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0)
     63  1.1    darran 			return (EFAULT);
     64  1.1    darran 
     65  1.1    darran 		mutex_enter(&dtrace_lock);
     66  1.1    darran 
     67  1.1    darran 		if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) {
     68  1.1    darran 			mutex_exit(&dtrace_lock);
     69  1.1    darran 			return (EINVAL);
     70  1.1    darran 		}
     71  1.1    darran 
     72  1.1    darran 		aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid;
     73  1.1    darran 
     74  1.1    darran 		nrecs = aggdesc.dtagd_nrecs;
     75  1.1    darran 		aggdesc.dtagd_nrecs = 0;
     76  1.1    darran 
     77  1.1    darran 		offs = agg->dtag_base;
     78  1.1    darran 		lrec = &agg->dtag_action.dta_rec;
     79  1.1    darran 		aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs;
     80  1.1    darran 
     81  1.1    darran 		for (act = agg->dtag_first; ; act = act->dta_next) {
     82  1.1    darran 			ASSERT(act->dta_intuple ||
     83  1.1    darran 			    DTRACEACT_ISAGG(act->dta_kind));
     84  1.1    darran 
     85  1.1    darran 			/*
     86  1.1    darran 			 * If this action has a record size of zero, it
     87  1.1    darran 			 * denotes an argument to the aggregating action.
     88  1.1    darran 			 * Because the presence of this record doesn't (or
     89  1.1    darran 			 * shouldn't) affect the way the data is interpreted,
     90  1.1    darran 			 * we don't copy it out to save user-level the
     91  1.1    darran 			 * confusion of dealing with a zero-length record.
     92  1.1    darran 			 */
     93  1.1    darran 			if (act->dta_rec.dtrd_size == 0) {
     94  1.1    darran 				ASSERT(agg->dtag_hasarg);
     95  1.1    darran 				continue;
     96  1.1    darran 			}
     97  1.1    darran 
     98  1.1    darran 			aggdesc.dtagd_nrecs++;
     99  1.1    darran 
    100  1.1    darran 			if (act == &agg->dtag_action)
    101  1.1    darran 				break;
    102  1.1    darran 		}
    103  1.1    darran 
    104  1.1    darran 		/*
    105  1.1    darran 		 * Now that we have the size, we need to allocate a temporary
    106  1.1    darran 		 * buffer in which to store the complete description.  We need
    107  1.1    darran 		 * the temporary buffer to be able to drop dtrace_lock()
    108  1.1    darran 		 * across the copyout(), below.
    109  1.1    darran 		 */
    110  1.1    darran 		size = sizeof (dtrace_aggdesc_t) +
    111  1.1    darran 		    (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t));
    112  1.1    darran 
    113  1.1    darran 		buf = kmem_alloc(size, KM_SLEEP);
    114  1.1    darran 		dest = (uintptr_t)buf;
    115  1.1    darran 
    116  1.1    darran 		bcopy(&aggdesc, (void *)dest, sizeof (aggdesc));
    117  1.1    darran 		dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]);
    118  1.1    darran 
    119  1.1    darran 		for (act = agg->dtag_first; ; act = act->dta_next) {
    120  1.1    darran 			dtrace_recdesc_t rec = act->dta_rec;
    121  1.1    darran 
    122  1.1    darran 			/*
    123  1.1    darran 			 * See the comment in the above loop for why we pass
    124  1.1    darran 			 * over zero-length records.
    125  1.1    darran 			 */
    126  1.1    darran 			if (rec.dtrd_size == 0) {
    127  1.1    darran 				ASSERT(agg->dtag_hasarg);
    128  1.1    darran 				continue;
    129  1.1    darran 			}
    130  1.1    darran 
    131  1.1    darran 			if (nrecs-- == 0)
    132  1.1    darran 				break;
    133  1.1    darran 
    134  1.1    darran 			rec.dtrd_offset -= offs;
    135  1.1    darran 			bcopy(&rec, (void *)dest, sizeof (rec));
    136  1.1    darran 			dest += sizeof (dtrace_recdesc_t);
    137  1.1    darran 
    138  1.1    darran 			if (act == &agg->dtag_action)
    139  1.1    darran 				break;
    140  1.1    darran 		}
    141  1.1    darran 
    142  1.1    darran 		mutex_exit(&dtrace_lock);
    143  1.1    darran 
    144  1.1    darran 		if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) {
    145  1.1    darran 			kmem_free(buf, size);
    146  1.1    darran 			return (EFAULT);
    147  1.1    darran 		}
    148  1.1    darran 
    149  1.1    darran 		kmem_free(buf, size);
    150  1.1    darran 		return (0);
    151  1.1    darran 	}
    152  1.1    darran 	case DTRACEIOC_AGGSNAP:
    153  1.1    darran 	case DTRACEIOC_BUFSNAP: {
    154  1.1    darran 		dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr;
    155  1.1    darran 		dtrace_bufdesc_t desc;
    156  1.1    darran 		caddr_t cached;
    157  1.1    darran 		dtrace_buffer_t *buf;
    158  1.1    darran 
    159  1.1    darran 		dtrace_debug_output();
    160  1.1    darran 
    161  1.1    darran 		if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0)
    162  1.1    darran 			return (EFAULT);
    163  1.1    darran 
    164  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n",
    165  1.1    darran 		    __func__,__LINE__,
    166  1.1    darran 		    cmd == DTRACEIOC_AGGSNAP ?
    167  1.1    darran 		    "DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP",
    168  1.2    darran 		    cpu_number(), desc.dtbd_cpu);
    169  1.1    darran 
    170  1.3  christos 		if (desc.dtbd_cpu >= ncpu)
    171  1.1    darran 			return (ENOENT);
    172  1.1    darran 
    173  1.1    darran 		mutex_enter(&dtrace_lock);
    174  1.1    darran 
    175  1.1    darran 		if (cmd == DTRACEIOC_BUFSNAP) {
    176  1.1    darran 			buf = &state->dts_buffer[desc.dtbd_cpu];
    177  1.1    darran 		} else {
    178  1.1    darran 			buf = &state->dts_aggbuffer[desc.dtbd_cpu];
    179  1.1    darran 		}
    180  1.1    darran 
    181  1.1    darran 		if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) {
    182  1.1    darran 			size_t sz = buf->dtb_offset;
    183  1.1    darran 
    184  1.1    darran 			if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) {
    185  1.1    darran 				mutex_exit(&dtrace_lock);
    186  1.1    darran 				return (EBUSY);
    187  1.1    darran 			}
    188  1.1    darran 
    189  1.1    darran 			/*
    190  1.1    darran 			 * If this buffer has already been consumed, we're
    191  1.1    darran 			 * going to indicate that there's nothing left here
    192  1.1    darran 			 * to consume.
    193  1.1    darran 			 */
    194  1.1    darran 			if (buf->dtb_flags & DTRACEBUF_CONSUMED) {
    195  1.1    darran 				mutex_exit(&dtrace_lock);
    196  1.1    darran 
    197  1.1    darran 				desc.dtbd_size = 0;
    198  1.1    darran 				desc.dtbd_drops = 0;
    199  1.1    darran 				desc.dtbd_errors = 0;
    200  1.1    darran 				desc.dtbd_oldest = 0;
    201  1.1    darran 				sz = sizeof (desc);
    202  1.1    darran 
    203  1.1    darran 				if (copyout(&desc, (void *) *pdesc, sz) != 0)
    204  1.1    darran 					return (EFAULT);
    205  1.1    darran 
    206  1.1    darran 				return (0);
    207  1.1    darran 			}
    208  1.1    darran 
    209  1.1    darran 			/*
    210  1.1    darran 			 * If this is a ring buffer that has wrapped, we want
    211  1.1    darran 			 * to copy the whole thing out.
    212  1.1    darran 			 */
    213  1.1    darran 			if (buf->dtb_flags & DTRACEBUF_WRAPPED) {
    214  1.1    darran 				dtrace_buffer_polish(buf);
    215  1.1    darran 				sz = buf->dtb_size;
    216  1.1    darran 			}
    217  1.1    darran 
    218  1.1    darran 			if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) {
    219  1.1    darran 				mutex_exit(&dtrace_lock);
    220  1.1    darran 				return (EFAULT);
    221  1.1    darran 			}
    222  1.1    darran 
    223  1.1    darran 			desc.dtbd_size = sz;
    224  1.1    darran 			desc.dtbd_drops = buf->dtb_drops;
    225  1.1    darran 			desc.dtbd_errors = buf->dtb_errors;
    226  1.1    darran 			desc.dtbd_oldest = buf->dtb_xamot_offset;
    227  1.1    darran 
    228  1.1    darran 			mutex_exit(&dtrace_lock);
    229  1.1    darran 
    230  1.1    darran 			if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
    231  1.1    darran 				return (EFAULT);
    232  1.1    darran 
    233  1.1    darran 			buf->dtb_flags |= DTRACEBUF_CONSUMED;
    234  1.1    darran 
    235  1.1    darran 			return (0);
    236  1.1    darran 		}
    237  1.1    darran 
    238  1.1    darran 		if (buf->dtb_tomax == NULL) {
    239  1.1    darran 			ASSERT(buf->dtb_xamot == NULL);
    240  1.1    darran 			mutex_exit(&dtrace_lock);
    241  1.1    darran 			return (ENOENT);
    242  1.1    darran 		}
    243  1.1    darran 
    244  1.1    darran 		cached = buf->dtb_tomax;
    245  1.1    darran 		ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH));
    246  1.1    darran 
    247  1.1    darran 		dtrace_xcall(desc.dtbd_cpu,
    248  1.1    darran 		    (dtrace_xcall_t)dtrace_buffer_switch, buf);
    249  1.1    darran 
    250  1.1    darran 		state->dts_errors += buf->dtb_xamot_errors;
    251  1.1    darran 
    252  1.1    darran 		/*
    253  1.1    darran 		 * If the buffers did not actually switch, then the cross call
    254  1.1    darran 		 * did not take place -- presumably because the given CPU is
    255  1.1    darran 		 * not in the ready set.  If this is the case, we'll return
    256  1.1    darran 		 * ENOENT.
    257  1.1    darran 		 */
    258  1.1    darran 		if (buf->dtb_tomax == cached) {
    259  1.1    darran 			ASSERT(buf->dtb_xamot != cached);
    260  1.1    darran 			mutex_exit(&dtrace_lock);
    261  1.1    darran 			return (ENOENT);
    262  1.1    darran 		}
    263  1.1    darran 
    264  1.1    darran 		ASSERT(cached == buf->dtb_xamot);
    265  1.1    darran 
    266  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__);
    267  1.1    darran 
    268  1.1    darran 		/*
    269  1.1    darran 		 * We have our snapshot; now copy it out.
    270  1.1    darran 		 */
    271  1.1    darran 		if (copyout(buf->dtb_xamot, desc.dtbd_data,
    272  1.1    darran 		    buf->dtb_xamot_offset) != 0) {
    273  1.1    darran 			mutex_exit(&dtrace_lock);
    274  1.1    darran 			return (EFAULT);
    275  1.1    darran 		}
    276  1.1    darran 
    277  1.1    darran 		desc.dtbd_size = buf->dtb_xamot_offset;
    278  1.1    darran 		desc.dtbd_drops = buf->dtb_xamot_drops;
    279  1.1    darran 		desc.dtbd_errors = buf->dtb_xamot_errors;
    280  1.1    darran 		desc.dtbd_oldest = 0;
    281  1.1    darran 
    282  1.1    darran 		mutex_exit(&dtrace_lock);
    283  1.1    darran 
    284  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): copyout buffer desc: size %zd drops %lu errors %lu\n",__func__,__LINE__,(size_t) desc.dtbd_size,(u_long) desc.dtbd_drops,(u_long) desc.dtbd_errors);
    285  1.1    darran 
    286  1.1    darran 		/*
    287  1.1    darran 		 * Finally, copy out the buffer description.
    288  1.1    darran 		 */
    289  1.1    darran 		if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
    290  1.1    darran 			return (EFAULT);
    291  1.1    darran 
    292  1.1    darran 		return (0);
    293  1.1    darran 	}
    294  1.1    darran 	case DTRACEIOC_CONF: {
    295  1.1    darran 		dtrace_conf_t conf;
    296  1.1    darran 
    297  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__);
    298  1.1    darran 
    299  1.1    darran 		bzero(&conf, sizeof (conf));
    300  1.1    darran 		conf.dtc_difversion = DIF_VERSION;
    301  1.1    darran 		conf.dtc_difintregs = DIF_DIR_NREGS;
    302  1.1    darran 		conf.dtc_diftupregs = DIF_DTR_NREGS;
    303  1.1    darran 		conf.dtc_ctfmodel = CTF_MODEL_NATIVE;
    304  1.1    darran 
    305  1.1    darran 		*((dtrace_conf_t *) addr) = conf;
    306  1.1    darran 
    307  1.1    darran 		return (0);
    308  1.1    darran 	}
    309  1.1    darran 	case DTRACEIOC_DOFGET: {
    310  1.1    darran 		dof_hdr_t **pdof = (dof_hdr_t **) addr;
    311  1.1    darran 		dof_hdr_t hdr, *dof = *pdof;
    312  1.1    darran 		int rval;
    313  1.1    darran 		uint64_t len;
    314  1.1    darran 
    315  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__);
    316  1.1    darran 
    317  1.1    darran 		if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0)
    318  1.1    darran 			return (EFAULT);
    319  1.1    darran 
    320  1.1    darran 		mutex_enter(&dtrace_lock);
    321  1.1    darran 		dof = dtrace_dof_create(state);
    322  1.1    darran 		mutex_exit(&dtrace_lock);
    323  1.1    darran 
    324  1.1    darran 		len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz);
    325  1.1    darran 		rval = copyout(dof, (void *) *pdof, len);
    326  1.1    darran 		dtrace_dof_destroy(dof);
    327  1.1    darran 
    328  1.1    darran 		return (rval == 0 ? 0 : EFAULT);
    329  1.1    darran 	}
    330  1.1    darran 	case DTRACEIOC_ENABLE: {
    331  1.1    darran 		dof_hdr_t *dof = NULL;
    332  1.1    darran 		dtrace_enabling_t *enab = NULL;
    333  1.1    darran 		dtrace_vstate_t *vstate;
    334  1.1    darran 		int err = 0;
    335  1.1    darran 		int rval;
    336  1.1    darran 		dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr;
    337  1.1    darran 
    338  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__);
    339  1.1    darran 
    340  1.1    darran 		/*
    341  1.1    darran 		 * If a NULL argument has been passed, we take this as our
    342  1.1    darran 		 * cue to reevaluate our enablings.
    343  1.1    darran 		 */
    344  1.1    darran 		if (p->dof == NULL) {
    345  1.1    darran 			dtrace_enabling_matchall();
    346  1.1    darran 
    347  1.1    darran 			return (0);
    348  1.1    darran 		}
    349  1.1    darran 
    350  1.1    darran 		if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL)
    351  1.1    darran 			return (EINVAL);
    352  1.1    darran 
    353  1.1    darran 		mutex_enter(&cpu_lock);
    354  1.1    darran 		mutex_enter(&dtrace_lock);
    355  1.1    darran 		vstate = &state->dts_vstate;
    356  1.1    darran 
    357  1.1    darran 		if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) {
    358  1.1    darran 			mutex_exit(&dtrace_lock);
    359  1.1    darran 			mutex_exit(&cpu_lock);
    360  1.1    darran 			dtrace_dof_destroy(dof);
    361  1.1    darran 			return (EBUSY);
    362  1.1    darran 		}
    363  1.1    darran 
    364  1.2    darran 		if (dtrace_dof_slurp(dof, vstate, curlwp->l_cred, &enab, 0, B_TRUE) != 0) {
    365  1.1    darran 			mutex_exit(&dtrace_lock);
    366  1.1    darran 			mutex_exit(&cpu_lock);
    367  1.1    darran 			dtrace_dof_destroy(dof);
    368  1.1    darran 			return (EINVAL);
    369  1.1    darran 		}
    370  1.1    darran 
    371  1.1    darran 		if ((rval = dtrace_dof_options(dof, state)) != 0) {
    372  1.1    darran 			dtrace_enabling_destroy(enab);
    373  1.1    darran 			mutex_exit(&dtrace_lock);
    374  1.1    darran 			mutex_exit(&cpu_lock);
    375  1.1    darran 			dtrace_dof_destroy(dof);
    376  1.1    darran 			return (rval);
    377  1.1    darran 		}
    378  1.1    darran 
    379  1.1    darran 		if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) {
    380  1.1    darran 			err = dtrace_enabling_retain(enab);
    381  1.1    darran 		} else {
    382  1.1    darran 			dtrace_enabling_destroy(enab);
    383  1.1    darran 		}
    384  1.1    darran 
    385  1.1    darran 		mutex_exit(&cpu_lock);
    386  1.1    darran 		mutex_exit(&dtrace_lock);
    387  1.1    darran 		dtrace_dof_destroy(dof);
    388  1.1    darran 
    389  1.1    darran 		return (err);
    390  1.1    darran 	}
    391  1.1    darran 	case DTRACEIOC_EPROBE: {
    392  1.1    darran 		dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr;
    393  1.1    darran 		dtrace_eprobedesc_t epdesc;
    394  1.1    darran 		dtrace_ecb_t *ecb;
    395  1.1    darran 		dtrace_action_t *act;
    396  1.1    darran 		void *buf;
    397  1.1    darran 		size_t size;
    398  1.1    darran 		uintptr_t dest;
    399  1.1    darran 		int nrecs;
    400  1.1    darran 
    401  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__);
    402  1.1    darran 
    403  1.1    darran 		if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0)
    404  1.1    darran 			return (EFAULT);
    405  1.1    darran 
    406  1.1    darran 		mutex_enter(&dtrace_lock);
    407  1.1    darran 
    408  1.1    darran 		if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) {
    409  1.1    darran 			mutex_exit(&dtrace_lock);
    410  1.1    darran 			return (EINVAL);
    411  1.1    darran 		}
    412  1.1    darran 
    413  1.1    darran 		if (ecb->dte_probe == NULL) {
    414  1.1    darran 			mutex_exit(&dtrace_lock);
    415  1.1    darran 			return (EINVAL);
    416  1.1    darran 		}
    417  1.1    darran 
    418  1.1    darran 		epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id;
    419  1.1    darran 		epdesc.dtepd_uarg = ecb->dte_uarg;
    420  1.1    darran 		epdesc.dtepd_size = ecb->dte_size;
    421  1.1    darran 
    422  1.1    darran 		nrecs = epdesc.dtepd_nrecs;
    423  1.1    darran 		epdesc.dtepd_nrecs = 0;
    424  1.1    darran 		for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
    425  1.1    darran 			if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
    426  1.1    darran 				continue;
    427  1.1    darran 
    428  1.1    darran 			epdesc.dtepd_nrecs++;
    429  1.1    darran 		}
    430  1.1    darran 
    431  1.1    darran 		/*
    432  1.1    darran 		 * Now that we have the size, we need to allocate a temporary
    433  1.1    darran 		 * buffer in which to store the complete description.  We need
    434  1.1    darran 		 * the temporary buffer to be able to drop dtrace_lock()
    435  1.1    darran 		 * across the copyout(), below.
    436  1.1    darran 		 */
    437  1.1    darran 		size = sizeof (dtrace_eprobedesc_t) +
    438  1.1    darran 		    (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t));
    439  1.1    darran 
    440  1.1    darran 		buf = kmem_alloc(size, KM_SLEEP);
    441  1.1    darran 		dest = (uintptr_t)buf;
    442  1.1    darran 
    443  1.1    darran 		bcopy(&epdesc, (void *)dest, sizeof (epdesc));
    444  1.1    darran 		dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]);
    445  1.1    darran 
    446  1.1    darran 		for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
    447  1.1    darran 			if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
    448  1.1    darran 				continue;
    449  1.1    darran 
    450  1.1    darran 			if (nrecs-- == 0)
    451  1.1    darran 				break;
    452  1.1    darran 
    453  1.1    darran 			bcopy(&act->dta_rec, (void *)dest,
    454  1.1    darran 			    sizeof (dtrace_recdesc_t));
    455  1.1    darran 			dest += sizeof (dtrace_recdesc_t);
    456  1.1    darran 		}
    457  1.1    darran 
    458  1.1    darran 		mutex_exit(&dtrace_lock);
    459  1.1    darran 
    460  1.1    darran 		if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) {
    461  1.1    darran 			kmem_free(buf, size);
    462  1.1    darran 			return (EFAULT);
    463  1.1    darran 		}
    464  1.1    darran 
    465  1.1    darran 		kmem_free(buf, size);
    466  1.1    darran 		return (0);
    467  1.1    darran 	}
    468  1.1    darran 	case DTRACEIOC_FORMAT: {
    469  1.1    darran 		dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr;
    470  1.1    darran 		char *str;
    471  1.1    darran 		int len;
    472  1.1    darran 
    473  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__);
    474  1.1    darran 
    475  1.1    darran 		mutex_enter(&dtrace_lock);
    476  1.1    darran 
    477  1.1    darran 		if (fmt->dtfd_format == 0 ||
    478  1.1    darran 		    fmt->dtfd_format > state->dts_nformats) {
    479  1.1    darran 			mutex_exit(&dtrace_lock);
    480  1.1    darran 			return (EINVAL);
    481  1.1    darran 		}
    482  1.1    darran 
    483  1.1    darran 		/*
    484  1.1    darran 		 * Format strings are allocated contiguously and they are
    485  1.1    darran 		 * never freed; if a format index is less than the number
    486  1.1    darran 		 * of formats, we can assert that the format map is non-NULL
    487  1.1    darran 		 * and that the format for the specified index is non-NULL.
    488  1.1    darran 		 */
    489  1.1    darran 		ASSERT(state->dts_formats != NULL);
    490  1.1    darran 		str = state->dts_formats[fmt->dtfd_format - 1];
    491  1.1    darran 		ASSERT(str != NULL);
    492  1.1    darran 
    493  1.1    darran 		len = strlen(str) + 1;
    494  1.1    darran 
    495  1.1    darran 		if (len > fmt->dtfd_length) {
    496  1.1    darran 			fmt->dtfd_length = len;
    497  1.1    darran 		} else {
    498  1.1    darran 			if (copyout(str, fmt->dtfd_string, len) != 0) {
    499  1.1    darran 				mutex_exit(&dtrace_lock);
    500  1.1    darran 				return (EINVAL);
    501  1.1    darran 			}
    502  1.1    darran 		}
    503  1.1    darran 
    504  1.1    darran 		mutex_exit(&dtrace_lock);
    505  1.1    darran 		return (0);
    506  1.1    darran 	}
    507  1.1    darran 	case DTRACEIOC_GO: {
    508  1.1    darran 		int rval;
    509  1.1    darran 		processorid_t *cpuid = (processorid_t *) addr;
    510  1.1    darran 
    511  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__);
    512  1.1    darran 
    513  1.1    darran 		rval = dtrace_state_go(state, cpuid);
    514  1.1    darran 
    515  1.1    darran 		return (rval);
    516  1.1    darran 	}
    517  1.1    darran 	case DTRACEIOC_PROBEARG: {
    518  1.1    darran 		dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr;
    519  1.1    darran 		dtrace_probe_t *probe;
    520  1.1    darran 		dtrace_provider_t *prov;
    521  1.1    darran 
    522  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__);
    523  1.1    darran 
    524  1.1    darran 		if (desc->dtargd_id == DTRACE_IDNONE)
    525  1.1    darran 			return (EINVAL);
    526  1.1    darran 
    527  1.1    darran 		if (desc->dtargd_ndx == DTRACE_ARGNONE)
    528  1.1    darran 			return (EINVAL);
    529  1.1    darran 
    530  1.1    darran 		mutex_enter(&dtrace_provider_lock);
    531  1.1    darran 		mutex_enter(&mod_lock);
    532  1.1    darran 		mutex_enter(&dtrace_lock);
    533  1.1    darran 
    534  1.1    darran 		if (desc->dtargd_id > dtrace_nprobes) {
    535  1.1    darran 			mutex_exit(&dtrace_lock);
    536  1.1    darran 			mutex_exit(&mod_lock);
    537  1.1    darran 			mutex_exit(&dtrace_provider_lock);
    538  1.1    darran 			return (EINVAL);
    539  1.1    darran 		}
    540  1.1    darran 
    541  1.1    darran 		if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) {
    542  1.1    darran 			mutex_exit(&dtrace_lock);
    543  1.1    darran 			mutex_exit(&mod_lock);
    544  1.1    darran 			mutex_exit(&dtrace_provider_lock);
    545  1.1    darran 			return (EINVAL);
    546  1.1    darran 		}
    547  1.1    darran 
    548  1.1    darran 		mutex_exit(&dtrace_lock);
    549  1.1    darran 
    550  1.1    darran 		prov = probe->dtpr_provider;
    551  1.1    darran 
    552  1.1    darran 		if (prov->dtpv_pops.dtps_getargdesc == NULL) {
    553  1.1    darran 			/*
    554  1.1    darran 			 * There isn't any typed information for this probe.
    555  1.1    darran 			 * Set the argument number to DTRACE_ARGNONE.
    556  1.1    darran 			 */
    557  1.1    darran 			desc->dtargd_ndx = DTRACE_ARGNONE;
    558  1.1    darran 		} else {
    559  1.1    darran 			desc->dtargd_native[0] = '\0';
    560  1.1    darran 			desc->dtargd_xlate[0] = '\0';
    561  1.1    darran 			desc->dtargd_mapping = desc->dtargd_ndx;
    562  1.1    darran 
    563  1.1    darran 			prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg,
    564  1.1    darran 			    probe->dtpr_id, probe->dtpr_arg, desc);
    565  1.1    darran 		}
    566  1.1    darran 
    567  1.1    darran 		mutex_exit(&mod_lock);
    568  1.1    darran 		mutex_exit(&dtrace_provider_lock);
    569  1.1    darran 
    570  1.1    darran 		return (0);
    571  1.1    darran 	}
    572  1.1    darran 	case DTRACEIOC_PROBEMATCH:
    573  1.1    darran 	case DTRACEIOC_PROBES: {
    574  1.1    darran 		dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr;
    575  1.1    darran 		dtrace_probe_t *probe = NULL;
    576  1.1    darran 		dtrace_probekey_t pkey;
    577  1.1    darran 		dtrace_id_t i;
    578  1.1    darran 		int m = 0;
    579  1.1    darran 		uint32_t priv = 0;
    580  1.1    darran 		uid_t uid = 0;
    581  1.1    darran 		zoneid_t zoneid = 0;
    582  1.1    darran 
    583  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__,
    584  1.1    darran 		    cmd == DTRACEIOC_PROBEMATCH ?
    585  1.1    darran 		    "DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES");
    586  1.1    darran 
    587  1.1    darran 		p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
    588  1.1    darran 		p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
    589  1.1    darran 		p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
    590  1.1    darran 		p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
    591  1.1    darran 
    592  1.1    darran 		/*
    593  1.1    darran 		 * Before we attempt to match this probe, we want to give
    594  1.1    darran 		 * all providers the opportunity to provide it.
    595  1.1    darran 		 */
    596  1.1    darran 		if (p_desc->dtpd_id == DTRACE_IDNONE) {
    597  1.1    darran 			mutex_enter(&dtrace_provider_lock);
    598  1.1    darran 			dtrace_probe_provide(p_desc, NULL);
    599  1.1    darran 			mutex_exit(&dtrace_provider_lock);
    600  1.1    darran 			p_desc->dtpd_id++;
    601  1.1    darran 		}
    602  1.1    darran 
    603  1.1    darran 		if (cmd == DTRACEIOC_PROBEMATCH)  {
    604  1.1    darran 			dtrace_probekey(p_desc, &pkey);
    605  1.1    darran 			pkey.dtpk_id = DTRACE_IDNONE;
    606  1.1    darran 		}
    607  1.1    darran 
    608  1.2    darran 		dtrace_cred2priv(curlwp->l_cred, &priv, &uid, &zoneid);
    609  1.1    darran 
    610  1.1    darran 		mutex_enter(&dtrace_lock);
    611  1.1    darran 
    612  1.1    darran 		if (cmd == DTRACEIOC_PROBEMATCH) {
    613  1.1    darran 			for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
    614  1.1    darran 				if ((probe = dtrace_probes[i - 1]) != NULL &&
    615  1.1    darran 				    (m = dtrace_match_probe(probe, &pkey,
    616  1.1    darran 				    priv, uid, zoneid)) != 0)
    617  1.1    darran 					break;
    618  1.1    darran 			}
    619  1.1    darran 
    620  1.1    darran 			if (m < 0) {
    621  1.1    darran 				mutex_exit(&dtrace_lock);
    622  1.1    darran 				return (EINVAL);
    623  1.1    darran 			}
    624  1.1    darran 
    625  1.1    darran 		} else {
    626  1.1    darran 			for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
    627  1.1    darran 				if ((probe = dtrace_probes[i - 1]) != NULL &&
    628  1.1    darran 				    dtrace_match_priv(probe, priv, uid, zoneid))
    629  1.1    darran 					break;
    630  1.1    darran 			}
    631  1.1    darran 		}
    632  1.1    darran 
    633  1.1    darran 		if (probe == NULL) {
    634  1.1    darran 			mutex_exit(&dtrace_lock);
    635  1.1    darran 			return (ESRCH);
    636  1.1    darran 		}
    637  1.1    darran 
    638  1.1    darran 		dtrace_probe_description(probe, p_desc);
    639  1.1    darran 		mutex_exit(&dtrace_lock);
    640  1.1    darran 
    641  1.1    darran 		return (0);
    642  1.1    darran 	}
    643  1.1    darran 	case DTRACEIOC_PROVIDER: {
    644  1.1    darran 		dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr;
    645  1.1    darran 		dtrace_provider_t *pvp;
    646  1.1    darran 
    647  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__);
    648  1.1    darran 
    649  1.1    darran 		pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0';
    650  1.4  christos 		error = 0;
    651  1.4  christos again:
    652  1.1    darran 		mutex_enter(&dtrace_provider_lock);
    653  1.1    darran 
    654  1.1    darran 		for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) {
    655  1.1    darran 			if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0)
    656  1.1    darran 				break;
    657  1.1    darran 		}
    658  1.1    darran 
    659  1.1    darran 		mutex_exit(&dtrace_provider_lock);
    660  1.1    darran 
    661  1.4  christos 		if (pvp == NULL && error == 0) {
    662  1.5  riastrad 			char name[NAME_MAX];
    663  1.6  christos 			const char *provider;
    664  1.6  christos 			if (strcmp(pvd->dtvd_name, "proc") == 0)
    665  1.6  christos 				provider = "sdt";
    666  1.6  christos 			else
    667  1.6  christos 				provider = pvd->dtvd_name;
    668  1.5  riastrad 
    669  1.5  riastrad 			if (snprintf(name, sizeof name, "dtrace_%s",
    670  1.6  christos 			    provider) < sizeof name) {
    671  1.5  riastrad 				error = module_autoload(name,
    672  1.5  riastrad 				    MODULE_CLASS_MISC);
    673  1.5  riastrad 				if (error == 0)
    674  1.5  riastrad 					goto again;
    675  1.5  riastrad 			}
    676  1.4  christos 		}
    677  1.4  christos 
    678  1.1    darran 		if (pvp == NULL)
    679  1.1    darran 			return (ESRCH);
    680  1.1    darran 
    681  1.1    darran 		bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t));
    682  1.1    darran 		bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t));
    683  1.1    darran 
    684  1.1    darran 		return (0);
    685  1.1    darran 	}
    686  1.1    darran 	case DTRACEIOC_REPLICATE: {
    687  1.1    darran 		dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr;
    688  1.1    darran 		dtrace_probedesc_t *match = &desc->dtrpd_match;
    689  1.1    darran 		dtrace_probedesc_t *create = &desc->dtrpd_create;
    690  1.1    darran 		int err;
    691  1.1    darran 
    692  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__);
    693  1.1    darran 
    694  1.1    darran 		match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
    695  1.1    darran 		match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
    696  1.1    darran 		match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
    697  1.1    darran 		match->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
    698  1.1    darran 
    699  1.1    darran 		create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
    700  1.1    darran 		create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
    701  1.1    darran 		create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
    702  1.1    darran 		create->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
    703  1.1    darran 
    704  1.1    darran 		mutex_enter(&dtrace_lock);
    705  1.1    darran 		err = dtrace_enabling_replicate(state, match, create);
    706  1.1    darran 		mutex_exit(&dtrace_lock);
    707  1.1    darran 
    708  1.1    darran 		return (err);
    709  1.1    darran 	}
    710  1.1    darran 	case DTRACEIOC_STATUS: {
    711  1.1    darran 		dtrace_status_t *stat = (dtrace_status_t *) addr;
    712  1.1    darran 		dtrace_dstate_t *dstate;
    713  1.2    darran 		int j;
    714  1.1    darran 		uint64_t nerrs;
    715  1.2    darran 		CPU_INFO_ITERATOR cpuind;
    716  1.2    darran 		struct cpu_info *cinfo;
    717  1.1    darran 
    718  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__);
    719  1.1    darran 
    720  1.1    darran 		/*
    721  1.1    darran 		 * See the comment in dtrace_state_deadman() for the reason
    722  1.1    darran 		 * for setting dts_laststatus to INT64_MAX before setting
    723  1.1    darran 		 * it to the correct value.
    724  1.1    darran 		 */
    725  1.1    darran 		state->dts_laststatus = INT64_MAX;
    726  1.1    darran 		dtrace_membar_producer();
    727  1.1    darran 		state->dts_laststatus = dtrace_gethrtime();
    728  1.1    darran 
    729  1.1    darran 		bzero(stat, sizeof (*stat));
    730  1.1    darran 
    731  1.1    darran 		mutex_enter(&dtrace_lock);
    732  1.1    darran 
    733  1.1    darran 		if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
    734  1.1    darran 			mutex_exit(&dtrace_lock);
    735  1.1    darran 			return (ENOENT);
    736  1.1    darran 		}
    737  1.1    darran 
    738  1.1    darran 		if (state->dts_activity == DTRACE_ACTIVITY_DRAINING)
    739  1.1    darran 			stat->dtst_exiting = 1;
    740  1.1    darran 
    741  1.1    darran 		nerrs = state->dts_errors;
    742  1.1    darran 		dstate = &state->dts_vstate.dtvs_dynvars;
    743  1.1    darran 
    744  1.2    darran 		for (CPU_INFO_FOREACH(cpuind, cinfo)) {
    745  1.2    darran 		    	int ci = cpu_index(cinfo);
    746  1.2    darran 			dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[ci];
    747  1.1    darran 
    748  1.1    darran 			stat->dtst_dyndrops += dcpu->dtdsc_drops;
    749  1.1    darran 			stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops;
    750  1.1    darran 			stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops;
    751  1.1    darran 
    752  1.2    darran 			if (state->dts_buffer[ci].dtb_flags & DTRACEBUF_FULL)
    753  1.1    darran 				stat->dtst_filled++;
    754  1.1    darran 
    755  1.2    darran 			nerrs += state->dts_buffer[ci].dtb_errors;
    756  1.1    darran 
    757  1.1    darran 			for (j = 0; j < state->dts_nspeculations; j++) {
    758  1.1    darran 				dtrace_speculation_t *spec;
    759  1.1    darran 				dtrace_buffer_t *buf;
    760  1.1    darran 
    761  1.1    darran 				spec = &state->dts_speculations[j];
    762  1.2    darran 				buf = &spec->dtsp_buffer[ci];
    763  1.1    darran 				stat->dtst_specdrops += buf->dtb_xamot_drops;
    764  1.1    darran 			}
    765  1.1    darran 		}
    766  1.1    darran 
    767  1.1    darran 		stat->dtst_specdrops_busy = state->dts_speculations_busy;
    768  1.1    darran 		stat->dtst_specdrops_unavail = state->dts_speculations_unavail;
    769  1.1    darran 		stat->dtst_stkstroverflows = state->dts_stkstroverflows;
    770  1.1    darran 		stat->dtst_dblerrors = state->dts_dblerrors;
    771  1.1    darran 		stat->dtst_killed =
    772  1.1    darran 		    (state->dts_activity == DTRACE_ACTIVITY_KILLED);
    773  1.1    darran 		stat->dtst_errors = nerrs;
    774  1.1    darran 
    775  1.1    darran 		mutex_exit(&dtrace_lock);
    776  1.1    darran 
    777  1.1    darran 		return (0);
    778  1.1    darran 	}
    779  1.1    darran 	case DTRACEIOC_STOP: {
    780  1.1    darran 		processorid_t *cpuid = (processorid_t *) addr;
    781  1.1    darran 
    782  1.1    darran 		DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__);
    783  1.1    darran 
    784  1.1    darran 		mutex_enter(&dtrace_lock);
    785  1.4  christos 		error = dtrace_state_stop(state, cpuid);
    786  1.1    darran 		mutex_exit(&dtrace_lock);
    787  1.1    darran 
    788  1.4  christos 		return (error);
    789  1.1    darran 	}
    790  1.1    darran 	default:
    791  1.1    darran 		error = ENOTTY;
    792  1.1    darran 	}
    793  1.1    darran 	return (error);
    794  1.1    darran }
    795