Path: blob/main/sys/cddl/dev/dtrace/dtrace_ioctl.c
48254 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*20*/2122static int dtrace_verbose_ioctl;23SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW,24&dtrace_verbose_ioctl, 0, "log DTrace ioctls");2526#define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ )2728static int29dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,30struct thread *td)31{32struct proc *p;33dof_helper_t *dhp;34dof_hdr_t *dof;35int rval;3637dhp = NULL;38dof = NULL;39rval = 0;40switch (cmd) {41case DTRACEHIOC_ADDDOF:42dhp = (dof_helper_t *)addr;43addr = (caddr_t)(uintptr_t)dhp->dofhp_dof;44p = curproc;45if (p->p_pid == dhp->dofhp_pid) {46dof = dtrace_dof_copyin((uintptr_t)addr, &rval);47} else {48p = pfind(dhp->dofhp_pid);49if (p == NULL)50return (EINVAL);51if (!P_SHOULDSTOP(p) ||52(p->p_flag & (P_TRACED | P_WEXIT)) != P_TRACED ||53p->p_pptr != curproc) {54PROC_UNLOCK(p);55return (EINVAL);56}57_PHOLD(p);58PROC_UNLOCK(p);59dof = dtrace_dof_copyin_proc(p, (uintptr_t)addr, &rval);60}6162if (dof == NULL) {63if (p != curproc)64PRELE(p);65break;66}6768mutex_enter(&dtrace_lock);69if ((rval = dtrace_helper_slurp(dof, dhp, p)) != -1) {70dhp->dofhp_gen = rval;71rval = 0;72} else {73rval = EINVAL;74}75mutex_exit(&dtrace_lock);76if (p != curproc)77PRELE(p);78break;79case DTRACEHIOC_REMOVE:80mutex_enter(&dtrace_lock);81rval = dtrace_helper_destroygen(NULL, *(int *)(uintptr_t)addr);82mutex_exit(&dtrace_lock);83break;84default:85rval = ENOTTY;86break;87}88return (rval);89}9091/* ARGSUSED */92static int93dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,94int flags __unused, struct thread *td)95{96dtrace_state_t *state;97devfs_get_cdevpriv((void **) &state);9899int error = 0;100if (state == NULL)101return (EINVAL);102103if (state->dts_anon) {104ASSERT(dtrace_anon.dta_state == NULL);105state = state->dts_anon;106}107108switch (cmd) {109case DTRACEIOC_AGGDESC: {110dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr;111dtrace_aggdesc_t aggdesc;112dtrace_action_t *act;113dtrace_aggregation_t *agg;114int nrecs;115uint32_t offs;116dtrace_recdesc_t *lrec;117void *buf;118size_t size;119uintptr_t dest;120121DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__);122123if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0)124return (EFAULT);125126mutex_enter(&dtrace_lock);127128if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) {129mutex_exit(&dtrace_lock);130return (EINVAL);131}132133aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid;134135nrecs = aggdesc.dtagd_nrecs;136aggdesc.dtagd_nrecs = 0;137138offs = agg->dtag_base;139lrec = &agg->dtag_action.dta_rec;140aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs;141142for (act = agg->dtag_first; ; act = act->dta_next) {143ASSERT(act->dta_intuple ||144DTRACEACT_ISAGG(act->dta_kind));145146/*147* If this action has a record size of zero, it148* denotes an argument to the aggregating action.149* Because the presence of this record doesn't (or150* shouldn't) affect the way the data is interpreted,151* we don't copy it out to save user-level the152* confusion of dealing with a zero-length record.153*/154if (act->dta_rec.dtrd_size == 0) {155ASSERT(agg->dtag_hasarg);156continue;157}158159aggdesc.dtagd_nrecs++;160161if (act == &agg->dtag_action)162break;163}164165/*166* Now that we have the size, we need to allocate a temporary167* buffer in which to store the complete description. We need168* the temporary buffer to be able to drop dtrace_lock()169* across the copyout(), below.170*/171size = sizeof (dtrace_aggdesc_t) +172(aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t));173174buf = kmem_alloc(size, KM_SLEEP);175dest = (uintptr_t)buf;176177bcopy(&aggdesc, (void *)dest, sizeof (aggdesc));178dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]);179180for (act = agg->dtag_first; ; act = act->dta_next) {181dtrace_recdesc_t rec = act->dta_rec;182183/*184* See the comment in the above loop for why we pass185* over zero-length records.186*/187if (rec.dtrd_size == 0) {188ASSERT(agg->dtag_hasarg);189continue;190}191192if (nrecs-- == 0)193break;194195rec.dtrd_offset -= offs;196bcopy(&rec, (void *)dest, sizeof (rec));197dest += sizeof (dtrace_recdesc_t);198199if (act == &agg->dtag_action)200break;201}202203mutex_exit(&dtrace_lock);204205if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) {206kmem_free(buf, size);207return (EFAULT);208}209210kmem_free(buf, size);211return (0);212}213case DTRACEIOC_AGGSNAP:214case DTRACEIOC_BUFSNAP: {215dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr;216dtrace_bufdesc_t desc;217caddr_t cached;218dtrace_buffer_t *buf;219220dtrace_debug_output();221222if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0)223return (EFAULT);224225DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n",226__func__,__LINE__,227cmd == DTRACEIOC_AGGSNAP ?228"DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP",229curcpu, desc.dtbd_cpu);230231if (desc.dtbd_cpu > mp_maxid || CPU_ABSENT(desc.dtbd_cpu))232return (ENOENT);233234mutex_enter(&dtrace_lock);235236if (cmd == DTRACEIOC_BUFSNAP) {237buf = &state->dts_buffer[desc.dtbd_cpu];238} else {239buf = &state->dts_aggbuffer[desc.dtbd_cpu];240}241242if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) {243size_t sz = buf->dtb_offset;244245if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) {246mutex_exit(&dtrace_lock);247return (EBUSY);248}249250/*251* If this buffer has already been consumed, we're252* going to indicate that there's nothing left here253* to consume.254*/255if (buf->dtb_flags & DTRACEBUF_CONSUMED) {256mutex_exit(&dtrace_lock);257258desc.dtbd_size = 0;259desc.dtbd_drops = 0;260desc.dtbd_errors = 0;261desc.dtbd_oldest = 0;262sz = sizeof (desc);263264if (copyout(&desc, (void *) *pdesc, sz) != 0)265return (EFAULT);266267return (0);268}269270/*271* If this is a ring buffer that has wrapped, we want272* to copy the whole thing out.273*/274if (buf->dtb_flags & DTRACEBUF_WRAPPED) {275dtrace_buffer_polish(buf);276sz = buf->dtb_size;277}278279if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) {280mutex_exit(&dtrace_lock);281return (EFAULT);282}283284desc.dtbd_size = sz;285desc.dtbd_drops = buf->dtb_drops;286desc.dtbd_errors = buf->dtb_errors;287desc.dtbd_oldest = buf->dtb_xamot_offset;288desc.dtbd_timestamp = dtrace_gethrtime();289290mutex_exit(&dtrace_lock);291292if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)293return (EFAULT);294295buf->dtb_flags |= DTRACEBUF_CONSUMED;296297return (0);298}299300if (buf->dtb_tomax == NULL) {301ASSERT(buf->dtb_xamot == NULL);302mutex_exit(&dtrace_lock);303return (ENOENT);304}305306cached = buf->dtb_tomax;307ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH));308309dtrace_xcall(desc.dtbd_cpu,310(dtrace_xcall_t)dtrace_buffer_switch, buf);311312state->dts_errors += buf->dtb_xamot_errors;313314/*315* If the buffers did not actually switch, then the cross call316* did not take place -- presumably because the given CPU is317* not in the ready set. If this is the case, we'll return318* ENOENT.319*/320if (buf->dtb_tomax == cached) {321ASSERT(buf->dtb_xamot != cached);322mutex_exit(&dtrace_lock);323return (ENOENT);324}325326ASSERT(cached == buf->dtb_xamot);327328DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__);329330/*331* We have our snapshot; now copy it out.332*/333if (copyout(buf->dtb_xamot, desc.dtbd_data,334buf->dtb_xamot_offset) != 0) {335mutex_exit(&dtrace_lock);336return (EFAULT);337}338339desc.dtbd_size = buf->dtb_xamot_offset;340desc.dtbd_drops = buf->dtb_xamot_drops;341desc.dtbd_errors = buf->dtb_xamot_errors;342desc.dtbd_oldest = 0;343desc.dtbd_timestamp = buf->dtb_switched;344345mutex_exit(&dtrace_lock);346347DTRACE_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);348349/*350* Finally, copy out the buffer description.351*/352if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)353return (EFAULT);354355return (0);356}357case DTRACEIOC_CONF: {358dtrace_conf_t conf;359360DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__);361362bzero(&conf, sizeof (conf));363conf.dtc_difversion = DIF_VERSION;364conf.dtc_difintregs = DIF_DIR_NREGS;365conf.dtc_diftupregs = DIF_DTR_NREGS;366conf.dtc_ctfmodel = CTF_MODEL_NATIVE;367368*((dtrace_conf_t *) addr) = conf;369370return (0);371}372case DTRACEIOC_DOFGET: {373dof_hdr_t **pdof = (dof_hdr_t **) addr;374dof_hdr_t hdr, *dof = *pdof;375int rval;376uint64_t len;377378DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__);379380if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0)381return (EFAULT);382383mutex_enter(&dtrace_lock);384dof = dtrace_dof_create(state);385mutex_exit(&dtrace_lock);386387len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz);388rval = copyout(dof, (void *) *pdof, len);389dtrace_dof_destroy(dof);390391return (rval == 0 ? 0 : EFAULT);392}393case DTRACEIOC_ENABLE: {394dof_hdr_t *dof = NULL;395dtrace_enabling_t *enab = NULL;396dtrace_vstate_t *vstate;397int err = 0;398int rval;399dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr;400401DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__);402403/*404* If a NULL argument has been passed, we take this as our405* cue to reevaluate our enablings.406*/407if (p->dof == NULL) {408dtrace_enabling_matchall();409410return (0);411}412413if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL)414return (EINVAL);415416mutex_enter(&cpu_lock);417mutex_enter(&dtrace_lock);418vstate = &state->dts_vstate;419420if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) {421mutex_exit(&dtrace_lock);422mutex_exit(&cpu_lock);423dtrace_dof_destroy(dof);424return (EBUSY);425}426427if (dtrace_dof_slurp(dof, vstate, td->td_ucred, &enab, 0, 0,428B_TRUE) != 0) {429mutex_exit(&dtrace_lock);430mutex_exit(&cpu_lock);431dtrace_dof_destroy(dof);432return (EINVAL);433}434435if ((rval = dtrace_dof_options(dof, state)) != 0) {436dtrace_enabling_destroy(enab);437mutex_exit(&dtrace_lock);438mutex_exit(&cpu_lock);439dtrace_dof_destroy(dof);440return (rval);441}442443if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) {444err = dtrace_enabling_retain(enab);445} else {446dtrace_enabling_destroy(enab);447}448449mutex_exit(&cpu_lock);450mutex_exit(&dtrace_lock);451dtrace_dof_destroy(dof);452453return (err);454}455case DTRACEIOC_EPROBE: {456dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr;457dtrace_eprobedesc_t epdesc;458dtrace_ecb_t *ecb;459dtrace_action_t *act;460void *buf;461size_t size;462uintptr_t dest;463int nrecs;464465DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__);466467if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0)468return (EFAULT);469470mutex_enter(&dtrace_lock);471472if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) {473mutex_exit(&dtrace_lock);474return (EINVAL);475}476477if (ecb->dte_probe == NULL) {478mutex_exit(&dtrace_lock);479return (EINVAL);480}481482epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id;483epdesc.dtepd_uarg = ecb->dte_uarg;484epdesc.dtepd_size = ecb->dte_size;485486nrecs = epdesc.dtepd_nrecs;487epdesc.dtepd_nrecs = 0;488for (act = ecb->dte_action; act != NULL; act = act->dta_next) {489if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)490continue;491492epdesc.dtepd_nrecs++;493}494495/*496* Now that we have the size, we need to allocate a temporary497* buffer in which to store the complete description. We need498* the temporary buffer to be able to drop dtrace_lock()499* across the copyout(), below.500*/501size = sizeof (dtrace_eprobedesc_t) +502(epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t));503504buf = kmem_alloc(size, KM_SLEEP);505dest = (uintptr_t)buf;506507bcopy(&epdesc, (void *)dest, sizeof (epdesc));508dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]);509510for (act = ecb->dte_action; act != NULL; act = act->dta_next) {511if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)512continue;513514if (nrecs-- == 0)515break;516517bcopy(&act->dta_rec, (void *)dest,518sizeof (dtrace_recdesc_t));519dest += sizeof (dtrace_recdesc_t);520}521522mutex_exit(&dtrace_lock);523524if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) {525kmem_free(buf, size);526return (EFAULT);527}528529kmem_free(buf, size);530return (0);531}532case DTRACEIOC_FORMAT: {533dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr;534char *str;535int len;536537DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__);538539mutex_enter(&dtrace_lock);540541if (fmt->dtfd_format == 0 ||542fmt->dtfd_format > state->dts_nformats) {543mutex_exit(&dtrace_lock);544return (EINVAL);545}546547/*548* Format strings are allocated contiguously and they are549* never freed; if a format index is less than the number550* of formats, we can assert that the format map is non-NULL551* and that the format for the specified index is non-NULL.552*/553ASSERT(state->dts_formats != NULL);554str = state->dts_formats[fmt->dtfd_format - 1];555ASSERT(str != NULL);556557len = strlen(str) + 1;558559if (len > fmt->dtfd_length) {560fmt->dtfd_length = len;561} else {562if (copyout(str, fmt->dtfd_string, len) != 0) {563mutex_exit(&dtrace_lock);564return (EINVAL);565}566}567568mutex_exit(&dtrace_lock);569return (0);570}571case DTRACEIOC_GO: {572int rval;573processorid_t *cpuid = (processorid_t *) addr;574575DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__);576577rval = dtrace_state_go(state, cpuid);578579return (rval);580}581case DTRACEIOC_PROBEARG: {582dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr;583dtrace_probe_t *probe;584dtrace_provider_t *prov;585586DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__);587588if (desc->dtargd_id == DTRACE_IDNONE)589return (EINVAL);590591if (desc->dtargd_ndx == DTRACE_ARGNONE)592return (EINVAL);593594mutex_enter(&dtrace_provider_lock);595#ifdef illumos596mutex_enter(&mod_lock);597#endif598mutex_enter(&dtrace_lock);599600if (desc->dtargd_id > dtrace_nprobes) {601mutex_exit(&dtrace_lock);602#ifdef illumos603mutex_exit(&mod_lock);604#endif605mutex_exit(&dtrace_provider_lock);606return (EINVAL);607}608609if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) {610mutex_exit(&dtrace_lock);611#ifdef illumos612mutex_exit(&mod_lock);613#endif614mutex_exit(&dtrace_provider_lock);615return (EINVAL);616}617618mutex_exit(&dtrace_lock);619620prov = probe->dtpr_provider;621622if (prov->dtpv_pops.dtps_getargdesc == NULL) {623/*624* There isn't any typed information for this probe.625* Set the argument number to DTRACE_ARGNONE.626*/627desc->dtargd_ndx = DTRACE_ARGNONE;628} else {629desc->dtargd_native[0] = '\0';630desc->dtargd_xlate[0] = '\0';631desc->dtargd_mapping = desc->dtargd_ndx;632633prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg,634probe->dtpr_id, probe->dtpr_arg, desc);635}636637#ifdef illumos638mutex_exit(&mod_lock);639#endif640mutex_exit(&dtrace_provider_lock);641642return (0);643}644case DTRACEIOC_PROBEMATCH:645case DTRACEIOC_PROBES: {646dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr;647dtrace_probe_t *probe = NULL;648dtrace_probekey_t pkey;649dtrace_id_t i;650int m = 0;651uint32_t priv = 0;652uid_t uid = 0;653zoneid_t zoneid = 0;654655DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__,656cmd == DTRACEIOC_PROBEMATCH ?657"DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES");658659p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';660p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';661p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';662p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0';663664/*665* Before we attempt to match this probe, we want to give666* all providers the opportunity to provide it.667*/668if (p_desc->dtpd_id == DTRACE_IDNONE) {669mutex_enter(&dtrace_provider_lock);670dtrace_probe_provide(p_desc, NULL);671mutex_exit(&dtrace_provider_lock);672p_desc->dtpd_id++;673}674675if (cmd == DTRACEIOC_PROBEMATCH) {676dtrace_probekey(p_desc, &pkey);677pkey.dtpk_id = DTRACE_IDNONE;678}679680dtrace_cred2priv(td->td_ucred, &priv, &uid, &zoneid);681682mutex_enter(&dtrace_lock);683684if (cmd == DTRACEIOC_PROBEMATCH) {685for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {686if ((probe = dtrace_probes[i - 1]) != NULL &&687(m = dtrace_match_probe(probe, &pkey,688priv, uid, zoneid)) != 0)689break;690}691692if (m < 0) {693mutex_exit(&dtrace_lock);694return (EINVAL);695}696697} else {698for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {699if ((probe = dtrace_probes[i - 1]) != NULL &&700dtrace_match_priv(probe, priv, uid, zoneid))701break;702}703}704705if (probe == NULL) {706mutex_exit(&dtrace_lock);707return (ESRCH);708}709710dtrace_probe_description(probe, p_desc);711mutex_exit(&dtrace_lock);712713return (0);714}715case DTRACEIOC_PROVIDER: {716dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr;717dtrace_provider_t *pvp;718719DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__);720721pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0';722mutex_enter(&dtrace_provider_lock);723724for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) {725if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0)726break;727}728729mutex_exit(&dtrace_provider_lock);730731if (pvp == NULL)732return (ESRCH);733734bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t));735bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t));736737return (0);738}739case DTRACEIOC_REPLICATE: {740dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr;741dtrace_probedesc_t *match = &desc->dtrpd_match;742dtrace_probedesc_t *create = &desc->dtrpd_create;743int err;744745DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__);746747match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';748match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';749match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';750match->dtpd_name[DTRACE_NAMELEN - 1] = '\0';751752create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';753create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';754create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';755create->dtpd_name[DTRACE_NAMELEN - 1] = '\0';756757mutex_enter(&dtrace_lock);758err = dtrace_enabling_replicate(state, match, create);759mutex_exit(&dtrace_lock);760761return (err);762}763case DTRACEIOC_STATUS: {764dtrace_status_t *stat = (dtrace_status_t *) addr;765dtrace_dstate_t *dstate;766int i, j;767uint64_t nerrs;768769DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__);770771/*772* See the comment in dtrace_state_deadman() for the reason773* for setting dts_laststatus to INT64_MAX before setting774* it to the correct value.775*/776state->dts_laststatus = INT64_MAX;777dtrace_membar_producer();778state->dts_laststatus = dtrace_gethrtime();779780bzero(stat, sizeof (*stat));781782mutex_enter(&dtrace_lock);783784if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {785mutex_exit(&dtrace_lock);786return (ENOENT);787}788789if (state->dts_activity == DTRACE_ACTIVITY_DRAINING)790stat->dtst_exiting = 1;791792nerrs = state->dts_errors;793dstate = &state->dts_vstate.dtvs_dynvars;794795CPU_FOREACH(i) {796dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i];797798stat->dtst_dyndrops += dcpu->dtdsc_drops;799stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops;800stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops;801802if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL)803stat->dtst_filled++;804805nerrs += state->dts_buffer[i].dtb_errors;806807for (j = 0; j < state->dts_nspeculations; j++) {808dtrace_speculation_t *spec;809dtrace_buffer_t *buf;810811spec = &state->dts_speculations[j];812buf = &spec->dtsp_buffer[i];813stat->dtst_specdrops += buf->dtb_xamot_drops;814}815}816817stat->dtst_specdrops_busy = state->dts_speculations_busy;818stat->dtst_specdrops_unavail = state->dts_speculations_unavail;819stat->dtst_stkstroverflows = state->dts_stkstroverflows;820stat->dtst_dblerrors = state->dts_dblerrors;821stat->dtst_killed =822(state->dts_activity == DTRACE_ACTIVITY_KILLED);823stat->dtst_errors = nerrs;824825mutex_exit(&dtrace_lock);826827return (0);828}829case DTRACEIOC_STOP: {830int rval;831processorid_t *cpuid = (processorid_t *) addr;832833DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__);834835mutex_enter(&dtrace_lock);836rval = dtrace_state_stop(state, cpuid);837mutex_exit(&dtrace_lock);838839return (rval);840}841default:842error = ENOTTY;843}844return (error);845}846847848