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) 2017, 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
= 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
);
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 for (ap
= (uintptr_t)ecb
.dte_action
, nactions
= 0; ap
!= NULL
; ) {
139 if (mdb_vread(&act
, sizeof (act
), ap
) == -1) {
140 mdb_warn("failed to read action %p on ecb %p",
145 if (!DTRACEACT_ISAGG(act
.dta_kind
) && !act
.dta_intuple
)
148 ap
= (uintptr_t)act
.dta_next
;
151 nrecs
= epd
->dtepd_nrecs
;
152 epd
->dtepd_nrecs
= nactions
;
153 epd
->dtepd_probeid
= probe
.dtpr_id
;
154 epd
->dtepd_uarg
= ecb
.dte_uarg
;
155 epd
->dtepd_size
= ecb
.dte_size
;
157 for (ap
= (uintptr_t)ecb
.dte_action
, nactions
= 0; ap
!= NULL
; ) {
158 if (mdb_vread(&act
, sizeof (act
), ap
) == -1) {
159 mdb_warn("failed to read action %p on ecb %p",
164 if (!DTRACEACT_ISAGG(act
.dta_kind
) && !act
.dta_intuple
) {
168 epd
->dtepd_rec
[nactions
++] = act
.dta_rec
;
171 ap
= (uintptr_t)act
.dta_next
;
179 dtracemdb_probe(dtrace_state_t
*state
, dtrace_probedesc_t
*pd
)
181 uintptr_t base
, addr
, paddr
, praddr
;
183 dtrace_probe_t probe
;
184 dtrace_provider_t prov
;
186 if (pd
->dtpd_id
== DTRACE_IDNONE
)
189 if (mdb_readvar(&base
, "dtrace_probes") == -1) {
190 mdb_warn("failed to read 'dtrace_probes'");
194 if (mdb_readvar(&nprobes
, "dtrace_nprobes") == -1) {
195 mdb_warn("failed to read 'dtrace_nprobes'");
199 for (i
= pd
->dtpd_id
; i
<= nprobes
; i
++) {
200 addr
= base
+ (i
- 1) * sizeof (dtrace_probe_t
*);
202 if (mdb_vread(&paddr
, sizeof (paddr
), addr
) == -1) {
203 mdb_warn("couldn't read probe pointer at %p", addr
);
216 if (mdb_vread(&probe
, sizeof (probe
), paddr
) == -1) {
217 mdb_warn("couldn't read probe at %p", paddr
);
221 pd
->dtpd_id
= probe
.dtpr_id
;
223 if (mdb_vread(pd
->dtpd_name
, DTRACE_NAMELEN
,
224 (uintptr_t)probe
.dtpr_name
) == -1) {
225 mdb_warn("failed to read probe name for probe %p", paddr
);
229 if (mdb_vread(pd
->dtpd_func
, DTRACE_FUNCNAMELEN
,
230 (uintptr_t)probe
.dtpr_func
) == -1) {
231 mdb_warn("failed to read function name for probe %p", paddr
);
235 if (mdb_vread(pd
->dtpd_mod
, DTRACE_MODNAMELEN
,
236 (uintptr_t)probe
.dtpr_mod
) == -1) {
237 mdb_warn("failed to read module name for probe %p", paddr
);
241 praddr
= (uintptr_t)probe
.dtpr_provider
;
243 if (mdb_vread(&prov
, sizeof (prov
), praddr
) == -1) {
244 mdb_warn("failed to read provider for probe %p", paddr
);
248 if (mdb_vread(pd
->dtpd_provider
, DTRACE_PROVNAMELEN
,
249 (uintptr_t)prov
.dtpv_name
) == -1) {
250 mdb_warn("failed to read provider name for probe %p", paddr
);
259 dtracemdb_aggdesc(dtrace_state_t
*state
, dtrace_aggdesc_t
*agd
)
261 dtrace_aggid_t aggid
= agd
->dtagd_id
;
262 dtrace_aggregation_t agg
;
264 uintptr_t addr
, eaddr
, ap
, last
;
266 dtrace_recdesc_t
*lrec
;
269 addr
= (uintptr_t)state
->dts_aggregations
+
270 (aggid
- 1) * sizeof (dtrace_aggregation_t
*);
272 if (mdb_vread(&addr
, sizeof (addr
), addr
) == -1) {
273 mdb_warn("failed to read aggregation for aggid %d", aggid
);
278 mdb_warn("aggid %d doesn't match an aggregation\n", aggid
);
282 if (mdb_vread(&agg
, sizeof (agg
), addr
) == -1) {
283 mdb_warn("failed to read aggregation at %p", addr
);
287 eaddr
= (uintptr_t)agg
.dtag_ecb
;
289 if (mdb_vread(&ecb
, sizeof (ecb
), eaddr
) == -1) {
290 mdb_warn("failed to read ecb for aggregation %p", addr
);
294 last
= (uintptr_t)addr
+ offsetof(dtrace_aggregation_t
, dtag_action
);
297 * This is a little painful: in order to find the number of actions,
298 * we need to first walk through them.
300 ap
= (uintptr_t)agg
.dtag_first
;
304 if (mdb_vread(&act
, sizeof (act
), ap
) == -1) {
305 mdb_warn("failed to read action %p on aggregation %p",
315 ap
= (uintptr_t)act
.dta_next
;
319 agd
->dtagd_size
= lrec
->dtrd_offset
+ lrec
->dtrd_size
- agg
.dtag_base
;
321 nrecs
= agd
->dtagd_nrecs
;
322 agd
->dtagd_nrecs
= nactions
;
323 agd
->dtagd_epid
= ecb
.dte_epid
;
325 ap
= (uintptr_t)agg
.dtag_first
;
329 dtrace_recdesc_t rec
;
331 if (mdb_vread(&act
, sizeof (act
), ap
) == -1) {
332 mdb_warn("failed to read action %p on aggregation %p",
341 rec
.dtrd_offset
-= agg
.dtag_base
;
343 agd
->dtagd_rec
[nactions
++] = rec
;
348 ap
= (uintptr_t)act
.dta_next
;
355 dtracemdb_bufsnap(dtrace_buffer_t
*which
, dtrace_bufdesc_t
*desc
)
360 caddr_t data
= desc
->dtbd_data
;
361 processorid_t max_cpuid
, cpu
= desc
->dtbd_cpu
;
363 if (mdb_readvar(&max_cpuid
, "max_cpuid") == -1) {
364 mdb_warn("failed to read 'max_cpuid'");
369 if (cpu
< 0 || cpu
> max_cpuid
) {
374 addr
= (uintptr_t)which
+ cpu
* sizeof (dtrace_buffer_t
);
376 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
377 mdb_warn("failed to read buffer description at %p", addr
);
382 if (buf
.dtb_tomax
== NULL
) {
387 if (buf
.dtb_flags
& DTRACEBUF_WRAPPED
) {
388 bufsize
= buf
.dtb_size
;
390 bufsize
= buf
.dtb_offset
;
393 if (mdb_vread(data
, bufsize
, (uintptr_t)buf
.dtb_tomax
) == -1) {
394 mdb_warn("couldn't read buffer for CPU %d", cpu
);
399 if (buf
.dtb_offset
> buf
.dtb_size
) {
400 mdb_warn("buffer for CPU %d has corrupt offset\n", cpu
);
405 if (buf
.dtb_flags
& DTRACEBUF_WRAPPED
) {
406 if (buf
.dtb_xamot_offset
> buf
.dtb_size
) {
407 mdb_warn("ringbuffer for CPU %d has corrupt "
408 "wrapped offset\n", cpu
);
414 * If the ring buffer has wrapped, it needs to be polished.
415 * See the comment in dtrace_buffer_polish() for details.
417 if (buf
.dtb_offset
< buf
.dtb_xamot_offset
) {
418 bzero(data
+ buf
.dtb_offset
,
419 buf
.dtb_xamot_offset
- buf
.dtb_offset
);
422 if (buf
.dtb_offset
> buf
.dtb_xamot_offset
) {
423 bzero(data
+ buf
.dtb_offset
,
424 buf
.dtb_size
- buf
.dtb_offset
);
425 bzero(data
, buf
.dtb_xamot_offset
);
428 desc
->dtbd_oldest
= buf
.dtb_xamot_offset
;
430 desc
->dtbd_oldest
= 0;
433 desc
->dtbd_size
= bufsize
;
434 desc
->dtbd_drops
= buf
.dtb_drops
;
435 desc
->dtbd_errors
= buf
.dtb_errors
;
441 * This is essentially identical to its cousin in the kernel -- with the
442 * notable exception that we automatically set DTRACEOPT_GRABANON if this
443 * state is an anonymous enabling.
446 dtracemdb_dof_create(dtrace_state_t
*state
, int isanon
)
451 int i
, len
= sizeof (dof_hdr_t
) +
452 roundup(sizeof (dof_sec_t
), sizeof (uint64_t)) +
453 sizeof (dof_optdesc_t
) * DTRACEOPT_MAX
;
455 dof
= mdb_zalloc(len
, UM_SLEEP
);
456 dof
->dofh_ident
[DOF_ID_MAG0
] = DOF_MAG_MAG0
;
457 dof
->dofh_ident
[DOF_ID_MAG1
] = DOF_MAG_MAG1
;
458 dof
->dofh_ident
[DOF_ID_MAG2
] = DOF_MAG_MAG2
;
459 dof
->dofh_ident
[DOF_ID_MAG3
] = DOF_MAG_MAG3
;
461 dof
->dofh_ident
[DOF_ID_MODEL
] = DOF_MODEL_NATIVE
;
462 dof
->dofh_ident
[DOF_ID_ENCODING
] = DOF_ENCODE_NATIVE
;
463 dof
->dofh_ident
[DOF_ID_VERSION
] = DOF_VERSION
;
464 dof
->dofh_ident
[DOF_ID_DIFVERS
] = DIF_VERSION
;
465 dof
->dofh_ident
[DOF_ID_DIFIREG
] = DIF_DIR_NREGS
;
466 dof
->dofh_ident
[DOF_ID_DIFTREG
] = DIF_DTR_NREGS
;
469 dof
->dofh_hdrsize
= sizeof (dof_hdr_t
);
470 dof
->dofh_secsize
= sizeof (dof_sec_t
);
471 dof
->dofh_secnum
= 1; /* only DOF_SECT_OPTDESC */
472 dof
->dofh_secoff
= sizeof (dof_hdr_t
);
473 dof
->dofh_loadsz
= len
;
474 dof
->dofh_filesz
= len
;
478 * Fill in the option section header...
480 sec
= (dof_sec_t
*)((uintptr_t)dof
+ sizeof (dof_hdr_t
));
481 sec
->dofs_type
= DOF_SECT_OPTDESC
;
482 sec
->dofs_align
= sizeof (uint64_t);
483 sec
->dofs_flags
= DOF_SECF_LOAD
;
484 sec
->dofs_entsize
= sizeof (dof_optdesc_t
);
486 opt
= (dof_optdesc_t
*)((uintptr_t)sec
+
487 roundup(sizeof (dof_sec_t
), sizeof (uint64_t)));
489 sec
->dofs_offset
= (uintptr_t)opt
- (uintptr_t)dof
;
490 sec
->dofs_size
= sizeof (dof_optdesc_t
) * DTRACEOPT_MAX
;
492 for (i
= 0; i
< DTRACEOPT_MAX
; i
++) {
493 opt
[i
].dofo_option
= i
;
494 opt
[i
].dofo_strtab
= DOF_SECIDX_NONE
;
495 opt
[i
].dofo_value
= state
->dts_options
[i
];
499 opt
[DTRACEOPT_GRABANON
].dofo_value
= 1;
505 dtracemdb_format(dtrace_state_t
*state
, dtrace_fmtdesc_t
*desc
)
507 uintptr_t addr
, faddr
;
511 if (desc
->dtfd_format
== 0 || desc
->dtfd_format
> state
->dts_nformats
) {
516 faddr
= (uintptr_t)state
->dts_formats
+
517 (desc
->dtfd_format
- 1) * sizeof (char *);
519 if (mdb_vread(&addr
, sizeof (addr
), faddr
) == -1) {
520 mdb_warn("failed to read format string pointer at %p", faddr
);
525 if (mdb_vread(&c
, sizeof (c
), addr
+ len
++) == -1) {
526 mdb_warn("failed to read format string at %p", addr
);
531 if (len
> desc
->dtfd_length
) {
532 desc
->dtfd_length
= len
;
536 if (mdb_vread(desc
->dtfd_string
, len
, addr
) == -1) {
537 mdb_warn("failed to reread format string at %p", addr
);
545 dtracemdb_status(dtrace_state_t
*state
, dtrace_status_t
*status
)
547 dtrace_dstate_t
*dstate
;
553 if (mdb_readvar(&ncpu
, "_ncpu") == -1) {
554 mdb_warn("failed to read '_ncpu'");
558 bzero(status
, sizeof (dtrace_status_t
));
560 if (state
->dts_activity
== DTRACE_ACTIVITY_INACTIVE
) {
566 * For the MDB backend, we never set dtst_exiting or dtst_filled. This
567 * is by design: we don't want the library to try to stop tracing,
568 * because it doesn't particularly mean anything.
570 nerrs
= state
->dts_errors
;
571 dstate
= &state
->dts_vstate
.dtvs_dynvars
;
573 for (i
= 0; i
< ncpu
; i
++) {
574 dtrace_dstate_percpu_t dcpu
;
577 addr
= (uintptr_t)&dstate
->dtds_percpu
[i
];
579 if (mdb_vread(&dcpu
, sizeof (dcpu
), addr
) == -1) {
580 mdb_warn("failed to read per-CPU dstate at %p", addr
);
584 status
->dtst_dyndrops
+= dcpu
.dtdsc_drops
;
585 status
->dtst_dyndrops_dirty
+= dcpu
.dtdsc_dirty_drops
;
586 status
->dtst_dyndrops_rinsing
+= dcpu
.dtdsc_rinsing_drops
;
588 addr
= (uintptr_t)&state
->dts_buffer
[i
];
590 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
591 mdb_warn("failed to read per-CPU buffer at %p", addr
);
595 nerrs
+= buf
.dtb_errors
;
597 for (j
= 0; j
< state
->dts_nspeculations
; j
++) {
598 dtrace_speculation_t spec
;
600 addr
= (uintptr_t)&state
->dts_speculations
[j
];
602 if (mdb_vread(&spec
, sizeof (spec
), addr
) == -1) {
603 mdb_warn("failed to read "
604 "speculation at %p", addr
);
608 addr
= (uintptr_t)&spec
.dtsp_buffer
[i
];
610 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
611 mdb_warn("failed to read "
612 "speculative buffer at %p", addr
);
616 status
->dtst_specdrops
+= buf
.dtb_xamot_drops
;
620 status
->dtst_specdrops_busy
= state
->dts_speculations_busy
;
621 status
->dtst_specdrops_unavail
= state
->dts_speculations_unavail
;
622 status
->dtst_errors
= nerrs
;
627 typedef struct dtracemdb_data
{
628 dtrace_state_t
*dtmd_state
;
636 dtracemdb_ioctl(void *varg
, int cmd
, void *arg
)
638 dtracemdb_data_t
*data
= varg
;
639 dtrace_state_t
*state
= data
->dtmd_state
;
642 case DTRACEIOC_CONF
: {
643 dtrace_conf_t
*conf
= arg
;
645 bzero(conf
, sizeof (conf
));
646 conf
->dtc_difversion
= DIF_VERSION
;
647 conf
->dtc_difintregs
= DIF_DIR_NREGS
;
648 conf
->dtc_diftupregs
= DIF_DTR_NREGS
;
649 conf
->dtc_ctfmodel
= CTF_MODEL_NATIVE
;
654 case DTRACEIOC_DOFGET
: {
655 dof_hdr_t
*hdr
= arg
, *dof
;
657 dof
= dtracemdb_dof_create(state
, data
->dtmd_isanon
);
658 bcopy(dof
, hdr
, MIN(hdr
->dofh_loadsz
, dof
->dofh_loadsz
));
659 mdb_free(dof
, dof
->dofh_loadsz
);
664 case DTRACEIOC_BUFSNAP
:
665 return (dtracemdb_bufsnap(state
->dts_buffer
, arg
));
667 case DTRACEIOC_AGGSNAP
:
668 return (dtracemdb_bufsnap(state
->dts_aggbuffer
, arg
));
670 case DTRACEIOC_AGGDESC
:
671 return (dtracemdb_aggdesc(state
, arg
));
673 case DTRACEIOC_EPROBE
:
674 return (dtracemdb_eprobe(state
, arg
));
676 case DTRACEIOC_PROBES
:
677 return (dtracemdb_probe(state
, arg
));
679 case DTRACEIOC_FORMAT
:
680 return (dtracemdb_format(state
, arg
));
682 case DTRACEIOC_STATUS
:
683 return (dtracemdb_status(state
, arg
));
686 *(processorid_t
*)arg
= -1;
689 case DTRACEIOC_ENABLE
:
690 errno
= ENOTTY
; /* see dt_open.c:dtrace_go() */
693 case DTRACEIOC_PROVIDER
:
694 case DTRACEIOC_PROBEMATCH
:
699 mdb_warn("unexpected ioctl 0x%x (%s)\n", cmd
,
700 cmd
== DTRACEIOC_PROVIDER
? "DTRACEIOC_PROVIDER" :
701 cmd
== DTRACEIOC_PROBES
? "DTRACEIOC_PROBES" :
702 cmd
== DTRACEIOC_BUFSNAP
? "DTRACEIOC_BUFSNAP" :
703 cmd
== DTRACEIOC_PROBEMATCH
? "DTRACEIOC_PROBEMATCH" :
704 cmd
== DTRACEIOC_ENABLE
? "DTRACEIOC_ENABLE" :
705 cmd
== DTRACEIOC_AGGSNAP
? "DTRACEIOC_AGGSNAP" :
706 cmd
== DTRACEIOC_EPROBE
? "DTRACEIOC_EPROBE" :
707 cmd
== DTRACEIOC_PROBEARG
? "DTRACEIOC_PROBEARG" :
708 cmd
== DTRACEIOC_CONF
? "DTRACEIOC_CONF" :
709 cmd
== DTRACEIOC_STATUS
? "DTRACEIOC_STATUS" :
710 cmd
== DTRACEIOC_GO
? "DTRACEIOC_GO" :
711 cmd
== DTRACEIOC_STOP
? "DTRACEIOC_STOP" :
712 cmd
== DTRACEIOC_AGGDESC
? "DTRACEIOC_AGGDESC" :
713 cmd
== DTRACEIOC_FORMAT
? "DTRACEIOC_FORMAT" :
714 cmd
== DTRACEIOC_DOFGET
? "DTRACEIOC_DOFGET" :
715 cmd
== DTRACEIOC_REPLICATE
? "DTRACEIOC_REPLICATE" :
723 dtracemdb_modctl(uintptr_t addr
, const struct modctl
*m
, dtracemdb_data_t
*data
)
727 if (m
->mod_mp
== NULL
)
730 if (mdb_vread(&mod
, sizeof (mod
), (uintptr_t)m
->mod_mp
) == -1) {
731 mdb_warn("couldn't read modctl %p's module", addr
);
735 if ((uintptr_t)mod
.text
> data
->dtmd_addr
)
738 if ((uintptr_t)mod
.text
+ mod
.text_size
<= data
->dtmd_addr
)
741 if (mdb_readstr(data
->dtmd_modstr
, MDB_SYM_NAMLEN
,
742 (uintptr_t)m
->mod_modname
) == -1)
749 dtracemdb_lookup_by_addr(void *varg
, GElf_Addr addr
, GElf_Sym
*symp
,
750 dtrace_syminfo_t
*sip
)
752 dtracemdb_data_t
*data
= varg
;
754 if (data
->dtmd_symstr
== NULL
) {
755 data
->dtmd_symstr
= mdb_zalloc(MDB_SYM_NAMLEN
,
759 if (data
->dtmd_modstr
== NULL
) {
760 data
->dtmd_modstr
= mdb_zalloc(MDB_SYM_NAMLEN
,
765 if (mdb_lookup_by_addr(addr
, MDB_SYM_FUZZY
, data
->dtmd_symstr
,
766 MDB_SYM_NAMLEN
, symp
) == -1)
771 data
->dtmd_addr
= addr
;
773 (void) strcpy(data
->dtmd_modstr
, "???");
775 if (mdb_walk("modctl",
776 (mdb_walk_cb_t
)dtracemdb_modctl
, varg
) == -1) {
777 mdb_warn("couldn't walk 'modctl'");
781 sip
->dts_object
= data
->dtmd_modstr
;
783 sip
->dts_name
= symp
!= NULL
? data
->dtmd_symstr
: NULL
;
791 dtracemdb_stat(void *varg
, processorid_t cpu
)
795 uintptr_t caddr
, addr
;
797 if (mdb_lookup_by_name("cpu", &sym
) == -1) {
798 mdb_warn("failed to find symbol for 'cpu'");
802 if (cpu
* sizeof (uintptr_t) > sym
.st_size
)
805 addr
= (uintptr_t)sym
.st_value
+ cpu
* sizeof (uintptr_t);
807 if (mdb_vread(&caddr
, sizeof (caddr
), addr
) == -1) {
808 mdb_warn("failed to read cpu[%d]", cpu
);
815 if (mdb_vread(&c
, sizeof (c
), caddr
) == -1) {
816 mdb_warn("failed to read cpu at %p", caddr
);
820 if (c
.cpu_flags
& CPU_POWEROFF
) {
822 } else if (c
.cpu_flags
& CPU_SPARE
) {
824 } else if (c
.cpu_flags
& CPU_FAULTED
) {
826 } else if ((c
.cpu_flags
& (CPU_READY
| CPU_OFFLINE
)) != CPU_READY
) {
828 } else if (c
.cpu_flags
& CPU_ENABLE
) {
837 dtracemdb_sysconf(void *varg
, int name
)
840 processorid_t max_cpuid
;
844 if (mdb_readvar(&max_cpuid
, "max_cpuid") == -1) {
845 mdb_warn("failed to read 'max_cpuid'");
851 case _SC_NPROCESSORS_MAX
:
852 if (mdb_readvar(&max_ncpus
, "max_ncpus") == -1) {
853 mdb_warn("failed to read 'max_ncpus'");
860 mdb_warn("unexpected sysconf code %d\n", name
);
865 const dtrace_vector_t dtrace_mdbops
= {
867 dtracemdb_lookup_by_addr
,
872 typedef struct dtrace_dcmddata
{
873 dtrace_hdl_t
*dtdd_dtp
;
882 * Helper to grab all the content from a file, spit it into a string, and erase
883 * and reset the file.
886 print_and_truncate_file(FILE *fp
)
891 /* flush, find length of file, seek to beginning, initialize buffer */
892 if (fflush(fp
) || (len
= ftell(fp
)) < 0 ||
893 fseek(fp
, 0, SEEK_SET
) < 0) {
894 mdb_warn("couldn't prepare DTrace output file: %d\n", errno
);
898 out
= mdb_alloc(len
+ 1, UM_SLEEP
);
901 /* read file into buffer, truncate file, and seek to beginning */
902 if ((fread(out
, len
+ 1, sizeof (char), fp
) == 0 && ferror(fp
)) ||
903 ftruncate(fileno(fp
), 0) < 0 || fseek(fp
, 0, SEEK_SET
) < 0) {
904 mdb_warn("couldn't read DTrace output file: %d\n", errno
);
905 mdb_free(out
, len
+ 1);
909 mdb_printf("%s", out
);
910 mdb_free(out
, len
+ 1);
915 dtrace_dcmdrec(const dtrace_probedata_t
*data
,
916 const dtrace_recdesc_t
*rec
, void *arg
)
918 dtrace_dcmddata_t
*dd
= arg
;
920 print_and_truncate_file(dd
->dtdd_output
);
924 * We have processed the final record; output the newline if
925 * we're not in quiet mode.
930 return (DTRACE_CONSUME_NEXT
);
933 return (DTRACE_CONSUME_THIS
);
938 dtrace_dcmdprobe(const dtrace_probedata_t
*data
, void *arg
)
940 dtrace_probedesc_t
*pd
= data
->dtpda_pdesc
;
941 processorid_t cpu
= data
->dtpda_cpu
;
942 dtrace_dcmddata_t
*dd
= arg
;
943 char name
[DTRACE_FUNCNAMELEN
+ DTRACE_NAMELEN
+ 2];
945 if (dd
->dtdd_cpu
!= -1UL && dd
->dtdd_cpu
!= cpu
)
946 return (DTRACE_CONSUME_NEXT
);
948 if (dd
->dtdd_heading
== 0) {
949 if (!dd
->dtdd_flowindent
) {
950 if (!dd
->dtdd_quiet
) {
951 mdb_printf("%3s %6s %32s\n",
952 "CPU", "ID", "FUNCTION:NAME");
955 mdb_printf("%3s %-41s\n", "CPU", "FUNCTION");
957 dd
->dtdd_heading
= 1;
960 if (!dd
->dtdd_flowindent
) {
961 if (!dd
->dtdd_quiet
) {
962 (void) mdb_snprintf(name
, sizeof (name
), "%s:%s",
963 pd
->dtpd_func
, pd
->dtpd_name
);
965 mdb_printf("%3d %6d %32s ", cpu
, pd
->dtpd_id
, name
);
968 int indent
= data
->dtpda_indent
;
970 if (data
->dtpda_flow
== DTRACEFLOW_NONE
) {
971 (void) mdb_snprintf(name
, sizeof (name
), "%*s%s%s:%s",
972 indent
, "", data
->dtpda_prefix
, pd
->dtpd_func
,
975 (void) mdb_snprintf(name
, sizeof (name
), "%*s%s%s",
976 indent
, "", data
->dtpda_prefix
, pd
->dtpd_func
);
979 mdb_printf("%3d %-41s ", cpu
, name
);
982 return (DTRACE_CONSUME_THIS
);
987 dtrace_dcmderr(const dtrace_errdata_t
*data
, void *arg
)
989 mdb_warn(data
->dteda_msg
);
990 return (DTRACE_HANDLE_OK
);
995 dtrace_dcmddrop(const dtrace_dropdata_t
*data
, void *arg
)
997 mdb_warn(data
->dtdda_msg
);
998 return (DTRACE_HANDLE_OK
);
1003 dtrace_dcmdbuffered(const dtrace_bufdata_t
*bufdata
, void *arg
)
1005 mdb_printf("%s", bufdata
->dtbda_buffered
);
1006 return (DTRACE_HANDLE_OK
);
1011 dtrace(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1013 dtrace_state_t state
;
1017 dtrace_dcmddata_t dd
;
1018 dtrace_optval_t val
;
1019 dtracemdb_data_t md
;
1020 int rval
= DCMD_ERR
;
1023 if (!(flags
& DCMD_ADDRSPEC
))
1024 return (DCMD_USAGE
);
1026 if (mdb_getopts(argc
, argv
, 'c', MDB_OPT_UINTPTR
, &c
, NULL
) != argc
)
1027 return (DCMD_USAGE
);
1029 if (mdb_readvar(&ncpu
, "_ncpu") == -1) {
1030 mdb_warn("failed to read '_ncpu'");
1034 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
1035 mdb_warn("couldn't read dtrace_state_t at %p", addr
);
1039 if (state
.dts_anon
!= NULL
) {
1040 addr
= (uintptr_t)state
.dts_anon
;
1042 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
1043 mdb_warn("couldn't read anonymous state at %p", addr
);
1048 bzero(&md
, sizeof (md
));
1049 md
.dtmd_state
= &state
;
1051 if ((dtp
= dtrace_vopen(DTRACE_VERSION
, DTRACE_O_NOSYS
, &err
,
1052 &dtrace_mdbops
, &md
)) == NULL
) {
1053 mdb_warn("failed to initialize dtrace: %s\n",
1054 dtrace_errmsg(NULL
, err
));
1059 * If this is the anonymous enabling, we need to set a bit indicating
1060 * that DTRACEOPT_GRABANON should be set.
1062 if (mdb_readvar(&anon
, "dtrace_anon") == -1) {
1063 mdb_warn("failed to read 'dtrace_anon'");
1067 md
.dtmd_isanon
= ((uintptr_t)anon
.dta_state
== addr
);
1069 if (dtrace_go(dtp
) != 0) {
1070 mdb_warn("failed to initialize dtrace: %s\n",
1071 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1075 bzero(&dd
, sizeof (dd
));
1079 if (dtrace_getopt(dtp
, "flowindent", &val
) == -1) {
1080 mdb_warn("couldn't get 'flowindent' option: %s\n",
1081 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1085 dd
.dtdd_flowindent
= (val
!= DTRACEOPT_UNSET
);
1087 if (dtrace_getopt(dtp
, "quiet", &val
) == -1) {
1088 mdb_warn("couldn't get 'quiet' option: %s\n",
1089 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1093 dd
.dtdd_quiet
= (val
!= DTRACEOPT_UNSET
);
1095 if (dtrace_handle_err(dtp
, dtrace_dcmderr
, NULL
) == -1) {
1096 mdb_warn("couldn't add err handler: %s\n",
1097 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1101 if (dtrace_handle_drop(dtp
, dtrace_dcmddrop
, NULL
) == -1) {
1102 mdb_warn("couldn't add drop handler: %s\n",
1103 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1107 if (dtrace_handle_buffered(dtp
, dtrace_dcmdbuffered
, NULL
) == -1) {
1108 mdb_warn("couldn't add buffered handler: %s\n",
1109 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1113 if (dtrace_status(dtp
) == -1) {
1114 mdb_warn("couldn't get status: %s\n",
1115 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1119 if (dtrace_aggregate_snap(dtp
) == -1) {
1120 mdb_warn("couldn't snapshot aggregation: %s\n",
1121 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1125 if ((dd
.dtdd_output
= tmpfile()) == NULL
) {
1126 mdb_warn("couldn't open DTrace output file: %d\n", errno
);
1130 if (dtrace_consume(dtp
, dd
.dtdd_output
,
1131 dtrace_dcmdprobe
, dtrace_dcmdrec
, &dd
) == -1) {
1132 mdb_warn("couldn't consume DTrace buffers: %s\n",
1133 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1136 if (dtrace_aggregate_print(dtp
, NULL
, NULL
) == -1) {
1137 mdb_warn("couldn't print aggregation: %s\n",
1138 dtrace_errmsg(dtp
, dtrace_errno(dtp
)));
1145 fclose(dd
.dtdd_output
);
1150 dtrace_errhash_cmp(const void *l
, const void *r
)
1152 uintptr_t lhs
= *((uintptr_t *)l
);
1153 uintptr_t rhs
= *((uintptr_t *)r
);
1154 dtrace_errhash_t lerr
, rerr
;
1155 char lmsg
[256], rmsg
[256];
1157 (void) mdb_vread(&lerr
, sizeof (lerr
), lhs
);
1158 (void) mdb_vread(&rerr
, sizeof (rerr
), rhs
);
1160 if (lerr
.dter_msg
== NULL
)
1163 if (rerr
.dter_msg
== NULL
)
1166 (void) mdb_readstr(lmsg
, sizeof (lmsg
), (uintptr_t)lerr
.dter_msg
);
1167 (void) mdb_readstr(rmsg
, sizeof (rmsg
), (uintptr_t)rerr
.dter_msg
);
1169 return (strcmp(lmsg
, rmsg
));
1173 dtrace_errhash_init(mdb_walk_state_t
*wsp
)
1176 uintptr_t *hash
, addr
;
1179 if (wsp
->walk_addr
!= NULL
) {
1180 mdb_warn("dtrace_errhash walk only supports global walks\n");
1184 if (mdb_lookup_by_name("dtrace_errhash", &sym
) == -1) {
1185 mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)");
1189 addr
= (uintptr_t)sym
.st_value
;
1190 hash
= mdb_alloc(DTRACE_ERRHASHSZ
* sizeof (uintptr_t),
1193 for (i
= 0; i
< DTRACE_ERRHASHSZ
; i
++)
1194 hash
[i
] = addr
+ i
* sizeof (dtrace_errhash_t
);
1196 qsort(hash
, DTRACE_ERRHASHSZ
, sizeof (uintptr_t), dtrace_errhash_cmp
);
1199 wsp
->walk_data
= hash
;
1205 dtrace_errhash_step(mdb_walk_state_t
*wsp
)
1207 int ndx
= (int)wsp
->walk_addr
;
1208 uintptr_t *hash
= wsp
->walk_data
;
1209 dtrace_errhash_t err
;
1212 if (ndx
>= DTRACE_ERRHASHSZ
)
1215 wsp
->walk_addr
= ndx
+ 1;
1218 if (mdb_vread(&err
, sizeof (err
), addr
) == -1) {
1219 mdb_warn("failed to read dtrace_errhash_t at %p", addr
);
1223 if (err
.dter_msg
== NULL
)
1226 return (wsp
->walk_callback(addr
, &err
, wsp
->walk_cbdata
));
1231 dtrace_errhash(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1233 dtrace_errhash_t err
;
1236 if (!(flags
& DCMD_ADDRSPEC
)) {
1237 if (mdb_walk_dcmd("dtrace_errhash", "dtrace_errhash",
1238 argc
, argv
) == -1) {
1239 mdb_warn("can't walk 'dtrace_errhash'");
1246 if (DCMD_HDRSPEC(flags
))
1247 mdb_printf("%8s %s\n", "COUNT", "ERROR");
1249 if (mdb_vread(&err
, sizeof (err
), addr
) == -1) {
1250 mdb_warn("failed to read dtrace_errhash_t at %p", addr
);
1254 addr
= (uintptr_t)err
.dter_msg
;
1256 if (mdb_readstr(msg
, sizeof (msg
), addr
) == -1) {
1257 mdb_warn("failed to read error msg at %p", addr
);
1261 mdb_printf("%8d %s", err
.dter_count
, msg
);
1264 * Some error messages include a newline -- only print the newline
1265 * if the message doesn't have one.
1267 if (msg
[strlen(msg
) - 1] != '\n')
1274 dtrace_helptrace_init(mdb_walk_state_t
*wsp
)
1279 if (wsp
->walk_addr
!= NULL
) {
1280 mdb_warn("dtrace_helptrace only supports global walks\n");
1284 if (mdb_readvar(&buffer
, "dtrace_helptrace_buffer") == -1) {
1285 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1289 if (buffer
== NULL
) {
1290 mdb_warn("helper tracing is not enabled\n");
1294 if (mdb_readvar(&next
, "dtrace_helptrace_next") == -1) {
1295 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1299 wsp
->walk_addr
= next
;
1305 dtrace_helptrace_step(mdb_walk_state_t
*wsp
)
1307 uint32_t next
, size
, nlocals
, bufsize
;
1308 uintptr_t buffer
, addr
;
1309 dtrace_helptrace_t
*ht
;
1312 if (mdb_readvar(&next
, "dtrace_helptrace_next") == -1) {
1313 mdb_warn("couldn't read 'dtrace_helptrace_next'");
1317 if (mdb_readvar(&bufsize
, "dtrace_helptrace_bufsize") == -1) {
1318 mdb_warn("couldn't read 'dtrace_helptrace_bufsize'");
1322 if (mdb_readvar(&buffer
, "dtrace_helptrace_buffer") == -1) {
1323 mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1327 if (mdb_readvar(&nlocals
, "dtrace_helptrace_nlocals") == -1) {
1328 mdb_warn("couldn't read 'dtrace_helptrace_nlocals'");
1332 size
= sizeof (dtrace_helptrace_t
) +
1333 nlocals
* sizeof (uint64_t) - sizeof (uint64_t);
1335 if (wsp
->walk_addr
+ size
> bufsize
) {
1342 addr
= buffer
+ wsp
->walk_addr
;
1345 if (mdb_vread(ht
, size
, addr
) == -1) {
1346 mdb_warn("couldn't read entry at %p", addr
);
1350 if (ht
->dtht_helper
!= NULL
) {
1351 rval
= wsp
->walk_callback(addr
, ht
, wsp
->walk_cbdata
);
1353 if (rval
!= WALK_NEXT
)
1357 if (wsp
->walk_addr
< next
&& wsp
->walk_addr
+ size
>= next
)
1360 wsp
->walk_addr
+= size
;
1365 dtrace_helptrace(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1367 dtrace_helptrace_t help
;
1368 dtrace_helper_action_t helper
;
1370 uint_t opt_v
= FALSE
;
1373 if (!(flags
& DCMD_ADDRSPEC
)) {
1374 if (mdb_walk_dcmd("dtrace_helptrace", "dtrace_helptrace",
1375 argc
, argv
) == -1) {
1376 mdb_warn("can't walk 'dtrace_helptrace'");
1383 if (mdb_getopts(argc
, argv
, 'v',
1384 MDB_OPT_SETBITS
, TRUE
, &opt_v
, NULL
) != argc
)
1385 return (DCMD_USAGE
);
1387 if (DCMD_HDRSPEC(flags
)) {
1388 mdb_printf(" %?s %?s %12s %s\n",
1389 "ADDR", "HELPER", "WHERE", "DIFO");
1392 if (mdb_vread(&help
, sizeof (help
), addr
) == -1) {
1393 mdb_warn("failed to read dtrace_helptrace_t at %p", addr
);
1397 switch (help
.dtht_where
) {
1399 (void) mdb_snprintf(where
, sizeof (where
), "predicate");
1402 case DTRACE_HELPTRACE_NEXT
:
1403 (void) mdb_snprintf(where
, sizeof (where
), "next");
1406 case DTRACE_HELPTRACE_DONE
:
1407 (void) mdb_snprintf(where
, sizeof (where
), "done");
1410 case DTRACE_HELPTRACE_ERR
:
1411 (void) mdb_snprintf(where
, sizeof (where
), "err");
1415 (void) mdb_snprintf(where
, sizeof (where
),
1416 "action #%d", help
.dtht_where
);
1420 mdb_printf(" %?p %?p %12s ", addr
, help
.dtht_helper
, where
);
1422 haddr
= (uintptr_t)help
.dtht_helper
;
1424 if (mdb_vread(&helper
, sizeof (helper
), haddr
) == -1) {
1426 * We're not going to warn in this case -- we're just not going
1427 * to print anything exciting.
1429 mdb_printf("???\n");
1431 switch (help
.dtht_where
) {
1433 mdb_printf("%p\n", helper
.dtha_predicate
);
1436 case DTRACE_HELPTRACE_NEXT
:
1437 case DTRACE_HELPTRACE_DONE
:
1438 case DTRACE_HELPTRACE_ERR
:
1443 haddr
= (uintptr_t)helper
.dtha_actions
+
1444 (help
.dtht_where
- 1) * sizeof (uintptr_t);
1446 if (mdb_vread(&haddr
, sizeof (haddr
), haddr
) == -1) {
1447 mdb_printf("???\n");
1449 mdb_printf("%p\n", haddr
);
1457 if (help
.dtht_where
== DTRACE_HELPTRACE_ERR
) {
1458 int f
= help
.dtht_fault
;
1460 mdb_printf("%?s| %?s %10s |\n", "", "", "");
1461 mdb_printf("%?s| %?s %10s +-> fault: %s\n", "", "", "",
1462 f
== DTRACEFLT_BADADDR
? "BADADDR" :
1463 f
== DTRACEFLT_BADALIGN
? "BADALIGN" :
1464 f
== DTRACEFLT_ILLOP
? "ILLOP" :
1465 f
== DTRACEFLT_DIVZERO
? "DIVZERO" :
1466 f
== DTRACEFLT_NOSCRATCH
? "NOSCRATCH" :
1467 f
== DTRACEFLT_KPRIV
? "KPRIV" :
1468 f
== DTRACEFLT_UPRIV
? "UPRIV" :
1469 f
== DTRACEFLT_TUPOFLOW
? "TUPOFLOW" :
1470 f
== DTRACEFLT_BADSTACK
? "BADSTACK" :
1471 "DTRACEFLT_UNKNOWN");
1472 mdb_printf("%?s| %?s %12s addr: 0x%x\n", "", "", "",
1474 mdb_printf("%?s| %?s %12s offset: %d\n", "", "", "",
1478 mdb_printf("%?s|\n%?s+--> %?s %4s %s\n", "", "",
1479 "ADDR", "NDX", "VALUE");
1480 addr
+= sizeof (help
) - sizeof (uint64_t);
1482 for (i
= 0; i
< help
.dtht_nlocals
; i
++) {
1485 if (mdb_vread(&val
, sizeof (val
), addr
) == -1) {
1486 mdb_warn("couldn't read local at %p", addr
);
1490 mdb_printf("%?s %?p %4d %p\n", "", addr
, i
, val
);
1491 addr
+= sizeof (uint64_t);
1502 dtrace_state_walk(uintptr_t addr
, const vmem_seg_t
*seg
, minor_t
*highest
)
1504 if (seg
->vs_end
> *highest
)
1505 *highest
= seg
->vs_end
;
1510 typedef struct dtrace_state_walk
{
1511 uintptr_t dtsw_softstate
;
1513 minor_t dtsw_current
;
1514 } dtrace_state_walk_t
;
1517 dtrace_state_init(mdb_walk_state_t
*wsp
)
1519 uintptr_t dtrace_minor
;
1521 dtrace_state_walk_t
*dw
;
1523 if (wsp
->walk_addr
!= NULL
) {
1524 mdb_warn("dtrace_state only supports global walks\n");
1529 * Find the dtrace_minor vmem arena and walk it to get the maximum
1532 if (mdb_readvar(&dtrace_minor
, "dtrace_minor") == -1) {
1533 mdb_warn("failed to read 'dtrace_minor'");
1537 if (mdb_pwalk("vmem_alloc", (mdb_walk_cb_t
)dtrace_state_walk
,
1538 &max
, dtrace_minor
) == -1) {
1539 mdb_warn("couldn't walk 'vmem_alloc'");
1543 dw
= mdb_zalloc(sizeof (dtrace_state_walk_t
), UM_SLEEP
| UM_GC
);
1544 dw
->dtsw_current
= 0;
1547 if (mdb_readvar(&dw
->dtsw_softstate
, "dtrace_softstate") == -1) {
1548 mdb_warn("failed to read 'dtrace_softstate'");
1552 wsp
->walk_data
= dw
;
1558 dtrace_state_step(mdb_walk_state_t
*wsp
)
1560 dtrace_state_walk_t
*dw
= wsp
->walk_data
;
1562 dtrace_state_t state
;
1565 while (mdb_get_soft_state_byaddr(dw
->dtsw_softstate
, dw
->dtsw_current
,
1566 &statep
, NULL
, 0) == -1) {
1567 if (dw
->dtsw_current
>= dw
->dtsw_max
)
1573 if (mdb_vread(&state
, sizeof (state
), statep
) == -1) {
1574 mdb_warn("couldn't read dtrace_state_t at %p", statep
);
1578 rval
= wsp
->walk_callback(statep
, &state
, wsp
->walk_cbdata
);
1584 typedef struct dtrace_state_data
{
1586 uintptr_t dtsd_proc
;
1587 uintptr_t dtsd_softstate
;
1588 uintptr_t dtsd_state
;
1589 } dtrace_state_data_t
;
1592 dtrace_state_file(uintptr_t addr
, struct file
*f
, dtrace_state_data_t
*data
)
1599 if (mdb_vread(&vnode
, sizeof (vnode
), (uintptr_t)f
->f_vnode
) == -1) {
1600 mdb_warn("couldn't read vnode at %p", (uintptr_t)f
->f_vnode
);
1604 if (getmajor(vnode
.v_rdev
) != data
->dtsd_major
)
1607 minor
= getminor(vnode
.v_rdev
);
1609 if (mdb_vread(&proc
, sizeof (proc
), data
->dtsd_proc
) == -1) {
1610 mdb_warn("failed to read proc at %p", data
->dtsd_proc
);
1614 if (mdb_get_soft_state_byaddr(data
->dtsd_softstate
, minor
,
1615 &statep
, NULL
, 0) == -1) {
1616 mdb_warn("failed to read softstate for minor %d", minor
);
1620 if (statep
!= data
->dtsd_state
)
1623 mdb_printf("%?p %5d %?p %-*s %?p\n", statep
, minor
,
1624 data
->dtsd_proc
, MAXCOMLEN
, proc
.p_user
.u_comm
, addr
);
1631 dtrace_state_proc(uintptr_t addr
, void *ignored
, dtrace_state_data_t
*data
)
1633 data
->dtsd_proc
= addr
;
1635 if (mdb_pwalk("file",
1636 (mdb_walk_cb_t
)dtrace_state_file
, data
, addr
) == -1) {
1637 mdb_warn("couldn't walk 'file' for proc %p", addr
);
1645 dtrace_state_help(void)
1647 mdb_printf("Given a dtrace_state_t structure, displays all "
1649 "consumers, or \"<anonymous>\"\nif the consumer is anonymous. If "
1650 "no state structure is provided, iterates\nover all state "
1652 "Addresses in ADDR column may be provided to ::dtrace to obtain\n"
1653 "dtrace(1M)-like output for in-kernel DTrace data.\n");
1657 dtrace_state(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1660 struct dev_info info
;
1661 dtrace_state_data_t data
;
1663 dtrace_state_t state
;
1665 if (!(flags
& DCMD_ADDRSPEC
)) {
1666 if (mdb_walk_dcmd("dtrace_state",
1667 "dtrace_state", argc
, argv
) == -1) {
1668 mdb_warn("can't walk dtrace_state");
1674 if (DCMD_HDRSPEC(flags
)) {
1675 mdb_printf("%?s %5s %?s %-*s %?s\n", "ADDR", "MINOR", "PROC",
1676 MAXCOMLEN
, "NAME", "FILE");
1680 * First determine if this is anonymous state.
1682 if (mdb_readvar(&anon
, "dtrace_anon") == -1) {
1683 mdb_warn("failed to read 'dtrace_anon'");
1687 if ((uintptr_t)anon
.dta_state
== addr
) {
1688 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
1689 mdb_warn("failed to read anon at %p", addr
);
1693 mdb_printf("%?p %5d %?s %-*s %?s\n", addr
,
1694 getminor(state
.dts_dev
), "-", MAXCOMLEN
,
1695 "<anonymous>", "-");
1700 if (mdb_readvar(&devi
, "dtrace_devi") == -1) {
1701 mdb_warn("failed to read 'dtrace_devi'");
1705 if (mdb_vread(&info
, sizeof (struct dev_info
), devi
) == -1) {
1706 mdb_warn("failed to read 'dev_info'");
1710 data
.dtsd_major
= info
.devi_major
;
1712 if (mdb_readvar(&data
.dtsd_softstate
, "dtrace_softstate") == -1) {
1713 mdb_warn("failed to read 'dtrace_softstate'");
1717 data
.dtsd_state
= addr
;
1720 * Walk through all processes and all open files looking for this
1721 * state. It must be open somewhere...
1723 if (mdb_walk("proc", (mdb_walk_cb_t
)dtrace_state_proc
, &data
) == -1) {
1724 mdb_warn("couldn't walk 'proc'");
1731 typedef struct dtrace_aggkey_data
{
1732 uintptr_t *dtakd_hash
;
1733 uintptr_t dtakd_hashsize
;
1734 uintptr_t dtakd_next
;
1735 uintptr_t dtakd_ndx
;
1736 } dtrace_aggkey_data_t
;
1739 dtrace_aggkey_init(mdb_walk_state_t
*wsp
)
1741 dtrace_buffer_t buf
;
1743 dtrace_aggbuffer_t agb
;
1744 dtrace_aggkey_data_t
*data
;
1747 if ((addr
= wsp
->walk_addr
) == NULL
) {
1748 mdb_warn("dtrace_aggkey walk needs aggregation buffer\n");
1752 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
1753 mdb_warn("failed to read aggregation buffer at %p", addr
);
1757 addr
= (uintptr_t)buf
.dtb_tomax
+
1758 buf
.dtb_size
- sizeof (dtrace_aggbuffer_t
);
1760 if (mdb_vread(&agb
, sizeof (agb
), addr
) == -1) {
1761 mdb_warn("failed to read dtrace_aggbuffer_t at %p", addr
);
1765 data
= mdb_zalloc(sizeof (dtrace_aggkey_data_t
), UM_SLEEP
);
1767 data
->dtakd_hashsize
= agb
.dtagb_hashsize
;
1768 hsize
= agb
.dtagb_hashsize
* sizeof (dtrace_aggkey_t
*);
1769 data
->dtakd_hash
= mdb_alloc(hsize
, UM_SLEEP
);
1771 if (mdb_vread(data
->dtakd_hash
, hsize
,
1772 (uintptr_t)agb
.dtagb_hash
) == -1) {
1773 mdb_warn("failed to read hash at %p",
1774 (uintptr_t)agb
.dtagb_hash
);
1775 mdb_free(data
->dtakd_hash
, hsize
);
1776 mdb_free(data
, sizeof (dtrace_aggkey_data_t
));
1780 wsp
->walk_data
= data
;
1785 dtrace_aggkey_step(mdb_walk_state_t
*wsp
)
1787 dtrace_aggkey_data_t
*data
= wsp
->walk_data
;
1788 dtrace_aggkey_t key
;
1791 while ((addr
= data
->dtakd_next
) == NULL
) {
1792 if (data
->dtakd_ndx
== data
->dtakd_hashsize
)
1795 data
->dtakd_next
= data
->dtakd_hash
[data
->dtakd_ndx
++];
1798 if (mdb_vread(&key
, sizeof (key
), addr
) == -1) {
1799 mdb_warn("failed to read dtrace_aggkey_t at %p", addr
);
1803 data
->dtakd_next
= (uintptr_t)key
.dtak_next
;
1805 return (wsp
->walk_callback(addr
, &key
, wsp
->walk_cbdata
));
1809 dtrace_aggkey_fini(mdb_walk_state_t
*wsp
)
1811 dtrace_aggkey_data_t
*data
= wsp
->walk_data
;
1814 hsize
= data
->dtakd_hashsize
* sizeof (dtrace_aggkey_t
*);
1815 mdb_free(data
->dtakd_hash
, hsize
);
1816 mdb_free(data
, sizeof (dtrace_aggkey_data_t
));
1819 typedef struct dtrace_dynvar_data
{
1820 dtrace_dynhash_t
*dtdvd_hash
;
1821 uintptr_t dtdvd_hashsize
;
1822 uintptr_t dtdvd_next
;
1823 uintptr_t dtdvd_ndx
;
1824 uintptr_t dtdvd_sink
;
1825 } dtrace_dynvar_data_t
;
1828 dtrace_dynvar_init(mdb_walk_state_t
*wsp
)
1831 dtrace_dstate_t dstate
;
1832 dtrace_dynvar_data_t
*data
;
1836 if ((addr
= wsp
->walk_addr
) == NULL
) {
1837 mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n");
1841 if (mdb_vread(&dstate
, sizeof (dstate
), addr
) == -1) {
1842 mdb_warn("failed to read dynamic state at %p", addr
);
1846 if (mdb_lookup_by_name("dtrace_dynhash_sink", &sym
) == -1) {
1847 mdb_warn("couldn't find 'dtrace_dynhash_sink'");
1851 data
= mdb_zalloc(sizeof (dtrace_dynvar_data_t
), UM_SLEEP
);
1853 data
->dtdvd_hashsize
= dstate
.dtds_hashsize
;
1854 hsize
= dstate
.dtds_hashsize
* sizeof (dtrace_dynhash_t
);
1855 data
->dtdvd_hash
= mdb_alloc(hsize
, UM_SLEEP
);
1856 data
->dtdvd_sink
= (uintptr_t)sym
.st_value
;
1858 if (mdb_vread(data
->dtdvd_hash
, hsize
,
1859 (uintptr_t)dstate
.dtds_hash
) == -1) {
1860 mdb_warn("failed to read hash at %p",
1861 (uintptr_t)dstate
.dtds_hash
);
1862 mdb_free(data
->dtdvd_hash
, hsize
);
1863 mdb_free(data
, sizeof (dtrace_dynvar_data_t
));
1867 data
->dtdvd_next
= (uintptr_t)data
->dtdvd_hash
[0].dtdh_chain
;
1869 wsp
->walk_data
= data
;
1874 dtrace_dynvar_step(mdb_walk_state_t
*wsp
)
1876 dtrace_dynvar_data_t
*data
= wsp
->walk_data
;
1877 dtrace_dynvar_t dynvar
, *dvar
;
1882 while ((addr
= data
->dtdvd_next
) == data
->dtdvd_sink
) {
1883 if (data
->dtdvd_ndx
== data
->dtdvd_hashsize
)
1887 (uintptr_t)data
->dtdvd_hash
[data
->dtdvd_ndx
++].dtdh_chain
;
1890 if (mdb_vread(&dynvar
, sizeof (dynvar
), addr
) == -1) {
1891 mdb_warn("failed to read dtrace_dynvar_t at %p", addr
);
1896 * Now we need to allocate the correct size.
1898 nkeys
= dynvar
.dtdv_tuple
.dtt_nkeys
;
1899 dvarsize
= (uintptr_t)&dynvar
.dtdv_tuple
.dtt_key
[nkeys
] -
1902 dvar
= alloca(dvarsize
);
1904 if (mdb_vread(dvar
, dvarsize
, addr
) == -1) {
1905 mdb_warn("failed to read dtrace_dynvar_t at %p", addr
);
1909 data
->dtdvd_next
= (uintptr_t)dynvar
.dtdv_next
;
1911 return (wsp
->walk_callback(addr
, dvar
, wsp
->walk_cbdata
));
1915 dtrace_dynvar_fini(mdb_walk_state_t
*wsp
)
1917 dtrace_dynvar_data_t
*data
= wsp
->walk_data
;
1920 hsize
= data
->dtdvd_hashsize
* sizeof (dtrace_dynvar_t
*);
1921 mdb_free(data
->dtdvd_hash
, hsize
);
1922 mdb_free(data
, sizeof (dtrace_dynvar_data_t
));
1925 typedef struct dtrace_hashstat_data
{
1926 size_t *dthsd_counts
;
1927 size_t dthsd_hashsize
;
1931 } dtrace_hashstat_data_t
;
1933 typedef void (*dtrace_hashstat_func_t
)(dtrace_hashstat_data_t
*);
1936 dtrace_hashstat_additive(dtrace_hashstat_data_t
*data
)
1941 for (i
= 0; i
< data
->dthsd_size
; i
++)
1942 hval
+= data
->dthsd_data
[i
];
1944 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
1948 dtrace_hashstat_shifty(dtrace_hashstat_data_t
*data
)
1953 if (data
->dthsd_size
< sizeof (uint64_t)) {
1954 dtrace_hashstat_additive(data
);
1958 for (i
= 0; i
< data
->dthsd_size
; i
+= sizeof (uint64_t)) {
1959 /* LINTED - alignment */
1960 uint64_t val
= *((uint64_t *)&data
->dthsd_data
[i
]);
1962 hval
+= (val
& ((1 << NBBY
) - 1)) +
1963 ((val
>> NBBY
) & ((1 << NBBY
) - 1)) +
1964 ((val
>> (NBBY
<< 1)) & ((1 << NBBY
) - 1)) +
1965 ((val
>> (NBBY
<< 2)) & ((1 << NBBY
) - 1)) +
1966 (val
& USHRT_MAX
) + (val
>> (NBBY
<< 1) & USHRT_MAX
);
1969 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
1973 dtrace_hashstat_knuth(dtrace_hashstat_data_t
*data
)
1976 int hval
= data
->dthsd_size
;
1978 for (i
= 0; i
< data
->dthsd_size
; i
++)
1979 hval
= (hval
<< 4) ^ (hval
>> 28) ^ data
->dthsd_data
[i
];
1981 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
1985 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t
*data
)
1990 for (i
= 0; i
< data
->dthsd_size
; i
++) {
1991 hval
+= data
->dthsd_data
[i
];
1992 hval
+= (hval
<< 10);
1993 hval
^= (hval
>> 6);
1996 hval
+= (hval
<< 3);
1997 hval
^= (hval
>> 11);
1998 hval
+= (hval
<< 15);
2000 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
2004 dtrace_hashstat_fnv(dtrace_hashstat_data_t
*data
)
2006 static const uint32_t prime
= 0x01000193;
2010 for (i
= 0; i
< data
->dthsd_size
; i
++) {
2012 hval
^= data
->dthsd_data
[i
];
2015 data
->dthsd_counts
[hval
% data
->dthsd_hashsize
]++;
2019 dtrace_hashstat_stats(char *name
, dtrace_hashstat_data_t
*data
)
2026 uint_t util
, stddev
;
2028 if (!data
->dthsd_header
) {
2029 mdb_printf("%15s %11s %11s %11s %11s %11s\n", "NAME",
2030 "HASHSIZE", "%UTIL", "LONGEST", "AVERAGE", "STDDEV");
2031 data
->dthsd_header
= 1;
2034 for (i
= 0; i
< data
->dthsd_hashsize
; i
++) {
2035 if (data
->dthsd_counts
[i
] != 0) {
2038 if (data
->dthsd_counts
[i
] > longest
)
2039 longest
= data
->dthsd_counts
[i
];
2041 ttl
+= data
->dthsd_counts
[i
];
2046 mdb_printf("%15s %11d %11s %11s %11s %11s\n", name
,
2047 data
->dthsd_hashsize
, "-", "-", "-", "-");
2051 avg
= (double)ttl
/ (double)nz
;
2053 for (i
= 0; i
< data
->dthsd_hashsize
; i
++) {
2054 double delta
= (double)data
->dthsd_counts
[i
] - avg
;
2056 if (data
->dthsd_counts
[i
] == 0)
2059 sum
+= delta
* delta
;
2062 util
= (nz
* 1000) / data
->dthsd_hashsize
;
2063 stddev
= (uint_t
)sqrt(sum
/ (double)nz
) * 10;
2065 mdb_printf("%15s %11d %9u.%1u %11d %11d %9u.%1u\n", name
,
2066 data
->dthsd_hashsize
, util
/ 10, util
% 10, longest
, ttl
/ nz
,
2067 stddev
/ 10, stddev
% 10);
2070 static struct dtrace_hashstat
{
2072 dtrace_hashstat_func_t dths_func
;
2073 } _dtrace_hashstat
[] = {
2074 { "<actual>", NULL
},
2075 { "additive", dtrace_hashstat_additive
},
2076 { "shifty", dtrace_hashstat_shifty
},
2077 { "knuth", dtrace_hashstat_knuth
},
2078 { "one-at-a-time", dtrace_hashstat_oneatatime
},
2079 { "fnv", dtrace_hashstat_fnv
},
2083 typedef struct dtrace_aggstat_data
{
2084 dtrace_hashstat_data_t dtagsd_hash
;
2085 dtrace_hashstat_func_t dtagsd_func
;
2086 } dtrace_aggstat_data_t
;
2089 dtrace_aggstat_walk(uintptr_t addr
, dtrace_aggkey_t
*key
,
2090 dtrace_aggstat_data_t
*data
)
2092 dtrace_hashstat_data_t
*hdata
= &data
->dtagsd_hash
;
2095 if (data
->dtagsd_func
== NULL
) {
2096 size_t bucket
= key
->dtak_hashval
% hdata
->dthsd_hashsize
;
2098 hdata
->dthsd_counts
[bucket
]++;
2103 * We need to read the data.
2105 size
= key
->dtak_size
- sizeof (dtrace_aggid_t
);
2106 addr
= (uintptr_t)key
->dtak_data
+ sizeof (dtrace_aggid_t
);
2107 hdata
->dthsd_data
= alloca(size
);
2108 hdata
->dthsd_size
= size
;
2110 if (mdb_vread(hdata
->dthsd_data
, size
, addr
) == -1) {
2111 mdb_warn("couldn't read data at %p", addr
);
2115 data
->dtagsd_func(hdata
);
2122 dtrace_aggstat(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2124 dtrace_buffer_t buf
;
2126 dtrace_aggbuffer_t agb
;
2127 size_t hsize
, i
, actual
, prime
, evenpow
;
2128 dtrace_aggstat_data_t data
;
2129 dtrace_hashstat_data_t
*hdata
= &data
.dtagsd_hash
;
2131 bzero(&data
, sizeof (data
));
2133 if (!(flags
& DCMD_ADDRSPEC
))
2134 return (DCMD_USAGE
);
2136 if (mdb_vread(&buf
, sizeof (buf
), addr
) == -1) {
2137 mdb_warn("failed to read aggregation buffer at %p", addr
);
2141 aaddr
= (uintptr_t)buf
.dtb_tomax
+
2142 buf
.dtb_size
- sizeof (dtrace_aggbuffer_t
);
2144 if (mdb_vread(&agb
, sizeof (agb
), aaddr
) == -1) {
2145 mdb_warn("failed to read dtrace_aggbuffer_t at %p", aaddr
);
2149 hsize
= (actual
= agb
.dtagb_hashsize
) * sizeof (size_t);
2150 hdata
->dthsd_counts
= mdb_alloc(hsize
, UM_SLEEP
| UM_GC
);
2153 * Now pick the largest prime smaller than the hash size. (If the
2154 * existing size is prime, we'll pick a smaller prime just for the
2157 for (prime
= agb
.dtagb_hashsize
- 1; prime
> 7; prime
--) {
2158 size_t limit
= prime
/ 7;
2160 for (i
= 2; i
< limit
; i
++) {
2161 if ((prime
% i
) == 0)
2170 * And now we want to pick the largest power of two smaller than the
2173 for (i
= 0; (1 << i
) < agb
.dtagb_hashsize
; i
++)
2176 evenpow
= (1 << (i
- 1));
2178 for (i
= 0; _dtrace_hashstat
[i
].dths_name
!= NULL
; i
++) {
2179 data
.dtagsd_func
= _dtrace_hashstat
[i
].dths_func
;
2181 hdata
->dthsd_hashsize
= actual
;
2182 hsize
= hdata
->dthsd_hashsize
* sizeof (size_t);
2183 bzero(hdata
->dthsd_counts
, hsize
);
2185 if (mdb_pwalk("dtrace_aggkey",
2186 (mdb_walk_cb_t
)dtrace_aggstat_walk
, &data
, addr
) == -1) {
2187 mdb_warn("failed to walk dtrace_aggkey at %p", addr
);
2191 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2194 * If we were just printing the actual value, we won't try
2195 * any of the sizing experiments.
2197 if (data
.dtagsd_func
== NULL
)
2200 hdata
->dthsd_hashsize
= prime
;
2201 hsize
= hdata
->dthsd_hashsize
* sizeof (size_t);
2202 bzero(hdata
->dthsd_counts
, hsize
);
2204 if (mdb_pwalk("dtrace_aggkey",
2205 (mdb_walk_cb_t
)dtrace_aggstat_walk
, &data
, addr
) == -1) {
2206 mdb_warn("failed to walk dtrace_aggkey at %p", addr
);
2210 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2212 hdata
->dthsd_hashsize
= evenpow
;
2213 hsize
= hdata
->dthsd_hashsize
* sizeof (size_t);
2214 bzero(hdata
->dthsd_counts
, hsize
);
2216 if (mdb_pwalk("dtrace_aggkey",
2217 (mdb_walk_cb_t
)dtrace_aggstat_walk
, &data
, addr
) == -1) {
2218 mdb_warn("failed to walk dtrace_aggkey at %p", addr
);
2222 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2230 dtrace_dynstat_walk(uintptr_t addr
, dtrace_dynvar_t
*dynvar
,
2231 dtrace_aggstat_data_t
*data
)
2233 dtrace_hashstat_data_t
*hdata
= &data
->dtagsd_hash
;
2234 dtrace_tuple_t
*tuple
= &dynvar
->dtdv_tuple
;
2235 dtrace_key_t
*key
= tuple
->dtt_key
;
2236 size_t size
= 0, offs
= 0;
2237 int i
, nkeys
= tuple
->dtt_nkeys
;
2240 if (data
->dtagsd_func
== NULL
) {
2241 size_t bucket
= dynvar
->dtdv_hashval
% hdata
->dthsd_hashsize
;
2243 hdata
->dthsd_counts
[bucket
]++;
2248 * We want to hand the hashing algorithm a contiguous buffer. First
2249 * run through the tuple and determine the size.
2251 for (i
= 0; i
< nkeys
; i
++) {
2252 if (key
[i
].dttk_size
== 0) {
2253 size
+= sizeof (uint64_t);
2255 size
+= key
[i
].dttk_size
;
2262 * Now go back through the tuple and copy the data into the buffer.
2264 for (i
= 0; i
< nkeys
; i
++) {
2265 if (key
[i
].dttk_size
== 0) {
2266 bcopy(&key
[i
].dttk_value
, &buf
[offs
],
2268 offs
+= sizeof (uint64_t);
2270 if (mdb_vread(&buf
[offs
], key
[i
].dttk_size
,
2271 key
[i
].dttk_value
) == -1) {
2272 mdb_warn("couldn't read tuple data at %p",
2277 offs
+= key
[i
].dttk_size
;
2281 hdata
->dthsd_data
= buf
;
2282 hdata
->dthsd_size
= size
;
2284 data
->dtagsd_func(hdata
);
2291 dtrace_dynstat(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2293 dtrace_dstate_t dstate
;
2294 size_t hsize
, i
, actual
, prime
;
2295 dtrace_aggstat_data_t data
;
2296 dtrace_hashstat_data_t
*hdata
= &data
.dtagsd_hash
;
2298 bzero(&data
, sizeof (data
));
2300 if (!(flags
& DCMD_ADDRSPEC
))
2301 return (DCMD_USAGE
);
2303 if (mdb_vread(&dstate
, sizeof (dstate
), addr
) == -1) {
2304 mdb_warn("failed to read dynamic variable state at %p", addr
);
2308 hsize
= (actual
= dstate
.dtds_hashsize
) * sizeof (size_t);
2309 hdata
->dthsd_counts
= mdb_alloc(hsize
, UM_SLEEP
| UM_GC
);
2312 * Now pick the largest prime smaller than the hash size. (If the
2313 * existing size is prime, we'll pick a smaller prime just for the
2316 for (prime
= dstate
.dtds_hashsize
- 1; prime
> 7; prime
--) {
2317 size_t limit
= prime
/ 7;
2319 for (i
= 2; i
< limit
; i
++) {
2320 if ((prime
% i
) == 0)
2328 for (i
= 0; _dtrace_hashstat
[i
].dths_name
!= NULL
; i
++) {
2329 data
.dtagsd_func
= _dtrace_hashstat
[i
].dths_func
;
2331 hdata
->dthsd_hashsize
= actual
;
2332 hsize
= hdata
->dthsd_hashsize
* sizeof (size_t);
2333 bzero(hdata
->dthsd_counts
, hsize
);
2335 if (mdb_pwalk("dtrace_dynvar",
2336 (mdb_walk_cb_t
)dtrace_dynstat_walk
, &data
, addr
) == -1) {
2337 mdb_warn("failed to walk dtrace_dynvar at %p", addr
);
2341 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2344 * If we were just printing the actual value, we won't try
2345 * any of the sizing experiments.
2347 if (data
.dtagsd_func
== NULL
)
2350 hdata
->dthsd_hashsize
= prime
;
2351 hsize
= hdata
->dthsd_hashsize
* sizeof (size_t);
2352 bzero(hdata
->dthsd_counts
, hsize
);
2354 if (mdb_pwalk("dtrace_dynvar",
2355 (mdb_walk_cb_t
)dtrace_dynstat_walk
, &data
, addr
) == -1) {
2356 mdb_warn("failed to walk dtrace_aggkey at %p", addr
);
2360 dtrace_hashstat_stats(_dtrace_hashstat
[i
].dths_name
, hdata
);
2366 typedef struct dtrace_ecb_walk
{
2367 dtrace_ecb_t
**dtew_ecbs
;
2370 } dtrace_ecb_walk_t
;
2373 dtrace_ecb_init(mdb_walk_state_t
*wsp
)
2376 dtrace_state_t state
;
2377 dtrace_ecb_walk_t
*ecbwp
;
2379 if ((addr
= wsp
->walk_addr
) == NULL
) {
2380 mdb_warn("dtrace_ecb walk needs dtrace_state_t\n");
2384 if (mdb_vread(&state
, sizeof (state
), addr
) == -1) {
2385 mdb_warn("failed to read dtrace state pointer at %p", addr
);
2389 ecbwp
= mdb_zalloc(sizeof (dtrace_ecb_walk_t
), UM_SLEEP
| UM_GC
);
2391 ecbwp
->dtew_ecbs
= state
.dts_ecbs
;
2392 ecbwp
->dtew_necbs
= state
.dts_necbs
;
2393 ecbwp
->dtew_curecb
= 0;
2395 wsp
->walk_data
= ecbwp
;
2401 dtrace_ecb_step(mdb_walk_state_t
*wsp
)
2403 uintptr_t ecbp
, addr
;
2404 dtrace_ecb_walk_t
*ecbwp
= wsp
->walk_data
;
2406 addr
= (uintptr_t)ecbwp
->dtew_ecbs
+
2407 ecbwp
->dtew_curecb
* sizeof (dtrace_ecb_t
*);
2409 if (ecbwp
->dtew_curecb
++ == ecbwp
->dtew_necbs
)
2412 if (mdb_vread(&ecbp
, sizeof (addr
), addr
) == -1) {
2413 mdb_warn("failed to read ecb at entry %d\n",
2414 ecbwp
->dtew_curecb
);
2421 return (wsp
->walk_callback(ecbp
, NULL
, wsp
->walk_cbdata
));
2425 dtrace_options_numtostr(uint64_t num
, char *buf
, size_t len
)
2432 n
= (n
+ (1024 / 2)) / 1024; /* Round up or down */
2436 u
= " KMGTPE"[index
];
2439 (void) mdb_snprintf(buf
, len
, "%llu", (u_longlong_t
)n
);
2440 } else if (n
< 10 && (num
& (num
- 1)) != 0) {
2441 (void) mdb_snprintf(buf
, len
, "%.2f%c",
2442 (double)num
/ (1ULL << 10 * index
), u
);
2443 } else if (n
< 100 && (num
& (num
- 1)) != 0) {
2444 (void) mdb_snprintf(buf
, len
, "%.1f%c",
2445 (double)num
/ (1ULL << 10 * index
), u
);
2447 (void) mdb_snprintf(buf
, len
, "%llu%c", (u_longlong_t
)n
, u
);
2452 dtrace_options_numtohz(uint64_t num
, char *buf
, size_t len
)
2454 (void) mdb_snprintf(buf
, len
, "%dhz", NANOSEC
/num
);
2458 dtrace_options_numtobufpolicy(uint64_t num
, char *buf
, size_t len
)
2460 char *policy
= "unknown";
2463 case DTRACEOPT_BUFPOLICY_RING
:
2467 case DTRACEOPT_BUFPOLICY_FILL
:
2471 case DTRACEOPT_BUFPOLICY_SWITCH
:
2476 (void) mdb_snprintf(buf
, len
, "%s", policy
);
2480 dtrace_options_numtocpu(uint64_t cpu
, char *buf
, size_t len
)
2482 if (cpu
== DTRACE_CPUALL
)
2483 (void) mdb_snprintf(buf
, len
, "%7s", "unbound");
2485 (void) mdb_snprintf(buf
, len
, "%d", cpu
);
2488 typedef void (*dtrace_options_func_t
)(uint64_t, char *, size_t);
2490 static struct dtrace_options
{
2492 dtrace_options_func_t dtop_func
;
2493 } _dtrace_options
[] = {
2494 { "bufsize", dtrace_options_numtostr
},
2495 { "bufpolicy", dtrace_options_numtobufpolicy
},
2496 { "dynvarsize", dtrace_options_numtostr
},
2497 { "aggsize", dtrace_options_numtostr
},
2498 { "specsize", dtrace_options_numtostr
},
2499 { "nspec", dtrace_options_numtostr
},
2500 { "strsize", dtrace_options_numtostr
},
2501 { "cleanrate", dtrace_options_numtohz
},
2502 { "cpu", dtrace_options_numtocpu
},
2503 { "bufresize", dtrace_options_numtostr
},
2504 { "grabanon", dtrace_options_numtostr
},
2505 { "flowindent", dtrace_options_numtostr
},
2506 { "quiet", dtrace_options_numtostr
},
2507 { "stackframes", dtrace_options_numtostr
},
2508 { "ustackframes", dtrace_options_numtostr
},
2509 { "aggrate", dtrace_options_numtohz
},
2510 { "switchrate", dtrace_options_numtohz
},
2511 { "statusrate", dtrace_options_numtohz
},
2512 { "destructive", dtrace_options_numtostr
},
2513 { "stackindent", dtrace_options_numtostr
},
2514 { "rawbytes", dtrace_options_numtostr
},
2515 { "jstackframes", dtrace_options_numtostr
},
2516 { "jstackstrsize", dtrace_options_numtostr
},
2517 { "aggsortkey", dtrace_options_numtostr
},
2518 { "aggsortrev", dtrace_options_numtostr
},
2519 { "aggsortpos", dtrace_options_numtostr
},
2520 { "aggsortkeypos", dtrace_options_numtostr
}
2524 dtrace_options_help(void)
2526 mdb_printf("Given a dtrace_state_t structure, displays the "
2527 "current tunable option\nsettings.\n");
2532 dtrace_options(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2534 dtrace_state_t state
;
2536 dtrace_optval_t
*options
;
2539 if (!(flags
& DCMD_ADDRSPEC
))
2540 return (DCMD_USAGE
);
2542 if (mdb_vread(&state
, sizeof (dtrace_state_t
), (uintptr_t)addr
) == -1) {
2543 mdb_warn("failed to read state pointer at %p\n", addr
);
2547 options
= &state
.dts_options
[0];
2549 mdb_printf("%<u>%-25s %s%</u>\n", "OPTION", "VALUE");
2550 for (i
= 0; i
< DTRACEOPT_MAX
; i
++) {
2551 if (options
[i
] == DTRACEOPT_UNSET
) {
2552 mdb_printf("%-25s %s\n",
2553 _dtrace_options
[i
].dtop_optstr
, "UNSET");
2555 (void) _dtrace_options
[i
].dtop_func(options
[i
],
2557 mdb_printf("%-25s %s\n",
2558 _dtrace_options
[i
].dtop_optstr
, val
);
2566 pid2state_init(mdb_walk_state_t
*wsp
)
2568 dtrace_state_data_t
*data
;
2571 struct dev_info info
;
2572 pid_t pid
= (pid_t
)wsp
->walk_addr
;
2574 if (wsp
->walk_addr
== NULL
) {
2575 mdb_warn("pid2state walk requires PID\n");
2579 data
= mdb_zalloc(sizeof (dtrace_state_data_t
), UM_SLEEP
| UM_GC
);
2581 if (mdb_readvar(&data
->dtsd_softstate
, "dtrace_softstate") == -1) {
2582 mdb_warn("failed to read 'dtrace_softstate'");
2586 if ((proc
= mdb_pid2proc(pid
, NULL
)) == 0) {
2587 mdb_warn("PID 0t%d not found\n", pid
);
2591 if (mdb_readvar(&devi
, "dtrace_devi") == -1) {
2592 mdb_warn("failed to read 'dtrace_devi'");
2596 if (mdb_vread(&info
, sizeof (struct dev_info
), devi
) == -1) {
2597 mdb_warn("failed to read 'dev_info'");
2601 data
->dtsd_major
= info
.devi_major
;
2602 data
->dtsd_proc
= proc
;
2604 wsp
->walk_data
= data
;
2611 pid2state_file(uintptr_t addr
, struct file
*f
, dtrace_state_data_t
*data
)
2617 /* Get the vnode for this file */
2618 if (mdb_vread(&vnode
, sizeof (vnode
), (uintptr_t)f
->f_vnode
) == -1) {
2619 mdb_warn("couldn't read vnode at %p", (uintptr_t)f
->f_vnode
);
2624 /* Is this the dtrace device? */
2625 if (getmajor(vnode
.v_rdev
) != data
->dtsd_major
)
2628 /* Get the minor number for this device entry */
2629 minor
= getminor(vnode
.v_rdev
);
2631 if (mdb_get_soft_state_byaddr(data
->dtsd_softstate
, minor
,
2632 &statep
, NULL
, 0) == -1) {
2633 mdb_warn("failed to read softstate for minor %d", minor
);
2637 mdb_printf("%p\n", statep
);
2643 pid2state_step(mdb_walk_state_t
*wsp
)
2645 dtrace_state_data_t
*ds
= wsp
->walk_data
;
2647 if (mdb_pwalk("file",
2648 (mdb_walk_cb_t
)pid2state_file
, ds
, ds
->dtsd_proc
) == -1) {
2649 mdb_warn("couldn't walk 'file' for proc %p", ds
->dtsd_proc
);
2658 dtrace_probes_walk(uintptr_t addr
, void *ignored
, uintptr_t *target
)
2661 dtrace_probe_t probe
;
2662 dtrace_probedesc_t pd
;
2667 if (mdb_vread(&ecb
, sizeof (dtrace_ecb_t
), addr
) == -1) {
2668 mdb_warn("failed to read ecb %p\n", addr
);
2672 if (ecb
.dte_probe
== NULL
)
2675 if (mdb_vread(&probe
, sizeof (dtrace_probe_t
),
2676 (uintptr_t)ecb
.dte_probe
) == -1) {
2677 mdb_warn("failed to read probe %p\n", ecb
.dte_probe
);
2681 pd
.dtpd_id
= probe
.dtpr_id
;
2682 dtracemdb_probe(NULL
, &pd
);
2684 mdb_printf("%5d %10s %17s %33s %s\n", pd
.dtpd_id
, pd
.dtpd_provider
,
2685 pd
.dtpd_mod
, pd
.dtpd_func
, pd
.dtpd_name
);
2691 dtrace_probes_help(void)
2693 mdb_printf("Given a dtrace_state_t structure, displays all "
2694 "its active enablings. If no\nstate structure is provided, "
2695 "all available probes are listed.\n");
2700 dtrace_probes(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2702 dtrace_probedesc_t pd
;
2703 uintptr_t caddr
, base
, paddr
;
2706 mdb_printf("%5s %10s %17s %33s %s\n",
2707 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
2709 if (!(flags
& DCMD_ADDRSPEC
)) {
2711 * If no argument is provided just display all available
2714 if (mdb_readvar(&base
, "dtrace_probes") == -1) {
2715 mdb_warn("failed to read 'dtrace_probes'");
2719 if (mdb_readvar(&nprobes
, "dtrace_nprobes") == -1) {
2720 mdb_warn("failed to read 'dtrace_nprobes'");
2724 for (i
= 0; i
< nprobes
; i
++) {
2725 caddr
= base
+ i
* sizeof (dtrace_probe_t
*);
2727 if (mdb_vread(&paddr
, sizeof (paddr
), caddr
) == -1) {
2728 mdb_warn("couldn't read probe pointer at %p",
2737 if (dtracemdb_probe(NULL
, &pd
) == 0) {
2738 mdb_printf("%5d %10s %17s %33s %s\n",
2739 pd
.dtpd_id
, pd
.dtpd_provider
,
2740 pd
.dtpd_mod
, pd
.dtpd_func
, pd
.dtpd_name
);
2744 if (mdb_pwalk("dtrace_ecb", (mdb_walk_cb_t
)dtrace_probes_walk
,
2745 NULL
, addr
) == -1) {
2746 mdb_warn("couldn't walk 'dtrace_ecb'");
2754 const mdb_dcmd_t kernel_dcmds
[] = {
2755 { "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t",
2757 { "dtrace", ":[-c cpu]", "print dtrace(1M)-like output",
2758 dtrace
, dtrace_help
},
2759 { "dtrace_errhash", ":", "print DTrace error hash", dtrace_errhash
},
2760 { "dtrace_helptrace", ":", "print DTrace helper trace",
2762 { "dtrace_state", ":", "print active DTrace consumers", dtrace_state
,
2763 dtrace_state_help
},
2764 { "dtrace_aggstat", ":",
2765 "print DTrace aggregation hash statistics", dtrace_aggstat
},
2766 { "dtrace_dynstat", ":",
2767 "print DTrace dynamic variable hash statistics", dtrace_dynstat
},
2768 { "dtrace_options", ":",
2769 "print a DTrace consumer's current tuneable options",
2770 dtrace_options
, dtrace_options_help
},
2771 { "dtrace_probes", "?", "print a DTrace consumer's enabled probes",
2772 dtrace_probes
, dtrace_probes_help
},
2776 const mdb_walker_t kernel_walkers
[] = {
2777 { "dtrace_errhash", "walk hash of DTrace error messasges",
2778 dtrace_errhash_init
, dtrace_errhash_step
},
2779 { "dtrace_helptrace", "walk DTrace helper trace entries",
2780 dtrace_helptrace_init
, dtrace_helptrace_step
},
2781 { "dtrace_state", "walk DTrace per-consumer softstate",
2782 dtrace_state_init
, dtrace_state_step
},
2783 { "dtrace_aggkey", "walk DTrace aggregation keys",
2784 dtrace_aggkey_init
, dtrace_aggkey_step
, dtrace_aggkey_fini
},
2785 { "dtrace_dynvar", "walk DTrace dynamic variables",
2786 dtrace_dynvar_init
, dtrace_dynvar_step
, dtrace_dynvar_fini
},
2787 { "dtrace_ecb", "walk a DTrace consumer's enabling control blocks",
2788 dtrace_ecb_init
, dtrace_ecb_step
},
2789 { "pid2state", "walk a processes dtrace_state structures",
2790 pid2state_init
, pid2state_step
},