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