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 /* 22*12683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 260Sstevel@tonic-gate #include <mdb/mdb_ctf.h> 270Sstevel@tonic-gate #include <sys/cpuvar.h> 280Sstevel@tonic-gate #include <sys/systm.h> 290Sstevel@tonic-gate #include <sys/traptrace.h> 303446Smrj #include <sys/x_call.h> 319489SJoe.Bonasera@sun.com #include <sys/xc_levels.h> 320Sstevel@tonic-gate #include <sys/avintr.h> 330Sstevel@tonic-gate #include <sys/systm.h> 340Sstevel@tonic-gate #include <sys/trap.h> 350Sstevel@tonic-gate #include <sys/mutex.h> 360Sstevel@tonic-gate #include <sys/mutex_impl.h> 370Sstevel@tonic-gate #include "i86mmu.h" 38*12683SJimmy.Vetayases@oracle.com #include <sys/apix.h> 390Sstevel@tonic-gate 400Sstevel@tonic-gate #define TT_HDLR_WIDTH 17 410Sstevel@tonic-gate 42*12683SJimmy.Vetayases@oracle.com 43*12683SJimmy.Vetayases@oracle.com /* apix only */ 44*12683SJimmy.Vetayases@oracle.com static apix_impl_t *d_apixs[NCPU]; 45*12683SJimmy.Vetayases@oracle.com static int use_apix = 0; 46*12683SJimmy.Vetayases@oracle.com 470Sstevel@tonic-gate static int 480Sstevel@tonic-gate ttrace_ttr_size_check(void) 490Sstevel@tonic-gate { 500Sstevel@tonic-gate mdb_ctf_id_t ttrtid; 510Sstevel@tonic-gate ssize_t ttr_size; 520Sstevel@tonic-gate 530Sstevel@tonic-gate if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || 540Sstevel@tonic-gate mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { 550Sstevel@tonic-gate mdb_warn("failed to determine size of trap_trace_rec_t; " 560Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 570Sstevel@tonic-gate return (0); 580Sstevel@tonic-gate } 590Sstevel@tonic-gate 600Sstevel@tonic-gate if ((ttr_size = mdb_ctf_type_size(ttrtid)) != 610Sstevel@tonic-gate sizeof (trap_trace_rec_t)) { 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * On Intel machines, this will happen when TTR_STACK_DEPTH 640Sstevel@tonic-gate * is changed. This code could be smarter, and could 650Sstevel@tonic-gate * dynamically adapt to different depths, but not until a 660Sstevel@tonic-gate * need for such adaptation is demonstrated. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " 690Sstevel@tonic-gate "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); 700Sstevel@tonic-gate return (0); 710Sstevel@tonic-gate } 720Sstevel@tonic-gate 730Sstevel@tonic-gate return (1); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 760Sstevel@tonic-gate int 770Sstevel@tonic-gate ttrace_walk_init(mdb_walk_state_t *wsp) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate trap_trace_ctl_t *ttcp; 800Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 810Sstevel@tonic-gate int i; 820Sstevel@tonic-gate 830Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 840Sstevel@tonic-gate return (WALK_ERR); 850Sstevel@tonic-gate 860Sstevel@tonic-gate ttcp = mdb_zalloc(ttc_size, UM_SLEEP); 870Sstevel@tonic-gate 880Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 890Sstevel@tonic-gate mdb_warn("ttrace only supports global walks\n"); 900Sstevel@tonic-gate return (WALK_ERR); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { 940Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 950Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 960Sstevel@tonic-gate mdb_free(ttcp, ttc_size); 970Sstevel@tonic-gate return (WALK_ERR); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * We'll poach the ttc_current pointer (which isn't used for 1020Sstevel@tonic-gate * anything) to store a pointer to our current TRAPTRACE record. 1030Sstevel@tonic-gate * This allows us to only keep the array of trap_trace_ctl structures 1040Sstevel@tonic-gate * as our walker state (ttc_current may be the only kernel data 1050Sstevel@tonic-gate * structure member added exclusively to make writing the mdb walker 1060Sstevel@tonic-gate * a little easier). 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1090Sstevel@tonic-gate trap_trace_ctl_t *ttc = &ttcp[i]; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate if (ttc->ttc_first == NULL) 1120Sstevel@tonic-gate continue; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * Assign ttc_current to be the last completed record. 1160Sstevel@tonic-gate * Note that the error checking (i.e. in the ttc_next == 1170Sstevel@tonic-gate * ttc_first case) is performed in the step function. 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate wsp->walk_data = ttcp; 1230Sstevel@tonic-gate return (WALK_NEXT); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate int 1270Sstevel@tonic-gate ttrace_walk_step(mdb_walk_state_t *wsp) 1280Sstevel@tonic-gate { 1290Sstevel@tonic-gate trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc; 1300Sstevel@tonic-gate trap_trace_rec_t rec; 1310Sstevel@tonic-gate int rval, i, recsize = sizeof (trap_trace_rec_t); 1320Sstevel@tonic-gate hrtime_t latest = 0; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* 1350Sstevel@tonic-gate * Loop through the CPUs, looking for the latest trap trace record 1360Sstevel@tonic-gate * (we want to walk through the trap trace records in reverse 1370Sstevel@tonic-gate * chronological order). 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1400Sstevel@tonic-gate ttc = &ttcp[i]; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate if (ttc->ttc_current == NULL) 1430Sstevel@tonic-gate continue; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate if (ttc->ttc_current < ttc->ttc_first) 1460Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_limit - recsize; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1490Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1500Sstevel@tonic-gate return (WALK_ERR); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate if (rec.ttr_stamp > latest) { 1540Sstevel@tonic-gate latest = rec.ttr_stamp; 1550Sstevel@tonic-gate latest_ttc = ttc; 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate if (latest == 0) 1600Sstevel@tonic-gate return (WALK_DONE); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate ttc = latest_ttc; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1650Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1660Sstevel@tonic-gate return (WALK_ERR); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate if (ttc->ttc_current == ttc->ttc_next) 1720Sstevel@tonic-gate ttc->ttc_current = NULL; 1730Sstevel@tonic-gate else 1740Sstevel@tonic-gate ttc->ttc_current -= sizeof (trap_trace_rec_t); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate return (rval); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate void 1800Sstevel@tonic-gate ttrace_walk_fini(mdb_walk_state_t *wsp) 1810Sstevel@tonic-gate { 1820Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate static int 1860Sstevel@tonic-gate ttrace_syscall(trap_trace_rec_t *rec) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate GElf_Sym sym; 1890Sstevel@tonic-gate int sysnum = rec->ttr_sysnum; 1900Sstevel@tonic-gate uintptr_t addr; 1910Sstevel@tonic-gate struct sysent sys; 1920Sstevel@tonic-gate 1933446Smrj mdb_printf("%-3x", sysnum); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate if (rec->ttr_sysnum > NSYSCALL) { 1963446Smrj mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum); 1970Sstevel@tonic-gate return (0); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (mdb_lookup_by_name("sysent", &sym) == -1) { 2010Sstevel@tonic-gate mdb_warn("\ncouldn't find 'sysent'"); 2020Sstevel@tonic-gate return (-1); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent); 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2080Sstevel@tonic-gate mdb_warn("\nsysnum %d out-of-range\n", sysnum); 2090Sstevel@tonic-gate return (-1); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate if (mdb_vread(&sys, sizeof (sys), addr) == -1) { 2130Sstevel@tonic-gate mdb_warn("\nfailed to read sysent at %p", addr); 2140Sstevel@tonic-gate return (-1); 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2173446Smrj mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate return (0); 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate static int 2230Sstevel@tonic-gate ttrace_interrupt(trap_trace_rec_t *rec) 2240Sstevel@tonic-gate { 2250Sstevel@tonic-gate GElf_Sym sym; 2260Sstevel@tonic-gate uintptr_t addr; 2270Sstevel@tonic-gate struct av_head hd; 2280Sstevel@tonic-gate struct autovec av; 2290Sstevel@tonic-gate 2303446Smrj switch (rec->ttr_regs.r_trapno) { 2313446Smrj case T_SOFTINT: 2323446Smrj mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 2330Sstevel@tonic-gate return (0); 2343446Smrj default: 2353446Smrj break; 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate 2383446Smrj mdb_printf("%-3x ", rec->ttr_vector); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (mdb_lookup_by_name("autovect", &sym) == -1) { 2410Sstevel@tonic-gate mdb_warn("\ncouldn't find 'autovect'"); 2420Sstevel@tonic-gate return (-1); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + 2460Sstevel@tonic-gate rec->ttr_vector * sizeof (struct av_head); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2490Sstevel@tonic-gate mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector); 2500Sstevel@tonic-gate return (-1); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate if (mdb_vread(&hd, sizeof (hd), addr) == -1) { 2540Sstevel@tonic-gate mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector); 2550Sstevel@tonic-gate return (-1); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (hd.avh_link == NULL) { 2593446Smrj if (rec->ttr_ipl == XC_CPUPOKE_PIL) 2603446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 2613446Smrj else 2623446Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 2630Sstevel@tonic-gate } else { 2640Sstevel@tonic-gate if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) { 2650Sstevel@tonic-gate mdb_warn("couldn't read autovec at %p", 2660Sstevel@tonic-gate (uintptr_t)hd.avh_link); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate return (0); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 275*12683SJimmy.Vetayases@oracle.com static int 276*12683SJimmy.Vetayases@oracle.com ttrace_apix_interrupt(trap_trace_rec_t *rec) 277*12683SJimmy.Vetayases@oracle.com { 278*12683SJimmy.Vetayases@oracle.com struct autovec av; 279*12683SJimmy.Vetayases@oracle.com apix_impl_t apix; 280*12683SJimmy.Vetayases@oracle.com apix_vector_t apix_vector; 281*12683SJimmy.Vetayases@oracle.com 282*12683SJimmy.Vetayases@oracle.com switch (rec->ttr_regs.r_trapno) { 283*12683SJimmy.Vetayases@oracle.com case T_SOFTINT: 284*12683SJimmy.Vetayases@oracle.com mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 285*12683SJimmy.Vetayases@oracle.com return (0); 286*12683SJimmy.Vetayases@oracle.com default: 287*12683SJimmy.Vetayases@oracle.com break; 288*12683SJimmy.Vetayases@oracle.com } 289*12683SJimmy.Vetayases@oracle.com 290*12683SJimmy.Vetayases@oracle.com mdb_printf("%-3x ", rec->ttr_vector); 291*12683SJimmy.Vetayases@oracle.com 292*12683SJimmy.Vetayases@oracle.com /* Read the per CPU apix entry */ 293*12683SJimmy.Vetayases@oracle.com if (mdb_vread(&apix, sizeof (apix_impl_t), 294*12683SJimmy.Vetayases@oracle.com (uintptr_t)d_apixs[rec->ttr_cpuid]) == -1) { 295*12683SJimmy.Vetayases@oracle.com mdb_warn("\ncouldn't read apix[%d]", rec->ttr_cpuid); 296*12683SJimmy.Vetayases@oracle.com return (-1); 297*12683SJimmy.Vetayases@oracle.com } 298*12683SJimmy.Vetayases@oracle.com if (mdb_vread(&apix_vector, sizeof (apix_vector_t), 299*12683SJimmy.Vetayases@oracle.com (uintptr_t)apix.x_vectbl[rec->ttr_vector]) == -1) { 300*12683SJimmy.Vetayases@oracle.com mdb_warn("\ncouldn't read apix_vector_t[%d]", rec->ttr_vector); 301*12683SJimmy.Vetayases@oracle.com return (-1); 302*12683SJimmy.Vetayases@oracle.com } 303*12683SJimmy.Vetayases@oracle.com if (apix_vector.v_share == 0) { 304*12683SJimmy.Vetayases@oracle.com if (rec->ttr_ipl == XC_CPUPOKE_PIL) 305*12683SJimmy.Vetayases@oracle.com mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 306*12683SJimmy.Vetayases@oracle.com else 307*12683SJimmy.Vetayases@oracle.com mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 308*12683SJimmy.Vetayases@oracle.com } else { 309*12683SJimmy.Vetayases@oracle.com if (mdb_vread(&av, sizeof (struct autovec), 310*12683SJimmy.Vetayases@oracle.com (uintptr_t)(apix_vector.v_autovect)) == -1) { 311*12683SJimmy.Vetayases@oracle.com mdb_warn("couldn't read autovec at %p", 312*12683SJimmy.Vetayases@oracle.com (uintptr_t)apix_vector.v_autovect); 313*12683SJimmy.Vetayases@oracle.com } 314*12683SJimmy.Vetayases@oracle.com 315*12683SJimmy.Vetayases@oracle.com mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 316*12683SJimmy.Vetayases@oracle.com } 317*12683SJimmy.Vetayases@oracle.com 318*12683SJimmy.Vetayases@oracle.com return (0); 319*12683SJimmy.Vetayases@oracle.com } 320*12683SJimmy.Vetayases@oracle.com 321*12683SJimmy.Vetayases@oracle.com 3220Sstevel@tonic-gate static struct { 3230Sstevel@tonic-gate int tt_trapno; 3240Sstevel@tonic-gate char *tt_name; 3250Sstevel@tonic-gate } ttrace_traps[] = { 3260Sstevel@tonic-gate { T_ZERODIV, "divide-error" }, 3270Sstevel@tonic-gate { T_SGLSTP, "debug-exception" }, 3280Sstevel@tonic-gate { T_NMIFLT, "nmi-interrupt" }, 3290Sstevel@tonic-gate { T_BPTFLT, "breakpoint" }, 3300Sstevel@tonic-gate { T_OVFLW, "into-overflow" }, 3310Sstevel@tonic-gate { T_BOUNDFLT, "bound-exceeded" }, 3320Sstevel@tonic-gate { T_ILLINST, "invalid-opcode" }, 3330Sstevel@tonic-gate { T_NOEXTFLT, "device-not-avail" }, 3340Sstevel@tonic-gate { T_DBLFLT, "double-fault" }, 3350Sstevel@tonic-gate { T_EXTOVRFLT, "segment-overrun" }, 3360Sstevel@tonic-gate { T_TSSFLT, "invalid-tss" }, 3370Sstevel@tonic-gate { T_SEGFLT, "segment-not-pres" }, 3380Sstevel@tonic-gate { T_STKFLT, "stack-fault" }, 3390Sstevel@tonic-gate { T_GPFLT, "general-protectn" }, 3400Sstevel@tonic-gate { T_PGFLT, "page-fault" }, 3410Sstevel@tonic-gate { T_EXTERRFLT, "error-fault" }, 3420Sstevel@tonic-gate { T_ALIGNMENT, "alignment-check" }, 3430Sstevel@tonic-gate { T_MCE, "machine-check" }, 3440Sstevel@tonic-gate { T_SIMDFPE, "sse-exception" }, 3453446Smrj 3463446Smrj { T_DBGENTR, "debug-enter" }, 3473446Smrj { T_FASTTRAP, "fasttrap-0xd2" }, 3483446Smrj { T_SYSCALLINT, "syscall-0x91" }, 3493446Smrj { T_DTRACE_RET, "dtrace-ret" }, 3503446Smrj { T_SOFTINT, "softint" }, 3513446Smrj { T_INTERRUPT, "interrupt" }, 3523446Smrj { T_FAULT, "fault" }, 3533446Smrj { T_AST, "ast" }, 3543446Smrj { T_SYSCALL, "syscall" }, 3553446Smrj 3560Sstevel@tonic-gate { 0, NULL } 3570Sstevel@tonic-gate }; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate static int 3600Sstevel@tonic-gate ttrace_trap(trap_trace_rec_t *rec) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate int i; 3630Sstevel@tonic-gate 3643446Smrj if (rec->ttr_regs.r_trapno == T_AST) 3653446Smrj mdb_printf("%-3s ", "-"); 3663446Smrj else 3673446Smrj mdb_printf("%-3x ", rec->ttr_regs.r_trapno); 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate for (i = 0; ttrace_traps[i].tt_name != NULL; i++) { 3700Sstevel@tonic-gate if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno) 3710Sstevel@tonic-gate break; 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (ttrace_traps[i].tt_name == NULL) 3750Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 3760Sstevel@tonic-gate else 3770Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate return (0); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3823446Smrj static void 3833446Smrj ttrace_intr_detail(trap_trace_rec_t *rec) 3843446Smrj { 3853446Smrj mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector, 3863446Smrj rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl); 3873446Smrj } 3883446Smrj 3893446Smrj static struct { 3900Sstevel@tonic-gate uchar_t t_marker; 3910Sstevel@tonic-gate char *t_name; 3920Sstevel@tonic-gate int (*t_hdlr)(trap_trace_rec_t *); 3930Sstevel@tonic-gate } ttrace_hdlr[] = { 3940Sstevel@tonic-gate { TT_SYSCALL, "sysc", ttrace_syscall }, 3950Sstevel@tonic-gate { TT_SYSENTER, "syse", ttrace_syscall }, 3960Sstevel@tonic-gate { TT_SYSC, "asys", ttrace_syscall }, 3970Sstevel@tonic-gate { TT_SYSC64, "sc64", ttrace_syscall }, 3980Sstevel@tonic-gate { TT_INTERRUPT, "intr", ttrace_interrupt }, 3990Sstevel@tonic-gate { TT_TRAP, "trap", ttrace_trap }, 4003446Smrj { TT_EVENT, "evnt", ttrace_trap }, 4010Sstevel@tonic-gate { 0, NULL, NULL } 4020Sstevel@tonic-gate }; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate typedef struct ttrace_dcmd { 4050Sstevel@tonic-gate processorid_t ttd_cpu; 4060Sstevel@tonic-gate uint_t ttd_extended; 4070Sstevel@tonic-gate trap_trace_ctl_t ttd_ttc[NCPU]; 4080Sstevel@tonic-gate } ttrace_dcmd_t; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate #if defined(__amd64) 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 4130Sstevel@tonic-gate #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n" 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate static void 4160Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx)); 4210Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9)); 4220Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp)); 4230Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12)); 4240Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15)); 4253446Smrj mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs)); 4263446Smrj mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err)); 4273446Smrj mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl)); 4283446Smrj mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2); 4290Sstevel@tonic-gate mdb_printf("\n"); 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate #else 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 4350Sstevel@tonic-gate #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n" 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate static void 4380Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds)); 4430Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp)); 4440Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax)); 4450Sstevel@tonic-gate mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err), 4460Sstevel@tonic-gate DUMP(pc), DUMP(cs)); 4470Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss), 4480Sstevel@tonic-gate "cr2", rec->ttr_cr2); 4490Sstevel@tonic-gate mdb_printf("\n"); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate #endif /* __amd64 */ 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate int 4550Sstevel@tonic-gate ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd) 4560Sstevel@tonic-gate { 4570Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4580Sstevel@tonic-gate processorid_t cpu = -1, i; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 4610Sstevel@tonic-gate if (addr >= dcmd->ttd_ttc[i].ttc_first && 4620Sstevel@tonic-gate addr < dcmd->ttd_ttc[i].ttc_limit) { 4630Sstevel@tonic-gate cpu = i; 4640Sstevel@tonic-gate break; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate if (cpu == -1) { 4690Sstevel@tonic-gate mdb_warn("couldn't find %p in any trap trace ctl\n", addr); 4700Sstevel@tonic-gate return (WALK_ERR); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu) 4740Sstevel@tonic-gate return (WALK_NEXT); 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) { 4790Sstevel@tonic-gate if (rec->ttr_marker != ttrace_hdlr[i].t_marker) 4800Sstevel@tonic-gate continue; 4810Sstevel@tonic-gate mdb_printf("%4s ", ttrace_hdlr[i].t_name); 4820Sstevel@tonic-gate if (ttrace_hdlr[i].t_hdlr(rec) == -1) 4830Sstevel@tonic-gate return (WALK_ERR); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4863446Smrj mdb_printf(" %a\n", regs->r_pc); 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate if (dcmd->ttd_extended == FALSE) 4890Sstevel@tonic-gate return (WALK_NEXT); 4900Sstevel@tonic-gate 4919489SJoe.Bonasera@sun.com if (rec->ttr_marker == TT_INTERRUPT) 4923446Smrj ttrace_intr_detail(rec); 4933446Smrj else 4943446Smrj ttrace_dumpregs(rec); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate if (rec->ttr_sdepth > 0) { 4970Sstevel@tonic-gate for (i = 0; i < rec->ttr_sdepth; i++) { 4980Sstevel@tonic-gate if (i >= TTR_STACK_DEPTH) { 4990Sstevel@tonic-gate mdb_printf("%17s*** invalid ttr_sdepth (is %d, " 5000Sstevel@tonic-gate "should be <= %d)\n", " ", rec->ttr_sdepth, 5010Sstevel@tonic-gate TTR_STACK_DEPTH); 5020Sstevel@tonic-gate break; 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate mdb_printf("\n"); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate return (WALK_NEXT); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate int 5140Sstevel@tonic-gate ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5150Sstevel@tonic-gate { 5160Sstevel@tonic-gate ttrace_dcmd_t dcmd; 5170Sstevel@tonic-gate trap_trace_ctl_t *ttc = dcmd.ttd_ttc; 5180Sstevel@tonic-gate trap_trace_rec_t rec; 5190Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 5220Sstevel@tonic-gate return (WALK_ERR); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate bzero(&dcmd, sizeof (dcmd)); 5250Sstevel@tonic-gate dcmd.ttd_cpu = -1; 5260Sstevel@tonic-gate dcmd.ttd_extended = FALSE; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { 5290Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 5300Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 5310Sstevel@tonic-gate return (DCMD_ERR); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (mdb_getopts(argc, argv, 5350Sstevel@tonic-gate 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc) 5360Sstevel@tonic-gate return (DCMD_USAGE); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 5390Sstevel@tonic-gate mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", 5403446Smrj "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", 5413446Smrj " EIP"); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 5450Sstevel@tonic-gate if (addr >= NCPU) { 5460Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), addr) == -1) { 5470Sstevel@tonic-gate mdb_warn("couldn't read trap trace record " 5480Sstevel@tonic-gate "at %p", addr); 5490Sstevel@tonic-gate return (DCMD_ERR); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) 5530Sstevel@tonic-gate return (DCMD_ERR); 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate return (DCMD_OK); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate dcmd.ttd_cpu = addr; 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 560*12683SJimmy.Vetayases@oracle.com if (mdb_readvar(&use_apix, "apix_enable") == -1) { 561*12683SJimmy.Vetayases@oracle.com mdb_warn("failed to read apix_enable"); 562*12683SJimmy.Vetayases@oracle.com use_apix = 0; 563*12683SJimmy.Vetayases@oracle.com } 564*12683SJimmy.Vetayases@oracle.com 565*12683SJimmy.Vetayases@oracle.com if (use_apix) { 566*12683SJimmy.Vetayases@oracle.com if (mdb_readvar(&d_apixs, "apixs") == -1) { 567*12683SJimmy.Vetayases@oracle.com mdb_warn("\nfailed to read apixs."); 568*12683SJimmy.Vetayases@oracle.com return (DCMD_ERR); 569*12683SJimmy.Vetayases@oracle.com } 570*12683SJimmy.Vetayases@oracle.com /* change to apix ttrace interrupt handler */ 571*12683SJimmy.Vetayases@oracle.com ttrace_hdlr[4].t_hdlr = ttrace_apix_interrupt; 572*12683SJimmy.Vetayases@oracle.com } 573*12683SJimmy.Vetayases@oracle.com 5740Sstevel@tonic-gate if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { 5750Sstevel@tonic-gate mdb_warn("couldn't walk 'ttrace'"); 5760Sstevel@tonic-gate return (DCMD_ERR); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate return (DCMD_OK); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate /*ARGSUSED*/ 5830Sstevel@tonic-gate int 5840Sstevel@tonic-gate mutex_owner_init(mdb_walk_state_t *wsp) 5850Sstevel@tonic-gate { 5860Sstevel@tonic-gate return (WALK_NEXT); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate int 5900Sstevel@tonic-gate mutex_owner_step(mdb_walk_state_t *wsp) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 5930Sstevel@tonic-gate mutex_impl_t mtx; 5940Sstevel@tonic-gate uintptr_t owner; 5950Sstevel@tonic-gate kthread_t thr; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 5980Sstevel@tonic-gate return (WALK_ERR); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 6010Sstevel@tonic-gate return (WALK_DONE); 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL) 6040Sstevel@tonic-gate return (WALK_DONE); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate if (mdb_vread(&thr, sizeof (thr), owner) != -1) 6070Sstevel@tonic-gate (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate return (WALK_DONE); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate static void 6130Sstevel@tonic-gate gate_desc_dump(gate_desc_t *gate, const char *label, int header) 6140Sstevel@tonic-gate { 6150Sstevel@tonic-gate const char *lastnm; 6160Sstevel@tonic-gate uint_t lastval; 6170Sstevel@tonic-gate char type[4]; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate switch (gate->sgd_type) { 6200Sstevel@tonic-gate case SDT_SYSIGT: 6210Sstevel@tonic-gate strcpy(type, "int"); 6220Sstevel@tonic-gate break; 6230Sstevel@tonic-gate case SDT_SYSTGT: 6240Sstevel@tonic-gate strcpy(type, "trp"); 6250Sstevel@tonic-gate break; 6260Sstevel@tonic-gate case SDT_SYSTASKGT: 6270Sstevel@tonic-gate strcpy(type, "tsk"); 6280Sstevel@tonic-gate break; 6290Sstevel@tonic-gate default: 6300Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate #if defined(__amd64) 6340Sstevel@tonic-gate lastnm = "IST"; 6350Sstevel@tonic-gate lastval = gate->sgd_ist; 6360Sstevel@tonic-gate #else 6370Sstevel@tonic-gate lastnm = "STK"; 6380Sstevel@tonic-gate lastval = gate->sgd_stkcpy; 6390Sstevel@tonic-gate #endif 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if (header) { 6420Sstevel@tonic-gate mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> " 6430Sstevel@tonic-gate "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label), 6440Sstevel@tonic-gate "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate mdb_printf("%s", label); 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (gate->sgd_type == SDT_SYSTASKGT) 6500Sstevel@tonic-gate mdb_printf("%-30s ", "-"); 6510Sstevel@tonic-gate else 6520Sstevel@tonic-gate mdb_printf("%-30a ", GATESEG_GETOFFSET(gate)); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector, 6550Sstevel@tonic-gate gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /*ARGSUSED*/ 6590Sstevel@tonic-gate static int 6600Sstevel@tonic-gate gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6610Sstevel@tonic-gate { 6620Sstevel@tonic-gate gate_desc_t gate; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 6650Sstevel@tonic-gate return (DCMD_USAGE); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 6680Sstevel@tonic-gate sizeof (gate_desc_t)) { 6690Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", addr); 6700Sstevel@tonic-gate return (DCMD_ERR); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags)); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate return (DCMD_OK); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /*ARGSUSED*/ 6790Sstevel@tonic-gate static int 6800Sstevel@tonic-gate idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate int i; 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 6855487Sjosephb GElf_Sym idt0_va; 6865487Sjosephb gate_desc_t *idt0; 6870Sstevel@tonic-gate 6885487Sjosephb if (mdb_lookup_by_name("idt0", &idt0_va) < 0) { 6895487Sjosephb mdb_warn("failed to find VA of idt0"); 6900Sstevel@tonic-gate return (DCMD_ERR); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6935487Sjosephb addr = idt0_va.st_value; 6945487Sjosephb if (mdb_vread(&idt0, sizeof (idt0), addr) != sizeof (idt0)) { 6955487Sjosephb mdb_warn("failed to read idt0 at %p\n", addr); 6965487Sjosephb return (DCMD_ERR); 6975487Sjosephb } 6985487Sjosephb 6995487Sjosephb addr = (uintptr_t)idt0; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) { 7030Sstevel@tonic-gate gate_desc_t gate; 7040Sstevel@tonic-gate char label[6]; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 7070Sstevel@tonic-gate sizeof (gate_desc_t)) { 7080Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", 7090Sstevel@tonic-gate addr); 7100Sstevel@tonic-gate return (DCMD_ERR); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate (void) mdb_snprintf(label, sizeof (label), "%3d: ", i); 7140Sstevel@tonic-gate gate_desc_dump(&gate, label, i == 0); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate return (DCMD_OK); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7203446Smrj static void 7213446Smrj htables_help(void) 7223446Smrj { 7233446Smrj mdb_printf( 7243446Smrj "Given a (hat_t *), generates the list of all (htable_t *)s\n" 7253446Smrj "that correspond to that address space\n"); 7263446Smrj } 7273446Smrj 7283446Smrj static void 7293446Smrj report_maps_help(void) 7303446Smrj { 7313446Smrj mdb_printf( 7323446Smrj "Given a PFN, report HAT structures that map the page, or use\n" 7333446Smrj "the page as a pagetable.\n" 7343446Smrj "\n" 7355084Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 7363446Smrj } 7373446Smrj 7383446Smrj static void 7393446Smrj ptable_help(void) 7403446Smrj { 7413446Smrj mdb_printf( 7423446Smrj "Given a PFN holding a page table, print its contents, and\n" 7433446Smrj "the address of the corresponding htable structure.\n" 7443446Smrj "\n" 7455084Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 7463446Smrj } 7473446Smrj 7480Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = { 7490Sstevel@tonic-gate { "gate_desc", ":", "dump a gate descriptor", gate_desc }, 7500Sstevel@tonic-gate { "idt", ":[-v]", "dump an IDT", idt }, 7510Sstevel@tonic-gate { "ttrace", "[-x]", "dump trap trace buffers", ttrace }, 7520Sstevel@tonic-gate { "vatopfn", ":[-a as]", "translate address to physical page", 7530Sstevel@tonic-gate va2pfn_dcmd }, 7543446Smrj { "report_maps", ":[-m]", 7553446Smrj "Given PFN, report mappings / page table usage", 7563446Smrj report_maps_dcmd, report_maps_help }, 7573446Smrj { "htables", "", "Given hat_t *, lists all its htable_t * values", 7583446Smrj htables_dcmd, htables_help }, 7593446Smrj { "ptable", ":[-m]", "Given PFN, dump contents of a page table", 7603446Smrj ptable_dcmd, ptable_help }, 7610Sstevel@tonic-gate { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry", 7620Sstevel@tonic-gate pte_dcmd }, 7635084Sjohnlev { "pfntomfn", ":", "convert physical page to hypervisor machine page", 7645084Sjohnlev pfntomfn_dcmd }, 7655084Sjohnlev { "mfntopfn", ":", "convert hypervisor machine page to physical page", 7665084Sjohnlev mfntopfn_dcmd }, 7670Sstevel@tonic-gate { "memseg_list", ":", "show memseg list", memseg_list }, 7680Sstevel@tonic-gate { NULL } 7690Sstevel@tonic-gate }; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate static const mdb_walker_t walkers[] = { 7720Sstevel@tonic-gate { "ttrace", "walks trap trace buffers in reverse chronological order", 7730Sstevel@tonic-gate ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 7740Sstevel@tonic-gate { "mutex_owner", "walks the owner of a mutex", 7750Sstevel@tonic-gate mutex_owner_init, mutex_owner_step }, 7760Sstevel@tonic-gate { "memseg", "walk the memseg structures", 7770Sstevel@tonic-gate memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 7780Sstevel@tonic-gate { NULL } 7790Sstevel@tonic-gate }; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate const mdb_modinfo_t * 7840Sstevel@tonic-gate _mdb_init(void) 7850Sstevel@tonic-gate { 7860Sstevel@tonic-gate return (&modinfo); 7870Sstevel@tonic-gate } 7885084Sjohnlev 7895084Sjohnlev void 7905084Sjohnlev _mdb_fini(void) 7915084Sjohnlev { 7925084Sjohnlev free_mmu(); 7935084Sjohnlev } 794