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