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