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