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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * explicitly define DTRACE_ERRDEBUG to pull in definition of dtrace_errhash_t 29 * explicitly define _STDARG_H to avoid stdarg.h/varargs.h u/k defn conflict 30 */ 31 #define DTRACE_ERRDEBUG 32 #define _STDARG_H 33 34 #include <mdb/mdb_param.h> 35 #include <mdb/mdb_modapi.h> 36 #include <mdb/mdb_ks.h> 37 #include <sys/dtrace_impl.h> 38 #include <sys/vmem_impl.h> 39 #include <sys/ddi_impldefs.h> 40 #include <sys/sysmacros.h> 41 #include <sys/kobj.h> 42 #include <dtrace.h> 43 #include <alloca.h> 44 #include <ctype.h> 45 #include <errno.h> 46 #include <math.h> 47 48 /*ARGSUSED*/ 49 int 50 id2probe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 51 { 52 uintptr_t probe = NULL; 53 uintptr_t probes; 54 55 if (!(flags & DCMD_ADDRSPEC)) 56 return (DCMD_USAGE); 57 58 if (addr == DTRACE_IDNONE || addr > UINT32_MAX) 59 goto out; 60 61 if (mdb_readvar(&probes, "dtrace_probes") == -1) { 62 mdb_warn("failed to read 'dtrace_probes'"); 63 return (DCMD_ERR); 64 } 65 66 probes += (addr - 1) * sizeof (dtrace_probe_t *); 67 68 if (mdb_vread(&probe, sizeof (uintptr_t), probes) == -1) { 69 mdb_warn("failed to read dtrace_probes[%d]", addr - 1); 70 return (DCMD_ERR); 71 } 72 73 out: 74 mdb_printf("%p\n", probe); 75 return (DCMD_OK); 76 } 77 78 void 79 dtrace_help(void) 80 { 81 82 mdb_printf("Given a dtrace_state_t structure that represents a " 83 "DTrace consumer, prints\n" 84 "dtrace(1M)-like output for in-kernel DTrace data. (The " 85 "dtrace_state_t\n" 86 "structures for all DTrace consumers may be obtained by running " 87 "the \n" 88 "::dtrace_state dcmd.) When data is present on multiple CPUs, " 89 "data are\n" 90 "presented in CPU order, with records within each CPU ordered " 91 "oldest to \n" 92 "youngest. Options:\n\n" 93 "-c cpu Only provide output for specified CPU.\n"); 94 } 95 96 static int 97 dtracemdb_eprobe(dtrace_state_t *state, dtrace_eprobedesc_t *epd) 98 { 99 dtrace_epid_t epid = epd->dtepd_epid; 100 dtrace_probe_t probe; 101 dtrace_ecb_t ecb; 102 uintptr_t addr, paddr, ap; 103 dtrace_action_t act; 104 int nactions, nrecs; 105 106 addr = (uintptr_t)state->dts_ecbs + 107 (epid - 1) * sizeof (dtrace_ecb_t *); 108 109 if (mdb_vread(&addr, sizeof (addr), addr) == -1) { 110 mdb_warn("failed to read ecb for epid %d", epid); 111 return (-1); 112 } 113 114 if (addr == NULL) { 115 mdb_warn("epid %d doesn't match an ecb\n", epid); 116 return (-1); 117 } 118 119 if (mdb_vread(&ecb, sizeof (ecb), addr) == -1) { 120 mdb_warn("failed to read ecb at %p", addr); 121 return (-1); 122 } 123 124 paddr = (uintptr_t)ecb.dte_probe; 125 126 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) { 127 mdb_warn("failed to read probe for ecb %p", addr); 128 return (-1); 129 } 130 131 /* 132 * This is a little painful: in order to find the number of actions, 133 * we need to first walk through them. 134 */ 135 for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) { 136 if (mdb_vread(&act, sizeof (act), ap) == -1) { 137 mdb_warn("failed to read action %p on ecb %p", 138 ap, addr); 139 return (-1); 140 } 141 142 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) 143 nactions++; 144 145 ap = (uintptr_t)act.dta_next; 146 } 147 148 nrecs = epd->dtepd_nrecs; 149 epd->dtepd_nrecs = nactions; 150 epd->dtepd_probeid = probe.dtpr_id; 151 epd->dtepd_uarg = ecb.dte_uarg; 152 epd->dtepd_size = ecb.dte_size; 153 154 for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) { 155 if (mdb_vread(&act, sizeof (act), ap) == -1) { 156 mdb_warn("failed to read action %p on ecb %p", 157 ap, addr); 158 return (-1); 159 } 160 161 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) { 162 if (nrecs-- == 0) 163 break; 164 165 epd->dtepd_rec[nactions++] = act.dta_rec; 166 } 167 168 ap = (uintptr_t)act.dta_next; 169 } 170 171 return (0); 172 } 173 174 /*ARGSUSED*/ 175 static int 176 dtracemdb_probe(dtrace_state_t *state, dtrace_probedesc_t *pd) 177 { 178 uintptr_t base, addr, paddr, praddr; 179 int nprobes, i; 180 dtrace_probe_t probe; 181 dtrace_provider_t prov; 182 183 if (pd->dtpd_id == DTRACE_IDNONE) 184 pd->dtpd_id++; 185 186 if (mdb_readvar(&base, "dtrace_probes") == -1) { 187 mdb_warn("failed to read 'dtrace_probes'"); 188 return (-1); 189 } 190 191 if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) { 192 mdb_warn("failed to read 'dtrace_nprobes'"); 193 return (-1); 194 } 195 196 for (i = pd->dtpd_id; i <= nprobes; i++) { 197 addr = base + (i - 1) * sizeof (dtrace_probe_t *); 198 199 if (mdb_vread(&paddr, sizeof (paddr), addr) == -1) { 200 mdb_warn("couldn't read probe pointer at %p", addr); 201 return (-1); 202 } 203 204 if (paddr != NULL) 205 break; 206 } 207 208 if (paddr == NULL) { 209 errno = ESRCH; 210 return (-1); 211 } 212 213 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) { 214 mdb_warn("couldn't read probe at %p", paddr); 215 return (-1); 216 } 217 218 pd->dtpd_id = probe.dtpr_id; 219 220 if (mdb_vread(pd->dtpd_name, DTRACE_NAMELEN, 221 (uintptr_t)probe.dtpr_name) == -1) { 222 mdb_warn("failed to read probe name for probe %p", paddr); 223 return (-1); 224 } 225 226 if (mdb_vread(pd->dtpd_func, DTRACE_FUNCNAMELEN, 227 (uintptr_t)probe.dtpr_func) == -1) { 228 mdb_warn("failed to read function name for probe %p", paddr); 229 return (-1); 230 } 231 232 if (mdb_vread(pd->dtpd_mod, DTRACE_MODNAMELEN, 233 (uintptr_t)probe.dtpr_mod) == -1) { 234 mdb_warn("failed to read module name for probe %p", paddr); 235 return (-1); 236 } 237 238 praddr = (uintptr_t)probe.dtpr_provider; 239 240 if (mdb_vread(&prov, sizeof (prov), praddr) == -1) { 241 mdb_warn("failed to read provider for probe %p", paddr); 242 return (-1); 243 } 244 245 if (mdb_vread(pd->dtpd_provider, DTRACE_PROVNAMELEN, 246 (uintptr_t)prov.dtpv_name) == -1) { 247 mdb_warn("failed to read provider name for probe %p", paddr); 248 return (-1); 249 } 250 251 return (0); 252 } 253 254 /*ARGSUSED*/ 255 static int 256 dtracemdb_aggdesc(dtrace_state_t *state, dtrace_aggdesc_t *agd) 257 { 258 dtrace_aggid_t aggid = agd->dtagd_id; 259 dtrace_aggregation_t agg; 260 dtrace_ecb_t ecb; 261 uintptr_t addr, eaddr, ap, last; 262 dtrace_action_t act; 263 dtrace_recdesc_t *lrec; 264 int nactions, nrecs; 265 266 addr = (uintptr_t)state->dts_aggregations + 267 (aggid - 1) * sizeof (dtrace_aggregation_t *); 268 269 if (mdb_vread(&addr, sizeof (addr), addr) == -1) { 270 mdb_warn("failed to read aggregation for aggid %d", aggid); 271 return (-1); 272 } 273 274 if (addr == NULL) { 275 mdb_warn("aggid %d doesn't match an aggregation\n", aggid); 276 return (-1); 277 } 278 279 if (mdb_vread(&agg, sizeof (agg), addr) == -1) { 280 mdb_warn("failed to read aggregation at %p", addr); 281 return (-1); 282 } 283 284 eaddr = (uintptr_t)agg.dtag_ecb; 285 286 if (mdb_vread(&ecb, sizeof (ecb), eaddr) == -1) { 287 mdb_warn("failed to read ecb for aggregation %p", addr); 288 return (-1); 289 } 290 291 last = (uintptr_t)addr + offsetof(dtrace_aggregation_t, dtag_action); 292 293 /* 294 * This is a little painful: in order to find the number of actions, 295 * we need to first walk through them. 296 */ 297 ap = (uintptr_t)agg.dtag_first; 298 nactions = 0; 299 300 for (;;) { 301 if (mdb_vread(&act, sizeof (act), ap) == -1) { 302 mdb_warn("failed to read action %p on aggregation %p", 303 ap, addr); 304 return (-1); 305 } 306 307 nactions++; 308 309 if (ap == last) 310 break; 311 312 ap = (uintptr_t)act.dta_next; 313 } 314 315 lrec = &act.dta_rec; 316 agd->dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - agg.dtag_base; 317 318 nrecs = agd->dtagd_nrecs; 319 agd->dtagd_nrecs = nactions; 320 agd->dtagd_epid = ecb.dte_epid; 321 322 ap = (uintptr_t)agg.dtag_first; 323 nactions = 0; 324 325 for (;;) { 326 dtrace_recdesc_t rec; 327 328 if (mdb_vread(&act, sizeof (act), ap) == -1) { 329 mdb_warn("failed to read action %p on aggregation %p", 330 ap, addr); 331 return (-1); 332 } 333 334 if (nrecs-- == 0) 335 break; 336 337 rec = act.dta_rec; 338 rec.dtrd_offset -= agg.dtag_base; 339 rec.dtrd_uarg = 0; 340 agd->dtagd_rec[nactions++] = rec; 341 342 if (ap == last) 343 break; 344 345 ap = (uintptr_t)act.dta_next; 346 } 347 348 return (0); 349 } 350 351 static int 352 dtracemdb_bufsnap(dtrace_buffer_t *which, dtrace_bufdesc_t *desc) 353 { 354 uintptr_t addr; 355 size_t bufsize; 356 dtrace_buffer_t buf; 357 caddr_t data = desc->dtbd_data; 358 processorid_t max_cpuid, cpu = desc->dtbd_cpu; 359 360 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) { 361 mdb_warn("failed to read 'max_cpuid'"); 362 errno = EIO; 363 return (-1); 364 } 365 366 if (cpu < 0 || cpu > max_cpuid) { 367 errno = EINVAL; 368 return (-1); 369 } 370 371 addr = (uintptr_t)which + cpu * sizeof (dtrace_buffer_t); 372 373 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 374 mdb_warn("failed to read buffer description at %p", addr); 375 errno = EIO; 376 return (-1); 377 } 378 379 if (buf.dtb_tomax == NULL) { 380 errno = ENOENT; 381 return (-1); 382 } 383 384 if (buf.dtb_flags & DTRACEBUF_WRAPPED) { 385 bufsize = buf.dtb_size; 386 } else { 387 bufsize = buf.dtb_offset; 388 } 389 390 if (mdb_vread(data, bufsize, (uintptr_t)buf.dtb_tomax) == -1) { 391 mdb_warn("couldn't read buffer for CPU %d", cpu); 392 errno = EIO; 393 return (-1); 394 } 395 396 if (buf.dtb_offset > buf.dtb_size) { 397 mdb_warn("buffer for CPU %d has corrupt offset\n", cpu); 398 errno = EIO; 399 return (-1); 400 } 401 402 if (buf.dtb_flags & DTRACEBUF_WRAPPED) { 403 if (buf.dtb_xamot_offset > buf.dtb_size) { 404 mdb_warn("ringbuffer for CPU %d has corrupt " 405 "wrapped offset\n", cpu); 406 errno = EIO; 407 return (-1); 408 } 409 410 /* 411 * If the ring buffer has wrapped, it needs to be polished. 412 * See the comment in dtrace_buffer_polish() for details. 413 */ 414 if (buf.dtb_offset < buf.dtb_xamot_offset) { 415 bzero(data + buf.dtb_offset, 416 buf.dtb_xamot_offset - buf.dtb_offset); 417 } 418 419 if (buf.dtb_offset > buf.dtb_xamot_offset) { 420 bzero(data + buf.dtb_offset, 421 buf.dtb_size - buf.dtb_offset); 422 bzero(data, buf.dtb_xamot_offset); 423 } 424 425 desc->dtbd_oldest = buf.dtb_xamot_offset; 426 } else { 427 desc->dtbd_oldest = 0; 428 } 429 430 desc->dtbd_size = bufsize; 431 desc->dtbd_drops = buf.dtb_drops; 432 desc->dtbd_errors = buf.dtb_errors; 433 434 return (0); 435 } 436 437 /* 438 * This is essentially identical to its cousin in the kernel. 439 */ 440 static dof_hdr_t * 441 dtracemdb_dof_create(dtrace_state_t *state) 442 { 443 dof_hdr_t *dof; 444 dof_sec_t *sec; 445 dof_optdesc_t *opt; 446 int i, len = sizeof (dof_hdr_t) + 447 roundup(sizeof (dof_sec_t), sizeof (uint64_t)) + 448 sizeof (dof_optdesc_t) * DTRACEOPT_MAX; 449 450 dof = mdb_zalloc(len, UM_SLEEP); 451 dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; 452 dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; 453 dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; 454 dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; 455 456 dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; 457 dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; 458 dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; 459 dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; 460 dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; 461 dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; 462 463 dof->dofh_flags = 0; 464 dof->dofh_hdrsize = sizeof (dof_hdr_t); 465 dof->dofh_secsize = sizeof (dof_sec_t); 466 dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ 467 dof->dofh_secoff = sizeof (dof_hdr_t); 468 dof->dofh_loadsz = len; 469 dof->dofh_filesz = len; 470 dof->dofh_pad = 0; 471 472 /* 473 * Fill in the option section header... 474 */ 475 sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); 476 sec->dofs_type = DOF_SECT_OPTDESC; 477 sec->dofs_align = sizeof (uint64_t); 478 sec->dofs_flags = DOF_SECF_LOAD; 479 sec->dofs_entsize = sizeof (dof_optdesc_t); 480 481 opt = (dof_optdesc_t *)((uintptr_t)sec + 482 roundup(sizeof (dof_sec_t), sizeof (uint64_t))); 483 484 sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof; 485 sec->dofs_size = sizeof (dof_optdesc_t) * DTRACEOPT_MAX; 486 487 for (i = 0; i < DTRACEOPT_MAX; i++) { 488 opt[i].dofo_option = i; 489 opt[i].dofo_strtab = DOF_SECIDX_NONE; 490 opt[i].dofo_value = state->dts_options[i]; 491 } 492 493 return (dof); 494 } 495 496 static int 497 dtracemdb_format(dtrace_state_t *state, dtrace_fmtdesc_t *desc) 498 { 499 uintptr_t addr, faddr; 500 char c; 501 int len = 0; 502 503 if (desc->dtfd_format == 0 || desc->dtfd_format > state->dts_nformats) { 504 errno = EINVAL; 505 return (-1); 506 } 507 508 faddr = (uintptr_t)state->dts_formats + 509 (desc->dtfd_format - 1) * sizeof (char *); 510 511 if (mdb_vread(&addr, sizeof (addr), faddr) == -1) { 512 mdb_warn("failed to read format string pointer at %p", faddr); 513 return (-1); 514 } 515 516 do { 517 if (mdb_vread(&c, sizeof (c), addr + len++) == -1) { 518 mdb_warn("failed to read format string at %p", addr); 519 return (-1); 520 } 521 } while (c != '\0'); 522 523 if (len > desc->dtfd_length) { 524 desc->dtfd_length = len; 525 return (0); 526 } 527 528 if (mdb_vread(desc->dtfd_string, len, addr) == -1) { 529 mdb_warn("failed to reread format string at %p", addr); 530 return (-1); 531 } 532 533 return (0); 534 } 535 536 static int 537 dtracemdb_status(dtrace_state_t *state, dtrace_status_t *status) 538 { 539 dtrace_dstate_t *dstate; 540 int i, j; 541 uint64_t nerrs; 542 uintptr_t addr; 543 int ncpu; 544 545 if (mdb_readvar(&ncpu, "_ncpu") == -1) { 546 mdb_warn("failed to read '_ncpu'"); 547 return (DCMD_ERR); 548 } 549 550 bzero(status, sizeof (dtrace_status_t)); 551 552 if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { 553 errno = ENOENT; 554 return (-1); 555 } 556 557 /* 558 * For the MDB backend, we never set dtst_exiting or dtst_filled. This 559 * is by design: we don't want the library to try to stop tracing, 560 * because it doesn't particularly mean anything. 561 */ 562 nerrs = state->dts_errors; 563 dstate = &state->dts_vstate.dtvs_dynvars; 564 565 for (i = 0; i < ncpu; i++) { 566 dtrace_dstate_percpu_t dcpu; 567 dtrace_buffer_t buf; 568 569 addr = (uintptr_t)&dstate->dtds_percpu[i]; 570 571 if (mdb_vread(&dcpu, sizeof (dcpu), addr) == -1) { 572 mdb_warn("failed to read per-CPU dstate at %p", addr); 573 return (-1); 574 } 575 576 status->dtst_dyndrops += dcpu.dtdsc_drops; 577 status->dtst_dyndrops_dirty += dcpu.dtdsc_dirty_drops; 578 status->dtst_dyndrops_rinsing += dcpu.dtdsc_rinsing_drops; 579 580 addr = (uintptr_t)&state->dts_buffer[i]; 581 582 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 583 mdb_warn("failed to read per-CPU buffer at %p", addr); 584 return (-1); 585 } 586 587 nerrs += buf.dtb_errors; 588 589 for (j = 0; j < state->dts_nspeculations; j++) { 590 dtrace_speculation_t spec; 591 592 addr = (uintptr_t)&state->dts_speculations[j]; 593 594 if (mdb_vread(&spec, sizeof (spec), addr) == -1) { 595 mdb_warn("failed to read " 596 "speculation at %p", addr); 597 return (-1); 598 } 599 600 addr = (uintptr_t)&spec.dtsp_buffer[i]; 601 602 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 603 mdb_warn("failed to read " 604 "speculative buffer at %p", addr); 605 return (-1); 606 } 607 608 status->dtst_specdrops += buf.dtb_xamot_drops; 609 } 610 } 611 612 status->dtst_specdrops_busy = state->dts_speculations_busy; 613 status->dtst_specdrops_unavail = state->dts_speculations_unavail; 614 status->dtst_errors = nerrs; 615 616 return (0); 617 } 618 619 typedef struct dtracemdb_data { 620 dtrace_state_t *dtmd_state; 621 char *dtmd_symstr; 622 char *dtmd_modstr; 623 uintptr_t dtmd_addr; 624 } dtracemdb_data_t; 625 626 static int 627 dtracemdb_ioctl(void *varg, int cmd, void *arg) 628 { 629 dtracemdb_data_t *data = varg; 630 dtrace_state_t *state = data->dtmd_state; 631 632 switch (cmd) { 633 case DTRACEIOC_CONF: { 634 dtrace_conf_t *conf = arg; 635 636 bzero(conf, sizeof (conf)); 637 conf->dtc_difversion = DIF_VERSION; 638 conf->dtc_difintregs = DIF_DIR_NREGS; 639 conf->dtc_diftupregs = DIF_DTR_NREGS; 640 conf->dtc_ctfmodel = CTF_MODEL_NATIVE; 641 642 return (0); 643 } 644 645 case DTRACEIOC_DOFGET: { 646 dof_hdr_t *hdr = arg, *dof; 647 648 dof = dtracemdb_dof_create(state); 649 bcopy(dof, hdr, MIN(hdr->dofh_loadsz, dof->dofh_loadsz)); 650 mdb_free(dof, dof->dofh_loadsz); 651 652 return (0); 653 } 654 655 case DTRACEIOC_BUFSNAP: 656 return (dtracemdb_bufsnap(state->dts_buffer, arg)); 657 658 case DTRACEIOC_AGGSNAP: 659 return (dtracemdb_bufsnap(state->dts_aggbuffer, arg)); 660 661 case DTRACEIOC_AGGDESC: 662 return (dtracemdb_aggdesc(state, arg)); 663 664 case DTRACEIOC_EPROBE: 665 return (dtracemdb_eprobe(state, arg)); 666 667 case DTRACEIOC_PROBES: 668 return (dtracemdb_probe(state, arg)); 669 670 case DTRACEIOC_FORMAT: 671 return (dtracemdb_format(state, arg)); 672 673 case DTRACEIOC_STATUS: 674 return (dtracemdb_status(state, arg)); 675 676 case DTRACEIOC_GO: 677 *(processorid_t *)arg = -1; 678 return (0); 679 680 case DTRACEIOC_ENABLE: 681 errno = ENOTTY; /* see dt_open.c:dtrace_go() */ 682 return (-1); 683 684 case DTRACEIOC_PROVIDER: 685 case DTRACEIOC_PROBEMATCH: 686 errno = ESRCH; 687 return (-1); 688 689 default: 690 mdb_warn("unexpected ioctl 0x%x (%s)\n", cmd, 691 cmd == DTRACEIOC_PROVIDER ? "DTRACEIOC_PROVIDER" : 692 cmd == DTRACEIOC_PROBES ? "DTRACEIOC_PROBES" : 693 cmd == DTRACEIOC_BUFSNAP ? "DTRACEIOC_BUFSNAP" : 694 cmd == DTRACEIOC_PROBEMATCH ? "DTRACEIOC_PROBEMATCH" : 695 cmd == DTRACEIOC_ENABLE ? "DTRACEIOC_ENABLE" : 696 cmd == DTRACEIOC_AGGSNAP ? "DTRACEIOC_AGGSNAP" : 697 cmd == DTRACEIOC_EPROBE ? "DTRACEIOC_EPROBE" : 698 cmd == DTRACEIOC_PROBEARG ? "DTRACEIOC_PROBEARG" : 699 cmd == DTRACEIOC_CONF ? "DTRACEIOC_CONF" : 700 cmd == DTRACEIOC_STATUS ? "DTRACEIOC_STATUS" : 701 cmd == DTRACEIOC_GO ? "DTRACEIOC_GO" : 702 cmd == DTRACEIOC_STOP ? "DTRACEIOC_STOP" : 703 cmd == DTRACEIOC_AGGDESC ? "DTRACEIOC_AGGDESC" : 704 cmd == DTRACEIOC_FORMAT ? "DTRACEIOC_FORMAT" : 705 cmd == DTRACEIOC_DOFGET ? "DTRACEIOC_DOFGET" : 706 cmd == DTRACEIOC_REPLICATE ? "DTRACEIOC_REPLICATE" : 707 "???"); 708 errno = ENXIO; 709 return (-1); 710 } 711 } 712 713 static int 714 dtracemdb_modctl(uintptr_t addr, const struct modctl *m, dtracemdb_data_t *data) 715 { 716 struct module mod; 717 718 if (m->mod_mp == NULL) 719 return (WALK_NEXT); 720 721 if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) { 722 mdb_warn("couldn't read modctl %p's module", addr); 723 return (WALK_NEXT); 724 } 725 726 if ((uintptr_t)mod.text > data->dtmd_addr) 727 return (WALK_NEXT); 728 729 if ((uintptr_t)mod.text + mod.text_size <= data->dtmd_addr) 730 return (WALK_NEXT); 731 732 if (mdb_readstr(data->dtmd_modstr, MDB_SYM_NAMLEN, 733 (uintptr_t)m->mod_modname) == -1) 734 return (WALK_ERR); 735 736 return (WALK_DONE); 737 } 738 739 static int 740 dtracemdb_lookup_by_addr(void *varg, GElf_Addr addr, GElf_Sym *symp, 741 dtrace_syminfo_t *sip) 742 { 743 dtracemdb_data_t *data = varg; 744 745 if (data->dtmd_symstr == NULL) { 746 data->dtmd_symstr = mdb_zalloc(MDB_SYM_NAMLEN, 747 UM_SLEEP | UM_GC); 748 } 749 750 if (data->dtmd_modstr == NULL) { 751 data->dtmd_modstr = mdb_zalloc(MDB_SYM_NAMLEN, 752 UM_SLEEP | UM_GC); 753 } 754 755 if (symp != NULL) { 756 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, data->dtmd_symstr, 757 MDB_SYM_NAMLEN, symp) == -1) 758 return (-1); 759 } 760 761 if (sip != NULL) { 762 data->dtmd_addr = addr; 763 764 (void) strcpy(data->dtmd_modstr, "???"); 765 766 if (mdb_walk("modctl", 767 (mdb_walk_cb_t)dtracemdb_modctl, varg) == -1) { 768 mdb_warn("couldn't walk 'modctl'"); 769 return (-1); 770 } 771 772 sip->dts_object = data->dtmd_modstr; 773 sip->dts_id = 0; 774 sip->dts_name = symp != NULL ? data->dtmd_symstr : NULL; 775 } 776 777 return (0); 778 } 779 780 /*ARGSUSED*/ 781 static int 782 dtracemdb_stat(void *varg, processorid_t cpu) 783 { 784 GElf_Sym sym; 785 cpu_t c; 786 uintptr_t caddr, addr; 787 788 if (mdb_lookup_by_name("cpu", &sym) == -1) { 789 mdb_warn("failed to find symbol for 'cpu'"); 790 return (-1); 791 } 792 793 if (cpu * sizeof (uintptr_t) > sym.st_size) 794 return (-1); 795 796 addr = (uintptr_t)sym.st_value + cpu * sizeof (uintptr_t); 797 798 if (mdb_vread(&caddr, sizeof (caddr), addr) == -1) { 799 mdb_warn("failed to read cpu[%d]", cpu); 800 return (-1); 801 } 802 803 if (caddr == NULL) 804 return (-1); 805 806 if (mdb_vread(&c, sizeof (c), caddr) == -1) { 807 mdb_warn("failed to read cpu at %p", caddr); 808 return (-1); 809 } 810 811 if (c.cpu_flags & CPU_POWEROFF) { 812 return (P_POWEROFF); 813 } else if (c.cpu_flags & CPU_SPARE) { 814 return (P_SPARE); 815 } else if (c.cpu_flags & CPU_FAULTED) { 816 return (P_FAULTED); 817 } else if ((c.cpu_flags & (CPU_READY | CPU_OFFLINE)) != CPU_READY) { 818 return (P_OFFLINE); 819 } else if (c.cpu_flags & CPU_ENABLE) { 820 return (P_ONLINE); 821 } else { 822 return (P_NOINTR); 823 } 824 } 825 826 /*ARGSUSED*/ 827 static long 828 dtracemdb_sysconf(void *varg, int name) 829 { 830 int max_ncpus; 831 processorid_t max_cpuid; 832 833 switch (name) { 834 case _SC_CPUID_MAX: 835 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) { 836 mdb_warn("failed to read 'max_cpuid'"); 837 return (-1); 838 } 839 840 return (max_cpuid); 841 842 case _SC_NPROCESSORS_MAX: 843 if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) { 844 mdb_warn("failed to read 'max_ncpus'"); 845 return (-1); 846 } 847 848 return (max_ncpus); 849 850 default: 851 mdb_warn("unexpected sysconf code %d\n", name); 852 return (-1); 853 } 854 } 855 856 const dtrace_vector_t dtrace_mdbops = { 857 dtracemdb_ioctl, 858 dtracemdb_lookup_by_addr, 859 dtracemdb_stat, 860 dtracemdb_sysconf 861 }; 862 863 typedef struct dtrace_dcmddata { 864 dtrace_hdl_t *dtdd_dtp; 865 int dtdd_cpu; 866 int dtdd_quiet; 867 int dtdd_flowindent; 868 int dtdd_heading; 869 } dtrace_dcmddata_t; 870 871 /*ARGSUSED*/ 872 static int 873 dtrace_dcmdrec(const dtrace_probedata_t *data, 874 const dtrace_recdesc_t *rec, void *arg) 875 { 876 dtrace_dcmddata_t *dd = arg; 877 878 if (rec == NULL) { 879 /* 880 * We have processed the final record; output the newline if 881 * we're not in quiet mode. 882 */ 883 if (!dd->dtdd_quiet) 884 mdb_printf("\n"); 885 886 return (DTRACE_CONSUME_NEXT); 887 } 888 889 return (DTRACE_CONSUME_THIS); 890 } 891 892 /*ARGSUSED*/ 893 static int 894 dtrace_dcmdprobe(const dtrace_probedata_t *data, void *arg) 895 { 896 dtrace_probedesc_t *pd = data->dtpda_pdesc; 897 processorid_t cpu = data->dtpda_cpu; 898 dtrace_dcmddata_t *dd = arg; 899 char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; 900 901 if (dd->dtdd_cpu != -1UL && dd->dtdd_cpu != cpu) 902 return (DTRACE_CONSUME_NEXT); 903 904 if (dd->dtdd_heading == 0) { 905 if (!dd->dtdd_flowindent) { 906 if (!dd->dtdd_quiet) { 907 mdb_printf("%3s %6s %32s\n", 908 "CPU", "ID", "FUNCTION:NAME"); 909 } 910 } else { 911 mdb_printf("%3s %-41s\n", "CPU", "FUNCTION"); 912 } 913 dd->dtdd_heading = 1; 914 } 915 916 if (!dd->dtdd_flowindent) { 917 if (!dd->dtdd_quiet) { 918 (void) mdb_snprintf(name, sizeof (name), "%s:%s", 919 pd->dtpd_func, pd->dtpd_name); 920 921 mdb_printf("%3d %6d %32s ", cpu, pd->dtpd_id, name); 922 } 923 } else { 924 int indent = data->dtpda_indent; 925 926 if (data->dtpda_flow == DTRACEFLOW_NONE) { 927 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s:%s", 928 indent, "", data->dtpda_prefix, pd->dtpd_func, 929 pd->dtpd_name); 930 } else { 931 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s", 932 indent, "", data->dtpda_prefix, pd->dtpd_func); 933 } 934 935 mdb_printf("%3d %-41s ", cpu, name); 936 } 937 938 return (DTRACE_CONSUME_THIS); 939 } 940 941 /*ARGSUSED*/ 942 static int 943 dtrace_dcmderr(const dtrace_errdata_t *data, void *arg) 944 { 945 mdb_warn(data->dteda_msg); 946 return (DTRACE_HANDLE_OK); 947 } 948 949 /*ARGSUSED*/ 950 static int 951 dtrace_dcmddrop(const dtrace_dropdata_t *data, void *arg) 952 { 953 mdb_warn(data->dtdda_msg); 954 return (DTRACE_HANDLE_OK); 955 } 956 957 /*ARGSUSED*/ 958 static int 959 dtrace_dcmdbuffered(const dtrace_bufdata_t *bufdata, void *arg) 960 { 961 mdb_printf("%s", bufdata->dtbda_buffered); 962 return (DTRACE_HANDLE_OK); 963 } 964 965 /*ARGSUSED*/ 966 int 967 dtrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 968 { 969 dtrace_state_t state; 970 dtrace_hdl_t *dtp; 971 int ncpu, err; 972 uintptr_t c = -1UL; 973 dtrace_dcmddata_t dd; 974 dtrace_optval_t val; 975 dtracemdb_data_t md; 976 int rval = DCMD_ERR; 977 978 if (!(flags & DCMD_ADDRSPEC)) 979 return (DCMD_USAGE); 980 981 if (mdb_getopts(argc, argv, 'c', MDB_OPT_UINTPTR, &c, NULL) != argc) 982 return (DCMD_USAGE); 983 984 if (mdb_readvar(&ncpu, "_ncpu") == -1) { 985 mdb_warn("failed to read '_ncpu'"); 986 return (DCMD_ERR); 987 } 988 989 if (mdb_vread(&state, sizeof (state), addr) == -1) { 990 mdb_warn("couldn't read dtrace_state_t at %p", addr); 991 return (DCMD_ERR); 992 } 993 994 bzero(&md, sizeof (md)); 995 md.dtmd_state = &state; 996 997 if ((dtp = dtrace_vopen(DTRACE_VERSION, DTRACE_O_NOSYS, &err, 998 &dtrace_mdbops, &md)) == NULL) { 999 mdb_warn("failed to initialize dtrace: %s\n", 1000 dtrace_errmsg(NULL, err)); 1001 return (DCMD_ERR); 1002 } 1003 1004 if (dtrace_go(dtp) != 0) { 1005 mdb_warn("failed to initialize dtrace: %s\n", 1006 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1007 goto err; 1008 } 1009 1010 bzero(&dd, sizeof (dd)); 1011 dd.dtdd_dtp = dtp; 1012 dd.dtdd_cpu = c; 1013 1014 if (dtrace_getopt(dtp, "flowindent", &val) == -1) { 1015 mdb_warn("couldn't get 'flowindent' option: %s\n", 1016 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1017 goto err; 1018 } 1019 1020 dd.dtdd_flowindent = (val != DTRACEOPT_UNSET); 1021 1022 if (dtrace_getopt(dtp, "quiet", &val) == -1) { 1023 mdb_warn("couldn't get 'quiet' option: %s\n", 1024 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1025 goto err; 1026 } 1027 1028 dd.dtdd_quiet = (val != DTRACEOPT_UNSET); 1029 1030 if (dtrace_handle_err(dtp, dtrace_dcmderr, NULL) == -1) { 1031 mdb_warn("couldn't add err handler: %s\n", 1032 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1033 goto err; 1034 } 1035 1036 if (dtrace_handle_drop(dtp, dtrace_dcmddrop, NULL) == -1) { 1037 mdb_warn("couldn't add drop handler: %s\n", 1038 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1039 goto err; 1040 } 1041 1042 if (dtrace_handle_buffered(dtp, dtrace_dcmdbuffered, NULL) == -1) { 1043 mdb_warn("couldn't add buffered handler: %s\n", 1044 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1045 goto err; 1046 } 1047 1048 if (dtrace_status(dtp) == -1) { 1049 mdb_warn("couldn't get status: %s\n", 1050 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1051 goto err; 1052 } 1053 1054 if (dtrace_aggregate_snap(dtp) == -1) { 1055 mdb_warn("couldn't snapshot aggregation: %s\n", 1056 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1057 goto err; 1058 } 1059 1060 if (dtrace_consume(dtp, NULL, 1061 dtrace_dcmdprobe, dtrace_dcmdrec, &dd) == -1) { 1062 mdb_warn("couldn't consume DTrace buffers: %s\n", 1063 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1064 } 1065 1066 if (dtrace_aggregate_print(dtp, NULL, NULL) == -1) { 1067 mdb_warn("couldn't print aggregation: %s\n", 1068 dtrace_errmsg(dtp, dtrace_errno(dtp))); 1069 goto err; 1070 } 1071 1072 rval = DCMD_OK; 1073 err: 1074 dtrace_close(dtp); 1075 return (rval); 1076 } 1077 1078 static int 1079 dtrace_errhash_cmp(const void *l, const void *r) 1080 { 1081 uintptr_t lhs = *((uintptr_t *)l); 1082 uintptr_t rhs = *((uintptr_t *)r); 1083 dtrace_errhash_t lerr, rerr; 1084 char lmsg[256], rmsg[256]; 1085 1086 (void) mdb_vread(&lerr, sizeof (lerr), lhs); 1087 (void) mdb_vread(&rerr, sizeof (rerr), rhs); 1088 1089 if (lerr.dter_msg == NULL) 1090 return (-1); 1091 1092 if (rerr.dter_msg == NULL) 1093 return (1); 1094 1095 (void) mdb_readstr(lmsg, sizeof (lmsg), (uintptr_t)lerr.dter_msg); 1096 (void) mdb_readstr(rmsg, sizeof (rmsg), (uintptr_t)rerr.dter_msg); 1097 1098 return (strcmp(lmsg, rmsg)); 1099 } 1100 1101 int 1102 dtrace_errhash_init(mdb_walk_state_t *wsp) 1103 { 1104 GElf_Sym sym; 1105 uintptr_t *hash, addr; 1106 int i; 1107 1108 if (wsp->walk_addr != NULL) { 1109 mdb_warn("dtrace_errhash walk only supports global walks\n"); 1110 return (WALK_ERR); 1111 } 1112 1113 if (mdb_lookup_by_name("dtrace_errhash", &sym) == -1) { 1114 mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)"); 1115 return (WALK_ERR); 1116 } 1117 1118 addr = (uintptr_t)sym.st_value; 1119 hash = mdb_alloc(DTRACE_ERRHASHSZ * sizeof (uintptr_t), 1120 UM_SLEEP | UM_GC); 1121 1122 for (i = 0; i < DTRACE_ERRHASHSZ; i++) 1123 hash[i] = addr + i * sizeof (dtrace_errhash_t); 1124 1125 qsort(hash, DTRACE_ERRHASHSZ, sizeof (uintptr_t), dtrace_errhash_cmp); 1126 1127 wsp->walk_addr = 0; 1128 wsp->walk_data = hash; 1129 1130 return (WALK_NEXT); 1131 } 1132 1133 int 1134 dtrace_errhash_step(mdb_walk_state_t *wsp) 1135 { 1136 int ndx = (int)wsp->walk_addr; 1137 uintptr_t *hash = wsp->walk_data; 1138 dtrace_errhash_t err; 1139 uintptr_t addr; 1140 1141 if (ndx >= DTRACE_ERRHASHSZ) 1142 return (WALK_DONE); 1143 1144 wsp->walk_addr = ndx + 1; 1145 addr = hash[ndx]; 1146 1147 if (mdb_vread(&err, sizeof (err), addr) == -1) { 1148 mdb_warn("failed to read dtrace_errhash_t at %p", addr); 1149 return (WALK_DONE); 1150 } 1151 1152 if (err.dter_msg == NULL) 1153 return (WALK_NEXT); 1154 1155 return (wsp->walk_callback(addr, &err, wsp->walk_cbdata)); 1156 } 1157 1158 /*ARGSUSED*/ 1159 int 1160 dtrace_errhash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1161 { 1162 dtrace_errhash_t err; 1163 char msg[256]; 1164 1165 if (!(flags & DCMD_ADDRSPEC)) { 1166 if (mdb_walk_dcmd("dtrace_errhash", "dtrace_errhash", 1167 argc, argv) == -1) { 1168 mdb_warn("can't walk 'dtrace_errhash'"); 1169 return (DCMD_ERR); 1170 } 1171 1172 return (DCMD_OK); 1173 } 1174 1175 if (DCMD_HDRSPEC(flags)) 1176 mdb_printf("%8s %s\n", "COUNT", "ERROR"); 1177 1178 if (mdb_vread(&err, sizeof (err), addr) == -1) { 1179 mdb_warn("failed to read dtrace_errhash_t at %p", addr); 1180 return (DCMD_ERR); 1181 } 1182 1183 addr = (uintptr_t)err.dter_msg; 1184 1185 if (mdb_readstr(msg, sizeof (msg), addr) == -1) { 1186 mdb_warn("failed to read error msg at %p", addr); 1187 return (DCMD_ERR); 1188 } 1189 1190 mdb_printf("%8d %s", err.dter_count, msg); 1191 1192 /* 1193 * Some error messages include a newline -- only print the newline 1194 * if the message doesn't have one. 1195 */ 1196 if (msg[strlen(msg) - 1] != '\n') 1197 mdb_printf("\n"); 1198 1199 return (DCMD_OK); 1200 } 1201 1202 int 1203 dtrace_helptrace_init(mdb_walk_state_t *wsp) 1204 { 1205 uint32_t next; 1206 int enabled; 1207 1208 if (wsp->walk_addr != NULL) { 1209 mdb_warn("dtrace_helptrace only supports global walks\n"); 1210 return (WALK_ERR); 1211 } 1212 1213 if (mdb_readvar(&enabled, "dtrace_helptrace_enabled") == -1) { 1214 mdb_warn("couldn't read 'dtrace_helptrace_enabled'"); 1215 return (WALK_ERR); 1216 } 1217 1218 if (!enabled) { 1219 mdb_warn("helper tracing is not enabled\n"); 1220 return (WALK_ERR); 1221 } 1222 1223 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) { 1224 mdb_warn("couldn't read 'dtrace_helptrace_next'"); 1225 return (WALK_ERR); 1226 } 1227 1228 wsp->walk_addr = next; 1229 1230 return (WALK_NEXT); 1231 } 1232 1233 int 1234 dtrace_helptrace_step(mdb_walk_state_t *wsp) 1235 { 1236 uint32_t next, size, nlocals, bufsize; 1237 uintptr_t buffer, addr; 1238 dtrace_helptrace_t *ht; 1239 int rval; 1240 1241 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) { 1242 mdb_warn("couldn't read 'dtrace_helptrace_next'"); 1243 return (WALK_ERR); 1244 } 1245 1246 if (mdb_readvar(&bufsize, "dtrace_helptrace_bufsize") == -1) { 1247 mdb_warn("couldn't read 'dtrace_helptrace_bufsize'"); 1248 return (WALK_ERR); 1249 } 1250 1251 if (mdb_readvar(&buffer, "dtrace_helptrace_buffer") == -1) { 1252 mdb_warn("couldn't read 'dtrace_helptrace_buffer'"); 1253 return (WALK_ERR); 1254 } 1255 1256 if (mdb_readvar(&nlocals, "dtrace_helptrace_nlocals") == -1) { 1257 mdb_warn("couldn't read 'dtrace_helptrace_nlocals'"); 1258 return (WALK_ERR); 1259 } 1260 1261 size = sizeof (dtrace_helptrace_t) + 1262 nlocals * sizeof (uint64_t) - sizeof (uint64_t); 1263 1264 if (wsp->walk_addr + size > bufsize) { 1265 if (next == 0) 1266 return (WALK_DONE); 1267 1268 wsp->walk_addr = 0; 1269 } 1270 1271 addr = buffer + wsp->walk_addr; 1272 ht = alloca(size); 1273 1274 if (mdb_vread(ht, size, addr) == -1) { 1275 mdb_warn("couldn't read entry at %p", addr); 1276 return (WALK_ERR); 1277 } 1278 1279 if (ht->dtht_helper != NULL) { 1280 rval = wsp->walk_callback(addr, ht, wsp->walk_cbdata); 1281 1282 if (rval != WALK_NEXT) 1283 return (rval); 1284 } 1285 1286 if (wsp->walk_addr < next && wsp->walk_addr + size >= next) 1287 return (WALK_DONE); 1288 1289 wsp->walk_addr += size; 1290 return (WALK_NEXT); 1291 } 1292 1293 int 1294 dtrace_helptrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1295 { 1296 dtrace_helptrace_t help; 1297 dtrace_helper_action_t helper; 1298 char where[30]; 1299 uint_t opt_v = FALSE; 1300 uintptr_t haddr; 1301 1302 if (!(flags & DCMD_ADDRSPEC)) { 1303 if (mdb_walk_dcmd("dtrace_helptrace", "dtrace_helptrace", 1304 argc, argv) == -1) { 1305 mdb_warn("can't walk 'dtrace_helptrace'"); 1306 return (DCMD_ERR); 1307 } 1308 1309 return (DCMD_OK); 1310 } 1311 1312 if (mdb_getopts(argc, argv, 'v', 1313 MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 1314 return (DCMD_USAGE); 1315 1316 if (DCMD_HDRSPEC(flags)) { 1317 mdb_printf(" %?s %?s %12s %s\n", 1318 "ADDR", "HELPER", "WHERE", "DIFO"); 1319 } 1320 1321 if (mdb_vread(&help, sizeof (help), addr) == -1) { 1322 mdb_warn("failed to read dtrace_helptrace_t at %p", addr); 1323 return (DCMD_ERR); 1324 } 1325 1326 switch (help.dtht_where) { 1327 case 0: 1328 (void) mdb_snprintf(where, sizeof (where), "predicate"); 1329 break; 1330 1331 case DTRACE_HELPTRACE_NEXT: 1332 (void) mdb_snprintf(where, sizeof (where), "next"); 1333 break; 1334 1335 case DTRACE_HELPTRACE_DONE: 1336 (void) mdb_snprintf(where, sizeof (where), "done"); 1337 break; 1338 1339 case DTRACE_HELPTRACE_ERR: 1340 (void) mdb_snprintf(where, sizeof (where), "err"); 1341 break; 1342 1343 default: 1344 (void) mdb_snprintf(where, sizeof (where), 1345 "action #%d", help.dtht_where); 1346 break; 1347 } 1348 1349 mdb_printf(" %?p %?p %12s ", addr, help.dtht_helper, where); 1350 1351 haddr = (uintptr_t)help.dtht_helper; 1352 1353 if (mdb_vread(&helper, sizeof (helper), haddr) == -1) { 1354 /* 1355 * We're not going to warn in this case -- we're just not going 1356 * to print anything exciting. 1357 */ 1358 mdb_printf("???\n"); 1359 } else { 1360 switch (help.dtht_where) { 1361 case 0: 1362 mdb_printf("%p\n", helper.dtha_predicate); 1363 break; 1364 1365 case DTRACE_HELPTRACE_NEXT: 1366 case DTRACE_HELPTRACE_DONE: 1367 case DTRACE_HELPTRACE_ERR: 1368 mdb_printf("-\n"); 1369 break; 1370 1371 default: 1372 haddr = (uintptr_t)helper.dtha_actions + 1373 (help.dtht_where - 1) * sizeof (uintptr_t); 1374 1375 if (mdb_vread(&haddr, sizeof (haddr), haddr) == -1) { 1376 mdb_printf("???\n"); 1377 } else { 1378 mdb_printf("%p\n", haddr); 1379 } 1380 } 1381 } 1382 1383 if (opt_v) { 1384 int i; 1385 1386 if (help.dtht_where == DTRACE_HELPTRACE_ERR) { 1387 int f = help.dtht_fault; 1388 1389 mdb_printf("%?s| %?s %10s |\n", "", "", ""); 1390 mdb_printf("%?s| %?s %10s +-> fault: %s\n", "", "", "", 1391 f == DTRACEFLT_BADADDR ? "BADADDR" : 1392 f == DTRACEFLT_BADALIGN ? "BADALIGN" : 1393 f == DTRACEFLT_ILLOP ? "ILLOP" : 1394 f == DTRACEFLT_DIVZERO ? "DIVZERO" : 1395 f == DTRACEFLT_NOSCRATCH ? "NOSCRATCH" : 1396 f == DTRACEFLT_KPRIV ? "KPRIV" : 1397 f == DTRACEFLT_UPRIV ? "UPRIV" : 1398 f == DTRACEFLT_TUPOFLOW ? "TUPOFLOW" : 1399 f == DTRACEFLT_BADSTACK ? "BADSTACK" : 1400 "DTRACEFLT_UNKNOWN"); 1401 mdb_printf("%?s| %?s %12s addr: 0x%x\n", "", "", "", 1402 help.dtht_illval); 1403 mdb_printf("%?s| %?s %12s offset: %d\n", "", "", "", 1404 help.dtht_fltoffs); 1405 } 1406 1407 mdb_printf("%?s|\n%?s+--> %?s %4s %s\n", "", "", 1408 "ADDR", "NDX", "VALUE"); 1409 addr += sizeof (help) - sizeof (uint64_t); 1410 1411 for (i = 0; i < help.dtht_nlocals; i++) { 1412 uint64_t val; 1413 1414 if (mdb_vread(&val, sizeof (val), addr) == -1) { 1415 mdb_warn("couldn't read local at %p", addr); 1416 continue; 1417 } 1418 1419 mdb_printf("%?s %?p %4d %p\n", "", addr, i, val); 1420 addr += sizeof (uint64_t); 1421 } 1422 1423 mdb_printf("\n"); 1424 } 1425 1426 return (DCMD_OK); 1427 } 1428 1429 /*ARGSUSED*/ 1430 static int 1431 dtrace_state_walk(uintptr_t addr, const vmem_seg_t *seg, minor_t *highest) 1432 { 1433 if (seg->vs_end > *highest) 1434 *highest = seg->vs_end; 1435 1436 return (WALK_NEXT); 1437 } 1438 1439 typedef struct dtrace_state_walk { 1440 uintptr_t dtsw_softstate; 1441 minor_t dtsw_max; 1442 minor_t dtsw_current; 1443 } dtrace_state_walk_t; 1444 1445 int 1446 dtrace_state_init(mdb_walk_state_t *wsp) 1447 { 1448 uintptr_t dtrace_minor; 1449 minor_t max = 0; 1450 dtrace_state_walk_t *dw; 1451 1452 if (wsp->walk_addr != NULL) { 1453 mdb_warn("dtrace_state only supports global walks\n"); 1454 return (WALK_ERR); 1455 } 1456 1457 /* 1458 * Find the dtrace_minor vmem arena and walk it to get the maximum 1459 * minor number. 1460 */ 1461 if (mdb_readvar(&dtrace_minor, "dtrace_minor") == -1) { 1462 mdb_warn("failed to read 'dtrace_minor'"); 1463 return (WALK_ERR); 1464 } 1465 1466 if (mdb_pwalk("vmem_alloc", (mdb_walk_cb_t)dtrace_state_walk, 1467 &max, dtrace_minor) == -1) { 1468 mdb_warn("couldn't walk 'vmem_alloc'"); 1469 return (WALK_ERR); 1470 } 1471 1472 dw = mdb_zalloc(sizeof (dtrace_state_walk_t), UM_SLEEP | UM_GC); 1473 dw->dtsw_current = 0; 1474 dw->dtsw_max = max; 1475 1476 if (mdb_readvar(&dw->dtsw_softstate, "dtrace_softstate") == -1) { 1477 mdb_warn("failed to read 'dtrace_softstate'"); 1478 return (DCMD_ERR); 1479 } 1480 1481 wsp->walk_data = dw; 1482 1483 return (WALK_NEXT); 1484 } 1485 1486 int 1487 dtrace_state_step(mdb_walk_state_t *wsp) 1488 { 1489 dtrace_state_walk_t *dw = wsp->walk_data; 1490 uintptr_t statep; 1491 dtrace_state_t state; 1492 int rval; 1493 1494 while (mdb_get_soft_state_byaddr(dw->dtsw_softstate, dw->dtsw_current, 1495 &statep, NULL, 0) == -1) { 1496 if (dw->dtsw_current >= dw->dtsw_max) 1497 return (WALK_DONE); 1498 1499 dw->dtsw_current++; 1500 } 1501 1502 if (mdb_vread(&state, sizeof (state), statep) == -1) { 1503 mdb_warn("couldn't read dtrace_state_t at %p", statep); 1504 return (WALK_NEXT); 1505 } 1506 1507 rval = wsp->walk_callback(statep, &state, wsp->walk_cbdata); 1508 dw->dtsw_current++; 1509 1510 return (rval); 1511 } 1512 1513 typedef struct dtrace_state_data { 1514 int dtsd_major; 1515 uintptr_t dtsd_proc; 1516 uintptr_t dtsd_softstate; 1517 uintptr_t dtsd_state; 1518 } dtrace_state_data_t; 1519 1520 static int 1521 dtrace_state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data) 1522 { 1523 vnode_t vnode; 1524 proc_t proc; 1525 minor_t minor; 1526 uintptr_t statep; 1527 1528 if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) { 1529 mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode); 1530 return (WALK_NEXT); 1531 } 1532 1533 if (getmajor(vnode.v_rdev) != data->dtsd_major) 1534 return (WALK_NEXT); 1535 1536 minor = getminor(vnode.v_rdev); 1537 1538 if (mdb_vread(&proc, sizeof (proc), data->dtsd_proc) == -1) { 1539 mdb_warn("failed to read proc at %p", data->dtsd_proc); 1540 return (WALK_NEXT); 1541 } 1542 1543 if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor, 1544 &statep, NULL, 0) == -1) { 1545 mdb_warn("failed to read softstate for minor %d", minor); 1546 return (WALK_NEXT); 1547 } 1548 1549 if (statep != data->dtsd_state) 1550 return (WALK_NEXT); 1551 1552 mdb_printf("%?p %5d %?p %-*s %?p\n", statep, minor, 1553 data->dtsd_proc, MAXCOMLEN, proc.p_user.u_comm, addr); 1554 1555 return (WALK_NEXT); 1556 } 1557 1558 /*ARGSUSED*/ 1559 static int 1560 dtrace_state_proc(uintptr_t addr, void *ignored, dtrace_state_data_t *data) 1561 { 1562 data->dtsd_proc = addr; 1563 1564 if (mdb_pwalk("file", 1565 (mdb_walk_cb_t)dtrace_state_file, data, addr) == -1) { 1566 mdb_warn("couldn't walk 'file' for proc %p", addr); 1567 return (WALK_ERR); 1568 } 1569 1570 return (WALK_NEXT); 1571 } 1572 1573 void 1574 dtrace_state_help(void) 1575 { 1576 mdb_printf("Given a dtrace_state_t structure, displays all " 1577 /*CSTYLED*/ 1578 "consumers, or \"<anonymous>\"\nif the consumer is anonymous. If " 1579 "no state structure is provided, iterates\nover all state " 1580 "structures.\n\n" 1581 "Addresses in ADDR column may be provided to ::dtrace to obtain\n" 1582 "dtrace(1M)-like output for in-kernel DTrace data.\n"); 1583 } 1584 1585 int 1586 dtrace_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1587 { 1588 uintptr_t devi; 1589 struct dev_info info; 1590 dtrace_state_data_t data; 1591 dtrace_anon_t anon; 1592 dtrace_state_t state; 1593 1594 if (!(flags & DCMD_ADDRSPEC)) { 1595 if (mdb_walk_dcmd("dtrace_state", 1596 "dtrace_state", argc, argv) == -1) { 1597 mdb_warn("can't walk dtrace_state"); 1598 return (DCMD_ERR); 1599 } 1600 return (DCMD_OK); 1601 } 1602 1603 if (DCMD_HDRSPEC(flags)) { 1604 mdb_printf("%?s %5s %?s %-*s %?s\n", "ADDR", "MINOR", "PROC", 1605 MAXCOMLEN, "NAME", "FILE"); 1606 } 1607 1608 /* 1609 * First determine if this is anonymous state. 1610 */ 1611 if (mdb_readvar(&anon, "dtrace_anon") == -1) { 1612 mdb_warn("failed to read 'dtrace_anon'"); 1613 return (DCMD_ERR); 1614 } 1615 1616 if ((uintptr_t)anon.dta_state == addr) { 1617 if (mdb_vread(&state, sizeof (state), addr) == -1) { 1618 mdb_warn("failed to read anon at %p", addr); 1619 return (DCMD_ERR); 1620 } 1621 1622 mdb_printf("%?p %5d %?s %-*s %?s\n", addr, 1623 getminor(state.dts_dev), "-", MAXCOMLEN, 1624 "<anonymous>", "-"); 1625 1626 return (DCMD_OK); 1627 } 1628 1629 if (mdb_readvar(&devi, "dtrace_devi") == -1) { 1630 mdb_warn("failed to read 'dtrace_devi'"); 1631 return (DCMD_ERR); 1632 } 1633 1634 if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) { 1635 mdb_warn("failed to read 'dev_info'"); 1636 return (DCMD_ERR); 1637 } 1638 1639 data.dtsd_major = info.devi_major; 1640 1641 if (mdb_readvar(&data.dtsd_softstate, "dtrace_softstate") == -1) { 1642 mdb_warn("failed to read 'dtrace_softstate'"); 1643 return (DCMD_ERR); 1644 } 1645 1646 data.dtsd_state = addr; 1647 1648 /* 1649 * Walk through all processes and all open files looking for this 1650 * state. It must be open somewhere... 1651 */ 1652 if (mdb_walk("proc", (mdb_walk_cb_t)dtrace_state_proc, &data) == -1) { 1653 mdb_warn("couldn't walk 'proc'"); 1654 return (DCMD_ERR); 1655 } 1656 1657 return (DCMD_OK); 1658 } 1659 1660 typedef struct dtrace_aggkey_data { 1661 uintptr_t *dtakd_hash; 1662 uintptr_t dtakd_hashsize; 1663 uintptr_t dtakd_next; 1664 uintptr_t dtakd_ndx; 1665 } dtrace_aggkey_data_t; 1666 1667 int 1668 dtrace_aggkey_init(mdb_walk_state_t *wsp) 1669 { 1670 dtrace_buffer_t buf; 1671 uintptr_t addr; 1672 dtrace_aggbuffer_t agb; 1673 dtrace_aggkey_data_t *data; 1674 size_t hsize; 1675 1676 if ((addr = wsp->walk_addr) == NULL) { 1677 mdb_warn("dtrace_aggkey walk needs aggregation buffer\n"); 1678 return (WALK_ERR); 1679 } 1680 1681 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 1682 mdb_warn("failed to read aggregation buffer at %p", addr); 1683 return (WALK_ERR); 1684 } 1685 1686 addr = (uintptr_t)buf.dtb_tomax + 1687 buf.dtb_size - sizeof (dtrace_aggbuffer_t); 1688 1689 if (mdb_vread(&agb, sizeof (agb), addr) == -1) { 1690 mdb_warn("failed to read dtrace_aggbuffer_t at %p", addr); 1691 return (WALK_ERR); 1692 } 1693 1694 data = mdb_zalloc(sizeof (dtrace_aggkey_data_t), UM_SLEEP); 1695 1696 data->dtakd_hashsize = agb.dtagb_hashsize; 1697 hsize = agb.dtagb_hashsize * sizeof (dtrace_aggkey_t *); 1698 data->dtakd_hash = mdb_alloc(hsize, UM_SLEEP); 1699 1700 if (mdb_vread(data->dtakd_hash, hsize, 1701 (uintptr_t)agb.dtagb_hash) == -1) { 1702 mdb_warn("failed to read hash at %p", 1703 (uintptr_t)agb.dtagb_hash); 1704 mdb_free(data->dtakd_hash, hsize); 1705 mdb_free(data, sizeof (dtrace_aggkey_data_t)); 1706 return (WALK_ERR); 1707 } 1708 1709 wsp->walk_data = data; 1710 return (WALK_NEXT); 1711 } 1712 1713 int 1714 dtrace_aggkey_step(mdb_walk_state_t *wsp) 1715 { 1716 dtrace_aggkey_data_t *data = wsp->walk_data; 1717 dtrace_aggkey_t key; 1718 uintptr_t addr; 1719 1720 while ((addr = data->dtakd_next) == NULL) { 1721 if (data->dtakd_ndx == data->dtakd_hashsize) 1722 return (WALK_DONE); 1723 1724 data->dtakd_next = data->dtakd_hash[data->dtakd_ndx++]; 1725 } 1726 1727 if (mdb_vread(&key, sizeof (key), addr) == -1) { 1728 mdb_warn("failed to read dtrace_aggkey_t at %p", addr); 1729 return (WALK_ERR); 1730 } 1731 1732 data->dtakd_next = (uintptr_t)key.dtak_next; 1733 1734 return (wsp->walk_callback(addr, &key, wsp->walk_cbdata)); 1735 } 1736 1737 void 1738 dtrace_aggkey_fini(mdb_walk_state_t *wsp) 1739 { 1740 dtrace_aggkey_data_t *data = wsp->walk_data; 1741 size_t hsize; 1742 1743 hsize = data->dtakd_hashsize * sizeof (dtrace_aggkey_t *); 1744 mdb_free(data->dtakd_hash, hsize); 1745 mdb_free(data, sizeof (dtrace_aggkey_data_t)); 1746 } 1747 1748 typedef struct dtrace_dynvar_data { 1749 dtrace_dynhash_t *dtdvd_hash; 1750 uintptr_t dtdvd_hashsize; 1751 uintptr_t dtdvd_next; 1752 uintptr_t dtdvd_ndx; 1753 } dtrace_dynvar_data_t; 1754 1755 int 1756 dtrace_dynvar_init(mdb_walk_state_t *wsp) 1757 { 1758 uintptr_t addr; 1759 dtrace_dstate_t dstate; 1760 dtrace_dynvar_data_t *data; 1761 size_t hsize; 1762 1763 if ((addr = wsp->walk_addr) == NULL) { 1764 mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n"); 1765 return (WALK_ERR); 1766 } 1767 1768 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) { 1769 mdb_warn("failed to read dynamic state at %p", addr); 1770 return (WALK_ERR); 1771 } 1772 1773 data = mdb_zalloc(sizeof (dtrace_dynvar_data_t), UM_SLEEP); 1774 1775 data->dtdvd_hashsize = dstate.dtds_hashsize; 1776 hsize = dstate.dtds_hashsize * sizeof (dtrace_dynhash_t); 1777 data->dtdvd_hash = mdb_alloc(hsize, UM_SLEEP); 1778 1779 if (mdb_vread(data->dtdvd_hash, hsize, 1780 (uintptr_t)dstate.dtds_hash) == -1) { 1781 mdb_warn("failed to read hash at %p", 1782 (uintptr_t)dstate.dtds_hash); 1783 mdb_free(data->dtdvd_hash, hsize); 1784 mdb_free(data, sizeof (dtrace_dynvar_data_t)); 1785 return (WALK_ERR); 1786 } 1787 1788 wsp->walk_data = data; 1789 return (WALK_NEXT); 1790 } 1791 1792 int 1793 dtrace_dynvar_step(mdb_walk_state_t *wsp) 1794 { 1795 dtrace_dynvar_data_t *data = wsp->walk_data; 1796 dtrace_dynvar_t dynvar, *dvar; 1797 size_t dvarsize; 1798 uintptr_t addr; 1799 int nkeys; 1800 1801 while ((addr = data->dtdvd_next) == NULL) { 1802 if (data->dtdvd_ndx == data->dtdvd_hashsize) 1803 return (WALK_DONE); 1804 1805 data->dtdvd_next = 1806 (uintptr_t)data->dtdvd_hash[data->dtdvd_ndx++].dtdh_chain; 1807 } 1808 1809 if (mdb_vread(&dynvar, sizeof (dynvar), addr) == -1) { 1810 mdb_warn("failed to read dtrace_dynvar_t at %p", addr); 1811 return (WALK_ERR); 1812 } 1813 1814 /* 1815 * Now we need to allocate the correct size. 1816 */ 1817 nkeys = dynvar.dtdv_tuple.dtt_nkeys; 1818 dvarsize = (uintptr_t)&dynvar.dtdv_tuple.dtt_key[nkeys] - 1819 (uintptr_t)&dynvar; 1820 1821 dvar = alloca(dvarsize); 1822 1823 if (mdb_vread(dvar, dvarsize, addr) == -1) { 1824 mdb_warn("failed to read dtrace_dynvar_t at %p", addr); 1825 return (WALK_ERR); 1826 } 1827 1828 data->dtdvd_next = (uintptr_t)dynvar.dtdv_next; 1829 1830 return (wsp->walk_callback(addr, dvar, wsp->walk_cbdata)); 1831 } 1832 1833 void 1834 dtrace_dynvar_fini(mdb_walk_state_t *wsp) 1835 { 1836 dtrace_dynvar_data_t *data = wsp->walk_data; 1837 size_t hsize; 1838 1839 hsize = data->dtdvd_hashsize * sizeof (dtrace_dynvar_t *); 1840 mdb_free(data->dtdvd_hash, hsize); 1841 mdb_free(data, sizeof (dtrace_dynvar_data_t)); 1842 } 1843 1844 typedef struct dtrace_hashstat_data { 1845 size_t *dthsd_counts; 1846 size_t dthsd_hashsize; 1847 char *dthsd_data; 1848 size_t dthsd_size; 1849 int dthsd_header; 1850 } dtrace_hashstat_data_t; 1851 1852 typedef void (*dtrace_hashstat_func_t)(dtrace_hashstat_data_t *); 1853 1854 static void 1855 dtrace_hashstat_additive(dtrace_hashstat_data_t *data) 1856 { 1857 int i; 1858 int hval = 0; 1859 1860 for (i = 0; i < data->dthsd_size; i++) 1861 hval += data->dthsd_data[i]; 1862 1863 data->dthsd_counts[hval % data->dthsd_hashsize]++; 1864 } 1865 1866 static void 1867 dtrace_hashstat_shifty(dtrace_hashstat_data_t *data) 1868 { 1869 uint64_t hval = 0; 1870 int i; 1871 1872 if (data->dthsd_size < sizeof (uint64_t)) { 1873 dtrace_hashstat_additive(data); 1874 return; 1875 } 1876 1877 for (i = 0; i < data->dthsd_size; i += sizeof (uint64_t)) { 1878 /* LINTED - alignment */ 1879 uint64_t val = *((uint64_t *)&data->dthsd_data[i]); 1880 1881 hval += (val & ((1 << NBBY) - 1)) + 1882 ((val >> NBBY) & ((1 << NBBY) - 1)) + 1883 ((val >> (NBBY << 1)) & ((1 << NBBY) - 1)) + 1884 ((val >> (NBBY << 2)) & ((1 << NBBY) - 1)) + 1885 (val & USHRT_MAX) + (val >> (NBBY << 1) & USHRT_MAX); 1886 } 1887 1888 data->dthsd_counts[hval % data->dthsd_hashsize]++; 1889 } 1890 1891 static void 1892 dtrace_hashstat_knuth(dtrace_hashstat_data_t *data) 1893 { 1894 int i; 1895 int hval = data->dthsd_size; 1896 1897 for (i = 0; i < data->dthsd_size; i++) 1898 hval = (hval << 4) ^ (hval >> 28) ^ data->dthsd_data[i]; 1899 1900 data->dthsd_counts[hval % data->dthsd_hashsize]++; 1901 } 1902 1903 static void 1904 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t *data) 1905 { 1906 int i; 1907 uint32_t hval = 0; 1908 1909 for (i = 0; i < data->dthsd_size; i++) { 1910 hval += data->dthsd_data[i]; 1911 hval += (hval << 10); 1912 hval ^= (hval >> 6); 1913 } 1914 1915 hval += (hval << 3); 1916 hval ^= (hval >> 11); 1917 hval += (hval << 15); 1918 1919 data->dthsd_counts[hval % data->dthsd_hashsize]++; 1920 } 1921 1922 static void 1923 dtrace_hashstat_fnv(dtrace_hashstat_data_t *data) 1924 { 1925 static const uint32_t prime = 0x01000193; 1926 uint32_t hval = 0; 1927 int i; 1928 1929 for (i = 0; i < data->dthsd_size; i++) { 1930 hval *= prime; 1931 hval ^= data->dthsd_data[i]; 1932 } 1933 1934 data->dthsd_counts[hval % data->dthsd_hashsize]++; 1935 } 1936 1937 static void 1938 dtrace_hashstat_stats(char *name, dtrace_hashstat_data_t *data) 1939 { 1940 size_t nz = 0, i; 1941 int longest = 0; 1942 size_t ttl = 0; 1943 double sum = 0.0; 1944 double avg; 1945 uint_t util, stddev; 1946 1947 if (!data->dthsd_header) { 1948 mdb_printf("%15s %11s %11s %11s %11s %11s\n", "NAME", 1949 "HASHSIZE", "%UTIL", "LONGEST", "AVERAGE", "STDDEV"); 1950 data->dthsd_header = 1; 1951 } 1952 1953 for (i = 0; i < data->dthsd_hashsize; i++) { 1954 if (data->dthsd_counts[i] != 0) { 1955 nz++; 1956 1957 if (data->dthsd_counts[i] > longest) 1958 longest = data->dthsd_counts[i]; 1959 1960 ttl += data->dthsd_counts[i]; 1961 } 1962 } 1963 1964 if (nz == 0) { 1965 mdb_printf("%15s %11d %11s %11s %11s %11s\n", name, 1966 data->dthsd_hashsize, "-", "-", "-", "-"); 1967 return; 1968 } 1969 1970 avg = (double)ttl / (double)nz; 1971 1972 for (i = 0; i < data->dthsd_hashsize; i++) { 1973 double delta = (double)data->dthsd_counts[i] - avg; 1974 1975 if (data->dthsd_counts[i] == 0) 1976 continue; 1977 1978 sum += delta * delta; 1979 } 1980 1981 util = (nz * 1000) / data->dthsd_hashsize; 1982 stddev = (uint_t)sqrt(sum / (double)nz) * 10; 1983 1984 mdb_printf("%15s %11d %9u.%1u %11d %11d %9u.%1u\n", name, 1985 data->dthsd_hashsize, util / 10, util % 10, longest, ttl / nz, 1986 stddev / 10, stddev % 10); 1987 } 1988 1989 static struct dtrace_hashstat { 1990 char *dths_name; 1991 dtrace_hashstat_func_t dths_func; 1992 } _dtrace_hashstat[] = { 1993 { "<actual>", NULL }, 1994 { "additive", dtrace_hashstat_additive }, 1995 { "shifty", dtrace_hashstat_shifty }, 1996 { "knuth", dtrace_hashstat_knuth }, 1997 { "one-at-a-time", dtrace_hashstat_oneatatime }, 1998 { "fnv", dtrace_hashstat_fnv }, 1999 { NULL, 0 } 2000 }; 2001 2002 typedef struct dtrace_aggstat_data { 2003 dtrace_hashstat_data_t dtagsd_hash; 2004 dtrace_hashstat_func_t dtagsd_func; 2005 } dtrace_aggstat_data_t; 2006 2007 static int 2008 dtrace_aggstat_walk(uintptr_t addr, dtrace_aggkey_t *key, 2009 dtrace_aggstat_data_t *data) 2010 { 2011 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash; 2012 size_t size; 2013 2014 if (data->dtagsd_func == NULL) { 2015 size_t bucket = key->dtak_hashval % hdata->dthsd_hashsize; 2016 2017 hdata->dthsd_counts[bucket]++; 2018 return (WALK_NEXT); 2019 } 2020 2021 /* 2022 * We need to read the data. 2023 */ 2024 size = key->dtak_size - sizeof (dtrace_aggid_t); 2025 addr = (uintptr_t)key->dtak_data + sizeof (dtrace_aggid_t); 2026 hdata->dthsd_data = alloca(size); 2027 hdata->dthsd_size = size; 2028 2029 if (mdb_vread(hdata->dthsd_data, size, addr) == -1) { 2030 mdb_warn("couldn't read data at %p", addr); 2031 return (WALK_ERR); 2032 } 2033 2034 data->dtagsd_func(hdata); 2035 2036 return (WALK_NEXT); 2037 } 2038 2039 /*ARGSUSED*/ 2040 int 2041 dtrace_aggstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2042 { 2043 dtrace_buffer_t buf; 2044 uintptr_t aaddr; 2045 dtrace_aggbuffer_t agb; 2046 size_t hsize, i, actual, prime, evenpow; 2047 dtrace_aggstat_data_t data; 2048 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash; 2049 2050 bzero(&data, sizeof (data)); 2051 2052 if (!(flags & DCMD_ADDRSPEC)) 2053 return (DCMD_USAGE); 2054 2055 if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 2056 mdb_warn("failed to read aggregation buffer at %p", addr); 2057 return (DCMD_ERR); 2058 } 2059 2060 aaddr = (uintptr_t)buf.dtb_tomax + 2061 buf.dtb_size - sizeof (dtrace_aggbuffer_t); 2062 2063 if (mdb_vread(&agb, sizeof (agb), aaddr) == -1) { 2064 mdb_warn("failed to read dtrace_aggbuffer_t at %p", aaddr); 2065 return (DCMD_ERR); 2066 } 2067 2068 hsize = (actual = agb.dtagb_hashsize) * sizeof (size_t); 2069 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC); 2070 2071 /* 2072 * Now pick the largest prime smaller than the hash size. (If the 2073 * existing size is prime, we'll pick a smaller prime just for the 2074 * hell of it.) 2075 */ 2076 for (prime = agb.dtagb_hashsize - 1; prime > 7; prime--) { 2077 size_t limit = prime / 7; 2078 2079 for (i = 2; i < limit; i++) { 2080 if ((prime % i) == 0) 2081 break; 2082 } 2083 2084 if (i == limit) 2085 break; 2086 } 2087 2088 /* 2089 * And now we want to pick the largest power of two smaller than the 2090 * hashsize. 2091 */ 2092 for (i = 0; (1 << i) < agb.dtagb_hashsize; i++) 2093 continue; 2094 2095 evenpow = (1 << (i - 1)); 2096 2097 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) { 2098 data.dtagsd_func = _dtrace_hashstat[i].dths_func; 2099 2100 hdata->dthsd_hashsize = actual; 2101 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2102 bzero(hdata->dthsd_counts, hsize); 2103 2104 if (mdb_pwalk("dtrace_aggkey", 2105 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2106 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2107 return (DCMD_ERR); 2108 } 2109 2110 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2111 2112 /* 2113 * If we were just printing the actual value, we won't try 2114 * any of the sizing experiments. 2115 */ 2116 if (data.dtagsd_func == NULL) 2117 continue; 2118 2119 hdata->dthsd_hashsize = prime; 2120 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2121 bzero(hdata->dthsd_counts, hsize); 2122 2123 if (mdb_pwalk("dtrace_aggkey", 2124 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2125 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2126 return (DCMD_ERR); 2127 } 2128 2129 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2130 2131 hdata->dthsd_hashsize = evenpow; 2132 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2133 bzero(hdata->dthsd_counts, hsize); 2134 2135 if (mdb_pwalk("dtrace_aggkey", 2136 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) { 2137 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2138 return (DCMD_ERR); 2139 } 2140 2141 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2142 } 2143 2144 return (DCMD_OK); 2145 } 2146 2147 /*ARGSUSED*/ 2148 static int 2149 dtrace_dynstat_walk(uintptr_t addr, dtrace_dynvar_t *dynvar, 2150 dtrace_aggstat_data_t *data) 2151 { 2152 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash; 2153 dtrace_tuple_t *tuple = &dynvar->dtdv_tuple; 2154 dtrace_key_t *key = tuple->dtt_key; 2155 size_t size = 0, offs = 0; 2156 int i, nkeys = tuple->dtt_nkeys; 2157 char *buf; 2158 2159 if (data->dtagsd_func == NULL) { 2160 size_t bucket = dynvar->dtdv_hashval % hdata->dthsd_hashsize; 2161 2162 hdata->dthsd_counts[bucket]++; 2163 return (WALK_NEXT); 2164 } 2165 2166 /* 2167 * We want to hand the hashing algorithm a contiguous buffer. First 2168 * run through the tuple and determine the size. 2169 */ 2170 for (i = 0; i < nkeys; i++) { 2171 if (key[i].dttk_size == 0) { 2172 size += sizeof (uint64_t); 2173 } else { 2174 size += key[i].dttk_size; 2175 } 2176 } 2177 2178 buf = alloca(size); 2179 2180 /* 2181 * Now go back through the tuple and copy the data into the buffer. 2182 */ 2183 for (i = 0; i < nkeys; i++) { 2184 if (key[i].dttk_size == 0) { 2185 bcopy(&key[i].dttk_value, &buf[offs], 2186 sizeof (uint64_t)); 2187 offs += sizeof (uint64_t); 2188 } else { 2189 if (mdb_vread(&buf[offs], key[i].dttk_size, 2190 key[i].dttk_value) == -1) { 2191 mdb_warn("couldn't read tuple data at %p", 2192 key[i].dttk_value); 2193 return (WALK_ERR); 2194 } 2195 2196 offs += key[i].dttk_size; 2197 } 2198 } 2199 2200 hdata->dthsd_data = buf; 2201 hdata->dthsd_size = size; 2202 2203 data->dtagsd_func(hdata); 2204 2205 return (WALK_NEXT); 2206 } 2207 2208 /*ARGSUSED*/ 2209 int 2210 dtrace_dynstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2211 { 2212 dtrace_dstate_t dstate; 2213 size_t hsize, i, actual, prime; 2214 dtrace_aggstat_data_t data; 2215 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash; 2216 2217 bzero(&data, sizeof (data)); 2218 2219 if (!(flags & DCMD_ADDRSPEC)) 2220 return (DCMD_USAGE); 2221 2222 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) { 2223 mdb_warn("failed to read dynamic variable state at %p", addr); 2224 return (DCMD_ERR); 2225 } 2226 2227 hsize = (actual = dstate.dtds_hashsize) * sizeof (size_t); 2228 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC); 2229 2230 /* 2231 * Now pick the largest prime smaller than the hash size. (If the 2232 * existing size is prime, we'll pick a smaller prime just for the 2233 * hell of it.) 2234 */ 2235 for (prime = dstate.dtds_hashsize - 1; prime > 7; prime--) { 2236 size_t limit = prime / 7; 2237 2238 for (i = 2; i < limit; i++) { 2239 if ((prime % i) == 0) 2240 break; 2241 } 2242 2243 if (i == limit) 2244 break; 2245 } 2246 2247 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) { 2248 data.dtagsd_func = _dtrace_hashstat[i].dths_func; 2249 2250 hdata->dthsd_hashsize = actual; 2251 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2252 bzero(hdata->dthsd_counts, hsize); 2253 2254 if (mdb_pwalk("dtrace_dynvar", 2255 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) { 2256 mdb_warn("failed to walk dtrace_dynvar at %p", addr); 2257 return (DCMD_ERR); 2258 } 2259 2260 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2261 2262 /* 2263 * If we were just printing the actual value, we won't try 2264 * any of the sizing experiments. 2265 */ 2266 if (data.dtagsd_func == NULL) 2267 continue; 2268 2269 hdata->dthsd_hashsize = prime; 2270 hsize = hdata->dthsd_hashsize * sizeof (size_t); 2271 bzero(hdata->dthsd_counts, hsize); 2272 2273 if (mdb_pwalk("dtrace_dynvar", 2274 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) { 2275 mdb_warn("failed to walk dtrace_aggkey at %p", addr); 2276 return (DCMD_ERR); 2277 } 2278 2279 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata); 2280 } 2281 2282 return (DCMD_OK); 2283 } 2284 2285 typedef struct dtrace_ecb_walk { 2286 dtrace_ecb_t **dtew_ecbs; 2287 int dtew_necbs; 2288 int dtew_curecb; 2289 } dtrace_ecb_walk_t; 2290 2291 static int 2292 dtrace_ecb_init(mdb_walk_state_t *wsp) 2293 { 2294 uintptr_t addr; 2295 dtrace_state_t state; 2296 dtrace_ecb_walk_t *ecbwp; 2297 2298 if ((addr = wsp->walk_addr) == NULL) { 2299 mdb_warn("dtrace_ecb walk needs dtrace_state_t\n"); 2300 return (WALK_ERR); 2301 } 2302 2303 if (mdb_vread(&state, sizeof (state), addr) == -1) { 2304 mdb_warn("failed to read dtrace state pointer at %p", addr); 2305 return (WALK_ERR); 2306 } 2307 2308 ecbwp = mdb_zalloc(sizeof (dtrace_ecb_walk_t), UM_SLEEP | UM_GC); 2309 2310 ecbwp->dtew_ecbs = state.dts_ecbs; 2311 ecbwp->dtew_necbs = state.dts_necbs; 2312 ecbwp->dtew_curecb = 0; 2313 2314 wsp->walk_data = ecbwp; 2315 2316 return (WALK_NEXT); 2317 } 2318 2319 static int 2320 dtrace_ecb_step(mdb_walk_state_t *wsp) 2321 { 2322 uintptr_t ecbp, addr; 2323 dtrace_ecb_walk_t *ecbwp = wsp->walk_data; 2324 2325 addr = (uintptr_t)ecbwp->dtew_ecbs + 2326 ecbwp->dtew_curecb * sizeof (dtrace_ecb_t *); 2327 2328 if (ecbwp->dtew_curecb++ == ecbwp->dtew_necbs) 2329 return (WALK_DONE); 2330 2331 if (mdb_vread(&ecbp, sizeof (addr), addr) == -1) { 2332 mdb_warn("failed to read ecb at entry %d\n", 2333 ecbwp->dtew_curecb); 2334 return (WALK_ERR); 2335 } 2336 2337 if (ecbp == NULL) 2338 return (WALK_NEXT); 2339 2340 return (wsp->walk_callback(ecbp, NULL, wsp->walk_cbdata)); 2341 } 2342 2343 static void 2344 dtrace_options_numtostr(uint64_t num, char *buf, size_t len) 2345 { 2346 uint64_t n = num; 2347 int index = 0; 2348 char u; 2349 2350 while (n >= 1024) { 2351 n = (n + (1024 / 2)) / 1024; /* Round up or down */ 2352 index++; 2353 } 2354 2355 u = " KMGTPE"[index]; 2356 2357 if (index == 0) { 2358 (void) mdb_snprintf(buf, len, "%llu", (u_longlong_t)n); 2359 } else if (n < 10 && (num & (num - 1)) != 0) { 2360 (void) mdb_snprintf(buf, len, "%.2f%c", 2361 (double)num / (1ULL << 10 * index), u); 2362 } else if (n < 100 && (num & (num - 1)) != 0) { 2363 (void) mdb_snprintf(buf, len, "%.1f%c", 2364 (double)num / (1ULL << 10 * index), u); 2365 } else { 2366 (void) mdb_snprintf(buf, len, "%llu%c", (u_longlong_t)n, u); 2367 } 2368 } 2369 2370 static void 2371 dtrace_options_numtohz(uint64_t num, char *buf, size_t len) 2372 { 2373 (void) mdb_snprintf(buf, len, "%dhz", NANOSEC/num); 2374 } 2375 2376 static void 2377 dtrace_options_numtobufpolicy(uint64_t num, char *buf, size_t len) 2378 { 2379 char *policy = "unknown"; 2380 2381 switch (num) { 2382 case DTRACEOPT_BUFPOLICY_RING: 2383 policy = "ring"; 2384 break; 2385 2386 case DTRACEOPT_BUFPOLICY_FILL: 2387 policy = "fill"; 2388 break; 2389 2390 case DTRACEOPT_BUFPOLICY_SWITCH: 2391 policy = "switch"; 2392 break; 2393 } 2394 2395 (void) mdb_snprintf(buf, len, "%s", policy); 2396 } 2397 2398 static void 2399 dtrace_options_numtocpu(uint64_t cpu, char *buf, size_t len) 2400 { 2401 if (cpu == DTRACE_CPUALL) 2402 (void) mdb_snprintf(buf, len, "%7s", "unbound"); 2403 else 2404 (void) mdb_snprintf(buf, len, "%d", cpu); 2405 } 2406 2407 typedef void (*dtrace_options_func_t)(uint64_t, char *, size_t); 2408 2409 static struct dtrace_options { 2410 char *dtop_optstr; 2411 dtrace_options_func_t dtop_func; 2412 } _dtrace_options[] = { 2413 { "bufsize", dtrace_options_numtostr }, 2414 { "bufpolicy", dtrace_options_numtobufpolicy }, 2415 { "dynvarsize", dtrace_options_numtostr }, 2416 { "aggsize", dtrace_options_numtostr }, 2417 { "specsize", dtrace_options_numtostr }, 2418 { "nspec", dtrace_options_numtostr }, 2419 { "strsize", dtrace_options_numtostr }, 2420 { "cleanrate", dtrace_options_numtohz }, 2421 { "cpu", dtrace_options_numtocpu }, 2422 { "bufresize", dtrace_options_numtostr }, 2423 { "grabanon", dtrace_options_numtostr }, 2424 { "flowindent", dtrace_options_numtostr }, 2425 { "quiet", dtrace_options_numtostr }, 2426 { "stackframes", dtrace_options_numtostr }, 2427 { "ustackframes", dtrace_options_numtostr }, 2428 { "aggrate", dtrace_options_numtohz }, 2429 { "switchrate", dtrace_options_numtohz }, 2430 { "statusrate", dtrace_options_numtohz }, 2431 { "destructive", dtrace_options_numtostr }, 2432 { "stackindent", dtrace_options_numtostr }, 2433 { "rawbytes", dtrace_options_numtostr }, 2434 { "jstackframes", dtrace_options_numtostr }, 2435 { "jstackstrsize", dtrace_options_numtostr }, 2436 { "aggsortkey", dtrace_options_numtostr }, 2437 { "aggsortrev", dtrace_options_numtostr }, 2438 { "aggsortpos", dtrace_options_numtostr }, 2439 { "aggsortkeypos", dtrace_options_numtostr } 2440 }; 2441 2442 static void 2443 dtrace_options_help(void) 2444 { 2445 mdb_printf("Given a dtrace_state_t structure, displays the " 2446 "current tunable option\nsettings.\n"); 2447 } 2448 2449 /*ARGSUSED*/ 2450 static int 2451 dtrace_options(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2452 { 2453 dtrace_state_t state; 2454 int i = 0; 2455 dtrace_optval_t *options; 2456 char val[32]; 2457 2458 if (!(flags & DCMD_ADDRSPEC)) 2459 return (DCMD_USAGE); 2460 2461 if (mdb_vread(&state, sizeof (dtrace_state_t), (uintptr_t)addr) == -1) { 2462 mdb_warn("failed to read state pointer at %p\n", addr); 2463 return (DCMD_ERR); 2464 } 2465 2466 options = &state.dts_options[0]; 2467 2468 mdb_printf("%<u>%-25s %s%</u>\n", "OPTION", "VALUE"); 2469 for (i = 0; i < DTRACEOPT_MAX; i++) { 2470 if (options[i] == DTRACEOPT_UNSET) { 2471 mdb_printf("%-25s %s\n", 2472 _dtrace_options[i].dtop_optstr, "UNSET"); 2473 } else { 2474 (void) _dtrace_options[i].dtop_func(options[i], 2475 val, 32); 2476 mdb_printf("%-25s %s\n", 2477 _dtrace_options[i].dtop_optstr, val); 2478 } 2479 } 2480 2481 return (DCMD_OK); 2482 } 2483 2484 static int 2485 pid2state_init(mdb_walk_state_t *wsp) 2486 { 2487 dtrace_state_data_t *data; 2488 uintptr_t devi; 2489 uintptr_t proc; 2490 struct dev_info info; 2491 pid_t pid = (pid_t)wsp->walk_addr; 2492 2493 if (wsp->walk_addr == NULL) { 2494 mdb_warn("pid2state walk requires PID\n"); 2495 return (WALK_ERR); 2496 } 2497 2498 data = mdb_zalloc(sizeof (dtrace_state_data_t), UM_SLEEP | UM_GC); 2499 2500 if (mdb_readvar(&data->dtsd_softstate, "dtrace_softstate") == -1) { 2501 mdb_warn("failed to read 'dtrace_softstate'"); 2502 return (DCMD_ERR); 2503 } 2504 2505 if ((proc = mdb_pid2proc(pid, NULL)) == NULL) { 2506 mdb_warn("PID 0t%d not found\n", pid); 2507 return (DCMD_ERR); 2508 } 2509 2510 if (mdb_readvar(&devi, "dtrace_devi") == -1) { 2511 mdb_warn("failed to read 'dtrace_devi'"); 2512 return (DCMD_ERR); 2513 } 2514 2515 if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) { 2516 mdb_warn("failed to read 'dev_info'"); 2517 return (DCMD_ERR); 2518 } 2519 2520 data->dtsd_major = info.devi_major; 2521 data->dtsd_proc = proc; 2522 2523 wsp->walk_data = data; 2524 2525 return (WALK_NEXT); 2526 } 2527 2528 /*ARGSUSED*/ 2529 static int 2530 pid2state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data) 2531 { 2532 vnode_t vnode; 2533 minor_t minor; 2534 uintptr_t statep; 2535 2536 /* Get the vnode for this file */ 2537 if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) { 2538 mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode); 2539 return (WALK_NEXT); 2540 } 2541 2542 2543 /* Is this the dtrace device? */ 2544 if (getmajor(vnode.v_rdev) != data->dtsd_major) 2545 return (WALK_NEXT); 2546 2547 /* Get the minor number for this device entry */ 2548 minor = getminor(vnode.v_rdev); 2549 2550 if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor, 2551 &statep, NULL, 0) == -1) { 2552 mdb_warn("failed to read softstate for minor %d", minor); 2553 return (WALK_NEXT); 2554 } 2555 2556 mdb_printf("%p\n", statep); 2557 2558 return (WALK_NEXT); 2559 } 2560 2561 static int 2562 pid2state_step(mdb_walk_state_t *wsp) 2563 { 2564 dtrace_state_data_t *ds = wsp->walk_data; 2565 2566 if (mdb_pwalk("file", 2567 (mdb_walk_cb_t)pid2state_file, ds, ds->dtsd_proc) == -1) { 2568 mdb_warn("couldn't walk 'file' for proc %p", ds->dtsd_proc); 2569 return (WALK_ERR); 2570 } 2571 2572 return (WALK_DONE); 2573 } 2574 2575 /*ARGSUSED*/ 2576 static int 2577 dtrace_probes_walk(uintptr_t addr, void *ignored, uintptr_t *target) 2578 { 2579 dtrace_ecb_t ecb; 2580 dtrace_probe_t probe; 2581 dtrace_probedesc_t pd; 2582 2583 if (addr == NULL) 2584 return (WALK_ERR); 2585 2586 if (mdb_vread(&ecb, sizeof (dtrace_ecb_t), addr) == -1) { 2587 mdb_warn("failed to read ecb %p\n", addr); 2588 return (WALK_ERR); 2589 } 2590 2591 if (ecb.dte_probe == NULL) 2592 return (WALK_ERR); 2593 2594 if (mdb_vread(&probe, sizeof (dtrace_probe_t), 2595 (uintptr_t)ecb.dte_probe) == -1) { 2596 mdb_warn("failed to read probe %p\n", ecb.dte_probe); 2597 return (WALK_ERR); 2598 } 2599 2600 pd.dtpd_id = probe.dtpr_id; 2601 dtracemdb_probe(NULL, &pd); 2602 2603 mdb_printf("%5d %10s %17s %33s %s\n", pd.dtpd_id, pd.dtpd_provider, 2604 pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name); 2605 2606 return (WALK_NEXT); 2607 } 2608 2609 static void 2610 dtrace_probes_help(void) 2611 { 2612 mdb_printf("Given a dtrace_state_t structure, displays all " 2613 "its active enablings. If no\nstate structure is provided, " 2614 "all available probes are listed.\n"); 2615 } 2616 2617 /*ARGSUSED*/ 2618 static int 2619 dtrace_probes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2620 { 2621 dtrace_probedesc_t pd; 2622 uintptr_t caddr, base, paddr; 2623 int nprobes, i; 2624 2625 mdb_printf("%5s %10s %17s %33s %s\n", 2626 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME"); 2627 2628 if (!(flags & DCMD_ADDRSPEC)) { 2629 /* 2630 * If no argument is provided just display all available 2631 * probes. 2632 */ 2633 if (mdb_readvar(&base, "dtrace_probes") == -1) { 2634 mdb_warn("failed to read 'dtrace_probes'"); 2635 return (-1); 2636 } 2637 2638 if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) { 2639 mdb_warn("failed to read 'dtrace_nprobes'"); 2640 return (-1); 2641 } 2642 2643 for (i = 0; i < nprobes; i++) { 2644 caddr = base + i * sizeof (dtrace_probe_t *); 2645 2646 if (mdb_vread(&paddr, sizeof (paddr), caddr) == -1) { 2647 mdb_warn("couldn't read probe pointer at %p", 2648 caddr); 2649 continue; 2650 } 2651 2652 if (paddr == NULL) 2653 continue; 2654 2655 pd.dtpd_id = i + 1; 2656 if (dtracemdb_probe(NULL, &pd) == 0) { 2657 mdb_printf("%5d %10s %17s %33s %s\n", 2658 pd.dtpd_id, pd.dtpd_provider, 2659 pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name); 2660 } 2661 } 2662 } else { 2663 if (mdb_pwalk("dtrace_ecb", (mdb_walk_cb_t)dtrace_probes_walk, 2664 NULL, addr) == -1) { 2665 mdb_warn("couldn't walk 'dtrace_ecb'"); 2666 return (DCMD_ERR); 2667 } 2668 } 2669 2670 return (DCMD_OK); 2671 } 2672 2673 const mdb_dcmd_t kernel_dcmds[] = { 2674 { "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t", 2675 id2probe }, 2676 { "dtrace", ":[-c cpu]", "print dtrace(1M)-like output", 2677 dtrace, dtrace_help }, 2678 { "dtrace_errhash", ":", "print DTrace error hash", dtrace_errhash }, 2679 { "dtrace_helptrace", ":", "print DTrace helper trace", 2680 dtrace_helptrace }, 2681 { "dtrace_state", ":", "print active DTrace consumers", dtrace_state, 2682 dtrace_state_help }, 2683 { "dtrace_aggstat", ":", 2684 "print DTrace aggregation hash statistics", dtrace_aggstat }, 2685 { "dtrace_dynstat", ":", 2686 "print DTrace dynamic variable hash statistics", dtrace_dynstat }, 2687 { "dtrace_options", ":", 2688 "print a DTrace consumer's current tuneable options", 2689 dtrace_options, dtrace_options_help }, 2690 { "dtrace_probes", "?", "print a DTrace consumer's enabled probes", 2691 dtrace_probes, dtrace_probes_help }, 2692 { NULL } 2693 }; 2694 2695 const mdb_walker_t kernel_walkers[] = { 2696 { "dtrace_errhash", "walk hash of DTrace error messasges", 2697 dtrace_errhash_init, dtrace_errhash_step }, 2698 { "dtrace_helptrace", "walk DTrace helper trace entries", 2699 dtrace_helptrace_init, dtrace_helptrace_step }, 2700 { "dtrace_state", "walk DTrace per-consumer softstate", 2701 dtrace_state_init, dtrace_state_step }, 2702 { "dtrace_aggkey", "walk DTrace aggregation keys", 2703 dtrace_aggkey_init, dtrace_aggkey_step, dtrace_aggkey_fini }, 2704 { "dtrace_dynvar", "walk DTrace dynamic variables", 2705 dtrace_dynvar_init, dtrace_dynvar_step, dtrace_dynvar_fini }, 2706 { "dtrace_ecb", "walk a DTrace consumer's enabling control blocks", 2707 dtrace_ecb_init, dtrace_ecb_step }, 2708 { "pid2state", "walk a processes dtrace_state structures", 2709 pid2state_init, pid2state_step }, 2710 { NULL } 2711 }; 2712