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