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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Joyent, Inc.
26 #include <mdb/mdb_modapi.h>
27 #include <mdb/mdb_ctf.h>
28 #include <sys/cpuvar.h>
29 #include <sys/systm.h>
30 #include <sys/traptrace.h>
31 #include <sys/x_call.h>
32 #include <sys/xc_levels.h>
33 #include <sys/avintr.h>
34 #include <sys/systm.h>
36 #include <sys/mutex.h>
37 #include <sys/mutex_impl.h>
41 #include <sys/x86_archext.h>
42 #include <sys/bitmap.h>
43 #include <sys/controlregs.h>
45 #define TT_HDLR_WIDTH 17
49 static apix_impl_t
*d_apixs
[NCPU
];
50 static int use_apix
= 0;
53 ttrace_ttr_size_check(void)
58 if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid
) != 0 ||
59 mdb_ctf_type_resolve(ttrtid
, &ttrtid
) != 0) {
60 mdb_warn("failed to determine size of trap_trace_rec_t; "
61 "non-TRAPTRACE kernel?\n");
65 if ((ttr_size
= mdb_ctf_type_size(ttrtid
)) !=
66 sizeof (trap_trace_rec_t
)) {
68 * On Intel machines, this will happen when TTR_STACK_DEPTH
69 * is changed. This code could be smarter, and could
70 * dynamically adapt to different depths, but not until a
71 * need for such adaptation is demonstrated.
73 mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't "
74 "match expected %d\n", ttr_size
, sizeof (trap_trace_rec_t
));
82 ttrace_walk_init(mdb_walk_state_t
*wsp
)
84 trap_trace_ctl_t
*ttcp
;
85 size_t ttc_size
= sizeof (trap_trace_ctl_t
) * NCPU
;
88 if (!ttrace_ttr_size_check())
91 ttcp
= mdb_zalloc(ttc_size
, UM_SLEEP
);
93 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
94 mdb_warn("ttrace only supports global walks\n");
98 if (mdb_readsym(ttcp
, ttc_size
, "trap_trace_ctl") == -1) {
99 mdb_warn("symbol 'trap_trace_ctl' not found; "
100 "non-TRAPTRACE kernel?\n");
101 mdb_free(ttcp
, ttc_size
);
106 * We'll poach the ttc_current pointer (which isn't used for
107 * anything) to store a pointer to our current TRAPTRACE record.
108 * This allows us to only keep the array of trap_trace_ctl structures
109 * as our walker state (ttc_current may be the only kernel data
110 * structure member added exclusively to make writing the mdb walker
113 for (i
= 0; i
< NCPU
; i
++) {
114 trap_trace_ctl_t
*ttc
= &ttcp
[i
];
116 if (ttc
->ttc_first
== (uintptr_t)NULL
)
120 * Assign ttc_current to be the last completed record.
121 * Note that the error checking (i.e. in the ttc_next ==
122 * ttc_first case) is performed in the step function.
124 ttc
->ttc_current
= ttc
->ttc_next
- sizeof (trap_trace_rec_t
);
127 wsp
->walk_data
= ttcp
;
132 ttrace_walk_step(mdb_walk_state_t
*wsp
)
134 trap_trace_ctl_t
*ttcp
= wsp
->walk_data
, *ttc
, *latest_ttc
;
135 trap_trace_rec_t rec
;
136 int rval
, i
, recsize
= sizeof (trap_trace_rec_t
);
140 * Loop through the CPUs, looking for the latest trap trace record
141 * (we want to walk through the trap trace records in reverse
142 * chronological order).
144 for (i
= 0; i
< NCPU
; i
++) {
147 if (ttc
->ttc_current
== (uintptr_t)NULL
)
150 if (ttc
->ttc_current
< ttc
->ttc_first
)
151 ttc
->ttc_current
= ttc
->ttc_limit
- recsize
;
153 if (mdb_vread(&rec
, sizeof (rec
), ttc
->ttc_current
) == -1) {
154 mdb_warn("couldn't read rec at %p", ttc
->ttc_current
);
158 if (rec
.ttr_stamp
> latest
) {
159 latest
= rec
.ttr_stamp
;
169 if (mdb_vread(&rec
, sizeof (rec
), ttc
->ttc_current
) == -1) {
170 mdb_warn("couldn't read rec at %p", ttc
->ttc_current
);
174 rval
= wsp
->walk_callback(ttc
->ttc_current
, &rec
, wsp
->walk_cbdata
);
176 if (ttc
->ttc_current
== ttc
->ttc_next
)
177 ttc
->ttc_current
= (uintptr_t)NULL
;
179 ttc
->ttc_current
-= sizeof (trap_trace_rec_t
);
185 ttrace_walk_fini(mdb_walk_state_t
*wsp
)
187 mdb_free(wsp
->walk_data
, sizeof (trap_trace_ctl_t
) * NCPU
);
191 ttrace_syscall(trap_trace_rec_t
*rec
)
194 int sysnum
= rec
->ttr_sysnum
;
198 mdb_printf("%-3x", sysnum
);
200 if (rec
->ttr_sysnum
> NSYSCALL
) {
201 mdb_printf(" %-*d", TT_HDLR_WIDTH
, rec
->ttr_sysnum
);
205 if (mdb_lookup_by_name("sysent", &sym
) == -1) {
206 mdb_warn("\ncouldn't find 'sysent'");
210 addr
= (uintptr_t)sym
.st_value
+ sysnum
* sizeof (struct sysent
);
212 if (addr
>= (uintptr_t)sym
.st_value
+ sym
.st_size
) {
213 mdb_warn("\nsysnum %d out-of-range\n", sysnum
);
217 if (mdb_vread(&sys
, sizeof (sys
), addr
) == -1) {
218 mdb_warn("\nfailed to read sysent at %p", addr
);
222 mdb_printf(" %-*a", TT_HDLR_WIDTH
, sys
.sy_callc
);
228 ttrace_interrupt(trap_trace_rec_t
*rec
)
235 switch (rec
->ttr_regs
.r_trapno
) {
237 mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH
, "(fakesoftint)");
243 mdb_printf("%-3x ", rec
->ttr_vector
);
245 if (mdb_lookup_by_name("autovect", &sym
) == -1) {
246 mdb_warn("\ncouldn't find 'autovect'");
250 addr
= (uintptr_t)sym
.st_value
+
251 rec
->ttr_vector
* sizeof (struct av_head
);
253 if (addr
>= (uintptr_t)sym
.st_value
+ sym
.st_size
) {
254 mdb_warn("\nav_head for vec %x is corrupt\n", rec
->ttr_vector
);
258 if (mdb_vread(&hd
, sizeof (hd
), addr
) == -1) {
259 mdb_warn("\ncouldn't read av_head for vec %x", rec
->ttr_vector
);
263 if (hd
.avh_link
== NULL
) {
264 if (rec
->ttr_ipl
== XC_CPUPOKE_PIL
)
265 mdb_printf("%-*s", TT_HDLR_WIDTH
, "(cpupoke)");
267 mdb_printf("%-*s", TT_HDLR_WIDTH
, "(spurious)");
269 if (mdb_vread(&av
, sizeof (av
), (uintptr_t)hd
.avh_link
) == -1) {
270 mdb_warn("couldn't read autovec at %p",
271 (uintptr_t)hd
.avh_link
);
274 mdb_printf("%-*a", TT_HDLR_WIDTH
, av
.av_vector
);
281 ttrace_apix_interrupt(trap_trace_rec_t
*rec
)
285 apix_vector_t apix_vector
;
287 switch (rec
->ttr_regs
.r_trapno
) {
289 mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH
, "(fakesoftint)");
295 mdb_printf("%-3x ", rec
->ttr_vector
);
297 /* Read the per CPU apix entry */
298 if (mdb_vread(&apix
, sizeof (apix_impl_t
),
299 (uintptr_t)d_apixs
[rec
->ttr_cpuid
]) == -1) {
300 mdb_warn("\ncouldn't read apix[%d]", rec
->ttr_cpuid
);
303 if (mdb_vread(&apix_vector
, sizeof (apix_vector_t
),
304 (uintptr_t)apix
.x_vectbl
[rec
->ttr_vector
]) == -1) {
305 mdb_warn("\ncouldn't read apix_vector_t[%d]", rec
->ttr_vector
);
308 if (apix_vector
.v_share
== 0) {
309 if (rec
->ttr_ipl
== XC_CPUPOKE_PIL
)
310 mdb_printf("%-*s", TT_HDLR_WIDTH
, "(cpupoke)");
312 mdb_printf("%-*s", TT_HDLR_WIDTH
, "(spurious)");
314 if (mdb_vread(&av
, sizeof (struct autovec
),
315 (uintptr_t)(apix_vector
.v_autovect
)) == -1) {
316 mdb_warn("couldn't read autovec at %p",
317 (uintptr_t)apix_vector
.v_autovect
);
320 mdb_printf("%-*a", TT_HDLR_WIDTH
, av
.av_vector
);
331 { T_ZERODIV
, "divide-error" },
332 { T_SGLSTP
, "debug-exception" },
333 { T_NMIFLT
, "nmi-interrupt" },
334 { T_BPTFLT
, "breakpoint" },
335 { T_OVFLW
, "into-overflow" },
336 { T_BOUNDFLT
, "bound-exceeded" },
337 { T_ILLINST
, "invalid-opcode" },
338 { T_NOEXTFLT
, "device-not-avail" },
339 { T_DBLFLT
, "double-fault" },
340 { T_EXTOVRFLT
, "segment-overrun" },
341 { T_TSSFLT
, "invalid-tss" },
342 { T_SEGFLT
, "segment-not-pres" },
343 { T_STKFLT
, "stack-fault" },
344 { T_GPFLT
, "general-protectn" },
345 { T_PGFLT
, "page-fault" },
346 { T_EXTERRFLT
, "error-fault" },
347 { T_ALIGNMENT
, "alignment-check" },
348 { T_MCE
, "machine-check" },
349 { T_SIMDFPE
, "sse-exception" },
351 { T_DBGENTR
, "debug-enter" },
352 { T_FASTTRAP
, "fasttrap-0xd2" },
353 { T_SYSCALLINT
, "syscall-0x91" },
354 { T_DTRACE_RET
, "dtrace-ret" },
355 { T_SOFTINT
, "softint" },
356 { T_INTERRUPT
, "interrupt" },
357 { T_FAULT
, "fault" },
359 { T_SYSCALL
, "syscall" },
365 ttrace_trap(trap_trace_rec_t
*rec
)
369 if (rec
->ttr_regs
.r_trapno
== T_AST
)
370 mdb_printf("%-3s ", "-");
372 mdb_printf("%-3x ", rec
->ttr_regs
.r_trapno
);
374 for (i
= 0; ttrace_traps
[i
].tt_name
!= NULL
; i
++) {
375 if (rec
->ttr_regs
.r_trapno
== ttrace_traps
[i
].tt_trapno
)
379 if (ttrace_traps
[i
].tt_name
== NULL
)
380 mdb_printf("%-*s", TT_HDLR_WIDTH
, "(unknown)");
382 mdb_printf("%-*s", TT_HDLR_WIDTH
, ttrace_traps
[i
].tt_name
);
388 ttrace_intr_detail(trap_trace_rec_t
*rec
)
390 mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec
->ttr_vector
,
391 rec
->ttr_ipl
, rec
->ttr_pri
, rec
->ttr_spl
);
397 int (*t_hdlr
)(trap_trace_rec_t
*);
399 { TT_SYSCALL
, "sysc", ttrace_syscall
},
400 { TT_SYSENTER
, "syse", ttrace_syscall
},
401 { TT_SYSC
, "asys", ttrace_syscall
},
402 { TT_SYSC64
, "sc64", ttrace_syscall
},
403 { TT_INTERRUPT
, "intr", ttrace_interrupt
},
404 { TT_TRAP
, "trap", ttrace_trap
},
405 { TT_EVENT
, "evnt", ttrace_trap
},
409 typedef struct ttrace_dcmd
{
410 processorid_t ttd_cpu
;
412 trap_trace_ctl_t ttd_ttc
[NCPU
];
417 #define DUMP(reg) #reg, regs->r_##reg
418 #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n"
421 ttrace_dumpregs(trap_trace_rec_t
*rec
)
423 struct regs
*regs
= &rec
->ttr_regs
;
425 mdb_printf(THREEREGS
, DUMP(rdi
), DUMP(rsi
), DUMP(rdx
));
426 mdb_printf(THREEREGS
, DUMP(rcx
), DUMP(r8
), DUMP(r9
));
427 mdb_printf(THREEREGS
, DUMP(rax
), DUMP(rbx
), DUMP(rbp
));
428 mdb_printf(THREEREGS
, DUMP(r10
), DUMP(r11
), DUMP(r12
));
429 mdb_printf(THREEREGS
, DUMP(r13
), DUMP(r14
), DUMP(r15
));
430 mdb_printf(THREEREGS
, DUMP(ds
), DUMP(es
), DUMP(fs
));
431 mdb_printf(THREEREGS
, DUMP(gs
), "trp", regs
->r_trapno
, DUMP(err
));
432 mdb_printf(THREEREGS
, DUMP(rip
), DUMP(cs
), DUMP(rfl
));
433 mdb_printf(THREEREGS
, DUMP(rsp
), DUMP(ss
), "cr2", rec
->ttr_cr2
);
439 #define DUMP(reg) #reg, regs->r_##reg
440 #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
443 ttrace_dumpregs(trap_trace_rec_t
*rec
)
445 struct regs
*regs
= &rec
->ttr_regs
;
447 mdb_printf(FOURREGS
, DUMP(gs
), DUMP(fs
), DUMP(es
), DUMP(ds
));
448 mdb_printf(FOURREGS
, DUMP(edi
), DUMP(esi
), DUMP(ebp
), DUMP(esp
));
449 mdb_printf(FOURREGS
, DUMP(ebx
), DUMP(edx
), DUMP(ecx
), DUMP(eax
));
450 mdb_printf(FOURREGS
, "trp", regs
->r_trapno
, DUMP(err
),
452 mdb_printf(FOURREGS
, DUMP(efl
), "usp", regs
->r_uesp
, DUMP(ss
),
453 "cr2", rec
->ttr_cr2
);
460 ttrace_walk(uintptr_t addr
, trap_trace_rec_t
*rec
, ttrace_dcmd_t
*dcmd
)
462 struct regs
*regs
= &rec
->ttr_regs
;
463 processorid_t cpu
= -1, i
;
465 for (i
= 0; i
< NCPU
; i
++) {
466 if (addr
>= dcmd
->ttd_ttc
[i
].ttc_first
&&
467 addr
< dcmd
->ttd_ttc
[i
].ttc_limit
) {
474 mdb_warn("couldn't find %p in any trap trace ctl\n", addr
);
478 if (dcmd
->ttd_cpu
!= -1 && cpu
!= dcmd
->ttd_cpu
)
481 mdb_printf("%3d %15llx ", cpu
, rec
->ttr_stamp
);
483 for (i
= 0; ttrace_hdlr
[i
].t_hdlr
!= NULL
; i
++) {
484 if (rec
->ttr_marker
!= ttrace_hdlr
[i
].t_marker
)
486 mdb_printf("%4s ", ttrace_hdlr
[i
].t_name
);
487 if (ttrace_hdlr
[i
].t_hdlr(rec
) == -1)
491 mdb_printf(" %a\n", regs
->r_pc
);
493 if (dcmd
->ttd_extended
== FALSE
)
496 if (rec
->ttr_marker
== TT_INTERRUPT
)
497 ttrace_intr_detail(rec
);
499 ttrace_dumpregs(rec
);
501 if (rec
->ttr_sdepth
> 0) {
502 for (i
= 0; i
< rec
->ttr_sdepth
; i
++) {
503 if (i
>= TTR_STACK_DEPTH
) {
504 mdb_printf("%17s*** invalid ttr_sdepth (is %d, "
505 "should be <= %d)\n", " ", rec
->ttr_sdepth
,
510 mdb_printf("%17s %a()\n", " ", rec
->ttr_stack
[i
]);
519 ttrace(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
522 trap_trace_ctl_t
*ttc
= dcmd
.ttd_ttc
;
523 trap_trace_rec_t rec
;
524 size_t ttc_size
= sizeof (trap_trace_ctl_t
) * NCPU
;
526 if (!ttrace_ttr_size_check())
529 bzero(&dcmd
, sizeof (dcmd
));
531 dcmd
.ttd_extended
= FALSE
;
533 if (mdb_readsym(ttc
, ttc_size
, "trap_trace_ctl") == -1) {
534 mdb_warn("symbol 'trap_trace_ctl' not found; "
535 "non-TRAPTRACE kernel?\n");
539 if (mdb_getopts(argc
, argv
,
540 'x', MDB_OPT_SETBITS
, TRUE
, &dcmd
.ttd_extended
, NULL
) != argc
)
543 if (DCMD_HDRSPEC(flags
)) {
544 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
545 "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH
, "HANDLER",
549 if (flags
& DCMD_ADDRSPEC
) {
551 if (mdb_vread(&rec
, sizeof (rec
), addr
) == -1) {
552 mdb_warn("couldn't read trap trace record "
557 if (ttrace_walk(addr
, &rec
, &dcmd
) == WALK_ERR
)
565 if (mdb_readvar(&use_apix
, "apix_enable") == -1) {
566 mdb_warn("failed to read apix_enable");
571 if (mdb_readvar(&d_apixs
, "apixs") == -1) {
572 mdb_warn("\nfailed to read apixs.");
575 /* change to apix ttrace interrupt handler */
576 ttrace_hdlr
[4].t_hdlr
= ttrace_apix_interrupt
;
579 if (mdb_walk("ttrace", (mdb_walk_cb_t
)ttrace_walk
, &dcmd
) == -1) {
580 mdb_warn("couldn't walk 'ttrace'");
589 mutex_owner_init(mdb_walk_state_t
*wsp
)
595 mutex_owner_step(mdb_walk_state_t
*wsp
)
597 uintptr_t addr
= wsp
->walk_addr
;
602 if (mdb_vread(&mtx
, sizeof (mtx
), addr
) == -1)
605 if (!MUTEX_TYPE_ADAPTIVE(&mtx
))
608 if ((owner
= (uintptr_t)MUTEX_OWNER(&mtx
)) == (uintptr_t)NULL
)
611 if (mdb_vread(&thr
, sizeof (thr
), owner
) != -1)
612 (void) wsp
->walk_callback(owner
, &thr
, wsp
->walk_cbdata
);
618 gate_desc_dump(gate_desc_t
*gate
, const char *label
, int header
)
624 switch (gate
->sgd_type
) {
635 (void) mdb_snprintf(type
, sizeof (type
), "%3x", gate
->sgd_type
);
640 lastval
= gate
->sgd_ist
;
643 lastval
= gate
->sgd_stkcpy
;
647 mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> "
648 "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label
),
649 "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm
);
652 mdb_printf("%s", label
);
654 if (gate
->sgd_type
== SDT_SYSTASKGT
)
655 mdb_printf("%-30s ", "-");
657 mdb_printf("%-30a ", GATESEG_GETOFFSET(gate
));
659 mdb_printf("%4x %d %c %3s %2x\n", gate
->sgd_selector
,
660 gate
->sgd_dpl
, (gate
->sgd_p
? '+' : ' '), type
, lastval
);
665 gate_desc(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
669 if (argc
!= 0 || !(flags
& DCMD_ADDRSPEC
))
672 if (mdb_vread(&gate
, sizeof (gate_desc_t
), addr
) !=
673 sizeof (gate_desc_t
)) {
674 mdb_warn("failed to read gate descriptor at %p\n", addr
);
678 gate_desc_dump(&gate
, "", DCMD_HDRSPEC(flags
));
685 idt(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
689 if (!(flags
& DCMD_ADDRSPEC
)) {
693 if (mdb_lookup_by_name("idt0", &idt0_va
) < 0) {
694 mdb_warn("failed to find VA of idt0");
698 addr
= idt0_va
.st_value
;
699 if (mdb_vread(&idt0
, sizeof (idt0
), addr
) != sizeof (idt0
)) {
700 mdb_warn("failed to read idt0 at %p\n", addr
);
704 addr
= (uintptr_t)idt0
;
707 for (i
= 0; i
< NIDT
; i
++, addr
+= sizeof (gate_desc_t
)) {
711 if (mdb_vread(&gate
, sizeof (gate_desc_t
), addr
) !=
712 sizeof (gate_desc_t
)) {
713 mdb_warn("failed to read gate descriptor at %p\n",
718 (void) mdb_snprintf(label
, sizeof (label
), "%3d: ", i
);
719 gate_desc_dump(&gate
, label
, i
== 0);
729 "Given a (hat_t *), generates the list of all (htable_t *)s\n"
730 "that correspond to that address space\n");
734 report_maps_help(void)
737 "Given a PFN, report HAT structures that map the page, or use\n"
738 "the page as a pagetable.\n"
740 "-m Interpret the PFN as an MFN (machine frame number)\n");
747 "Given a PFN holding a page table, print its contents, and\n"
748 "the address of the corresponding htable structure.\n"
750 "-m Interpret the PFN as an MFN (machine frame number)\n");
754 * NSEC_SHIFT is replicated here (it is not defined in a header file),
755 * but for amusement, the reader is directed to the comment that explains
756 * the rationale for this particular value on x86. Spoiler: the value is
757 * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice
758 * in that comment sounds too familiar, it's because your author also wrote
759 * that code -- some fifteen years prior to this writing in 2011...)
765 scalehrtime_cmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
768 hrtime_t tsc
= addr
, hrt
;
769 unsigned int *tscp
= (unsigned int *)&tsc
;
770 uintptr_t scalehrtimef
;
774 if (!(flags
& DCMD_ADDRSPEC
)) {
778 switch (argv
[0].a_type
) {
779 case MDB_TYPE_STRING
:
780 tsc
= mdb_strtoull(argv
[0].a_un
.a_str
);
782 case MDB_TYPE_IMMEDIATE
:
783 tsc
= argv
[0].a_un
.a_val
;
790 if (mdb_readsym(&scalehrtimef
,
791 sizeof (scalehrtimef
), "scalehrtimef") == -1) {
792 mdb_warn("couldn't read 'scalehrtimef'");
796 if (mdb_lookup_by_name("tsc_scalehrtime", &sym
) == -1) {
797 mdb_warn("couldn't find 'tsc_scalehrtime'");
801 if (sym
.st_value
!= scalehrtimef
) {
802 mdb_warn("::scalehrtime requires that scalehrtimef "
803 "be set to tsc_scalehrtime\n");
807 if (mdb_readsym(&nsec_scale
, sizeof (nsec_scale
), "nsec_scale") == -1) {
808 mdb_warn("couldn't read 'nsec_scale'");
812 scale
= (uint64_t)nsec_scale
;
814 hrt
= ((uint64_t)tscp
[1] * scale
) << NSEC_SHIFT
;
815 hrt
+= ((uint64_t)tscp
[0] * scale
) >> (32 - NSEC_SHIFT
);
817 mdb_printf("0x%llx\n", hrt
);
823 * The x86 feature set is implemented as a bitmap array. That bitmap array is
824 * stored across a number of uchars based on the BT_SIZEOFMAP(NUM_X86_FEATURES)
825 * macro. We have the names for each of these features in unix's text segment
826 * so we do not have to duplicate them and instead just look them up.
830 x86_featureset_cmd(uintptr_t addr
, uint_t flags
, int argc
,
831 const mdb_arg_t
*argv
)
839 size_t sz
= sizeof (uchar_t
) * BT_SIZEOFMAP(NUM_X86_FEATURES
);
844 if (mdb_lookup_by_name("x86_feature_names", &sym
) == -1) {
845 mdb_warn("couldn't find x86_feature_names");
849 fset
= mdb_zalloc(sz
, UM_NOSLEEP
);
851 mdb_warn("failed to allocate memory for x86_featureset");
855 if (mdb_readvar(fset
, "x86_featureset") != sz
) {
856 mdb_warn("failed to read x86_featureset");
861 for (ii
= 0; ii
< NUM_X86_FEATURES
; ii
++) {
862 if (!BT_TEST((ulong_t
*)fset
, ii
))
865 if (mdb_vread(&nptr
, sizeof (char *), sym
.st_value
+
866 sizeof (void *) * ii
) != sizeof (char *)) {
867 mdb_warn("failed to read feature array %d", ii
);
872 if (mdb_readstr(name
, sizeof (name
), nptr
) == -1) {
873 mdb_warn("failed to read feature %d", ii
);
877 mdb_printf("%s\n", name
);
887 crregs_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
890 static const mdb_bitmask_t cr0_flag_bits
[] = {
891 { "PE", CR0_PE
, CR0_PE
},
892 { "MP", CR0_MP
, CR0_MP
},
893 { "EM", CR0_EM
, CR0_EM
},
894 { "TS", CR0_TS
, CR0_TS
},
895 { "ET", CR0_ET
, CR0_ET
},
896 { "NE", CR0_NE
, CR0_NE
},
897 { "WP", CR0_WP
, CR0_WP
},
898 { "AM", CR0_AM
, CR0_AM
},
899 { "NW", CR0_NW
, CR0_NW
},
900 { "CD", CR0_CD
, CR0_CD
},
901 { "PG", CR0_PG
, CR0_PG
},
905 static const mdb_bitmask_t cr4_flag_bits
[] = {
906 { "VME", CR4_VME
, CR4_VME
},
907 { "PVI", CR4_PVI
, CR4_PVI
},
908 { "TSD", CR4_TSD
, CR4_TSD
},
909 { "DE", CR4_DE
, CR4_DE
},
910 { "PSE", CR4_PSE
, CR4_PSE
},
911 { "PAE", CR4_PAE
, CR4_PAE
},
912 { "MCE", CR4_MCE
, CR4_MCE
},
913 { "PGE", CR4_PGE
, CR4_PGE
},
914 { "PCE", CR4_PCE
, CR4_PCE
},
915 { "OSFXSR", CR4_OSFXSR
, CR4_OSFXSR
},
916 { "OSXMMEXCPT", CR4_OSXMMEXCPT
, CR4_OSXMMEXCPT
},
917 { "VMXE", CR4_VMXE
, CR4_VMXE
},
918 { "SMXE", CR4_SMXE
, CR4_SMXE
},
919 { "OSXSAVE", CR4_OSXSAVE
, CR4_OSXSAVE
},
920 { "SMEP", CR4_SMEP
, CR4_SMEP
},
921 { "SMAP", CR4_SMAP
, CR4_SMAP
},
925 cr0
= kmdb_unix_getcr0();
926 cr4
= kmdb_unix_getcr4();
927 mdb_printf("%%cr0 = 0x%08x <%b>\n", cr0
, cr0
, cr0_flag_bits
);
928 mdb_printf("%%cr4 = 0x%08x <%b>\n", cr4
, cr4
, cr4_flag_bits
);
933 static const mdb_dcmd_t dcmds
[] = {
934 { "gate_desc", ":", "dump a gate descriptor", gate_desc
},
935 { "idt", ":[-v]", "dump an IDT", idt
},
936 { "ttrace", "[-x]", "dump trap trace buffers", ttrace
},
937 { "vatopfn", ":[-a as]", "translate address to physical page",
939 { "report_maps", ":[-m]",
940 "Given PFN, report mappings / page table usage",
941 report_maps_dcmd
, report_maps_help
},
942 { "htables", "", "Given hat_t *, lists all its htable_t * values",
943 htables_dcmd
, htables_help
},
944 { "ptable", ":[-m]", "Given PFN, dump contents of a page table",
945 ptable_dcmd
, ptable_help
},
946 { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry",
948 { "pfntomfn", ":", "convert physical page to hypervisor machine page",
950 { "mfntopfn", ":", "convert hypervisor machine page to physical page",
952 { "memseg_list", ":", "show memseg list", memseg_list
},
953 { "scalehrtime", ":",
954 "scale an unscaled high-res time", scalehrtime_cmd
},
955 { "x86_featureset", NULL
, "dump the x86_featureset vector",
956 x86_featureset_cmd
},
958 { "crregs", NULL
, "dump control registers", crregs_dcmd
},
963 static const mdb_walker_t walkers
[] = {
964 { "ttrace", "walks trap trace buffers in reverse chronological order",
965 ttrace_walk_init
, ttrace_walk_step
, ttrace_walk_fini
},
966 { "mutex_owner", "walks the owner of a mutex",
967 mutex_owner_init
, mutex_owner_step
},
968 { "memseg", "walk the memseg structures",
969 memseg_walk_init
, memseg_walk_step
, memseg_walk_fini
},
973 static const mdb_modinfo_t modinfo
= { MDB_API_VERSION
, dcmds
, walkers
};
975 const mdb_modinfo_t
*