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