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