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 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 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 >= MAXCPU || 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