dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / mdb / common / modules / dtrace / dtrace.c
blob5dcfec20a757fb964f68bfbc26a270b8dacb7690
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
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
32 #define DTRACE_ERRDEBUG
33 #define _STDARG_H
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>
51 /*ARGSUSED*/
52 int
53 id2probe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
55 uintptr_t probe = (uintptr_t)NULL;
56 uintptr_t probes;
58 if (!(flags & DCMD_ADDRSPEC))
59 return (DCMD_USAGE);
61 if (addr == DTRACE_IDNONE || addr > UINT32_MAX)
62 goto out;
64 if (mdb_readvar(&probes, "dtrace_probes") == -1) {
65 mdb_warn("failed to read 'dtrace_probes'");
66 return (DCMD_ERR);
69 probes += (addr - 1) * sizeof (dtrace_probe_t *);
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);
76 out:
77 mdb_printf("%p\n", probe);
78 return (DCMD_OK);
81 void
82 dtrace_help(void)
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");
99 static int
100 dtracemdb_eprobe(dtrace_state_t *state, dtrace_eprobedesc_t *epd)
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;
109 addr = (uintptr_t)state->dts_ecbs +
110 (epid - 1) * sizeof (dtrace_ecb_t *);
112 if (mdb_vread(&addr, sizeof (addr), addr) == -1) {
113 mdb_warn("failed to read ecb for epid %d", epid);
114 return (-1);
117 if (addr == (uintptr_t)NULL) {
118 mdb_warn("epid %d doesn't match an ecb\n", epid);
119 return (-1);
122 if (mdb_vread(&ecb, sizeof (ecb), addr) == -1) {
123 mdb_warn("failed to read ecb at %p", addr);
124 return (-1);
127 paddr = (uintptr_t)ecb.dte_probe;
129 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) {
130 mdb_warn("failed to read probe for ecb %p", addr);
131 return (-1);
135 * This is a little painful: in order to find the number of actions,
136 * we need to first walk through them.
138 ap = (uintptr_t)ecb.dte_action;
139 nactions = 0;
140 while (ap != (uintptr_t)NULL) {
141 if (mdb_vread(&act, sizeof (act), ap) == -1) {
142 mdb_warn("failed to read action %p on ecb %p",
143 ap, addr);
144 return (-1);
147 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple)
148 nactions++;
150 ap = (uintptr_t)act.dta_next;
153 nrecs = epd->dtepd_nrecs;
154 epd->dtepd_nrecs = nactions;
155 epd->dtepd_probeid = probe.dtpr_id;
156 epd->dtepd_uarg = ecb.dte_uarg;
157 epd->dtepd_size = ecb.dte_size;
159 ap = (uintptr_t)ecb.dte_action;
160 nactions = 0;
161 while (ap != (uintptr_t)NULL) {
162 if (mdb_vread(&act, sizeof (act), ap) == -1) {
163 mdb_warn("failed to read action %p on ecb %p",
164 ap, addr);
165 return (-1);
168 if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) {
169 if (nrecs-- == 0)
170 break;
172 epd->dtepd_rec[nactions++] = act.dta_rec;
175 ap = (uintptr_t)act.dta_next;
178 return (0);
181 /*ARGSUSED*/
182 static int
183 dtracemdb_probe(dtrace_state_t *state, dtrace_probedesc_t *pd)
185 uintptr_t base, addr, paddr, praddr;
186 int nprobes, i;
187 dtrace_probe_t probe;
188 dtrace_provider_t prov;
190 if (pd->dtpd_id == DTRACE_IDNONE)
191 pd->dtpd_id++;
193 if (mdb_readvar(&base, "dtrace_probes") == -1) {
194 mdb_warn("failed to read 'dtrace_probes'");
195 return (-1);
198 if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) {
199 mdb_warn("failed to read 'dtrace_nprobes'");
200 return (-1);
203 for (i = pd->dtpd_id; i <= nprobes; i++) {
204 addr = base + (i - 1) * sizeof (dtrace_probe_t *);
206 if (mdb_vread(&paddr, sizeof (paddr), addr) == -1) {
207 mdb_warn("couldn't read probe pointer at %p", addr);
208 return (-1);
211 if (paddr != (uintptr_t)NULL)
212 break;
215 if (paddr == (uintptr_t)NULL) {
216 errno = ESRCH;
217 return (-1);
220 if (mdb_vread(&probe, sizeof (probe), paddr) == -1) {
221 mdb_warn("couldn't read probe at %p", paddr);
222 return (-1);
225 pd->dtpd_id = probe.dtpr_id;
227 if (mdb_vread(pd->dtpd_name, DTRACE_NAMELEN,
228 (uintptr_t)probe.dtpr_name) == -1) {
229 mdb_warn("failed to read probe name for probe %p", paddr);
230 return (-1);
233 if (mdb_vread(pd->dtpd_func, DTRACE_FUNCNAMELEN,
234 (uintptr_t)probe.dtpr_func) == -1) {
235 mdb_warn("failed to read function name for probe %p", paddr);
236 return (-1);
239 if (mdb_vread(pd->dtpd_mod, DTRACE_MODNAMELEN,
240 (uintptr_t)probe.dtpr_mod) == -1) {
241 mdb_warn("failed to read module name for probe %p", paddr);
242 return (-1);
245 praddr = (uintptr_t)probe.dtpr_provider;
247 if (mdb_vread(&prov, sizeof (prov), praddr) == -1) {
248 mdb_warn("failed to read provider for probe %p", paddr);
249 return (-1);
252 if (mdb_vread(pd->dtpd_provider, DTRACE_PROVNAMELEN,
253 (uintptr_t)prov.dtpv_name) == -1) {
254 mdb_warn("failed to read provider name for probe %p", paddr);
255 return (-1);
258 return (0);
261 /*ARGSUSED*/
262 static int
263 dtracemdb_aggdesc(dtrace_state_t *state, dtrace_aggdesc_t *agd)
265 dtrace_aggid_t aggid = agd->dtagd_id;
266 dtrace_aggregation_t agg;
267 dtrace_ecb_t ecb;
268 uintptr_t addr, eaddr, ap, last;
269 dtrace_action_t act;
270 dtrace_recdesc_t *lrec;
271 int nactions, nrecs;
273 addr = (uintptr_t)state->dts_aggregations +
274 (aggid - 1) * sizeof (dtrace_aggregation_t *);
276 if (mdb_vread(&addr, sizeof (addr), addr) == -1) {
277 mdb_warn("failed to read aggregation for aggid %d", aggid);
278 return (-1);
281 if (addr == (uintptr_t)NULL) {
282 mdb_warn("aggid %d doesn't match an aggregation\n", aggid);
283 return (-1);
286 if (mdb_vread(&agg, sizeof (agg), addr) == -1) {
287 mdb_warn("failed to read aggregation at %p", addr);
288 return (-1);
291 eaddr = (uintptr_t)agg.dtag_ecb;
293 if (mdb_vread(&ecb, sizeof (ecb), eaddr) == -1) {
294 mdb_warn("failed to read ecb for aggregation %p", addr);
295 return (-1);
298 last = (uintptr_t)addr + offsetof(dtrace_aggregation_t, dtag_action);
301 * This is a little painful: in order to find the number of actions,
302 * we need to first walk through them.
304 ap = (uintptr_t)agg.dtag_first;
305 nactions = 0;
307 for (;;) {
308 if (mdb_vread(&act, sizeof (act), ap) == -1) {
309 mdb_warn("failed to read action %p on aggregation %p",
310 ap, addr);
311 return (-1);
314 nactions++;
316 if (ap == last)
317 break;
319 ap = (uintptr_t)act.dta_next;
322 lrec = &act.dta_rec;
323 agd->dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - agg.dtag_base;
325 nrecs = agd->dtagd_nrecs;
326 agd->dtagd_nrecs = nactions;
327 agd->dtagd_epid = ecb.dte_epid;
329 ap = (uintptr_t)agg.dtag_first;
330 nactions = 0;
332 for (;;) {
333 dtrace_recdesc_t rec;
335 if (mdb_vread(&act, sizeof (act), ap) == -1) {
336 mdb_warn("failed to read action %p on aggregation %p",
337 ap, addr);
338 return (-1);
341 if (nrecs-- == 0)
342 break;
344 rec = act.dta_rec;
345 rec.dtrd_offset -= agg.dtag_base;
346 rec.dtrd_uarg = 0;
347 agd->dtagd_rec[nactions++] = rec;
349 if (ap == last)
350 break;
352 ap = (uintptr_t)act.dta_next;
355 return (0);
358 static int
359 dtracemdb_bufsnap(dtrace_buffer_t *which, dtrace_bufdesc_t *desc)
361 uintptr_t addr;
362 size_t bufsize;
363 dtrace_buffer_t buf;
364 caddr_t data = desc->dtbd_data;
365 processorid_t max_cpuid, cpu = desc->dtbd_cpu;
367 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) {
368 mdb_warn("failed to read 'max_cpuid'");
369 errno = EIO;
370 return (-1);
373 if (cpu < 0 || cpu > max_cpuid) {
374 errno = EINVAL;
375 return (-1);
378 addr = (uintptr_t)which + cpu * sizeof (dtrace_buffer_t);
380 if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
381 mdb_warn("failed to read buffer description at %p", addr);
382 errno = EIO;
383 return (-1);
386 if (buf.dtb_tomax == NULL) {
387 errno = ENOENT;
388 return (-1);
391 if (buf.dtb_flags & DTRACEBUF_WRAPPED) {
392 bufsize = buf.dtb_size;
393 } else {
394 bufsize = buf.dtb_offset;
397 if (mdb_vread(data, bufsize, (uintptr_t)buf.dtb_tomax) == -1) {
398 mdb_warn("couldn't read buffer for CPU %d", cpu);
399 errno = EIO;
400 return (-1);
403 if (buf.dtb_offset > buf.dtb_size) {
404 mdb_warn("buffer for CPU %d has corrupt offset\n", cpu);
405 errno = EIO;
406 return (-1);
409 if (buf.dtb_flags & DTRACEBUF_WRAPPED) {
410 if (buf.dtb_xamot_offset > buf.dtb_size) {
411 mdb_warn("ringbuffer for CPU %d has corrupt "
412 "wrapped offset\n", cpu);
413 errno = EIO;
414 return (-1);
418 * If the ring buffer has wrapped, it needs to be polished.
419 * See the comment in dtrace_buffer_polish() for details.
421 if (buf.dtb_offset < buf.dtb_xamot_offset) {
422 bzero(data + buf.dtb_offset,
423 buf.dtb_xamot_offset - buf.dtb_offset);
426 if (buf.dtb_offset > buf.dtb_xamot_offset) {
427 bzero(data + buf.dtb_offset,
428 buf.dtb_size - buf.dtb_offset);
429 bzero(data, buf.dtb_xamot_offset);
432 desc->dtbd_oldest = buf.dtb_xamot_offset;
433 } else {
434 desc->dtbd_oldest = 0;
437 desc->dtbd_size = bufsize;
438 desc->dtbd_drops = buf.dtb_drops;
439 desc->dtbd_errors = buf.dtb_errors;
441 return (0);
445 * This is essentially identical to its cousin in the kernel -- with the
446 * notable exception that we automatically set DTRACEOPT_GRABANON if this
447 * state is an anonymous enabling.
449 static dof_hdr_t *
450 dtracemdb_dof_create(dtrace_state_t *state, int isanon)
452 dof_hdr_t *dof;
453 dof_sec_t *sec;
454 dof_optdesc_t *opt;
455 int i, len = sizeof (dof_hdr_t) +
456 roundup(sizeof (dof_sec_t), sizeof (uint64_t)) +
457 sizeof (dof_optdesc_t) * DTRACEOPT_MAX;
459 dof = mdb_zalloc(len, UM_SLEEP);
460 dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
461 dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
462 dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
463 dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
465 dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE;
466 dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
467 dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION;
468 dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION;
469 dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS;
470 dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS;
472 dof->dofh_flags = 0;
473 dof->dofh_hdrsize = sizeof (dof_hdr_t);
474 dof->dofh_secsize = sizeof (dof_sec_t);
475 dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */
476 dof->dofh_secoff = sizeof (dof_hdr_t);
477 dof->dofh_loadsz = len;
478 dof->dofh_filesz = len;
479 dof->dofh_pad = 0;
482 * Fill in the option section header...
484 sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t));
485 sec->dofs_type = DOF_SECT_OPTDESC;
486 sec->dofs_align = sizeof (uint64_t);
487 sec->dofs_flags = DOF_SECF_LOAD;
488 sec->dofs_entsize = sizeof (dof_optdesc_t);
490 opt = (dof_optdesc_t *)((uintptr_t)sec +
491 roundup(sizeof (dof_sec_t), sizeof (uint64_t)));
493 sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof;
494 sec->dofs_size = sizeof (dof_optdesc_t) * DTRACEOPT_MAX;
496 for (i = 0; i < DTRACEOPT_MAX; i++) {
497 opt[i].dofo_option = i;
498 opt[i].dofo_strtab = DOF_SECIDX_NONE;
499 opt[i].dofo_value = state->dts_options[i];
502 if (isanon)
503 opt[DTRACEOPT_GRABANON].dofo_value = 1;
505 return (dof);
508 static int
509 dtracemdb_format(dtrace_state_t *state, dtrace_fmtdesc_t *desc)
511 uintptr_t addr, faddr;
512 char c;
513 int len = 0;
515 if (desc->dtfd_format == 0 || desc->dtfd_format > state->dts_nformats) {
516 errno = EINVAL;
517 return (-1);
520 faddr = (uintptr_t)state->dts_formats +
521 (desc->dtfd_format - 1) * sizeof (char *);
523 if (mdb_vread(&addr, sizeof (addr), faddr) == -1) {
524 mdb_warn("failed to read format string pointer at %p", faddr);
525 return (-1);
528 do {
529 if (mdb_vread(&c, sizeof (c), addr + len++) == -1) {
530 mdb_warn("failed to read format string at %p", addr);
531 return (-1);
533 } while (c != '\0');
535 if (len > desc->dtfd_length) {
536 desc->dtfd_length = len;
537 return (0);
540 if (mdb_vread(desc->dtfd_string, len, addr) == -1) {
541 mdb_warn("failed to reread format string at %p", addr);
542 return (-1);
545 return (0);
548 static int
549 dtracemdb_status(dtrace_state_t *state, dtrace_status_t *status)
551 dtrace_dstate_t *dstate;
552 int i, j;
553 uint64_t nerrs;
554 uintptr_t addr;
555 int ncpu;
557 if (mdb_readvar(&ncpu, "_ncpu") == -1) {
558 mdb_warn("failed to read '_ncpu'");
559 return (DCMD_ERR);
562 bzero(status, sizeof (dtrace_status_t));
564 if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
565 errno = ENOENT;
566 return (-1);
570 * For the MDB backend, we never set dtst_exiting or dtst_filled. This
571 * is by design: we don't want the library to try to stop tracing,
572 * because it doesn't particularly mean anything.
574 nerrs = state->dts_errors;
575 dstate = &state->dts_vstate.dtvs_dynvars;
577 for (i = 0; i < ncpu; i++) {
578 dtrace_dstate_percpu_t dcpu;
579 dtrace_buffer_t buf;
581 addr = (uintptr_t)&dstate->dtds_percpu[i];
583 if (mdb_vread(&dcpu, sizeof (dcpu), addr) == -1) {
584 mdb_warn("failed to read per-CPU dstate at %p", addr);
585 return (-1);
588 status->dtst_dyndrops += dcpu.dtdsc_drops;
589 status->dtst_dyndrops_dirty += dcpu.dtdsc_dirty_drops;
590 status->dtst_dyndrops_rinsing += dcpu.dtdsc_rinsing_drops;
592 addr = (uintptr_t)&state->dts_buffer[i];
594 if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
595 mdb_warn("failed to read per-CPU buffer at %p", addr);
596 return (-1);
599 nerrs += buf.dtb_errors;
601 for (j = 0; j < state->dts_nspeculations; j++) {
602 dtrace_speculation_t spec;
604 addr = (uintptr_t)&state->dts_speculations[j];
606 if (mdb_vread(&spec, sizeof (spec), addr) == -1) {
607 mdb_warn("failed to read "
608 "speculation at %p", addr);
609 return (-1);
612 addr = (uintptr_t)&spec.dtsp_buffer[i];
614 if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
615 mdb_warn("failed to read "
616 "speculative buffer at %p", addr);
617 return (-1);
620 status->dtst_specdrops += buf.dtb_xamot_drops;
624 status->dtst_specdrops_busy = state->dts_speculations_busy;
625 status->dtst_specdrops_unavail = state->dts_speculations_unavail;
626 status->dtst_errors = nerrs;
628 return (0);
631 typedef struct dtracemdb_data {
632 dtrace_state_t *dtmd_state;
633 char *dtmd_symstr;
634 char *dtmd_modstr;
635 uintptr_t dtmd_addr;
636 int dtmd_isanon;
637 } dtracemdb_data_t;
639 static int
640 dtracemdb_ioctl(void *varg, int cmd, void *arg)
642 dtracemdb_data_t *data = varg;
643 dtrace_state_t *state = data->dtmd_state;
645 switch (cmd) {
646 case DTRACEIOC_CONF: {
647 dtrace_conf_t *conf = arg;
649 bzero(conf, sizeof (conf));
650 conf->dtc_difversion = DIF_VERSION;
651 conf->dtc_difintregs = DIF_DIR_NREGS;
652 conf->dtc_diftupregs = DIF_DTR_NREGS;
653 conf->dtc_ctfmodel = CTF_MODEL_NATIVE;
655 return (0);
658 case DTRACEIOC_DOFGET: {
659 dof_hdr_t *hdr = arg, *dof;
661 dof = dtracemdb_dof_create(state, data->dtmd_isanon);
662 bcopy(dof, hdr, MIN(hdr->dofh_loadsz, dof->dofh_loadsz));
663 mdb_free(dof, dof->dofh_loadsz);
665 return (0);
668 case DTRACEIOC_BUFSNAP:
669 return (dtracemdb_bufsnap(state->dts_buffer, arg));
671 case DTRACEIOC_AGGSNAP:
672 return (dtracemdb_bufsnap(state->dts_aggbuffer, arg));
674 case DTRACEIOC_AGGDESC:
675 return (dtracemdb_aggdesc(state, arg));
677 case DTRACEIOC_EPROBE:
678 return (dtracemdb_eprobe(state, arg));
680 case DTRACEIOC_PROBES:
681 return (dtracemdb_probe(state, arg));
683 case DTRACEIOC_FORMAT:
684 return (dtracemdb_format(state, arg));
686 case DTRACEIOC_STATUS:
687 return (dtracemdb_status(state, arg));
689 case DTRACEIOC_GO:
690 *(processorid_t *)arg = -1;
691 return (0);
693 case DTRACEIOC_ENABLE:
694 errno = ENOTTY; /* see dt_open.c:dtrace_go() */
695 return (-1);
697 case DTRACEIOC_PROVIDER:
698 case DTRACEIOC_PROBEMATCH:
699 errno = ESRCH;
700 return (-1);
702 default:
703 mdb_warn("unexpected ioctl 0x%x (%s)\n", cmd,
704 cmd == DTRACEIOC_PROVIDER ? "DTRACEIOC_PROVIDER" :
705 cmd == DTRACEIOC_PROBES ? "DTRACEIOC_PROBES" :
706 cmd == DTRACEIOC_BUFSNAP ? "DTRACEIOC_BUFSNAP" :
707 cmd == DTRACEIOC_PROBEMATCH ? "DTRACEIOC_PROBEMATCH" :
708 cmd == DTRACEIOC_ENABLE ? "DTRACEIOC_ENABLE" :
709 cmd == DTRACEIOC_AGGSNAP ? "DTRACEIOC_AGGSNAP" :
710 cmd == DTRACEIOC_EPROBE ? "DTRACEIOC_EPROBE" :
711 cmd == DTRACEIOC_PROBEARG ? "DTRACEIOC_PROBEARG" :
712 cmd == DTRACEIOC_CONF ? "DTRACEIOC_CONF" :
713 cmd == DTRACEIOC_STATUS ? "DTRACEIOC_STATUS" :
714 cmd == DTRACEIOC_GO ? "DTRACEIOC_GO" :
715 cmd == DTRACEIOC_STOP ? "DTRACEIOC_STOP" :
716 cmd == DTRACEIOC_AGGDESC ? "DTRACEIOC_AGGDESC" :
717 cmd == DTRACEIOC_FORMAT ? "DTRACEIOC_FORMAT" :
718 cmd == DTRACEIOC_DOFGET ? "DTRACEIOC_DOFGET" :
719 cmd == DTRACEIOC_REPLICATE ? "DTRACEIOC_REPLICATE" :
720 "???");
721 errno = ENXIO;
722 return (-1);
726 static int
727 dtracemdb_modctl(uintptr_t addr, const struct modctl *m, dtracemdb_data_t *data)
729 struct module mod;
731 if (m->mod_mp == NULL)
732 return (WALK_NEXT);
734 if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) {
735 mdb_warn("couldn't read modctl %p's module", addr);
736 return (WALK_NEXT);
739 if ((uintptr_t)mod.text > data->dtmd_addr)
740 return (WALK_NEXT);
742 if ((uintptr_t)mod.text + mod.text_size <= data->dtmd_addr)
743 return (WALK_NEXT);
745 if (mdb_readstr(data->dtmd_modstr, MDB_SYM_NAMLEN,
746 (uintptr_t)m->mod_modname) == -1)
747 return (WALK_ERR);
749 return (WALK_DONE);
752 static int
753 dtracemdb_lookup_by_addr(void *varg, GElf_Addr addr, GElf_Sym *symp,
754 dtrace_syminfo_t *sip)
756 dtracemdb_data_t *data = varg;
758 if (data->dtmd_symstr == NULL) {
759 data->dtmd_symstr = mdb_zalloc(MDB_SYM_NAMLEN,
760 UM_SLEEP | UM_GC);
763 if (data->dtmd_modstr == NULL) {
764 data->dtmd_modstr = mdb_zalloc(MDB_SYM_NAMLEN,
765 UM_SLEEP | UM_GC);
768 if (symp != NULL) {
769 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, data->dtmd_symstr,
770 MDB_SYM_NAMLEN, symp) == -1)
771 return (-1);
774 if (sip != NULL) {
775 data->dtmd_addr = addr;
777 (void) strcpy(data->dtmd_modstr, "???");
779 if (mdb_walk("modctl",
780 (mdb_walk_cb_t)dtracemdb_modctl, varg) == -1) {
781 mdb_warn("couldn't walk 'modctl'");
782 return (-1);
785 sip->dts_object = data->dtmd_modstr;
786 sip->dts_id = 0;
787 sip->dts_name = symp != NULL ? data->dtmd_symstr : NULL;
790 return (0);
793 /*ARGSUSED*/
794 static int
795 dtracemdb_stat(void *varg, processorid_t cpu)
797 GElf_Sym sym;
798 cpu_t c;
799 uintptr_t caddr, addr;
801 if (mdb_lookup_by_name("cpu", &sym) == -1) {
802 mdb_warn("failed to find symbol for 'cpu'");
803 return (-1);
806 if (cpu * sizeof (uintptr_t) > sym.st_size)
807 return (-1);
809 addr = (uintptr_t)sym.st_value + cpu * sizeof (uintptr_t);
811 if (mdb_vread(&caddr, sizeof (caddr), addr) == -1) {
812 mdb_warn("failed to read cpu[%d]", cpu);
813 return (-1);
816 if (caddr == (uintptr_t)NULL)
817 return (-1);
819 if (mdb_vread(&c, sizeof (c), caddr) == -1) {
820 mdb_warn("failed to read cpu at %p", caddr);
821 return (-1);
824 if (c.cpu_flags & CPU_POWEROFF) {
825 return (P_POWEROFF);
826 } else if (c.cpu_flags & CPU_SPARE) {
827 return (P_SPARE);
828 } else if (c.cpu_flags & CPU_FAULTED) {
829 return (P_FAULTED);
830 } else if ((c.cpu_flags & (CPU_READY | CPU_OFFLINE)) != CPU_READY) {
831 return (P_OFFLINE);
832 } else if (c.cpu_flags & CPU_ENABLE) {
833 return (P_ONLINE);
834 } else {
835 return (P_NOINTR);
839 /*ARGSUSED*/
840 static long
841 dtracemdb_sysconf(void *varg, int name)
843 int max_ncpus;
844 processorid_t max_cpuid;
846 switch (name) {
847 case _SC_CPUID_MAX:
848 if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) {
849 mdb_warn("failed to read 'max_cpuid'");
850 return (-1);
853 return (max_cpuid);
855 case _SC_NPROCESSORS_MAX:
856 if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) {
857 mdb_warn("failed to read 'max_ncpus'");
858 return (-1);
861 return (max_ncpus);
863 default:
864 mdb_warn("unexpected sysconf code %d\n", name);
865 return (-1);
869 const dtrace_vector_t dtrace_mdbops = {
870 dtracemdb_ioctl,
871 dtracemdb_lookup_by_addr,
872 dtracemdb_stat,
873 dtracemdb_sysconf
876 typedef struct dtrace_dcmddata {
877 dtrace_hdl_t *dtdd_dtp;
878 int dtdd_cpu;
879 int dtdd_quiet;
880 int dtdd_flowindent;
881 int dtdd_heading;
882 FILE *dtdd_output;
883 } dtrace_dcmddata_t;
886 * Helper to grab all the content from a file, spit it into a string, and erase
887 * and reset the file.
889 static void
890 print_and_truncate_file(FILE *fp)
892 long len;
893 char *out;
895 /* flush, find length of file, seek to beginning, initialize buffer */
896 if (fflush(fp) || (len = ftell(fp)) < 0 ||
897 fseek(fp, 0, SEEK_SET) < 0) {
898 mdb_warn("couldn't prepare DTrace output file: %d\n", errno);
899 return;
902 out = mdb_alloc(len + 1, UM_SLEEP);
903 out[len] = '\0';
905 /* read file into buffer, truncate file, and seek to beginning */
906 if ((fread(out, len + 1, sizeof (char), fp) == 0 && ferror(fp)) ||
907 ftruncate(fileno(fp), 0) < 0 || fseek(fp, 0, SEEK_SET) < 0) {
908 mdb_warn("couldn't read DTrace output file: %d\n", errno);
909 mdb_free(out, len + 1);
910 return;
913 mdb_printf("%s", out);
914 mdb_free(out, len + 1);
917 /*ARGSUSED*/
918 static int
919 dtrace_dcmdrec(const dtrace_probedata_t *data,
920 const dtrace_recdesc_t *rec, void *arg)
922 dtrace_dcmddata_t *dd = arg;
924 print_and_truncate_file(dd->dtdd_output);
926 if (rec == NULL) {
928 * We have processed the final record; output the newline if
929 * we're not in quiet mode.
931 if (!dd->dtdd_quiet)
932 mdb_printf("\n");
934 return (DTRACE_CONSUME_NEXT);
937 return (DTRACE_CONSUME_THIS);
940 /*ARGSUSED*/
941 static int
942 dtrace_dcmdprobe(const dtrace_probedata_t *data, void *arg)
944 dtrace_probedesc_t *pd = data->dtpda_pdesc;
945 processorid_t cpu = data->dtpda_cpu;
946 dtrace_dcmddata_t *dd = arg;
947 char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2];
949 if (dd->dtdd_cpu != -1UL && dd->dtdd_cpu != cpu)
950 return (DTRACE_CONSUME_NEXT);
952 if (dd->dtdd_heading == 0) {
953 if (!dd->dtdd_flowindent) {
954 if (!dd->dtdd_quiet) {
955 mdb_printf("%3s %6s %32s\n",
956 "CPU", "ID", "FUNCTION:NAME");
958 } else {
959 mdb_printf("%3s %-41s\n", "CPU", "FUNCTION");
961 dd->dtdd_heading = 1;
964 if (!dd->dtdd_flowindent) {
965 if (!dd->dtdd_quiet) {
966 (void) mdb_snprintf(name, sizeof (name), "%s:%s",
967 pd->dtpd_func, pd->dtpd_name);
969 mdb_printf("%3d %6d %32s ", cpu, pd->dtpd_id, name);
971 } else {
972 int indent = data->dtpda_indent;
974 if (data->dtpda_flow == DTRACEFLOW_NONE) {
975 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s:%s",
976 indent, "", data->dtpda_prefix, pd->dtpd_func,
977 pd->dtpd_name);
978 } else {
979 (void) mdb_snprintf(name, sizeof (name), "%*s%s%s",
980 indent, "", data->dtpda_prefix, pd->dtpd_func);
983 mdb_printf("%3d %-41s ", cpu, name);
986 return (DTRACE_CONSUME_THIS);
989 /*ARGSUSED*/
990 static int
991 dtrace_dcmderr(const dtrace_errdata_t *data, void *arg)
993 mdb_warn(data->dteda_msg);
994 return (DTRACE_HANDLE_OK);
997 /*ARGSUSED*/
998 static int
999 dtrace_dcmddrop(const dtrace_dropdata_t *data, void *arg)
1001 mdb_warn(data->dtdda_msg);
1002 return (DTRACE_HANDLE_OK);
1005 /*ARGSUSED*/
1006 static int
1007 dtrace_dcmdbuffered(const dtrace_bufdata_t *bufdata, void *arg)
1009 mdb_printf("%s", bufdata->dtbda_buffered);
1010 return (DTRACE_HANDLE_OK);
1013 /*ARGSUSED*/
1015 dtrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1017 dtrace_state_t state;
1018 dtrace_hdl_t *dtp;
1019 int ncpu, err;
1020 uintptr_t c = -1UL;
1021 dtrace_dcmddata_t dd;
1022 dtrace_optval_t val;
1023 dtracemdb_data_t md;
1024 int rval = DCMD_ERR;
1025 dtrace_anon_t anon;
1027 if (!(flags & DCMD_ADDRSPEC))
1028 return (DCMD_USAGE);
1030 if (mdb_getopts(argc, argv, 'c', MDB_OPT_UINTPTR, &c, NULL) != argc)
1031 return (DCMD_USAGE);
1033 if (mdb_readvar(&ncpu, "_ncpu") == -1) {
1034 mdb_warn("failed to read '_ncpu'");
1035 return (DCMD_ERR);
1038 if (mdb_vread(&state, sizeof (state), addr) == -1) {
1039 mdb_warn("couldn't read dtrace_state_t at %p", addr);
1040 return (DCMD_ERR);
1043 if (state.dts_anon != NULL) {
1044 addr = (uintptr_t)state.dts_anon;
1046 if (mdb_vread(&state, sizeof (state), addr) == -1) {
1047 mdb_warn("couldn't read anonymous state at %p", addr);
1048 return (DCMD_ERR);
1052 bzero(&md, sizeof (md));
1053 md.dtmd_state = &state;
1055 if ((dtp = dtrace_vopen(DTRACE_VERSION, DTRACE_O_NOSYS, &err,
1056 &dtrace_mdbops, &md)) == NULL) {
1057 mdb_warn("failed to initialize dtrace: %s\n",
1058 dtrace_errmsg(NULL, err));
1059 return (DCMD_ERR);
1063 * If this is the anonymous enabling, we need to set a bit indicating
1064 * that DTRACEOPT_GRABANON should be set.
1066 if (mdb_readvar(&anon, "dtrace_anon") == -1) {
1067 mdb_warn("failed to read 'dtrace_anon'");
1068 return (DCMD_ERR);
1071 md.dtmd_isanon = ((uintptr_t)anon.dta_state == addr);
1073 if (dtrace_go(dtp) != 0) {
1074 mdb_warn("failed to initialize dtrace: %s\n",
1075 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1076 goto err;
1079 bzero(&dd, sizeof (dd));
1080 dd.dtdd_dtp = dtp;
1081 dd.dtdd_cpu = c;
1083 if (dtrace_getopt(dtp, "flowindent", &val) == -1) {
1084 mdb_warn("couldn't get 'flowindent' option: %s\n",
1085 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1086 goto err;
1089 dd.dtdd_flowindent = (val != DTRACEOPT_UNSET);
1091 if (dtrace_getopt(dtp, "quiet", &val) == -1) {
1092 mdb_warn("couldn't get 'quiet' option: %s\n",
1093 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1094 goto err;
1097 dd.dtdd_quiet = (val != DTRACEOPT_UNSET);
1099 if (dtrace_handle_err(dtp, dtrace_dcmderr, NULL) == -1) {
1100 mdb_warn("couldn't add err handler: %s\n",
1101 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1102 goto err;
1105 if (dtrace_handle_drop(dtp, dtrace_dcmddrop, NULL) == -1) {
1106 mdb_warn("couldn't add drop handler: %s\n",
1107 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1108 goto err;
1111 if (dtrace_handle_buffered(dtp, dtrace_dcmdbuffered, NULL) == -1) {
1112 mdb_warn("couldn't add buffered handler: %s\n",
1113 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1114 goto err;
1117 if (dtrace_status(dtp) == -1) {
1118 mdb_warn("couldn't get status: %s\n",
1119 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1120 goto err;
1123 if (dtrace_aggregate_snap(dtp) == -1) {
1124 mdb_warn("couldn't snapshot aggregation: %s\n",
1125 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1126 goto err;
1129 if ((dd.dtdd_output = tmpfile()) == NULL) {
1130 mdb_warn("couldn't open DTrace output file: %d\n", errno);
1131 goto err;
1134 if (dtrace_consume(dtp, dd.dtdd_output,
1135 dtrace_dcmdprobe, dtrace_dcmdrec, &dd) == -1) {
1136 mdb_warn("couldn't consume DTrace buffers: %s\n",
1137 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1140 if (dtrace_aggregate_print(dtp, NULL, NULL) == -1) {
1141 mdb_warn("couldn't print aggregation: %s\n",
1142 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1143 goto err;
1146 rval = DCMD_OK;
1147 err:
1148 dtrace_close(dtp);
1149 fclose(dd.dtdd_output);
1150 return (rval);
1153 static int
1154 dtrace_errhash_cmp(const void *l, const void *r)
1156 uintptr_t lhs = *((uintptr_t *)l);
1157 uintptr_t rhs = *((uintptr_t *)r);
1158 dtrace_errhash_t lerr, rerr;
1159 char lmsg[256], rmsg[256];
1161 (void) mdb_vread(&lerr, sizeof (lerr), lhs);
1162 (void) mdb_vread(&rerr, sizeof (rerr), rhs);
1164 if (lerr.dter_msg == NULL)
1165 return (-1);
1167 if (rerr.dter_msg == NULL)
1168 return (1);
1170 (void) mdb_readstr(lmsg, sizeof (lmsg), (uintptr_t)lerr.dter_msg);
1171 (void) mdb_readstr(rmsg, sizeof (rmsg), (uintptr_t)rerr.dter_msg);
1173 return (strcmp(lmsg, rmsg));
1177 dtrace_errhash_init(mdb_walk_state_t *wsp)
1179 GElf_Sym sym;
1180 uintptr_t *hash, addr;
1181 int i;
1183 if (wsp->walk_addr != (uintptr_t)NULL) {
1184 mdb_warn("dtrace_errhash walk only supports global walks\n");
1185 return (WALK_ERR);
1188 if (mdb_lookup_by_name("dtrace_errhash", &sym) == -1) {
1189 mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)");
1190 return (WALK_ERR);
1193 addr = (uintptr_t)sym.st_value;
1194 hash = mdb_alloc(DTRACE_ERRHASHSZ * sizeof (uintptr_t),
1195 UM_SLEEP | UM_GC);
1197 for (i = 0; i < DTRACE_ERRHASHSZ; i++)
1198 hash[i] = addr + i * sizeof (dtrace_errhash_t);
1200 qsort(hash, DTRACE_ERRHASHSZ, sizeof (uintptr_t), dtrace_errhash_cmp);
1202 wsp->walk_addr = 0;
1203 wsp->walk_data = hash;
1205 return (WALK_NEXT);
1209 dtrace_errhash_step(mdb_walk_state_t *wsp)
1211 int ndx = (int)wsp->walk_addr;
1212 uintptr_t *hash = wsp->walk_data;
1213 dtrace_errhash_t err;
1214 uintptr_t addr;
1216 if (ndx >= DTRACE_ERRHASHSZ)
1217 return (WALK_DONE);
1219 wsp->walk_addr = ndx + 1;
1220 addr = hash[ndx];
1222 if (mdb_vread(&err, sizeof (err), addr) == -1) {
1223 mdb_warn("failed to read dtrace_errhash_t at %p", addr);
1224 return (WALK_DONE);
1227 if (err.dter_msg == NULL)
1228 return (WALK_NEXT);
1230 return (wsp->walk_callback(addr, &err, wsp->walk_cbdata));
1233 /*ARGSUSED*/
1235 dtrace_errhash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1237 dtrace_errhash_t err;
1238 char msg[256];
1240 if (!(flags & DCMD_ADDRSPEC)) {
1241 if (mdb_walk_dcmd("dtrace_errhash", "dtrace_errhash",
1242 argc, argv) == -1) {
1243 mdb_warn("can't walk 'dtrace_errhash'");
1244 return (DCMD_ERR);
1247 return (DCMD_OK);
1250 if (DCMD_HDRSPEC(flags))
1251 mdb_printf("%8s %s\n", "COUNT", "ERROR");
1253 if (mdb_vread(&err, sizeof (err), addr) == -1) {
1254 mdb_warn("failed to read dtrace_errhash_t at %p", addr);
1255 return (DCMD_ERR);
1258 addr = (uintptr_t)err.dter_msg;
1260 if (mdb_readstr(msg, sizeof (msg), addr) == -1) {
1261 mdb_warn("failed to read error msg at %p", addr);
1262 return (DCMD_ERR);
1265 mdb_printf("%8d %s", err.dter_count, msg);
1268 * Some error messages include a newline -- only print the newline
1269 * if the message doesn't have one.
1271 if (msg[strlen(msg) - 1] != '\n')
1272 mdb_printf("\n");
1274 return (DCMD_OK);
1278 dtrace_helptrace_init(mdb_walk_state_t *wsp)
1280 uint32_t next;
1281 uintptr_t buffer;
1283 if (wsp->walk_addr != (uintptr_t)NULL) {
1284 mdb_warn("dtrace_helptrace only supports global walks\n");
1285 return (WALK_ERR);
1288 if (mdb_readvar(&buffer, "dtrace_helptrace_buffer") == -1) {
1289 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1290 return (WALK_ERR);
1293 if (buffer == (uintptr_t)NULL) {
1294 mdb_warn("helper tracing is not enabled\n");
1295 return (WALK_ERR);
1298 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) {
1299 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1300 return (WALK_ERR);
1303 wsp->walk_addr = next;
1305 return (WALK_NEXT);
1309 dtrace_helptrace_step(mdb_walk_state_t *wsp)
1311 uint32_t next, size, nlocals, bufsize;
1312 uintptr_t buffer, addr;
1313 dtrace_helptrace_t *ht;
1314 int rval;
1316 if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) {
1317 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1318 return (WALK_ERR);
1321 if (mdb_readvar(&bufsize, "dtrace_helptrace_bufsize") == -1) {
1322 mdb_warn("couldn't read 'dtrace_helptrace_bufsize'");
1323 return (WALK_ERR);
1326 if (mdb_readvar(&buffer, "dtrace_helptrace_buffer") == -1) {
1327 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1328 return (WALK_ERR);
1331 if (mdb_readvar(&nlocals, "dtrace_helptrace_nlocals") == -1) {
1332 mdb_warn("couldn't read 'dtrace_helptrace_nlocals'");
1333 return (WALK_ERR);
1336 size = sizeof (dtrace_helptrace_t) +
1337 nlocals * sizeof (uint64_t) - sizeof (uint64_t);
1339 if (wsp->walk_addr + size > bufsize) {
1340 if (next == 0)
1341 return (WALK_DONE);
1343 wsp->walk_addr = 0;
1346 addr = buffer + wsp->walk_addr;
1347 ht = alloca(size);
1349 if (mdb_vread(ht, size, addr) == -1) {
1350 mdb_warn("couldn't read entry at %p", addr);
1351 return (WALK_ERR);
1354 if (ht->dtht_helper != NULL) {
1355 rval = wsp->walk_callback(addr, ht, wsp->walk_cbdata);
1357 if (rval != WALK_NEXT)
1358 return (rval);
1361 if (wsp->walk_addr < next && wsp->walk_addr + size >= next)
1362 return (WALK_DONE);
1364 wsp->walk_addr += size;
1365 return (WALK_NEXT);
1369 dtrace_helptrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1371 dtrace_helptrace_t help;
1372 dtrace_helper_action_t helper;
1373 char where[30];
1374 uint_t opt_v = FALSE;
1375 uintptr_t haddr;
1377 if (!(flags & DCMD_ADDRSPEC)) {
1378 if (mdb_walk_dcmd("dtrace_helptrace", "dtrace_helptrace",
1379 argc, argv) == -1) {
1380 mdb_warn("can't walk 'dtrace_helptrace'");
1381 return (DCMD_ERR);
1384 return (DCMD_OK);
1387 if (mdb_getopts(argc, argv, 'v',
1388 MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1389 return (DCMD_USAGE);
1391 if (DCMD_HDRSPEC(flags)) {
1392 mdb_printf(" %?s %?s %12s %s\n",
1393 "ADDR", "HELPER", "WHERE", "DIFO");
1396 if (mdb_vread(&help, sizeof (help), addr) == -1) {
1397 mdb_warn("failed to read dtrace_helptrace_t at %p", addr);
1398 return (DCMD_ERR);
1401 switch (help.dtht_where) {
1402 case 0:
1403 (void) mdb_snprintf(where, sizeof (where), "predicate");
1404 break;
1406 case DTRACE_HELPTRACE_NEXT:
1407 (void) mdb_snprintf(where, sizeof (where), "next");
1408 break;
1410 case DTRACE_HELPTRACE_DONE:
1411 (void) mdb_snprintf(where, sizeof (where), "done");
1412 break;
1414 case DTRACE_HELPTRACE_ERR:
1415 (void) mdb_snprintf(where, sizeof (where), "err");
1416 break;
1418 default:
1419 (void) mdb_snprintf(where, sizeof (where),
1420 "action #%d", help.dtht_where);
1421 break;
1424 mdb_printf(" %?p %?p %12s ", addr, help.dtht_helper, where);
1426 haddr = (uintptr_t)help.dtht_helper;
1428 if (mdb_vread(&helper, sizeof (helper), haddr) == -1) {
1430 * We're not going to warn in this case -- we're just not going
1431 * to print anything exciting.
1433 mdb_printf("???\n");
1434 } else {
1435 switch (help.dtht_where) {
1436 case 0:
1437 mdb_printf("%p\n", helper.dtha_predicate);
1438 break;
1440 case DTRACE_HELPTRACE_NEXT:
1441 case DTRACE_HELPTRACE_DONE:
1442 case DTRACE_HELPTRACE_ERR:
1443 mdb_printf("-\n");
1444 break;
1446 default:
1447 haddr = (uintptr_t)helper.dtha_actions +
1448 (help.dtht_where - 1) * sizeof (uintptr_t);
1450 if (mdb_vread(&haddr, sizeof (haddr), haddr) == -1) {
1451 mdb_printf("???\n");
1452 } else {
1453 mdb_printf("%p\n", haddr);
1458 if (opt_v) {
1459 int i;
1461 if (help.dtht_where == DTRACE_HELPTRACE_ERR) {
1462 int f = help.dtht_fault;
1464 mdb_printf("%?s| %?s %10s |\n", "", "", "");
1465 mdb_printf("%?s| %?s %10s +-> fault: %s\n", "", "", "",
1466 f == DTRACEFLT_BADADDR ? "BADADDR" :
1467 f == DTRACEFLT_BADALIGN ? "BADALIGN" :
1468 f == DTRACEFLT_ILLOP ? "ILLOP" :
1469 f == DTRACEFLT_DIVZERO ? "DIVZERO" :
1470 f == DTRACEFLT_NOSCRATCH ? "NOSCRATCH" :
1471 f == DTRACEFLT_KPRIV ? "KPRIV" :
1472 f == DTRACEFLT_UPRIV ? "UPRIV" :
1473 f == DTRACEFLT_TUPOFLOW ? "TUPOFLOW" :
1474 f == DTRACEFLT_BADSTACK ? "BADSTACK" :
1475 "DTRACEFLT_UNKNOWN");
1476 mdb_printf("%?s| %?s %12s addr: 0x%x\n", "", "", "",
1477 help.dtht_illval);
1478 mdb_printf("%?s| %?s %12s offset: %d\n", "", "", "",
1479 help.dtht_fltoffs);
1482 mdb_printf("%?s|\n%?s+--> %?s %4s %s\n", "", "",
1483 "ADDR", "NDX", "VALUE");
1484 addr += sizeof (help) - sizeof (uint64_t);
1486 for (i = 0; i < help.dtht_nlocals; i++) {
1487 uint64_t val;
1489 if (mdb_vread(&val, sizeof (val), addr) == -1) {
1490 mdb_warn("couldn't read local at %p", addr);
1491 continue;
1494 mdb_printf("%?s %?p %4d %p\n", "", addr, i, val);
1495 addr += sizeof (uint64_t);
1498 mdb_printf("\n");
1501 return (DCMD_OK);
1504 /*ARGSUSED*/
1505 static int
1506 dtrace_state_walk(uintptr_t addr, const vmem_seg_t *seg, minor_t *highest)
1508 if (seg->vs_end > *highest)
1509 *highest = seg->vs_end;
1511 return (WALK_NEXT);
1514 typedef struct dtrace_state_walk {
1515 uintptr_t dtsw_softstate;
1516 minor_t dtsw_max;
1517 minor_t dtsw_current;
1518 } dtrace_state_walk_t;
1521 dtrace_state_init(mdb_walk_state_t *wsp)
1523 uintptr_t dtrace_minor;
1524 minor_t max = 0;
1525 dtrace_state_walk_t *dw;
1527 if (wsp->walk_addr != (uintptr_t)NULL) {
1528 mdb_warn("dtrace_state only supports global walks\n");
1529 return (WALK_ERR);
1533 * Find the dtrace_minor vmem arena and walk it to get the maximum
1534 * minor number.
1536 if (mdb_readvar(&dtrace_minor, "dtrace_minor") == -1) {
1537 mdb_warn("failed to read 'dtrace_minor'");
1538 return (WALK_ERR);
1541 if (mdb_pwalk("vmem_alloc", (mdb_walk_cb_t)dtrace_state_walk,
1542 &max, dtrace_minor) == -1) {
1543 mdb_warn("couldn't walk 'vmem_alloc'");
1544 return (WALK_ERR);
1547 dw = mdb_zalloc(sizeof (dtrace_state_walk_t), UM_SLEEP | UM_GC);
1548 dw->dtsw_current = 0;
1549 dw->dtsw_max = max;
1551 if (mdb_readvar(&dw->dtsw_softstate, "dtrace_softstate") == -1) {
1552 mdb_warn("failed to read 'dtrace_softstate'");
1553 return (DCMD_ERR);
1556 wsp->walk_data = dw;
1558 return (WALK_NEXT);
1562 dtrace_state_step(mdb_walk_state_t *wsp)
1564 dtrace_state_walk_t *dw = wsp->walk_data;
1565 uintptr_t statep;
1566 dtrace_state_t state;
1567 int rval;
1569 while (mdb_get_soft_state_byaddr(dw->dtsw_softstate, dw->dtsw_current,
1570 &statep, NULL, 0) == -1) {
1571 if (dw->dtsw_current >= dw->dtsw_max)
1572 return (WALK_DONE);
1574 dw->dtsw_current++;
1577 if (mdb_vread(&state, sizeof (state), statep) == -1) {
1578 mdb_warn("couldn't read dtrace_state_t at %p", statep);
1579 return (WALK_NEXT);
1582 rval = wsp->walk_callback(statep, &state, wsp->walk_cbdata);
1583 dw->dtsw_current++;
1585 return (rval);
1588 typedef struct dtrace_state_data {
1589 int dtsd_major;
1590 uintptr_t dtsd_proc;
1591 uintptr_t dtsd_softstate;
1592 uintptr_t dtsd_state;
1593 } dtrace_state_data_t;
1595 static int
1596 dtrace_state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data)
1598 vnode_t vnode;
1599 proc_t proc;
1600 minor_t minor;
1601 uintptr_t statep;
1603 if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) {
1604 mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode);
1605 return (WALK_NEXT);
1608 if (getmajor(vnode.v_rdev) != data->dtsd_major)
1609 return (WALK_NEXT);
1611 minor = getminor(vnode.v_rdev);
1613 if (mdb_vread(&proc, sizeof (proc), data->dtsd_proc) == -1) {
1614 mdb_warn("failed to read proc at %p", data->dtsd_proc);
1615 return (WALK_NEXT);
1618 if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor,
1619 &statep, NULL, 0) == -1) {
1620 mdb_warn("failed to read softstate for minor %d", minor);
1621 return (WALK_NEXT);
1624 if (statep != data->dtsd_state)
1625 return (WALK_NEXT);
1627 mdb_printf("%?p %5d %?p %-*s %?p\n", statep, minor,
1628 data->dtsd_proc, MAXCOMLEN, proc.p_user.u_comm, addr);
1630 return (WALK_NEXT);
1633 /*ARGSUSED*/
1634 static int
1635 dtrace_state_proc(uintptr_t addr, void *ignored, dtrace_state_data_t *data)
1637 data->dtsd_proc = addr;
1639 if (mdb_pwalk("file",
1640 (mdb_walk_cb_t)dtrace_state_file, data, addr) == -1) {
1641 mdb_warn("couldn't walk 'file' for proc %p", addr);
1642 return (WALK_ERR);
1645 return (WALK_NEXT);
1648 void
1649 dtrace_state_help(void)
1651 mdb_printf("Given a dtrace_state_t structure, displays all "
1652 /*CSTYLED*/
1653 "consumers, or \"<anonymous>\"\nif the consumer is anonymous. If "
1654 "no state structure is provided, iterates\nover all state "
1655 "structures.\n\n"
1656 "Addresses in ADDR column may be provided to ::dtrace to obtain\n"
1657 "dtrace(1M)-like output for in-kernel DTrace data.\n");
1661 dtrace_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1663 uintptr_t devi;
1664 struct dev_info info;
1665 dtrace_state_data_t data;
1666 dtrace_anon_t anon;
1667 dtrace_state_t state;
1669 if (!(flags & DCMD_ADDRSPEC)) {
1670 if (mdb_walk_dcmd("dtrace_state",
1671 "dtrace_state", argc, argv) == -1) {
1672 mdb_warn("can't walk dtrace_state");
1673 return (DCMD_ERR);
1675 return (DCMD_OK);
1678 if (DCMD_HDRSPEC(flags)) {
1679 mdb_printf("%?s %5s %?s %-*s %?s\n", "ADDR", "MINOR", "PROC",
1680 MAXCOMLEN, "NAME", "FILE");
1684 * First determine if this is anonymous state.
1686 if (mdb_readvar(&anon, "dtrace_anon") == -1) {
1687 mdb_warn("failed to read 'dtrace_anon'");
1688 return (DCMD_ERR);
1691 if ((uintptr_t)anon.dta_state == addr) {
1692 if (mdb_vread(&state, sizeof (state), addr) == -1) {
1693 mdb_warn("failed to read anon at %p", addr);
1694 return (DCMD_ERR);
1697 mdb_printf("%?p %5d %?s %-*s %?s\n", addr,
1698 getminor(state.dts_dev), "-", MAXCOMLEN,
1699 "<anonymous>", "-");
1701 return (DCMD_OK);
1704 if (mdb_readvar(&devi, "dtrace_devi") == -1) {
1705 mdb_warn("failed to read 'dtrace_devi'");
1706 return (DCMD_ERR);
1709 if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) {
1710 mdb_warn("failed to read 'dev_info'");
1711 return (DCMD_ERR);
1714 data.dtsd_major = info.devi_major;
1716 if (mdb_readvar(&data.dtsd_softstate, "dtrace_softstate") == -1) {
1717 mdb_warn("failed to read 'dtrace_softstate'");
1718 return (DCMD_ERR);
1721 data.dtsd_state = addr;
1724 * Walk through all processes and all open files looking for this
1725 * state. It must be open somewhere...
1727 if (mdb_walk("proc", (mdb_walk_cb_t)dtrace_state_proc, &data) == -1) {
1728 mdb_warn("couldn't walk 'proc'");
1729 return (DCMD_ERR);
1732 return (DCMD_OK);
1735 typedef struct dtrace_aggkey_data {
1736 uintptr_t *dtakd_hash;
1737 uintptr_t dtakd_hashsize;
1738 uintptr_t dtakd_next;
1739 uintptr_t dtakd_ndx;
1740 } dtrace_aggkey_data_t;
1743 dtrace_aggkey_init(mdb_walk_state_t *wsp)
1745 dtrace_buffer_t buf;
1746 uintptr_t addr;
1747 dtrace_aggbuffer_t agb;
1748 dtrace_aggkey_data_t *data;
1749 size_t hsize;
1751 if ((addr = wsp->walk_addr) == (uintptr_t)NULL) {
1752 mdb_warn("dtrace_aggkey walk needs aggregation buffer\n");
1753 return (WALK_ERR);
1756 if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
1757 mdb_warn("failed to read aggregation buffer at %p", addr);
1758 return (WALK_ERR);
1761 addr = (uintptr_t)buf.dtb_tomax +
1762 buf.dtb_size - sizeof (dtrace_aggbuffer_t);
1764 if (mdb_vread(&agb, sizeof (agb), addr) == -1) {
1765 mdb_warn("failed to read dtrace_aggbuffer_t at %p", addr);
1766 return (WALK_ERR);
1769 data = mdb_zalloc(sizeof (dtrace_aggkey_data_t), UM_SLEEP);
1771 data->dtakd_hashsize = agb.dtagb_hashsize;
1772 hsize = agb.dtagb_hashsize * sizeof (dtrace_aggkey_t *);
1773 data->dtakd_hash = mdb_alloc(hsize, UM_SLEEP);
1775 if (mdb_vread(data->dtakd_hash, hsize,
1776 (uintptr_t)agb.dtagb_hash) == -1) {
1777 mdb_warn("failed to read hash at %p",
1778 (uintptr_t)agb.dtagb_hash);
1779 mdb_free(data->dtakd_hash, hsize);
1780 mdb_free(data, sizeof (dtrace_aggkey_data_t));
1781 return (WALK_ERR);
1784 wsp->walk_data = data;
1785 return (WALK_NEXT);
1789 dtrace_aggkey_step(mdb_walk_state_t *wsp)
1791 dtrace_aggkey_data_t *data = wsp->walk_data;
1792 dtrace_aggkey_t key;
1793 uintptr_t addr;
1795 while ((addr = data->dtakd_next) == (uintptr_t)NULL) {
1796 if (data->dtakd_ndx == data->dtakd_hashsize)
1797 return (WALK_DONE);
1799 data->dtakd_next = data->dtakd_hash[data->dtakd_ndx++];
1802 if (mdb_vread(&key, sizeof (key), addr) == -1) {
1803 mdb_warn("failed to read dtrace_aggkey_t at %p", addr);
1804 return (WALK_ERR);
1807 data->dtakd_next = (uintptr_t)key.dtak_next;
1809 return (wsp->walk_callback(addr, &key, wsp->walk_cbdata));
1812 void
1813 dtrace_aggkey_fini(mdb_walk_state_t *wsp)
1815 dtrace_aggkey_data_t *data = wsp->walk_data;
1816 size_t hsize;
1818 hsize = data->dtakd_hashsize * sizeof (dtrace_aggkey_t *);
1819 mdb_free(data->dtakd_hash, hsize);
1820 mdb_free(data, sizeof (dtrace_aggkey_data_t));
1823 typedef struct dtrace_dynvar_data {
1824 dtrace_dynhash_t *dtdvd_hash;
1825 uintptr_t dtdvd_hashsize;
1826 uintptr_t dtdvd_next;
1827 uintptr_t dtdvd_ndx;
1828 uintptr_t dtdvd_sink;
1829 } dtrace_dynvar_data_t;
1832 dtrace_dynvar_init(mdb_walk_state_t *wsp)
1834 uintptr_t addr;
1835 dtrace_dstate_t dstate;
1836 dtrace_dynvar_data_t *data;
1837 size_t hsize;
1838 GElf_Sym sym;
1840 if ((addr = wsp->walk_addr) == (uintptr_t)NULL) {
1841 mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n");
1842 return (WALK_ERR);
1845 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) {
1846 mdb_warn("failed to read dynamic state at %p", addr);
1847 return (WALK_ERR);
1850 if (mdb_lookup_by_name("dtrace_dynhash_sink", &sym) == -1) {
1851 mdb_warn("couldn't find 'dtrace_dynhash_sink'");
1852 return (WALK_ERR);
1855 data = mdb_zalloc(sizeof (dtrace_dynvar_data_t), UM_SLEEP);
1857 data->dtdvd_hashsize = dstate.dtds_hashsize;
1858 hsize = dstate.dtds_hashsize * sizeof (dtrace_dynhash_t);
1859 data->dtdvd_hash = mdb_alloc(hsize, UM_SLEEP);
1860 data->dtdvd_sink = (uintptr_t)sym.st_value;
1862 if (mdb_vread(data->dtdvd_hash, hsize,
1863 (uintptr_t)dstate.dtds_hash) == -1) {
1864 mdb_warn("failed to read hash at %p",
1865 (uintptr_t)dstate.dtds_hash);
1866 mdb_free(data->dtdvd_hash, hsize);
1867 mdb_free(data, sizeof (dtrace_dynvar_data_t));
1868 return (WALK_ERR);
1871 data->dtdvd_next = (uintptr_t)data->dtdvd_hash[0].dtdh_chain;
1873 wsp->walk_data = data;
1874 return (WALK_NEXT);
1878 dtrace_dynvar_step(mdb_walk_state_t *wsp)
1880 dtrace_dynvar_data_t *data = wsp->walk_data;
1881 dtrace_dynvar_t dynvar, *dvar;
1882 size_t dvarsize;
1883 uintptr_t addr;
1884 int nkeys;
1886 while ((addr = data->dtdvd_next) == data->dtdvd_sink) {
1887 if (data->dtdvd_ndx == data->dtdvd_hashsize)
1888 return (WALK_DONE);
1890 data->dtdvd_next =
1891 (uintptr_t)data->dtdvd_hash[data->dtdvd_ndx++].dtdh_chain;
1894 if (mdb_vread(&dynvar, sizeof (dynvar), addr) == -1) {
1895 mdb_warn("failed to read dtrace_dynvar_t at %p", addr);
1896 return (WALK_ERR);
1900 * Now we need to allocate the correct size.
1902 nkeys = dynvar.dtdv_tuple.dtt_nkeys;
1903 dvarsize = (uintptr_t)&dynvar.dtdv_tuple.dtt_key[nkeys] -
1904 (uintptr_t)&dynvar;
1906 dvar = alloca(dvarsize);
1908 if (mdb_vread(dvar, dvarsize, addr) == -1) {
1909 mdb_warn("failed to read dtrace_dynvar_t at %p", addr);
1910 return (WALK_ERR);
1913 data->dtdvd_next = (uintptr_t)dynvar.dtdv_next;
1915 return (wsp->walk_callback(addr, dvar, wsp->walk_cbdata));
1918 void
1919 dtrace_dynvar_fini(mdb_walk_state_t *wsp)
1921 dtrace_dynvar_data_t *data = wsp->walk_data;
1922 size_t hsize;
1924 hsize = data->dtdvd_hashsize * sizeof (dtrace_dynvar_t *);
1925 mdb_free(data->dtdvd_hash, hsize);
1926 mdb_free(data, sizeof (dtrace_dynvar_data_t));
1929 typedef struct dtrace_hashstat_data {
1930 size_t *dthsd_counts;
1931 size_t dthsd_hashsize;
1932 char *dthsd_data;
1933 size_t dthsd_size;
1934 int dthsd_header;
1935 } dtrace_hashstat_data_t;
1937 typedef void (*dtrace_hashstat_func_t)(dtrace_hashstat_data_t *);
1939 static void
1940 dtrace_hashstat_additive(dtrace_hashstat_data_t *data)
1942 int i;
1943 int hval = 0;
1945 for (i = 0; i < data->dthsd_size; i++)
1946 hval += data->dthsd_data[i];
1948 data->dthsd_counts[hval % data->dthsd_hashsize]++;
1951 static void
1952 dtrace_hashstat_shifty(dtrace_hashstat_data_t *data)
1954 uint64_t hval = 0;
1955 int i;
1957 if (data->dthsd_size < sizeof (uint64_t)) {
1958 dtrace_hashstat_additive(data);
1959 return;
1962 for (i = 0; i < data->dthsd_size; i += sizeof (uint64_t)) {
1963 /* LINTED - alignment */
1964 uint64_t val = *((uint64_t *)&data->dthsd_data[i]);
1966 hval += (val & ((1 << NBBY) - 1)) +
1967 ((val >> NBBY) & ((1 << NBBY) - 1)) +
1968 ((val >> (NBBY << 1)) & ((1 << NBBY) - 1)) +
1969 ((val >> (NBBY << 2)) & ((1 << NBBY) - 1)) +
1970 (val & USHRT_MAX) + (val >> (NBBY << 1) & USHRT_MAX);
1973 data->dthsd_counts[hval % data->dthsd_hashsize]++;
1976 static void
1977 dtrace_hashstat_knuth(dtrace_hashstat_data_t *data)
1979 int i;
1980 int hval = data->dthsd_size;
1982 for (i = 0; i < data->dthsd_size; i++)
1983 hval = (hval << 4) ^ (hval >> 28) ^ data->dthsd_data[i];
1985 data->dthsd_counts[hval % data->dthsd_hashsize]++;
1988 static void
1989 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t *data)
1991 int i;
1992 uint32_t hval = 0;
1994 for (i = 0; i < data->dthsd_size; i++) {
1995 hval += data->dthsd_data[i];
1996 hval += (hval << 10);
1997 hval ^= (hval >> 6);
2000 hval += (hval << 3);
2001 hval ^= (hval >> 11);
2002 hval += (hval << 15);
2004 data->dthsd_counts[hval % data->dthsd_hashsize]++;
2007 static void
2008 dtrace_hashstat_fnv(dtrace_hashstat_data_t *data)
2010 static const uint32_t prime = 0x01000193;
2011 uint32_t hval = 0;
2012 int i;
2014 for (i = 0; i < data->dthsd_size; i++) {
2015 hval *= prime;
2016 hval ^= data->dthsd_data[i];
2019 data->dthsd_counts[hval % data->dthsd_hashsize]++;
2022 static void
2023 dtrace_hashstat_stats(char *name, dtrace_hashstat_data_t *data)
2025 size_t nz = 0, i;
2026 int longest = 0;
2027 size_t ttl = 0;
2028 double sum = 0.0;
2029 double avg;
2030 uint_t util, stddev;
2032 if (!data->dthsd_header) {
2033 mdb_printf("%15s %11s %11s %11s %11s %11s\n", "NAME",
2034 "HASHSIZE", "%UTIL", "LONGEST", "AVERAGE", "STDDEV");
2035 data->dthsd_header = 1;
2038 for (i = 0; i < data->dthsd_hashsize; i++) {
2039 if (data->dthsd_counts[i] != 0) {
2040 nz++;
2042 if (data->dthsd_counts[i] > longest)
2043 longest = data->dthsd_counts[i];
2045 ttl += data->dthsd_counts[i];
2049 if (nz == 0) {
2050 mdb_printf("%15s %11d %11s %11s %11s %11s\n", name,
2051 data->dthsd_hashsize, "-", "-", "-", "-");
2052 return;
2055 avg = (double)ttl / (double)nz;
2057 for (i = 0; i < data->dthsd_hashsize; i++) {
2058 double delta = (double)data->dthsd_counts[i] - avg;
2060 if (data->dthsd_counts[i] == 0)
2061 continue;
2063 sum += delta * delta;
2066 util = (nz * 1000) / data->dthsd_hashsize;
2067 stddev = (uint_t)sqrt(sum / (double)nz) * 10;
2069 mdb_printf("%15s %11d %9u.%1u %11d %11d %9u.%1u\n", name,
2070 data->dthsd_hashsize, util / 10, util % 10, longest, ttl / nz,
2071 stddev / 10, stddev % 10);
2074 static struct dtrace_hashstat {
2075 char *dths_name;
2076 dtrace_hashstat_func_t dths_func;
2077 } _dtrace_hashstat[] = {
2078 { "<actual>", NULL },
2079 { "additive", dtrace_hashstat_additive },
2080 { "shifty", dtrace_hashstat_shifty },
2081 { "knuth", dtrace_hashstat_knuth },
2082 { "one-at-a-time", dtrace_hashstat_oneatatime },
2083 { "fnv", dtrace_hashstat_fnv },
2084 { NULL, 0 }
2087 typedef struct dtrace_aggstat_data {
2088 dtrace_hashstat_data_t dtagsd_hash;
2089 dtrace_hashstat_func_t dtagsd_func;
2090 } dtrace_aggstat_data_t;
2092 static int
2093 dtrace_aggstat_walk(uintptr_t addr, dtrace_aggkey_t *key,
2094 dtrace_aggstat_data_t *data)
2096 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash;
2097 size_t size;
2099 if (data->dtagsd_func == NULL) {
2100 size_t bucket = key->dtak_hashval % hdata->dthsd_hashsize;
2102 hdata->dthsd_counts[bucket]++;
2103 return (WALK_NEXT);
2107 * We need to read the data.
2109 size = key->dtak_size - sizeof (dtrace_aggid_t);
2110 addr = (uintptr_t)key->dtak_data + sizeof (dtrace_aggid_t);
2111 hdata->dthsd_data = alloca(size);
2112 hdata->dthsd_size = size;
2114 if (mdb_vread(hdata->dthsd_data, size, addr) == -1) {
2115 mdb_warn("couldn't read data at %p", addr);
2116 return (WALK_ERR);
2119 data->dtagsd_func(hdata);
2121 return (WALK_NEXT);
2124 /*ARGSUSED*/
2126 dtrace_aggstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2128 dtrace_buffer_t buf;
2129 uintptr_t aaddr;
2130 dtrace_aggbuffer_t agb;
2131 size_t hsize, i, actual, prime, evenpow;
2132 dtrace_aggstat_data_t data;
2133 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash;
2135 bzero(&data, sizeof (data));
2137 if (!(flags & DCMD_ADDRSPEC))
2138 return (DCMD_USAGE);
2140 if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
2141 mdb_warn("failed to read aggregation buffer at %p", addr);
2142 return (DCMD_ERR);
2145 aaddr = (uintptr_t)buf.dtb_tomax +
2146 buf.dtb_size - sizeof (dtrace_aggbuffer_t);
2148 if (mdb_vread(&agb, sizeof (agb), aaddr) == -1) {
2149 mdb_warn("failed to read dtrace_aggbuffer_t at %p", aaddr);
2150 return (DCMD_ERR);
2153 hsize = (actual = agb.dtagb_hashsize) * sizeof (size_t);
2154 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2157 * Now pick the largest prime smaller than the hash size. (If the
2158 * existing size is prime, we'll pick a smaller prime just for the
2159 * hell of it.)
2161 for (prime = agb.dtagb_hashsize - 1; prime > 7; prime--) {
2162 size_t limit = prime / 7;
2164 for (i = 2; i < limit; i++) {
2165 if ((prime % i) == 0)
2166 break;
2169 if (i == limit)
2170 break;
2174 * And now we want to pick the largest power of two smaller than the
2175 * hashsize.
2177 for (i = 0; (1 << i) < agb.dtagb_hashsize; i++)
2178 continue;
2180 evenpow = (1 << (i - 1));
2182 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) {
2183 data.dtagsd_func = _dtrace_hashstat[i].dths_func;
2185 hdata->dthsd_hashsize = actual;
2186 hsize = hdata->dthsd_hashsize * sizeof (size_t);
2187 bzero(hdata->dthsd_counts, hsize);
2189 if (mdb_pwalk("dtrace_aggkey",
2190 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2191 mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2192 return (DCMD_ERR);
2195 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2198 * If we were just printing the actual value, we won't try
2199 * any of the sizing experiments.
2201 if (data.dtagsd_func == NULL)
2202 continue;
2204 hdata->dthsd_hashsize = prime;
2205 hsize = hdata->dthsd_hashsize * sizeof (size_t);
2206 bzero(hdata->dthsd_counts, hsize);
2208 if (mdb_pwalk("dtrace_aggkey",
2209 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2210 mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2211 return (DCMD_ERR);
2214 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2216 hdata->dthsd_hashsize = evenpow;
2217 hsize = hdata->dthsd_hashsize * sizeof (size_t);
2218 bzero(hdata->dthsd_counts, hsize);
2220 if (mdb_pwalk("dtrace_aggkey",
2221 (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2222 mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2223 return (DCMD_ERR);
2226 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2229 return (DCMD_OK);
2232 /*ARGSUSED*/
2233 static int
2234 dtrace_dynstat_walk(uintptr_t addr, dtrace_dynvar_t *dynvar,
2235 dtrace_aggstat_data_t *data)
2237 dtrace_hashstat_data_t *hdata = &data->dtagsd_hash;
2238 dtrace_tuple_t *tuple = &dynvar->dtdv_tuple;
2239 dtrace_key_t *key = tuple->dtt_key;
2240 size_t size = 0, offs = 0;
2241 int i, nkeys = tuple->dtt_nkeys;
2242 char *buf;
2244 if (data->dtagsd_func == NULL) {
2245 size_t bucket = dynvar->dtdv_hashval % hdata->dthsd_hashsize;
2247 hdata->dthsd_counts[bucket]++;
2248 return (WALK_NEXT);
2252 * We want to hand the hashing algorithm a contiguous buffer. First
2253 * run through the tuple and determine the size.
2255 for (i = 0; i < nkeys; i++) {
2256 if (key[i].dttk_size == 0) {
2257 size += sizeof (uint64_t);
2258 } else {
2259 size += key[i].dttk_size;
2263 buf = alloca(size);
2266 * Now go back through the tuple and copy the data into the buffer.
2268 for (i = 0; i < nkeys; i++) {
2269 if (key[i].dttk_size == 0) {
2270 bcopy(&key[i].dttk_value, &buf[offs],
2271 sizeof (uint64_t));
2272 offs += sizeof (uint64_t);
2273 } else {
2274 if (mdb_vread(&buf[offs], key[i].dttk_size,
2275 key[i].dttk_value) == -1) {
2276 mdb_warn("couldn't read tuple data at %p",
2277 key[i].dttk_value);
2278 return (WALK_ERR);
2281 offs += key[i].dttk_size;
2285 hdata->dthsd_data = buf;
2286 hdata->dthsd_size = size;
2288 data->dtagsd_func(hdata);
2290 return (WALK_NEXT);
2293 /*ARGSUSED*/
2295 dtrace_dynstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2297 dtrace_dstate_t dstate;
2298 size_t hsize, i, actual, prime;
2299 dtrace_aggstat_data_t data;
2300 dtrace_hashstat_data_t *hdata = &data.dtagsd_hash;
2302 bzero(&data, sizeof (data));
2304 if (!(flags & DCMD_ADDRSPEC))
2305 return (DCMD_USAGE);
2307 if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) {
2308 mdb_warn("failed to read dynamic variable state at %p", addr);
2309 return (DCMD_ERR);
2312 hsize = (actual = dstate.dtds_hashsize) * sizeof (size_t);
2313 hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2316 * Now pick the largest prime smaller than the hash size. (If the
2317 * existing size is prime, we'll pick a smaller prime just for the
2318 * hell of it.)
2320 for (prime = dstate.dtds_hashsize - 1; prime > 7; prime--) {
2321 size_t limit = prime / 7;
2323 for (i = 2; i < limit; i++) {
2324 if ((prime % i) == 0)
2325 break;
2328 if (i == limit)
2329 break;
2332 for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) {
2333 data.dtagsd_func = _dtrace_hashstat[i].dths_func;
2335 hdata->dthsd_hashsize = actual;
2336 hsize = hdata->dthsd_hashsize * sizeof (size_t);
2337 bzero(hdata->dthsd_counts, hsize);
2339 if (mdb_pwalk("dtrace_dynvar",
2340 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) {
2341 mdb_warn("failed to walk dtrace_dynvar at %p", addr);
2342 return (DCMD_ERR);
2345 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2348 * If we were just printing the actual value, we won't try
2349 * any of the sizing experiments.
2351 if (data.dtagsd_func == NULL)
2352 continue;
2354 hdata->dthsd_hashsize = prime;
2355 hsize = hdata->dthsd_hashsize * sizeof (size_t);
2356 bzero(hdata->dthsd_counts, hsize);
2358 if (mdb_pwalk("dtrace_dynvar",
2359 (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) {
2360 mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2361 return (DCMD_ERR);
2364 dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2367 return (DCMD_OK);
2370 typedef struct dtrace_ecb_walk {
2371 dtrace_ecb_t **dtew_ecbs;
2372 int dtew_necbs;
2373 int dtew_curecb;
2374 } dtrace_ecb_walk_t;
2376 static int
2377 dtrace_ecb_init(mdb_walk_state_t *wsp)
2379 uintptr_t addr;
2380 dtrace_state_t state;
2381 dtrace_ecb_walk_t *ecbwp;
2383 if ((addr = wsp->walk_addr) == (uintptr_t)NULL) {
2384 mdb_warn("dtrace_ecb walk needs dtrace_state_t\n");
2385 return (WALK_ERR);
2388 if (mdb_vread(&state, sizeof (state), addr) == -1) {
2389 mdb_warn("failed to read dtrace state pointer at %p", addr);
2390 return (WALK_ERR);
2393 ecbwp = mdb_zalloc(sizeof (dtrace_ecb_walk_t), UM_SLEEP | UM_GC);
2395 ecbwp->dtew_ecbs = state.dts_ecbs;
2396 ecbwp->dtew_necbs = state.dts_necbs;
2397 ecbwp->dtew_curecb = 0;
2399 wsp->walk_data = ecbwp;
2401 return (WALK_NEXT);
2404 static int
2405 dtrace_ecb_step(mdb_walk_state_t *wsp)
2407 uintptr_t ecbp, addr;
2408 dtrace_ecb_walk_t *ecbwp = wsp->walk_data;
2410 addr = (uintptr_t)ecbwp->dtew_ecbs +
2411 ecbwp->dtew_curecb * sizeof (dtrace_ecb_t *);
2413 if (ecbwp->dtew_curecb++ == ecbwp->dtew_necbs)
2414 return (WALK_DONE);
2416 if (mdb_vread(&ecbp, sizeof (addr), addr) == -1) {
2417 mdb_warn("failed to read ecb at entry %d\n",
2418 ecbwp->dtew_curecb);
2419 return (WALK_ERR);
2422 if (ecbp == (uintptr_t)NULL)
2423 return (WALK_NEXT);
2425 return (wsp->walk_callback(ecbp, NULL, wsp->walk_cbdata));
2428 static void
2429 dtrace_options_numtostr(uint64_t num, char *buf, size_t len)
2431 uint64_t n = num;
2432 int index = 0;
2433 char u;
2435 while (n >= 1024) {
2436 n = (n + (1024 / 2)) / 1024; /* Round up or down */
2437 index++;
2440 u = " KMGTPE"[index];
2442 if (index == 0) {
2443 (void) mdb_snprintf(buf, len, "%llu", (u_longlong_t)n);
2444 } else if (n < 10 && (num & (num - 1)) != 0) {
2445 (void) mdb_snprintf(buf, len, "%.2f%c",
2446 (double)num / (1ULL << 10 * index), u);
2447 } else if (n < 100 && (num & (num - 1)) != 0) {
2448 (void) mdb_snprintf(buf, len, "%.1f%c",
2449 (double)num / (1ULL << 10 * index), u);
2450 } else {
2451 (void) mdb_snprintf(buf, len, "%llu%c", (u_longlong_t)n, u);
2455 static void
2456 dtrace_options_numtohz(uint64_t num, char *buf, size_t len)
2458 (void) mdb_snprintf(buf, len, "%dhz", NANOSEC/num);
2461 static void
2462 dtrace_options_numtobufpolicy(uint64_t num, char *buf, size_t len)
2464 char *policy = "unknown";
2466 switch (num) {
2467 case DTRACEOPT_BUFPOLICY_RING:
2468 policy = "ring";
2469 break;
2471 case DTRACEOPT_BUFPOLICY_FILL:
2472 policy = "fill";
2473 break;
2475 case DTRACEOPT_BUFPOLICY_SWITCH:
2476 policy = "switch";
2477 break;
2480 (void) mdb_snprintf(buf, len, "%s", policy);
2483 static void
2484 dtrace_options_numtocpu(uint64_t cpu, char *buf, size_t len)
2486 if (cpu == DTRACE_CPUALL)
2487 (void) mdb_snprintf(buf, len, "%7s", "unbound");
2488 else
2489 (void) mdb_snprintf(buf, len, "%d", cpu);
2492 typedef void (*dtrace_options_func_t)(uint64_t, char *, size_t);
2494 static struct dtrace_options {
2495 char *dtop_optstr;
2496 dtrace_options_func_t dtop_func;
2497 } _dtrace_options[] = {
2498 { "bufsize", dtrace_options_numtostr },
2499 { "bufpolicy", dtrace_options_numtobufpolicy },
2500 { "dynvarsize", dtrace_options_numtostr },
2501 { "aggsize", dtrace_options_numtostr },
2502 { "specsize", dtrace_options_numtostr },
2503 { "nspec", dtrace_options_numtostr },
2504 { "strsize", dtrace_options_numtostr },
2505 { "cleanrate", dtrace_options_numtohz },
2506 { "cpu", dtrace_options_numtocpu },
2507 { "bufresize", dtrace_options_numtostr },
2508 { "grabanon", dtrace_options_numtostr },
2509 { "flowindent", dtrace_options_numtostr },
2510 { "quiet", dtrace_options_numtostr },
2511 { "stackframes", dtrace_options_numtostr },
2512 { "ustackframes", dtrace_options_numtostr },
2513 { "aggrate", dtrace_options_numtohz },
2514 { "switchrate", dtrace_options_numtohz },
2515 { "statusrate", dtrace_options_numtohz },
2516 { "destructive", dtrace_options_numtostr },
2517 { "stackindent", dtrace_options_numtostr },
2518 { "rawbytes", dtrace_options_numtostr },
2519 { "jstackframes", dtrace_options_numtostr },
2520 { "jstackstrsize", dtrace_options_numtostr },
2521 { "aggsortkey", dtrace_options_numtostr },
2522 { "aggsortrev", dtrace_options_numtostr },
2523 { "aggsortpos", dtrace_options_numtostr },
2524 { "aggsortkeypos", dtrace_options_numtostr }
2527 static void
2528 dtrace_options_help(void)
2530 mdb_printf("Given a dtrace_state_t structure, displays the "
2531 "current tunable option\nsettings.\n");
2534 /*ARGSUSED*/
2535 static int
2536 dtrace_options(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2538 dtrace_state_t state;
2539 int i = 0;
2540 dtrace_optval_t *options;
2541 char val[32];
2543 if (!(flags & DCMD_ADDRSPEC))
2544 return (DCMD_USAGE);
2546 if (mdb_vread(&state, sizeof (dtrace_state_t), (uintptr_t)addr) == -1) {
2547 mdb_warn("failed to read state pointer at %p\n", addr);
2548 return (DCMD_ERR);
2551 options = &state.dts_options[0];
2553 mdb_printf("%<u>%-25s %s%</u>\n", "OPTION", "VALUE");
2554 for (i = 0; i < DTRACEOPT_MAX; i++) {
2555 if (options[i] == DTRACEOPT_UNSET) {
2556 mdb_printf("%-25s %s\n",
2557 _dtrace_options[i].dtop_optstr, "UNSET");
2558 } else {
2559 (void) _dtrace_options[i].dtop_func(options[i],
2560 val, 32);
2561 mdb_printf("%-25s %s\n",
2562 _dtrace_options[i].dtop_optstr, val);
2566 return (DCMD_OK);
2569 static int
2570 pid2state_init(mdb_walk_state_t *wsp)
2572 dtrace_state_data_t *data;
2573 uintptr_t devi;
2574 uintptr_t proc;
2575 struct dev_info info;
2576 pid_t pid = (pid_t)wsp->walk_addr;
2578 if (wsp->walk_addr == (uintptr_t)NULL) {
2579 mdb_warn("pid2state walk requires PID\n");
2580 return (WALK_ERR);
2583 data = mdb_zalloc(sizeof (dtrace_state_data_t), UM_SLEEP | UM_GC);
2585 if (mdb_readvar(&data->dtsd_softstate, "dtrace_softstate") == -1) {
2586 mdb_warn("failed to read 'dtrace_softstate'");
2587 return (DCMD_ERR);
2590 if ((proc = mdb_pid2proc(pid, NULL)) == (uintptr_t)NULL) {
2591 mdb_warn("PID 0t%d not found\n", pid);
2592 return (DCMD_ERR);
2595 if (mdb_readvar(&devi, "dtrace_devi") == -1) {
2596 mdb_warn("failed to read 'dtrace_devi'");
2597 return (DCMD_ERR);
2600 if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) {
2601 mdb_warn("failed to read 'dev_info'");
2602 return (DCMD_ERR);
2605 data->dtsd_major = info.devi_major;
2606 data->dtsd_proc = proc;
2608 wsp->walk_data = data;
2610 return (WALK_NEXT);
2613 /*ARGSUSED*/
2614 static int
2615 pid2state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data)
2617 vnode_t vnode;
2618 minor_t minor;
2619 uintptr_t statep;
2621 /* Get the vnode for this file */
2622 if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) {
2623 mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode);
2624 return (WALK_NEXT);
2628 /* Is this the dtrace device? */
2629 if (getmajor(vnode.v_rdev) != data->dtsd_major)
2630 return (WALK_NEXT);
2632 /* Get the minor number for this device entry */
2633 minor = getminor(vnode.v_rdev);
2635 if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor,
2636 &statep, NULL, 0) == -1) {
2637 mdb_warn("failed to read softstate for minor %d", minor);
2638 return (WALK_NEXT);
2641 mdb_printf("%p\n", statep);
2643 return (WALK_NEXT);
2646 static int
2647 pid2state_step(mdb_walk_state_t *wsp)
2649 dtrace_state_data_t *ds = wsp->walk_data;
2651 if (mdb_pwalk("file",
2652 (mdb_walk_cb_t)pid2state_file, ds, ds->dtsd_proc) == -1) {
2653 mdb_warn("couldn't walk 'file' for proc %p", ds->dtsd_proc);
2654 return (WALK_ERR);
2657 return (WALK_DONE);
2660 /*ARGSUSED*/
2661 static int
2662 dtrace_probes_walk(uintptr_t addr, void *ignored, uintptr_t *target)
2664 dtrace_ecb_t ecb;
2665 dtrace_probe_t probe;
2666 dtrace_probedesc_t pd;
2668 if (addr == (uintptr_t)NULL)
2669 return (WALK_ERR);
2671 if (mdb_vread(&ecb, sizeof (dtrace_ecb_t), addr) == -1) {
2672 mdb_warn("failed to read ecb %p\n", addr);
2673 return (WALK_ERR);
2676 if (ecb.dte_probe == NULL)
2677 return (WALK_ERR);
2679 if (mdb_vread(&probe, sizeof (dtrace_probe_t),
2680 (uintptr_t)ecb.dte_probe) == -1) {
2681 mdb_warn("failed to read probe %p\n", ecb.dte_probe);
2682 return (WALK_ERR);
2685 pd.dtpd_id = probe.dtpr_id;
2686 dtracemdb_probe(NULL, &pd);
2688 mdb_printf("%5d %10s %17s %33s %s\n", pd.dtpd_id, pd.dtpd_provider,
2689 pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name);
2691 return (WALK_NEXT);
2694 static void
2695 dtrace_probes_help(void)
2697 mdb_printf("Given a dtrace_state_t structure, displays all "
2698 "its active enablings. If no\nstate structure is provided, "
2699 "all available probes are listed.\n");
2702 /*ARGSUSED*/
2703 static int
2704 dtrace_probes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2706 dtrace_probedesc_t pd;
2707 uintptr_t caddr, base, paddr;
2708 int nprobes, i;
2710 mdb_printf("%5s %10s %17s %33s %s\n",
2711 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
2713 if (!(flags & DCMD_ADDRSPEC)) {
2715 * If no argument is provided just display all available
2716 * probes.
2718 if (mdb_readvar(&base, "dtrace_probes") == -1) {
2719 mdb_warn("failed to read 'dtrace_probes'");
2720 return (-1);
2723 if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) {
2724 mdb_warn("failed to read 'dtrace_nprobes'");
2725 return (-1);
2728 for (i = 0; i < nprobes; i++) {
2729 caddr = base + i * sizeof (dtrace_probe_t *);
2731 if (mdb_vread(&paddr, sizeof (paddr), caddr) == -1) {
2732 mdb_warn("couldn't read probe pointer at %p",
2733 caddr);
2734 continue;
2737 if (paddr == (uintptr_t)NULL)
2738 continue;
2740 pd.dtpd_id = i + 1;
2741 if (dtracemdb_probe(NULL, &pd) == 0) {
2742 mdb_printf("%5d %10s %17s %33s %s\n",
2743 pd.dtpd_id, pd.dtpd_provider,
2744 pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name);
2747 } else {
2748 if (mdb_pwalk("dtrace_ecb", (mdb_walk_cb_t)dtrace_probes_walk,
2749 NULL, addr) == -1) {
2750 mdb_warn("couldn't walk 'dtrace_ecb'");
2751 return (DCMD_ERR);
2755 return (DCMD_OK);
2758 const mdb_dcmd_t kernel_dcmds[] = {
2759 { "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t",
2760 id2probe },
2761 { "dtrace", ":[-c cpu]", "print dtrace(1M)-like output",
2762 dtrace, dtrace_help },
2763 { "dtrace_errhash", ":", "print DTrace error hash", dtrace_errhash },
2764 { "dtrace_helptrace", ":", "print DTrace helper trace",
2765 dtrace_helptrace },
2766 { "dtrace_state", ":", "print active DTrace consumers", dtrace_state,
2767 dtrace_state_help },
2768 { "dtrace_aggstat", ":",
2769 "print DTrace aggregation hash statistics", dtrace_aggstat },
2770 { "dtrace_dynstat", ":",
2771 "print DTrace dynamic variable hash statistics", dtrace_dynstat },
2772 { "dtrace_options", ":",
2773 "print a DTrace consumer's current tuneable options",
2774 dtrace_options, dtrace_options_help },
2775 { "dtrace_probes", "?", "print a DTrace consumer's enabled probes",
2776 dtrace_probes, dtrace_probes_help },
2777 { NULL }
2780 const mdb_walker_t kernel_walkers[] = {
2781 { "dtrace_errhash", "walk hash of DTrace error messasges",
2782 dtrace_errhash_init, dtrace_errhash_step },
2783 { "dtrace_helptrace", "walk DTrace helper trace entries",
2784 dtrace_helptrace_init, dtrace_helptrace_step },
2785 { "dtrace_state", "walk DTrace per-consumer softstate",
2786 dtrace_state_init, dtrace_state_step },
2787 { "dtrace_aggkey", "walk DTrace aggregation keys",
2788 dtrace_aggkey_init, dtrace_aggkey_step, dtrace_aggkey_fini },
2789 { "dtrace_dynvar", "walk DTrace dynamic variables",
2790 dtrace_dynvar_init, dtrace_dynvar_step, dtrace_dynvar_fini },
2791 { "dtrace_ecb", "walk a DTrace consumer's enabling control blocks",
2792 dtrace_ecb_init, dtrace_ecb_step },
2793 { "pid2state", "walk a processes dtrace_state structures",
2794 pid2state_init, pid2state_step },
2795 { NULL }