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