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]
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
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>
53 id2probe(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
55 uintptr_t probe
= (uintptr_t)NULL
;
58 if (!(flags
& DCMD_ADDRSPEC
))
61 if (addr
== DTRACE_IDNONE
|| addr
> UINT32_MAX
)
64 if (mdb_readvar(&probes
, "dtrace_probes") == -1) {
65 mdb_warn("failed to read 'dtrace_probes'");
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);
77 mdb_printf("%p\n", probe
);
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 "
89 "structures for all DTrace consumers may be obtained by running "
91 "::dtrace_state dcmd.) When data is present on multiple CPUs, "
93 "presented in CPU order, with records within each CPU ordered "
95 "youngest. Options:\n\n"
96 "-c cpu Only provide output for specified CPU.\n");
100 dtracemdb_eprobe(dtrace_state_t
*state
, dtrace_eprobedesc_t
*epd
)
102 dtrace_epid_t epid
= epd
->dtepd_epid
;
103 dtrace_probe_t probe
;
105 uintptr_t addr
, paddr
, ap
;
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
);
117 if (addr
== (uintptr_t)NULL
) {
118 mdb_warn("epid %d doesn't match an ecb\n", epid
);
122 if (mdb_vread(&ecb
, sizeof (ecb
), addr
) == -1) {
123 mdb_warn("failed to read ecb at %p", addr
);
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
);
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
;
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",
147 if (!DTRACEACT_ISAGG(act
.dta_kind
) && !act
.dta_intuple
)
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
;
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",
168 if (!DTRACEACT_ISAGG(act
.dta_kind
) && !act
.dta_intuple
) {
172 epd
->dtepd_rec
[nactions
++] = act
.dta_rec
;
175 ap
= (uintptr_t)act
.dta_next
;
183 dtracemdb_probe(dtrace_state_t
*state
, dtrace_probedesc_t
*pd
)
185 uintptr_t base
, addr
, paddr
, praddr
;
187 dtrace_probe_t probe
;
188 dtrace_provider_t prov
;
190 if (pd
->dtpd_id
== DTRACE_IDNONE
)
193 if (mdb_readvar(&base
, "dtrace_probes") == -1) {
194 mdb_warn("failed to read 'dtrace_probes'");
198 if (mdb_readvar(&nprobes
, "dtrace_nprobes") == -1) {
199 mdb_warn("failed to read 'dtrace_nprobes'");
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
);
211 if (paddr
!= (uintptr_t)NULL
)
215 if (paddr
== (uintptr_t)NULL
) {
220 if (mdb_vread(&probe
, sizeof (probe
), paddr
) == -1) {
221 mdb_warn("couldn't read probe at %p", paddr
);
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
);
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
);
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
);
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
);
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
);
263 dtracemdb_aggdesc(dtrace_state_t
*state
, dtrace_aggdesc_t
*agd
)
265 dtrace_aggid_t aggid
= agd
->dtagd_id
;
266 dtrace_aggregation_t agg
;
268 uintptr_t addr
, eaddr
, ap
, last
;
270 dtrace_recdesc_t
*lrec
;
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
);
281 if (addr
== (uintptr_t)NULL
) {
282 mdb_warn("aggid %d doesn't match an aggregation\n", aggid
);
286 if (mdb_vread(&agg
, sizeof (agg
), addr
) == -1) {
287 mdb_warn("failed to read aggregation at %p", addr
);
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
);
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
;
308 if (mdb_vread(&act
, sizeof (act
), ap
) == -1) {
309 mdb_warn("failed to read action %p on aggregation %p",
319 ap
= (uintptr_t)act
.dta_next
;
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
;
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",
345 rec
.dtrd_offset
-= agg
.dtag_base
;
347 agd
->dtagd_rec
[nactions
++] = rec
;
352 ap
= (uintptr_t)act
.dta_next
;
359 dtracemdb_bufsnap(dtrace_buffer_t
*which
, dtrace_bufdesc_t
*desc
)
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'");
373 if (cpu
< 0 || cpu
> max_cpuid
) {
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
);
386 if (buf
.dtb_tomax
== NULL
) {
391 if (buf
.dtb_flags
& DTRACEBUF_WRAPPED
) {
392 bufsize
= buf
.dtb_size
;
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
);
403 if (buf
.dtb_offset
> buf
.dtb_size
) {
404 mdb_warn("buffer for CPU %d has corrupt offset\n", cpu
);
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
);
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
;
434 desc
->dtbd_oldest
= 0;
437 desc
->dtbd_size
= bufsize
;
438 desc
->dtbd_drops
= buf
.dtb_drops
;
439 desc
->dtbd_errors
= buf
.dtb_errors
;
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.
450 dtracemdb_dof_create(dtrace_state_t
*state
, int isanon
)
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
;
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
;
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
];
503 opt
[DTRACEOPT_GRABANON
].dofo_value
= 1;
509 dtracemdb_format(dtrace_state_t
*state
, dtrace_fmtdesc_t
*desc
)
511 uintptr_t addr
, faddr
;
515 if (desc
->dtfd_format
== 0 || desc
->dtfd_format
> state
->dts_nformats
) {
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
);
529 if (mdb_vread(&c
, sizeof (c
), addr
+ len
++) == -1) {
530 mdb_warn("failed to read format string at %p", addr
);
535 if (len
> desc
->dtfd_length
) {
536 desc
->dtfd_length
= len
;
540 if (mdb_vread(desc
->dtfd_string
, len
, addr
) == -1) {
541 mdb_warn("failed to reread format string at %p", addr
);
549 dtracemdb_status(dtrace_state_t
*state
, dtrace_status_t
*status
)
551 dtrace_dstate_t
*dstate
;
557 if (mdb_readvar(&ncpu
, "_ncpu") == -1) {
558 mdb_warn("failed to read '_ncpu'");
562 bzero(status
, sizeof (dtrace_status_t
));
564 if (state
->dts_activity
== DTRACE_ACTIVITY_INACTIVE
) {
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
;
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
);
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
);
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
);
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
);
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
;
631 typedef struct dtracemdb_data
{
632 dtrace_state_t
*dtmd_state
;
640 dtracemdb_ioctl(void *varg
, int cmd
, void *arg
)
642 dtracemdb_data_t
*data
= varg
;
643 dtrace_state_t
*state
= data
->dtmd_state
;
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
;
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
);
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
));
690 *(processorid_t
*)arg
= -1;
693 case DTRACEIOC_ENABLE
:
694 errno
= ENOTTY
; /* see dt_open.c:dtrace_go() */
697 case DTRACEIOC_PROVIDER
:
698 case DTRACEIOC_PROBEMATCH
:
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" :
727 dtracemdb_modctl(uintptr_t addr
, const struct modctl
*m
, dtracemdb_data_t
*data
)
731 if (m
->mod_mp
== NULL
)
734 if (mdb_vread(&mod
, sizeof (mod
), (uintptr_t)m
->mod_mp
) == -1) {
735 mdb_warn("couldn't read modctl %p's module", addr
);
739 if ((uintptr_t)mod
.text
> data
->dtmd_addr
)
742 if ((uintptr_t)mod
.text
+ mod
.text_size
<= data
->dtmd_addr
)
745 if (mdb_readstr(data
->dtmd_modstr
, MDB_SYM_NAMLEN
,
746 (uintptr_t)m
->mod_modname
) == -1)
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
,
763 if (data
->dtmd_modstr
== NULL
) {
764 data
->dtmd_modstr
= mdb_zalloc(MDB_SYM_NAMLEN
,
769 if (mdb_lookup_by_addr(addr
, MDB_SYM_FUZZY
, data
->dtmd_symstr
,
770 MDB_SYM_NAMLEN
, symp
) == -1)
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'");
785 sip
->dts_object
= data
->dtmd_modstr
;
787 sip
->dts_name
= symp
!= NULL
? data
->dtmd_symstr
: NULL
;
795 dtracemdb_stat(void *varg
, processorid_t cpu
)
799 uintptr_t caddr
, addr
;
801 if (mdb_lookup_by_name("cpu", &sym
) == -1) {
802 mdb_warn("failed to find symbol for 'cpu'");
806 if (cpu
* sizeof (uintptr_t) > sym
.st_size
)
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
);
816 if (caddr
== (uintptr_t)NULL
)
819 if (mdb_vread(&c
, sizeof (c
), caddr
) == -1) {
820 mdb_warn("failed to read cpu at %p", caddr
);
824 if (c
.cpu_flags
& CPU_POWEROFF
) {
826 } else if (c
.cpu_flags
& CPU_SPARE
) {
828 } else if (c
.cpu_flags
& CPU_FAULTED
) {
830 } else if ((c
.cpu_flags
& (CPU_READY
| CPU_OFFLINE
)) != CPU_READY
) {
832 } else if (c
.cpu_flags
& CPU_ENABLE
) {
841 dtracemdb_sysconf(void *varg
, int name
)
844 processorid_t max_cpuid
;
848 if (mdb_readvar(&max_cpuid
, "max_cpuid") == -1) {
849 mdb_warn("failed to read 'max_cpuid'");
855 case _SC_NPROCESSORS_MAX
:
856 if (mdb_readvar(&max_ncpus
, "max_ncpus") == -1) {
857 mdb_warn("failed to read 'max_ncpus'");
864 mdb_warn("unexpected sysconf code %d\n", name
);
869 const dtrace_vector_t dtrace_mdbops
= {
871 dtracemdb_lookup_by_addr
,
876 typedef struct dtrace_dcmddata
{
877 dtrace_hdl_t
*dtdd_dtp
;
886 * Helper to grab all the content from a file, spit it into a string, and erase
887 * and reset the file.
890 print_and_truncate_file(FILE *fp
)
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
);
902 out
= mdb_alloc(len
+ 1, UM_SLEEP
);
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);
913 mdb_printf("%s", out
);
914 mdb_free(out
, len
+ 1);
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
);
928 * We have processed the final record; output the newline if
929 * we're not in quiet mode.
934 return (DTRACE_CONSUME_NEXT
);
937 return (DTRACE_CONSUME_THIS
);
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");
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
);
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
,
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
);
991 dtrace_dcmderr(const dtrace_errdata_t
*data
, void *arg
)
993 mdb_warn(data
->dteda_msg
);
994 return (DTRACE_HANDLE_OK
);
999 dtrace_dcmddrop(const dtrace_dropdata_t
*data
, void *arg
)
1001 mdb_warn(data
->dtdda_msg
);
1002 return (DTRACE_HANDLE_OK
);
1007 dtrace_dcmdbuffered(const dtrace_bufdata_t
*bufdata
, void *arg
)
1009 mdb_printf("%s", bufdata
->dtbda_buffered
);
1010 return (DTRACE_HANDLE_OK
);
1015 dtrace(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1017 dtrace_state_t state
;
1021 dtrace_dcmddata_t dd
;
1022 dtrace_optval_t val
;
1023 dtracemdb_data_t md
;
1024 int rval
= DCMD_ERR
;
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'");
1038 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
1039 mdb_warn("couldn't read dtrace_state_t at %p", addr
);
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
);
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
));
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'");
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
)));
1079 bzero(&dd
, sizeof (dd
));
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
)));
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
)));
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
)));
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
)));
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
)));
1117 if (dtrace_status(dtp
) == -1) {
1118 mdb_warn("couldn't get status: %s\n",
1119 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1123 if (dtrace_aggregate_snap(dtp
) == -1) {
1124 mdb_warn("couldn't snapshot aggregation: %s\n",
1125 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1129 if ((dd
.dtdd_output
= tmpfile()) == NULL
) {
1130 mdb_warn("couldn't open DTrace output file: %d\n", errno
);
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
)));
1149 fclose(dd
.dtdd_output
);
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
)
1167 if (rerr
.dter_msg
== NULL
)
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
)
1180 uintptr_t *hash
, addr
;
1183 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
1184 mdb_warn("dtrace_errhash walk only supports global walks\n");
1188 if (mdb_lookup_by_name("dtrace_errhash", &sym
) == -1) {
1189 mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)");
1193 addr
= (uintptr_t)sym
.st_value
;
1194 hash
= mdb_alloc(DTRACE_ERRHASHSZ
* sizeof (uintptr_t),
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
);
1203 wsp
->walk_data
= hash
;
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
;
1216 if (ndx
>= DTRACE_ERRHASHSZ
)
1219 wsp
->walk_addr
= ndx
+ 1;
1222 if (mdb_vread(&err
, sizeof (err
), addr
) == -1) {
1223 mdb_warn("failed to read dtrace_errhash_t at %p", addr
);
1227 if (err
.dter_msg
== NULL
)
1230 return (wsp
->walk_callback(addr
, &err
, wsp
->walk_cbdata
));
1235 dtrace_errhash(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1237 dtrace_errhash_t err
;
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'");
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
);
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
);
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')
1278 dtrace_helptrace_init(mdb_walk_state_t
*wsp
)
1283 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
1284 mdb_warn("dtrace_helptrace only supports global walks\n");
1288 if (mdb_readvar(&buffer
, "dtrace_helptrace_buffer") == -1) {
1289 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1293 if (buffer
== (uintptr_t)NULL
) {
1294 mdb_warn("helper tracing is not enabled\n");
1298 if (mdb_readvar(&next
, "dtrace_helptrace_next") == -1) {
1299 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1303 wsp
->walk_addr
= 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
;
1316 if (mdb_readvar(&next
, "dtrace_helptrace_next") == -1) {
1317 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1321 if (mdb_readvar(&bufsize
, "dtrace_helptrace_bufsize") == -1) {
1322 mdb_warn("couldn't read 'dtrace_helptrace_bufsize'");
1326 if (mdb_readvar(&buffer
, "dtrace_helptrace_buffer") == -1) {
1327 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1331 if (mdb_readvar(&nlocals
, "dtrace_helptrace_nlocals") == -1) {
1332 mdb_warn("couldn't read 'dtrace_helptrace_nlocals'");
1336 size
= sizeof (dtrace_helptrace_t
) +
1337 nlocals
* sizeof (uint64_t) - sizeof (uint64_t);
1339 if (wsp
->walk_addr
+ size
> bufsize
) {
1346 addr
= buffer
+ wsp
->walk_addr
;
1349 if (mdb_vread(ht
, size
, addr
) == -1) {
1350 mdb_warn("couldn't read entry at %p", addr
);
1354 if (ht
->dtht_helper
!= NULL
) {
1355 rval
= wsp
->walk_callback(addr
, ht
, wsp
->walk_cbdata
);
1357 if (rval
!= WALK_NEXT
)
1361 if (wsp
->walk_addr
< next
&& wsp
->walk_addr
+ size
>= next
)
1364 wsp
->walk_addr
+= size
;
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
;
1374 uint_t opt_v
= FALSE
;
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'");
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
);
1401 switch (help
.dtht_where
) {
1403 (void) mdb_snprintf(where
, sizeof (where
), "predicate");
1406 case DTRACE_HELPTRACE_NEXT
:
1407 (void) mdb_snprintf(where
, sizeof (where
), "next");
1410 case DTRACE_HELPTRACE_DONE
:
1411 (void) mdb_snprintf(where
, sizeof (where
), "done");
1414 case DTRACE_HELPTRACE_ERR
:
1415 (void) mdb_snprintf(where
, sizeof (where
), "err");
1419 (void) mdb_snprintf(where
, sizeof (where
),
1420 "action #%d", help
.dtht_where
);
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");
1435 switch (help
.dtht_where
) {
1437 mdb_printf("%p\n", helper
.dtha_predicate
);
1440 case DTRACE_HELPTRACE_NEXT
:
1441 case DTRACE_HELPTRACE_DONE
:
1442 case DTRACE_HELPTRACE_ERR
:
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");
1453 mdb_printf("%p\n", haddr
);
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", "", "", "",
1478 mdb_printf("%?s| %?s %12s offset: %d\n", "", "", "",
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
++) {
1489 if (mdb_vread(&val
, sizeof (val
), addr
) == -1) {
1490 mdb_warn("couldn't read local at %p", addr
);
1494 mdb_printf("%?s %?p %4d %p\n", "", addr
, i
, val
);
1495 addr
+= sizeof (uint64_t);
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
;
1514 typedef struct dtrace_state_walk
{
1515 uintptr_t dtsw_softstate
;
1517 minor_t dtsw_current
;
1518 } dtrace_state_walk_t
;
1521 dtrace_state_init(mdb_walk_state_t
*wsp
)
1523 uintptr_t dtrace_minor
;
1525 dtrace_state_walk_t
*dw
;
1527 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
1528 mdb_warn("dtrace_state only supports global walks\n");
1533 * Find the dtrace_minor vmem arena and walk it to get the maximum
1536 if (mdb_readvar(&dtrace_minor
, "dtrace_minor") == -1) {
1537 mdb_warn("failed to read 'dtrace_minor'");
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'");
1547 dw
= mdb_zalloc(sizeof (dtrace_state_walk_t
), UM_SLEEP
| UM_GC
);
1548 dw
->dtsw_current
= 0;
1551 if (mdb_readvar(&dw
->dtsw_softstate
, "dtrace_softstate") == -1) {
1552 mdb_warn("failed to read 'dtrace_softstate'");
1556 wsp
->walk_data
= dw
;
1562 dtrace_state_step(mdb_walk_state_t
*wsp
)
1564 dtrace_state_walk_t
*dw
= wsp
->walk_data
;
1566 dtrace_state_t state
;
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
)
1577 if (mdb_vread(&state
, sizeof (state
), statep
) == -1) {
1578 mdb_warn("couldn't read dtrace_state_t at %p", statep
);
1582 rval
= wsp
->walk_callback(statep
, &state
, wsp
->walk_cbdata
);
1588 typedef struct dtrace_state_data
{
1590 uintptr_t dtsd_proc
;
1591 uintptr_t dtsd_softstate
;
1592 uintptr_t dtsd_state
;
1593 } dtrace_state_data_t
;
1596 dtrace_state_file(uintptr_t addr
, struct file
*f
, dtrace_state_data_t
*data
)
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
);
1608 if (getmajor(vnode
.v_rdev
) != data
->dtsd_major
)
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
);
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
);
1624 if (statep
!= data
->dtsd_state
)
1627 mdb_printf("%?p %5d %?p %-*s %?p\n", statep
, minor
,
1628 data
->dtsd_proc
, MAXCOMLEN
, proc
.p_user
.u_comm
, addr
);
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
);
1649 dtrace_state_help(void)
1651 mdb_printf("Given a dtrace_state_t structure, displays all "
1653 "consumers, or \"<anonymous>\"\nif the consumer is anonymous. If "
1654 "no state structure is provided, iterates\nover all state "
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
)
1664 struct dev_info info
;
1665 dtrace_state_data_t data
;
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");
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'");
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
);
1697 mdb_printf("%?p %5d %?s %-*s %?s\n", addr
,
1698 getminor(state
.dts_dev
), "-", MAXCOMLEN
,
1699 "<anonymous>", "-");
1704 if (mdb_readvar(&devi
, "dtrace_devi") == -1) {
1705 mdb_warn("failed to read 'dtrace_devi'");
1709 if (mdb_vread(&info
, sizeof (struct dev_info
), devi
) == -1) {
1710 mdb_warn("failed to read 'dev_info'");
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'");
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'");
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
;
1747 dtrace_aggbuffer_t agb
;
1748 dtrace_aggkey_data_t
*data
;
1751 if ((addr
= wsp
->walk_addr
) == (uintptr_t)NULL
) {
1752 mdb_warn("dtrace_aggkey walk needs aggregation buffer\n");
1756 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
1757 mdb_warn("failed to read aggregation buffer at %p", addr
);
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
);
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
));
1784 wsp
->walk_data
= data
;
1789 dtrace_aggkey_step(mdb_walk_state_t
*wsp
)
1791 dtrace_aggkey_data_t
*data
= wsp
->walk_data
;
1792 dtrace_aggkey_t key
;
1795 while ((addr
= data
->dtakd_next
) == (uintptr_t)NULL
) {
1796 if (data
->dtakd_ndx
== data
->dtakd_hashsize
)
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
);
1807 data
->dtakd_next
= (uintptr_t)key
.dtak_next
;
1809 return (wsp
->walk_callback(addr
, &key
, wsp
->walk_cbdata
));
1813 dtrace_aggkey_fini(mdb_walk_state_t
*wsp
)
1815 dtrace_aggkey_data_t
*data
= wsp
->walk_data
;
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
)
1835 dtrace_dstate_t dstate
;
1836 dtrace_dynvar_data_t
*data
;
1840 if ((addr
= wsp
->walk_addr
) == (uintptr_t)NULL
) {
1841 mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n");
1845 if (mdb_vread(&dstate
, sizeof (dstate
), addr
) == -1) {
1846 mdb_warn("failed to read dynamic state at %p", addr
);
1850 if (mdb_lookup_by_name("dtrace_dynhash_sink", &sym
) == -1) {
1851 mdb_warn("couldn't find 'dtrace_dynhash_sink'");
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
));
1871 data
->dtdvd_next
= (uintptr_t)data
->dtdvd_hash
[0].dtdh_chain
;
1873 wsp
->walk_data
= data
;
1878 dtrace_dynvar_step(mdb_walk_state_t
*wsp
)
1880 dtrace_dynvar_data_t
*data
= wsp
->walk_data
;
1881 dtrace_dynvar_t dynvar
, *dvar
;
1886 while ((addr
= data
->dtdvd_next
) == data
->dtdvd_sink
) {
1887 if (data
->dtdvd_ndx
== data
->dtdvd_hashsize
)
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
);
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
] -
1906 dvar
= alloca(dvarsize
);
1908 if (mdb_vread(dvar
, dvarsize
, addr
) == -1) {
1909 mdb_warn("failed to read dtrace_dynvar_t at %p", addr
);
1913 data
->dtdvd_next
= (uintptr_t)dynvar
.dtdv_next
;
1915 return (wsp
->walk_callback(addr
, dvar
, wsp
->walk_cbdata
));
1919 dtrace_dynvar_fini(mdb_walk_state_t
*wsp
)
1921 dtrace_dynvar_data_t
*data
= wsp
->walk_data
;
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
;
1935 } dtrace_hashstat_data_t
;
1937 typedef void (*dtrace_hashstat_func_t
)(dtrace_hashstat_data_t
*);
1940 dtrace_hashstat_additive(dtrace_hashstat_data_t
*data
)
1945 for (i
= 0; i
< data
->dthsd_size
; i
++)
1946 hval
+= data
->dthsd_data
[i
];
1948 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
1952 dtrace_hashstat_shifty(dtrace_hashstat_data_t
*data
)
1957 if (data
->dthsd_size
< sizeof (uint64_t)) {
1958 dtrace_hashstat_additive(data
);
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
]++;
1977 dtrace_hashstat_knuth(dtrace_hashstat_data_t
*data
)
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
]++;
1989 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t
*data
)
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
]++;
2008 dtrace_hashstat_fnv(dtrace_hashstat_data_t
*data
)
2010 static const uint32_t prime
= 0x01000193;
2014 for (i
= 0; i
< data
->dthsd_size
; i
++) {
2016 hval
^= data
->dthsd_data
[i
];
2019 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
2023 dtrace_hashstat_stats(char *name
, dtrace_hashstat_data_t
*data
)
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) {
2042 if (data
->dthsd_counts
[i
] > longest
)
2043 longest
= data
->dthsd_counts
[i
];
2045 ttl
+= data
->dthsd_counts
[i
];
2050 mdb_printf("%15s %11d %11s %11s %11s %11s\n", name
,
2051 data
->dthsd_hashsize
, "-", "-", "-", "-");
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)
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
{
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
},
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
;
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
;
2099 if (data
->dtagsd_func
== NULL
) {
2100 size_t bucket
= key
->dtak_hashval
% hdata
->dthsd_hashsize
;
2102 hdata
->dthsd_counts
[bucket
]++;
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
);
2119 data
->dtagsd_func(hdata
);
2126 dtrace_aggstat(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2128 dtrace_buffer_t buf
;
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
);
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
);
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
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)
2174 * And now we want to pick the largest power of two smaller than the
2177 for (i
= 0; (1 << i
) < agb
.dtagb_hashsize
; i
++)
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
);
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
)
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
);
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
);
2226 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
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
;
2244 if (data
->dtagsd_func
== NULL
) {
2245 size_t bucket
= dynvar
->dtdv_hashval
% hdata
->dthsd_hashsize
;
2247 hdata
->dthsd_counts
[bucket
]++;
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);
2259 size
+= key
[i
].dttk_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
],
2272 offs
+= sizeof (uint64_t);
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",
2281 offs
+= key
[i
].dttk_size
;
2285 hdata
->dthsd_data
= buf
;
2286 hdata
->dthsd_size
= size
;
2288 data
->dtagsd_func(hdata
);
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
);
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
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)
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
);
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
)
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
);
2364 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2370 typedef struct dtrace_ecb_walk
{
2371 dtrace_ecb_t
**dtew_ecbs
;
2374 } dtrace_ecb_walk_t
;
2377 dtrace_ecb_init(mdb_walk_state_t
*wsp
)
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");
2388 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
2389 mdb_warn("failed to read dtrace state pointer at %p", addr
);
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
;
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
)
2416 if (mdb_vread(&ecbp
, sizeof (addr
), addr
) == -1) {
2417 mdb_warn("failed to read ecb at entry %d\n",
2418 ecbwp
->dtew_curecb
);
2422 if (ecbp
== (uintptr_t)NULL
)
2425 return (wsp
->walk_callback(ecbp
, NULL
, wsp
->walk_cbdata
));
2429 dtrace_options_numtostr(uint64_t num
, char *buf
, size_t len
)
2436 n
= (n
+ (1024 / 2)) / 1024; /* Round up or down */
2440 u
= " KMGTPE"[index
];
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
);
2451 (void) mdb_snprintf(buf
, len
, "%llu%c", (u_longlong_t
)n
, u
);
2456 dtrace_options_numtohz(uint64_t num
, char *buf
, size_t len
)
2458 (void) mdb_snprintf(buf
, len
, "%dhz", NANOSEC
/num
);
2462 dtrace_options_numtobufpolicy(uint64_t num
, char *buf
, size_t len
)
2464 char *policy
= "unknown";
2467 case DTRACEOPT_BUFPOLICY_RING
:
2471 case DTRACEOPT_BUFPOLICY_FILL
:
2475 case DTRACEOPT_BUFPOLICY_SWITCH
:
2480 (void) mdb_snprintf(buf
, len
, "%s", policy
);
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");
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
{
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
}
2528 dtrace_options_help(void)
2530 mdb_printf("Given a dtrace_state_t structure, displays the "
2531 "current tunable option\nsettings.\n");
2536 dtrace_options(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2538 dtrace_state_t state
;
2540 dtrace_optval_t
*options
;
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
);
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");
2559 (void) _dtrace_options
[i
].dtop_func(options
[i
],
2561 mdb_printf("%-25s %s\n",
2562 _dtrace_options
[i
].dtop_optstr
, val
);
2570 pid2state_init(mdb_walk_state_t
*wsp
)
2572 dtrace_state_data_t
*data
;
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");
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'");
2590 if ((proc
= mdb_pid2proc(pid
, NULL
)) == (uintptr_t)NULL
) {
2591 mdb_warn("PID 0t%d not found\n", pid
);
2595 if (mdb_readvar(&devi
, "dtrace_devi") == -1) {
2596 mdb_warn("failed to read 'dtrace_devi'");
2600 if (mdb_vread(&info
, sizeof (struct dev_info
), devi
) == -1) {
2601 mdb_warn("failed to read 'dev_info'");
2605 data
->dtsd_major
= info
.devi_major
;
2606 data
->dtsd_proc
= proc
;
2608 wsp
->walk_data
= data
;
2615 pid2state_file(uintptr_t addr
, struct file
*f
, dtrace_state_data_t
*data
)
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
);
2628 /* Is this the dtrace device? */
2629 if (getmajor(vnode
.v_rdev
) != data
->dtsd_major
)
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
);
2641 mdb_printf("%p\n", statep
);
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
);
2662 dtrace_probes_walk(uintptr_t addr
, void *ignored
, uintptr_t *target
)
2665 dtrace_probe_t probe
;
2666 dtrace_probedesc_t pd
;
2668 if (addr
== (uintptr_t)NULL
)
2671 if (mdb_vread(&ecb
, sizeof (dtrace_ecb_t
), addr
) == -1) {
2672 mdb_warn("failed to read ecb %p\n", addr
);
2676 if (ecb
.dte_probe
== NULL
)
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
);
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
);
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");
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
;
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
2718 if (mdb_readvar(&base
, "dtrace_probes") == -1) {
2719 mdb_warn("failed to read 'dtrace_probes'");
2723 if (mdb_readvar(&nprobes
, "dtrace_nprobes") == -1) {
2724 mdb_warn("failed to read 'dtrace_nprobes'");
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",
2737 if (paddr
== (uintptr_t)NULL
)
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
);
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'");
2758 const mdb_dcmd_t kernel_dcmds
[] = {
2759 { "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t",
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",
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
},
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
},