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