10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 223446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 290Sstevel@tonic-gate #include <mdb/mdb_ctf.h> 300Sstevel@tonic-gate #include <sys/cpuvar.h> 310Sstevel@tonic-gate #include <sys/systm.h> 320Sstevel@tonic-gate #include <sys/traptrace.h> 333446Smrj #include <sys/x_call.h> 340Sstevel@tonic-gate #include <sys/avintr.h> 350Sstevel@tonic-gate #include <sys/systm.h> 360Sstevel@tonic-gate #include <sys/trap.h> 370Sstevel@tonic-gate #include <sys/mutex.h> 380Sstevel@tonic-gate #include <sys/mutex_impl.h> 390Sstevel@tonic-gate #include "i86mmu.h" 400Sstevel@tonic-gate 410Sstevel@tonic-gate #define TT_HDLR_WIDTH 17 420Sstevel@tonic-gate 430Sstevel@tonic-gate static int 440Sstevel@tonic-gate ttrace_ttr_size_check(void) 450Sstevel@tonic-gate { 460Sstevel@tonic-gate mdb_ctf_id_t ttrtid; 470Sstevel@tonic-gate ssize_t ttr_size; 480Sstevel@tonic-gate 490Sstevel@tonic-gate if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || 500Sstevel@tonic-gate mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { 510Sstevel@tonic-gate mdb_warn("failed to determine size of trap_trace_rec_t; " 520Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 530Sstevel@tonic-gate return (0); 540Sstevel@tonic-gate } 550Sstevel@tonic-gate 560Sstevel@tonic-gate if ((ttr_size = mdb_ctf_type_size(ttrtid)) != 570Sstevel@tonic-gate sizeof (trap_trace_rec_t)) { 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * On Intel machines, this will happen when TTR_STACK_DEPTH 600Sstevel@tonic-gate * is changed. This code could be smarter, and could 610Sstevel@tonic-gate * dynamically adapt to different depths, but not until a 620Sstevel@tonic-gate * need for such adaptation is demonstrated. 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " 650Sstevel@tonic-gate "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); 660Sstevel@tonic-gate return (0); 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate return (1); 700Sstevel@tonic-gate } 710Sstevel@tonic-gate 720Sstevel@tonic-gate int 730Sstevel@tonic-gate ttrace_walk_init(mdb_walk_state_t *wsp) 740Sstevel@tonic-gate { 750Sstevel@tonic-gate trap_trace_ctl_t *ttcp; 760Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 770Sstevel@tonic-gate int i; 780Sstevel@tonic-gate 790Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 800Sstevel@tonic-gate return (WALK_ERR); 810Sstevel@tonic-gate 820Sstevel@tonic-gate ttcp = mdb_zalloc(ttc_size, UM_SLEEP); 830Sstevel@tonic-gate 840Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 850Sstevel@tonic-gate mdb_warn("ttrace only supports global walks\n"); 860Sstevel@tonic-gate return (WALK_ERR); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { 900Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 910Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 920Sstevel@tonic-gate mdb_free(ttcp, ttc_size); 930Sstevel@tonic-gate return (WALK_ERR); 940Sstevel@tonic-gate } 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * We'll poach the ttc_current pointer (which isn't used for 980Sstevel@tonic-gate * anything) to store a pointer to our current TRAPTRACE record. 990Sstevel@tonic-gate * This allows us to only keep the array of trap_trace_ctl structures 1000Sstevel@tonic-gate * as our walker state (ttc_current may be the only kernel data 1010Sstevel@tonic-gate * structure member added exclusively to make writing the mdb walker 1020Sstevel@tonic-gate * a little easier). 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1050Sstevel@tonic-gate trap_trace_ctl_t *ttc = &ttcp[i]; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (ttc->ttc_first == NULL) 1080Sstevel@tonic-gate continue; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * Assign ttc_current to be the last completed record. 1120Sstevel@tonic-gate * Note that the error checking (i.e. in the ttc_next == 1130Sstevel@tonic-gate * ttc_first case) is performed in the step function. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate wsp->walk_data = ttcp; 1190Sstevel@tonic-gate return (WALK_NEXT); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate int 1230Sstevel@tonic-gate ttrace_walk_step(mdb_walk_state_t *wsp) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc; 1260Sstevel@tonic-gate trap_trace_rec_t rec; 1270Sstevel@tonic-gate int rval, i, recsize = sizeof (trap_trace_rec_t); 1280Sstevel@tonic-gate hrtime_t latest = 0; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Loop through the CPUs, looking for the latest trap trace record 1320Sstevel@tonic-gate * (we want to walk through the trap trace records in reverse 1330Sstevel@tonic-gate * chronological order). 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1360Sstevel@tonic-gate ttc = &ttcp[i]; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate if (ttc->ttc_current == NULL) 1390Sstevel@tonic-gate continue; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (ttc->ttc_current < ttc->ttc_first) 1420Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_limit - recsize; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1450Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1460Sstevel@tonic-gate return (WALK_ERR); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate if (rec.ttr_stamp > latest) { 1500Sstevel@tonic-gate latest = rec.ttr_stamp; 1510Sstevel@tonic-gate latest_ttc = ttc; 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if (latest == 0) 1560Sstevel@tonic-gate return (WALK_DONE); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate ttc = latest_ttc; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1610Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1620Sstevel@tonic-gate return (WALK_ERR); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (ttc->ttc_current == ttc->ttc_next) 1680Sstevel@tonic-gate ttc->ttc_current = NULL; 1690Sstevel@tonic-gate else 1700Sstevel@tonic-gate ttc->ttc_current -= sizeof (trap_trace_rec_t); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate return (rval); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate void 1760Sstevel@tonic-gate ttrace_walk_fini(mdb_walk_state_t *wsp) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate static int 1820Sstevel@tonic-gate ttrace_syscall(trap_trace_rec_t *rec) 1830Sstevel@tonic-gate { 1840Sstevel@tonic-gate GElf_Sym sym; 1850Sstevel@tonic-gate int sysnum = rec->ttr_sysnum; 1860Sstevel@tonic-gate uintptr_t addr; 1870Sstevel@tonic-gate struct sysent sys; 1880Sstevel@tonic-gate 1893446Smrj mdb_printf("%-3x", sysnum); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if (rec->ttr_sysnum > NSYSCALL) { 1923446Smrj mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum); 1930Sstevel@tonic-gate return (0); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (mdb_lookup_by_name("sysent", &sym) == -1) { 1970Sstevel@tonic-gate mdb_warn("\ncouldn't find 'sysent'"); 1980Sstevel@tonic-gate return (-1); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2040Sstevel@tonic-gate mdb_warn("\nsysnum %d out-of-range\n", sysnum); 2050Sstevel@tonic-gate return (-1); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate if (mdb_vread(&sys, sizeof (sys), addr) == -1) { 2090Sstevel@tonic-gate mdb_warn("\nfailed to read sysent at %p", addr); 2100Sstevel@tonic-gate return (-1); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2133446Smrj mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate return (0); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate static int 2190Sstevel@tonic-gate ttrace_interrupt(trap_trace_rec_t *rec) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate GElf_Sym sym; 2220Sstevel@tonic-gate uintptr_t addr; 2230Sstevel@tonic-gate struct av_head hd; 2240Sstevel@tonic-gate struct autovec av; 2250Sstevel@tonic-gate 2263446Smrj switch (rec->ttr_regs.r_trapno) { 2273446Smrj case T_SOFTINT: 2283446Smrj mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 2290Sstevel@tonic-gate return (0); 2303446Smrj default: 2313446Smrj break; 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2343446Smrj mdb_printf("%-3x ", rec->ttr_vector); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (mdb_lookup_by_name("autovect", &sym) == -1) { 2370Sstevel@tonic-gate mdb_warn("\ncouldn't find 'autovect'"); 2380Sstevel@tonic-gate return (-1); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + 2420Sstevel@tonic-gate rec->ttr_vector * sizeof (struct av_head); 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2450Sstevel@tonic-gate mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector); 2460Sstevel@tonic-gate return (-1); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (mdb_vread(&hd, sizeof (hd), addr) == -1) { 2500Sstevel@tonic-gate mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector); 2510Sstevel@tonic-gate return (-1); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate if (hd.avh_link == NULL) { 2553446Smrj if (rec->ttr_ipl == XC_CPUPOKE_PIL) 2563446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 2573446Smrj else 2583446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 2590Sstevel@tonic-gate } else { 2600Sstevel@tonic-gate if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) { 2610Sstevel@tonic-gate mdb_warn("couldn't read autovec at %p", 2620Sstevel@tonic-gate (uintptr_t)hd.avh_link); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate return (0); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate static struct { 2720Sstevel@tonic-gate int tt_trapno; 2730Sstevel@tonic-gate char *tt_name; 2740Sstevel@tonic-gate } ttrace_traps[] = { 2750Sstevel@tonic-gate { T_ZERODIV, "divide-error" }, 2760Sstevel@tonic-gate { T_SGLSTP, "debug-exception" }, 2770Sstevel@tonic-gate { T_NMIFLT, "nmi-interrupt" }, 2780Sstevel@tonic-gate { T_BPTFLT, "breakpoint" }, 2790Sstevel@tonic-gate { T_OVFLW, "into-overflow" }, 2800Sstevel@tonic-gate { T_BOUNDFLT, "bound-exceeded" }, 2810Sstevel@tonic-gate { T_ILLINST, "invalid-opcode" }, 2820Sstevel@tonic-gate { T_NOEXTFLT, "device-not-avail" }, 2830Sstevel@tonic-gate { T_DBLFLT, "double-fault" }, 2840Sstevel@tonic-gate { T_EXTOVRFLT, "segment-overrun" }, 2850Sstevel@tonic-gate { T_TSSFLT, "invalid-tss" }, 2860Sstevel@tonic-gate { T_SEGFLT, "segment-not-pres" }, 2870Sstevel@tonic-gate { T_STKFLT, "stack-fault" }, 2880Sstevel@tonic-gate { T_GPFLT, "general-protectn" }, 2890Sstevel@tonic-gate { T_PGFLT, "page-fault" }, 2900Sstevel@tonic-gate { T_EXTERRFLT, "error-fault" }, 2910Sstevel@tonic-gate { T_ALIGNMENT, "alignment-check" }, 2920Sstevel@tonic-gate { T_MCE, "machine-check" }, 2930Sstevel@tonic-gate { T_SIMDFPE, "sse-exception" }, 2943446Smrj 2953446Smrj { T_DBGENTR, "debug-enter" }, 2963446Smrj { T_FASTTRAP, "fasttrap-0xd2" }, 2973446Smrj { T_SYSCALLINT, "syscall-0x91" }, 2983446Smrj { T_DTRACE_RET, "dtrace-ret" }, 2993446Smrj { T_SOFTINT, "softint" }, 3003446Smrj { T_INTERRUPT, "interrupt" }, 3013446Smrj { T_FAULT, "fault" }, 3023446Smrj { T_AST, "ast" }, 3033446Smrj { T_SYSCALL, "syscall" }, 3043446Smrj 3050Sstevel@tonic-gate { 0, NULL } 3060Sstevel@tonic-gate }; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate static int 3090Sstevel@tonic-gate ttrace_trap(trap_trace_rec_t *rec) 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate int i; 3120Sstevel@tonic-gate 3133446Smrj if (rec->ttr_regs.r_trapno == T_AST) 3143446Smrj mdb_printf("%-3s ", "-"); 3153446Smrj else 3163446Smrj mdb_printf("%-3x ", rec->ttr_regs.r_trapno); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate for (i = 0; ttrace_traps[i].tt_name != NULL; i++) { 3190Sstevel@tonic-gate if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno) 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (ttrace_traps[i].tt_name == NULL) 3240Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 3250Sstevel@tonic-gate else 3260Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate return (0); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate static struct { 3323446Smrj int tt_type; 3333446Smrj char *tt_name; 3343446Smrj } ttrace_xcalls[] = { 3353446Smrj { TT_XC_SVC_BEGIN, "<svc-begin>" }, 3363446Smrj { TT_XC_SVC_END, "<svc-end>" }, 3373446Smrj { TT_XC_START, "<start>" }, 3383446Smrj { TT_XC_WAIT, "<wait>" }, 3393446Smrj { TT_XC_ACK, "<ack>" }, 3403446Smrj { TT_XC_CAPTURE, "<capture>" }, 3413446Smrj { TT_XC_RELEASE, "<release>" }, 3423446Smrj { TT_XC_POKE_CPU, "<poke-cpu>" }, 3433446Smrj { TT_XC_CBE_FIRE, "<cbe-fire>" }, 3443446Smrj { TT_XC_CBE_XCALL, "<cbe-xcall>" }, 3453446Smrj { 0, NULL } 3463446Smrj }; 3473446Smrj 3483446Smrj static int 3493446Smrj ttrace_xcall(trap_trace_rec_t *rec) 3503446Smrj { 3513446Smrj struct _xc_entry *xce = &(rec->ttr_info.xc_entry); 3523446Smrj int i; 3533446Smrj 3543446Smrj for (i = 0; ttrace_xcalls[i].tt_name != NULL; i++) 3553446Smrj if (ttrace_xcalls[i].tt_type == xce->xce_marker) 3563446Smrj break; 3573446Smrj 3583446Smrj switch (xce->xce_marker) { 3593446Smrj case TT_XC_SVC_BEGIN: 3603446Smrj case TT_XC_SVC_END: 3613446Smrj mdb_printf("%3s ", "-"); 3623446Smrj break; 3633446Smrj default: 3643446Smrj mdb_printf("%3x ", (int)xce->xce_arg); 3653446Smrj break; 3663446Smrj } 3673446Smrj 3683446Smrj if (ttrace_xcalls[i].tt_name == NULL) 3693446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 3703446Smrj else 3713446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_xcalls[i].tt_name); 3723446Smrj return (0); 3733446Smrj } 3743446Smrj 3753446Smrj static char * 3763446Smrj xc_pri_to_str(int pri) 3773446Smrj { 3783446Smrj switch (pri) { 3793446Smrj case X_CALL_LOPRI: 3803446Smrj return (" low"); 3813446Smrj case X_CALL_MEDPRI: 3823446Smrj return (" med"); 3833446Smrj case X_CALL_HIPRI: 3843446Smrj return ("high"); 3853446Smrj default: 3863446Smrj return ("bad?"); 3873446Smrj } 3883446Smrj } 3893446Smrj 3903446Smrj static char * 3913446Smrj xc_state_to_str(uint8_t state) 3923446Smrj { 3933446Smrj switch (state) { 3943446Smrj case XC_DONE: 3953446Smrj return ("done"); 3963446Smrj case XC_HOLD: 3973446Smrj return ("hold"); 3983446Smrj case XC_SYNC_OP: 3993446Smrj return ("sync"); 4003446Smrj case XC_CALL_OP: 4013446Smrj return ("call"); 4023446Smrj case XC_WAIT: 4033446Smrj return ("wait"); 4043446Smrj default: 4053446Smrj return ("bad?"); 4063446Smrj } 4073446Smrj } 4083446Smrj 4093446Smrj static void 4103446Smrj ttrace_intr_detail(trap_trace_rec_t *rec) 4113446Smrj { 4123446Smrj mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector, 4133446Smrj rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl); 4143446Smrj } 4153446Smrj 4163446Smrj static void 4173446Smrj ttrace_xcall_detail(trap_trace_rec_t *rec) 4183446Smrj { 4193446Smrj struct _xc_entry *xce = &(rec->ttr_info.xc_entry); 4203446Smrj 4213446Smrj if ((uint_t)xce->xce_pri < X_CALL_LEVELS) 4223446Smrj mdb_printf("\t%s pri [%s] ", xc_pri_to_str(xce->xce_pri), 4233446Smrj xc_state_to_str(xce->xce_state)); 4243446Smrj else 4253446Smrj mdb_printf("\t"); 4263446Smrj 4273446Smrj switch (xce->xce_marker) { 4283446Smrj case TT_XC_SVC_BEGIN: 4293446Smrj if (xce->xce_pri != X_CALL_MEDPRI && xce->xce_func != NULL) 4303446Smrj mdb_printf("call %a() ..", xce->xce_func); 4313446Smrj break; 4323446Smrj case TT_XC_SVC_END: 4333446Smrj if (xce->xce_arg == DDI_INTR_UNCLAIMED) 4343446Smrj mdb_printf("[spurious]"); 4353446Smrj else if (xce->xce_pri != X_CALL_MEDPRI && 4363446Smrj xce->xce_func != NULL) 4373446Smrj mdb_printf(".. called %a() returned %d", 4383446Smrj xce->xce_func, xce->xce_retval); 4393446Smrj break; 4403446Smrj case TT_XC_START: 4413446Smrj case TT_XC_CAPTURE: 4423446Smrj mdb_printf("--> cpu%d", (int)xce->xce_arg); 4433446Smrj break; 4443446Smrj case TT_XC_RELEASE: 4453446Smrj case TT_XC_WAIT: 4463446Smrj case TT_XC_ACK: 4473446Smrj mdb_printf("<-- cpu%d", (int)xce->xce_arg); 4483446Smrj break; 4493446Smrj case TT_XC_POKE_CPU: 4503446Smrj case TT_XC_CBE_FIRE: 4513446Smrj case TT_XC_CBE_XCALL: 4523446Smrj mdb_printf("--> cpu%d", (int)xce->xce_arg); 4533446Smrj break; 4543446Smrj default: 4553446Smrj mdb_printf("tag %d? arg 0x%lx", 4563446Smrj xce->xce_marker, xce->xce_arg); 4573446Smrj break; 4583446Smrj } 4593446Smrj mdb_printf("\n\n"); 4603446Smrj } 4613446Smrj 4623446Smrj static struct { 4630Sstevel@tonic-gate uchar_t t_marker; 4640Sstevel@tonic-gate char *t_name; 4650Sstevel@tonic-gate int (*t_hdlr)(trap_trace_rec_t *); 4660Sstevel@tonic-gate } ttrace_hdlr[] = { 4670Sstevel@tonic-gate { TT_SYSCALL, "sysc", ttrace_syscall }, 4680Sstevel@tonic-gate { TT_SYSENTER, "syse", ttrace_syscall }, 4690Sstevel@tonic-gate { TT_SYSC, "asys", ttrace_syscall }, 4700Sstevel@tonic-gate { TT_SYSC64, "sc64", ttrace_syscall }, 4710Sstevel@tonic-gate { TT_INTERRUPT, "intr", ttrace_interrupt }, 4720Sstevel@tonic-gate { TT_TRAP, "trap", ttrace_trap }, 4733446Smrj { TT_EVENT, "evnt", ttrace_trap }, 4743446Smrj { TT_XCALL, "xcal", ttrace_xcall }, 4750Sstevel@tonic-gate { 0, NULL, NULL } 4760Sstevel@tonic-gate }; 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate typedef struct ttrace_dcmd { 4790Sstevel@tonic-gate processorid_t ttd_cpu; 4800Sstevel@tonic-gate uint_t ttd_extended; 4810Sstevel@tonic-gate trap_trace_ctl_t ttd_ttc[NCPU]; 4820Sstevel@tonic-gate } ttrace_dcmd_t; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate #if defined(__amd64) 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 4870Sstevel@tonic-gate #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n" 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate static void 4900Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx)); 4950Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9)); 4960Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp)); 4970Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12)); 4980Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15)); 4993446Smrj mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs)); 5003446Smrj mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err)); 5013446Smrj mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl)); 5023446Smrj mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2); 5030Sstevel@tonic-gate mdb_printf("\n"); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate #else 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 5090Sstevel@tonic-gate #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n" 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate static void 5120Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds)); 5170Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp)); 5180Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax)); 5190Sstevel@tonic-gate mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err), 5200Sstevel@tonic-gate DUMP(pc), DUMP(cs)); 5210Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss), 5220Sstevel@tonic-gate "cr2", rec->ttr_cr2); 5230Sstevel@tonic-gate mdb_printf("\n"); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate #endif /* __amd64 */ 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate int 5290Sstevel@tonic-gate ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd) 5300Sstevel@tonic-gate { 5310Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 5320Sstevel@tonic-gate processorid_t cpu = -1, i; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 5350Sstevel@tonic-gate if (addr >= dcmd->ttd_ttc[i].ttc_first && 5360Sstevel@tonic-gate addr < dcmd->ttd_ttc[i].ttc_limit) { 5370Sstevel@tonic-gate cpu = i; 5380Sstevel@tonic-gate break; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (cpu == -1) { 5430Sstevel@tonic-gate mdb_warn("couldn't find %p in any trap trace ctl\n", addr); 5440Sstevel@tonic-gate return (WALK_ERR); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu) 5480Sstevel@tonic-gate return (WALK_NEXT); 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) { 5530Sstevel@tonic-gate if (rec->ttr_marker != ttrace_hdlr[i].t_marker) 5540Sstevel@tonic-gate continue; 5550Sstevel@tonic-gate mdb_printf("%4s ", ttrace_hdlr[i].t_name); 5560Sstevel@tonic-gate if (ttrace_hdlr[i].t_hdlr(rec) == -1) 5570Sstevel@tonic-gate return (WALK_ERR); 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 5603446Smrj mdb_printf(" %a\n", regs->r_pc); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate if (dcmd->ttd_extended == FALSE) 5630Sstevel@tonic-gate return (WALK_NEXT); 5640Sstevel@tonic-gate 5653446Smrj if (rec->ttr_marker == TT_XCALL) 5663446Smrj ttrace_xcall_detail(rec); 5673446Smrj else if (rec->ttr_marker == TT_INTERRUPT) 5683446Smrj ttrace_intr_detail(rec); 5693446Smrj else 5703446Smrj ttrace_dumpregs(rec); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if (rec->ttr_sdepth > 0) { 5730Sstevel@tonic-gate for (i = 0; i < rec->ttr_sdepth; i++) { 5740Sstevel@tonic-gate if (i >= TTR_STACK_DEPTH) { 5750Sstevel@tonic-gate mdb_printf("%17s*** invalid ttr_sdepth (is %d, " 5760Sstevel@tonic-gate "should be <= %d)\n", " ", rec->ttr_sdepth, 5770Sstevel@tonic-gate TTR_STACK_DEPTH); 5780Sstevel@tonic-gate break; 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate mdb_printf("\n"); 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate return (WALK_NEXT); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate int 5900Sstevel@tonic-gate ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate ttrace_dcmd_t dcmd; 5930Sstevel@tonic-gate trap_trace_ctl_t *ttc = dcmd.ttd_ttc; 5940Sstevel@tonic-gate trap_trace_rec_t rec; 5950Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 5980Sstevel@tonic-gate return (WALK_ERR); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate bzero(&dcmd, sizeof (dcmd)); 6010Sstevel@tonic-gate dcmd.ttd_cpu = -1; 6020Sstevel@tonic-gate dcmd.ttd_extended = FALSE; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { 6050Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 6060Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 6070Sstevel@tonic-gate return (DCMD_ERR); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate if (mdb_getopts(argc, argv, 6110Sstevel@tonic-gate 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc) 6120Sstevel@tonic-gate return (DCMD_USAGE); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 6150Sstevel@tonic-gate mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", 6163446Smrj "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", 6173446Smrj " EIP"); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 6210Sstevel@tonic-gate if (addr >= NCPU) { 6220Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), addr) == -1) { 6230Sstevel@tonic-gate mdb_warn("couldn't read trap trace record " 6240Sstevel@tonic-gate "at %p", addr); 6250Sstevel@tonic-gate return (DCMD_ERR); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) 6290Sstevel@tonic-gate return (DCMD_ERR); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate return (DCMD_OK); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate dcmd.ttd_cpu = addr; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { 6370Sstevel@tonic-gate mdb_warn("couldn't walk 'ttrace'"); 6380Sstevel@tonic-gate return (DCMD_ERR); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate return (DCMD_OK); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate /*ARGSUSED*/ 6450Sstevel@tonic-gate int 6460Sstevel@tonic-gate mutex_owner_init(mdb_walk_state_t *wsp) 6470Sstevel@tonic-gate { 6480Sstevel@tonic-gate return (WALK_NEXT); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate int 6520Sstevel@tonic-gate mutex_owner_step(mdb_walk_state_t *wsp) 6530Sstevel@tonic-gate { 6540Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 6550Sstevel@tonic-gate mutex_impl_t mtx; 6560Sstevel@tonic-gate uintptr_t owner; 6570Sstevel@tonic-gate kthread_t thr; 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 6600Sstevel@tonic-gate return (WALK_ERR); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 6630Sstevel@tonic-gate return (WALK_DONE); 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL) 6660Sstevel@tonic-gate return (WALK_DONE); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate if (mdb_vread(&thr, sizeof (thr), owner) != -1) 6690Sstevel@tonic-gate (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate return (WALK_DONE); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate static void 6750Sstevel@tonic-gate gate_desc_dump(gate_desc_t *gate, const char *label, int header) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate const char *lastnm; 6780Sstevel@tonic-gate uint_t lastval; 6790Sstevel@tonic-gate char type[4]; 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate switch (gate->sgd_type) { 6820Sstevel@tonic-gate case SDT_SYSIGT: 6830Sstevel@tonic-gate strcpy(type, "int"); 6840Sstevel@tonic-gate break; 6850Sstevel@tonic-gate case SDT_SYSTGT: 6860Sstevel@tonic-gate strcpy(type, "trp"); 6870Sstevel@tonic-gate break; 6880Sstevel@tonic-gate case SDT_SYSTASKGT: 6890Sstevel@tonic-gate strcpy(type, "tsk"); 6900Sstevel@tonic-gate break; 6910Sstevel@tonic-gate default: 6920Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate #if defined(__amd64) 6960Sstevel@tonic-gate lastnm = "IST"; 6970Sstevel@tonic-gate lastval = gate->sgd_ist; 6980Sstevel@tonic-gate #else 6990Sstevel@tonic-gate lastnm = "STK"; 7000Sstevel@tonic-gate lastval = gate->sgd_stkcpy; 7010Sstevel@tonic-gate #endif 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if (header) { 7040Sstevel@tonic-gate mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> " 7050Sstevel@tonic-gate "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label), 7060Sstevel@tonic-gate "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm); 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate mdb_printf("%s", label); 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (gate->sgd_type == SDT_SYSTASKGT) 7120Sstevel@tonic-gate mdb_printf("%-30s ", "-"); 7130Sstevel@tonic-gate else 7140Sstevel@tonic-gate mdb_printf("%-30a ", GATESEG_GETOFFSET(gate)); 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector, 7170Sstevel@tonic-gate gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate /*ARGSUSED*/ 7210Sstevel@tonic-gate static int 7220Sstevel@tonic-gate gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7230Sstevel@tonic-gate { 7240Sstevel@tonic-gate gate_desc_t gate; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 7270Sstevel@tonic-gate return (DCMD_USAGE); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 7300Sstevel@tonic-gate sizeof (gate_desc_t)) { 7310Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", addr); 7320Sstevel@tonic-gate return (DCMD_ERR); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags)); 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate return (DCMD_OK); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /*ARGSUSED*/ 7410Sstevel@tonic-gate static int 7420Sstevel@tonic-gate idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7430Sstevel@tonic-gate { 7440Sstevel@tonic-gate int i; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 7470Sstevel@tonic-gate GElf_Sym idt; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (mdb_lookup_by_name("idt0", &idt) < 0) { 7500Sstevel@tonic-gate mdb_warn("failed to find idt0"); 7510Sstevel@tonic-gate return (DCMD_ERR); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate addr = idt.st_value; 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) { 7580Sstevel@tonic-gate gate_desc_t gate; 7590Sstevel@tonic-gate char label[6]; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 7620Sstevel@tonic-gate sizeof (gate_desc_t)) { 7630Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", 7640Sstevel@tonic-gate addr); 7650Sstevel@tonic-gate return (DCMD_ERR); 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate (void) mdb_snprintf(label, sizeof (label), "%3d: ", i); 7690Sstevel@tonic-gate gate_desc_dump(&gate, label, i == 0); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate return (DCMD_OK); 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate 7753446Smrj static void 7763446Smrj htables_help(void) 7773446Smrj { 7783446Smrj mdb_printf( 7793446Smrj "Given a (hat_t *), generates the list of all (htable_t *)s\n" 7803446Smrj "that correspond to that address space\n"); 7813446Smrj } 7823446Smrj 7833446Smrj static void 7843446Smrj report_maps_help(void) 7853446Smrj { 7863446Smrj mdb_printf( 7873446Smrj "Given a PFN, report HAT structures that map the page, or use\n" 7883446Smrj "the page as a pagetable.\n" 7893446Smrj "\n" 790*5084Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 7913446Smrj } 7923446Smrj 7933446Smrj static void 7943446Smrj ptable_help(void) 7953446Smrj { 7963446Smrj mdb_printf( 7973446Smrj "Given a PFN holding a page table, print its contents, and\n" 7983446Smrj "the address of the corresponding htable structure.\n" 7993446Smrj "\n" 800*5084Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 8013446Smrj } 8023446Smrj 8030Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = { 8040Sstevel@tonic-gate { "gate_desc", ":", "dump a gate descriptor", gate_desc }, 8050Sstevel@tonic-gate { "idt", ":[-v]", "dump an IDT", idt }, 8060Sstevel@tonic-gate { "ttrace", "[-x]", "dump trap trace buffers", ttrace }, 8070Sstevel@tonic-gate { "vatopfn", ":[-a as]", "translate address to physical page", 8080Sstevel@tonic-gate va2pfn_dcmd }, 8093446Smrj { "report_maps", ":[-m]", 8103446Smrj "Given PFN, report mappings / page table usage", 8113446Smrj report_maps_dcmd, report_maps_help }, 8123446Smrj { "htables", "", "Given hat_t *, lists all its htable_t * values", 8133446Smrj htables_dcmd, htables_help }, 8143446Smrj { "ptable", ":[-m]", "Given PFN, dump contents of a page table", 8153446Smrj ptable_dcmd, ptable_help }, 8160Sstevel@tonic-gate { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry", 8170Sstevel@tonic-gate pte_dcmd }, 8180Sstevel@tonic-gate { "page_num2pp", ":", "page frame number to page structure", 8190Sstevel@tonic-gate page_num2pp }, 820*5084Sjohnlev { "pfntomfn", ":", "convert physical page to hypervisor machine page", 821*5084Sjohnlev pfntomfn_dcmd }, 822*5084Sjohnlev { "mfntopfn", ":", "convert hypervisor machine page to physical page", 823*5084Sjohnlev mfntopfn_dcmd }, 8240Sstevel@tonic-gate { "memseg_list", ":", "show memseg list", memseg_list }, 8250Sstevel@tonic-gate { NULL } 8260Sstevel@tonic-gate }; 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate static const mdb_walker_t walkers[] = { 8290Sstevel@tonic-gate { "ttrace", "walks trap trace buffers in reverse chronological order", 8300Sstevel@tonic-gate ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 8310Sstevel@tonic-gate { "mutex_owner", "walks the owner of a mutex", 8320Sstevel@tonic-gate mutex_owner_init, mutex_owner_step }, 8330Sstevel@tonic-gate { "memseg", "walk the memseg structures", 8340Sstevel@tonic-gate memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 8350Sstevel@tonic-gate { NULL } 8360Sstevel@tonic-gate }; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate const mdb_modinfo_t * 8410Sstevel@tonic-gate _mdb_init(void) 8420Sstevel@tonic-gate { 8430Sstevel@tonic-gate return (&modinfo); 8440Sstevel@tonic-gate } 845*5084Sjohnlev 846*5084Sjohnlev void 847*5084Sjohnlev _mdb_fini(void) 848*5084Sjohnlev { 849*5084Sjohnlev free_mmu(); 850*5084Sjohnlev } 851