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