17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 225cd376e8SJimmy Vetayases * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23399ca3a7SJohn Levon * Copyright 2018 Joyent, Inc. 24f7b98820SBryan Cantrill */ 25f7b98820SBryan Cantrill 267c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 277c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h> 287c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 297c478bd9Sstevel@tonic-gate #include <sys/systm.h> 307c478bd9Sstevel@tonic-gate #include <sys/traptrace.h> 31ae115bc7Smrj #include <sys/x_call.h> 32f34a7178SJoe Bonasera #include <sys/xc_levels.h> 337c478bd9Sstevel@tonic-gate #include <sys/avintr.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/trap.h> 367c478bd9Sstevel@tonic-gate #include <sys/mutex.h> 377c478bd9Sstevel@tonic-gate #include <sys/mutex_impl.h> 387c478bd9Sstevel@tonic-gate #include "i86mmu.h" 39799823bbSRobert Mustacchi #include "unix_sup.h" 407ff178cdSJimmy Vetayases #include <sys/apix.h> 4129f78cfaSRobert Mustacchi #include <sys/x86_archext.h> 4229f78cfaSRobert Mustacchi #include <sys/bitmap.h> 43799823bbSRobert Mustacchi #include <sys/controlregs.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #define TT_HDLR_WIDTH 17 467c478bd9Sstevel@tonic-gate 477ff178cdSJimmy Vetayases 487ff178cdSJimmy Vetayases /* apix only */ 497ff178cdSJimmy Vetayases static apix_impl_t *d_apixs[NCPU]; 507ff178cdSJimmy Vetayases static int use_apix = 0; 517ff178cdSJimmy Vetayases 527c478bd9Sstevel@tonic-gate static int 537c478bd9Sstevel@tonic-gate ttrace_ttr_size_check(void) 547c478bd9Sstevel@tonic-gate { 557c478bd9Sstevel@tonic-gate mdb_ctf_id_t ttrtid; 567c478bd9Sstevel@tonic-gate ssize_t ttr_size; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || 597c478bd9Sstevel@tonic-gate mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { 607c478bd9Sstevel@tonic-gate mdb_warn("failed to determine size of trap_trace_rec_t; " 617c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 627c478bd9Sstevel@tonic-gate return (0); 637c478bd9Sstevel@tonic-gate } 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate if ((ttr_size = mdb_ctf_type_size(ttrtid)) != 667c478bd9Sstevel@tonic-gate sizeof (trap_trace_rec_t)) { 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * On Intel machines, this will happen when TTR_STACK_DEPTH 697c478bd9Sstevel@tonic-gate * is changed. This code could be smarter, and could 707c478bd9Sstevel@tonic-gate * dynamically adapt to different depths, but not until a 717c478bd9Sstevel@tonic-gate * need for such adaptation is demonstrated. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " 747c478bd9Sstevel@tonic-gate "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); 757c478bd9Sstevel@tonic-gate return (0); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate return (1); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate int 827c478bd9Sstevel@tonic-gate ttrace_walk_init(mdb_walk_state_t *wsp) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttcp; 857c478bd9Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 867c478bd9Sstevel@tonic-gate int i; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 897c478bd9Sstevel@tonic-gate return (WALK_ERR); 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate ttcp = mdb_zalloc(ttc_size, UM_SLEEP); 927c478bd9Sstevel@tonic-gate 93*892ad162SToomas Soome if (wsp->walk_addr != 0) { 947c478bd9Sstevel@tonic-gate mdb_warn("ttrace only supports global walks\n"); 957c478bd9Sstevel@tonic-gate return (WALK_ERR); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { 997c478bd9Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 1007c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 1017c478bd9Sstevel@tonic-gate mdb_free(ttcp, ttc_size); 1027c478bd9Sstevel@tonic-gate return (WALK_ERR); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * We'll poach the ttc_current pointer (which isn't used for 1077c478bd9Sstevel@tonic-gate * anything) to store a pointer to our current TRAPTRACE record. 1087c478bd9Sstevel@tonic-gate * This allows us to only keep the array of trap_trace_ctl structures 1097c478bd9Sstevel@tonic-gate * as our walker state (ttc_current may be the only kernel data 1107c478bd9Sstevel@tonic-gate * structure member added exclusively to make writing the mdb walker 1117c478bd9Sstevel@tonic-gate * a little easier). 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1147c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttc = &ttcp[i]; 1157c478bd9Sstevel@tonic-gate 116*892ad162SToomas Soome if (ttc->ttc_first == 0) 1177c478bd9Sstevel@tonic-gate continue; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Assign ttc_current to be the last completed record. 1217c478bd9Sstevel@tonic-gate * Note that the error checking (i.e. in the ttc_next == 1227c478bd9Sstevel@tonic-gate * ttc_first case) is performed in the step function. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate wsp->walk_data = ttcp; 1287c478bd9Sstevel@tonic-gate return (WALK_NEXT); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate int 1327c478bd9Sstevel@tonic-gate ttrace_walk_step(mdb_walk_state_t *wsp) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc; 1357c478bd9Sstevel@tonic-gate trap_trace_rec_t rec; 1367c478bd9Sstevel@tonic-gate int rval, i, recsize = sizeof (trap_trace_rec_t); 1377c478bd9Sstevel@tonic-gate hrtime_t latest = 0; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Loop through the CPUs, looking for the latest trap trace record 1417c478bd9Sstevel@tonic-gate * (we want to walk through the trap trace records in reverse 1427c478bd9Sstevel@tonic-gate * chronological order). 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1457c478bd9Sstevel@tonic-gate ttc = &ttcp[i]; 1467c478bd9Sstevel@tonic-gate 147*892ad162SToomas Soome if (ttc->ttc_current == 0) 1487c478bd9Sstevel@tonic-gate continue; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate if (ttc->ttc_current < ttc->ttc_first) 1517c478bd9Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_limit - recsize; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1547c478bd9Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1557c478bd9Sstevel@tonic-gate return (WALK_ERR); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (rec.ttr_stamp > latest) { 1597c478bd9Sstevel@tonic-gate latest = rec.ttr_stamp; 1607c478bd9Sstevel@tonic-gate latest_ttc = ttc; 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (latest == 0) 1657c478bd9Sstevel@tonic-gate return (WALK_DONE); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate ttc = latest_ttc; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1707c478bd9Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1717c478bd9Sstevel@tonic-gate return (WALK_ERR); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (ttc->ttc_current == ttc->ttc_next) 177*892ad162SToomas Soome ttc->ttc_current = 0; 1787c478bd9Sstevel@tonic-gate else 1797c478bd9Sstevel@tonic-gate ttc->ttc_current -= sizeof (trap_trace_rec_t); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate return (rval); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate void 1857c478bd9Sstevel@tonic-gate ttrace_walk_fini(mdb_walk_state_t *wsp) 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate static int 1917c478bd9Sstevel@tonic-gate ttrace_syscall(trap_trace_rec_t *rec) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate GElf_Sym sym; 1947c478bd9Sstevel@tonic-gate int sysnum = rec->ttr_sysnum; 1957c478bd9Sstevel@tonic-gate uintptr_t addr; 1967c478bd9Sstevel@tonic-gate struct sysent sys; 1977c478bd9Sstevel@tonic-gate 198ae115bc7Smrj mdb_printf("%-3x", sysnum); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate if (rec->ttr_sysnum > NSYSCALL) { 2017c478bd9Sstevel@tonic-gate mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum); 2027c478bd9Sstevel@tonic-gate return (0); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("sysent", &sym) == -1) { 2067c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't find 'sysent'"); 2077c478bd9Sstevel@tonic-gate return (-1); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent); 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2137c478bd9Sstevel@tonic-gate mdb_warn("\nsysnum %d out-of-range\n", sysnum); 2147c478bd9Sstevel@tonic-gate return (-1); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate if (mdb_vread(&sys, sizeof (sys), addr) == -1) { 2187c478bd9Sstevel@tonic-gate mdb_warn("\nfailed to read sysent at %p", addr); 2197c478bd9Sstevel@tonic-gate return (-1); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate return (0); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static int 2287c478bd9Sstevel@tonic-gate ttrace_interrupt(trap_trace_rec_t *rec) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate GElf_Sym sym; 2317c478bd9Sstevel@tonic-gate uintptr_t addr; 2327c478bd9Sstevel@tonic-gate struct av_head hd; 2337c478bd9Sstevel@tonic-gate struct autovec av; 2347c478bd9Sstevel@tonic-gate 235ae115bc7Smrj switch (rec->ttr_regs.r_trapno) { 236ae115bc7Smrj case T_SOFTINT: 237ae115bc7Smrj mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 2387c478bd9Sstevel@tonic-gate return (0); 239ae115bc7Smrj default: 240ae115bc7Smrj break; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 243ae115bc7Smrj mdb_printf("%-3x ", rec->ttr_vector); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("autovect", &sym) == -1) { 2467c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't find 'autovect'"); 2477c478bd9Sstevel@tonic-gate return (-1); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + 2517c478bd9Sstevel@tonic-gate rec->ttr_vector * sizeof (struct av_head); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2547c478bd9Sstevel@tonic-gate mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector); 2557c478bd9Sstevel@tonic-gate return (-1); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (mdb_vread(&hd, sizeof (hd), addr) == -1) { 2597c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector); 2607c478bd9Sstevel@tonic-gate return (-1); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if (hd.avh_link == NULL) { 264ae115bc7Smrj if (rec->ttr_ipl == XC_CPUPOKE_PIL) 265ae115bc7Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 266ae115bc7Smrj else 2677c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 2687c478bd9Sstevel@tonic-gate } else { 2697c478bd9Sstevel@tonic-gate if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) { 2707c478bd9Sstevel@tonic-gate mdb_warn("couldn't read autovec at %p", 2717c478bd9Sstevel@tonic-gate (uintptr_t)hd.avh_link); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate return (0); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807ff178cdSJimmy Vetayases static int 2817ff178cdSJimmy Vetayases ttrace_apix_interrupt(trap_trace_rec_t *rec) 2827ff178cdSJimmy Vetayases { 2837ff178cdSJimmy Vetayases struct autovec av; 2847ff178cdSJimmy Vetayases apix_impl_t apix; 2857ff178cdSJimmy Vetayases apix_vector_t apix_vector; 2867ff178cdSJimmy Vetayases 2877ff178cdSJimmy Vetayases switch (rec->ttr_regs.r_trapno) { 2887ff178cdSJimmy Vetayases case T_SOFTINT: 2897ff178cdSJimmy Vetayases mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 2907ff178cdSJimmy Vetayases return (0); 2917ff178cdSJimmy Vetayases default: 2927ff178cdSJimmy Vetayases break; 2937ff178cdSJimmy Vetayases } 2947ff178cdSJimmy Vetayases 2957ff178cdSJimmy Vetayases mdb_printf("%-3x ", rec->ttr_vector); 2967ff178cdSJimmy Vetayases 2977ff178cdSJimmy Vetayases /* Read the per CPU apix entry */ 2987ff178cdSJimmy Vetayases if (mdb_vread(&apix, sizeof (apix_impl_t), 2997ff178cdSJimmy Vetayases (uintptr_t)d_apixs[rec->ttr_cpuid]) == -1) { 3007ff178cdSJimmy Vetayases mdb_warn("\ncouldn't read apix[%d]", rec->ttr_cpuid); 3017ff178cdSJimmy Vetayases return (-1); 3027ff178cdSJimmy Vetayases } 3037ff178cdSJimmy Vetayases if (mdb_vread(&apix_vector, sizeof (apix_vector_t), 3047ff178cdSJimmy Vetayases (uintptr_t)apix.x_vectbl[rec->ttr_vector]) == -1) { 3057ff178cdSJimmy Vetayases mdb_warn("\ncouldn't read apix_vector_t[%d]", rec->ttr_vector); 3067ff178cdSJimmy Vetayases return (-1); 3077ff178cdSJimmy Vetayases } 3087ff178cdSJimmy Vetayases if (apix_vector.v_share == 0) { 3097ff178cdSJimmy Vetayases if (rec->ttr_ipl == XC_CPUPOKE_PIL) 3107ff178cdSJimmy Vetayases mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 3117ff178cdSJimmy Vetayases else 3127ff178cdSJimmy Vetayases mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 3137ff178cdSJimmy Vetayases } else { 3147ff178cdSJimmy Vetayases if (mdb_vread(&av, sizeof (struct autovec), 3157ff178cdSJimmy Vetayases (uintptr_t)(apix_vector.v_autovect)) == -1) { 3167ff178cdSJimmy Vetayases mdb_warn("couldn't read autovec at %p", 3177ff178cdSJimmy Vetayases (uintptr_t)apix_vector.v_autovect); 3187ff178cdSJimmy Vetayases } 3197ff178cdSJimmy Vetayases 3207ff178cdSJimmy Vetayases mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 3217ff178cdSJimmy Vetayases } 3227ff178cdSJimmy Vetayases 3237ff178cdSJimmy Vetayases return (0); 3247ff178cdSJimmy Vetayases } 3257ff178cdSJimmy Vetayases 3267ff178cdSJimmy Vetayases 3277c478bd9Sstevel@tonic-gate static struct { 3287c478bd9Sstevel@tonic-gate int tt_trapno; 3297c478bd9Sstevel@tonic-gate char *tt_name; 3307c478bd9Sstevel@tonic-gate } ttrace_traps[] = { 3317c478bd9Sstevel@tonic-gate { T_ZERODIV, "divide-error" }, 3327c478bd9Sstevel@tonic-gate { T_SGLSTP, "debug-exception" }, 3337c478bd9Sstevel@tonic-gate { T_NMIFLT, "nmi-interrupt" }, 3347c478bd9Sstevel@tonic-gate { T_BPTFLT, "breakpoint" }, 3357c478bd9Sstevel@tonic-gate { T_OVFLW, "into-overflow" }, 3367c478bd9Sstevel@tonic-gate { T_BOUNDFLT, "bound-exceeded" }, 3377c478bd9Sstevel@tonic-gate { T_ILLINST, "invalid-opcode" }, 3387c478bd9Sstevel@tonic-gate { T_NOEXTFLT, "device-not-avail" }, 3397c478bd9Sstevel@tonic-gate { T_DBLFLT, "double-fault" }, 3407c478bd9Sstevel@tonic-gate { T_EXTOVRFLT, "segment-overrun" }, 3417c478bd9Sstevel@tonic-gate { T_TSSFLT, "invalid-tss" }, 3427c478bd9Sstevel@tonic-gate { T_SEGFLT, "segment-not-pres" }, 3437c478bd9Sstevel@tonic-gate { T_STKFLT, "stack-fault" }, 3447c478bd9Sstevel@tonic-gate { T_GPFLT, "general-protectn" }, 3457c478bd9Sstevel@tonic-gate { T_PGFLT, "page-fault" }, 3467c478bd9Sstevel@tonic-gate { T_EXTERRFLT, "error-fault" }, 3477c478bd9Sstevel@tonic-gate { T_ALIGNMENT, "alignment-check" }, 3487c478bd9Sstevel@tonic-gate { T_MCE, "machine-check" }, 3497c478bd9Sstevel@tonic-gate { T_SIMDFPE, "sse-exception" }, 350ae115bc7Smrj 351ae115bc7Smrj { T_DBGENTR, "debug-enter" }, 352ae115bc7Smrj { T_FASTTRAP, "fasttrap-0xd2" }, 353ae115bc7Smrj { T_SYSCALLINT, "syscall-0x91" }, 354ae115bc7Smrj { T_DTRACE_RET, "dtrace-ret" }, 355ae115bc7Smrj { T_SOFTINT, "softint" }, 356ae115bc7Smrj { T_INTERRUPT, "interrupt" }, 357ae115bc7Smrj { T_FAULT, "fault" }, 358ae115bc7Smrj { T_AST, "ast" }, 359ae115bc7Smrj { T_SYSCALL, "syscall" }, 360ae115bc7Smrj 3617c478bd9Sstevel@tonic-gate { 0, NULL } 3627c478bd9Sstevel@tonic-gate }; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate static int 3657c478bd9Sstevel@tonic-gate ttrace_trap(trap_trace_rec_t *rec) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate int i; 3687c478bd9Sstevel@tonic-gate 369ae115bc7Smrj if (rec->ttr_regs.r_trapno == T_AST) 370ae115bc7Smrj mdb_printf("%-3s ", "-"); 371ae115bc7Smrj else 372ae115bc7Smrj mdb_printf("%-3x ", rec->ttr_regs.r_trapno); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate for (i = 0; ttrace_traps[i].tt_name != NULL; i++) { 3757c478bd9Sstevel@tonic-gate if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno) 3767c478bd9Sstevel@tonic-gate break; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (ttrace_traps[i].tt_name == NULL) 3807c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 3817c478bd9Sstevel@tonic-gate else 3827c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate return (0); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 387ae115bc7Smrj static void 388ae115bc7Smrj ttrace_intr_detail(trap_trace_rec_t *rec) 389ae115bc7Smrj { 390ae115bc7Smrj mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector, 391ae115bc7Smrj rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl); 392ae115bc7Smrj } 393ae115bc7Smrj 394ae115bc7Smrj static struct { 3957c478bd9Sstevel@tonic-gate uchar_t t_marker; 3967c478bd9Sstevel@tonic-gate char *t_name; 3977c478bd9Sstevel@tonic-gate int (*t_hdlr)(trap_trace_rec_t *); 3987c478bd9Sstevel@tonic-gate } ttrace_hdlr[] = { 3997c478bd9Sstevel@tonic-gate { TT_SYSCALL, "sysc", ttrace_syscall }, 4007c478bd9Sstevel@tonic-gate { TT_SYSENTER, "syse", ttrace_syscall }, 4017c478bd9Sstevel@tonic-gate { TT_SYSC, "asys", ttrace_syscall }, 4027c478bd9Sstevel@tonic-gate { TT_SYSC64, "sc64", ttrace_syscall }, 4037c478bd9Sstevel@tonic-gate { TT_INTERRUPT, "intr", ttrace_interrupt }, 4047c478bd9Sstevel@tonic-gate { TT_TRAP, "trap", ttrace_trap }, 405ae115bc7Smrj { TT_EVENT, "evnt", ttrace_trap }, 4067c478bd9Sstevel@tonic-gate { 0, NULL, NULL } 4077c478bd9Sstevel@tonic-gate }; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate typedef struct ttrace_dcmd { 4107c478bd9Sstevel@tonic-gate processorid_t ttd_cpu; 4117c478bd9Sstevel@tonic-gate uint_t ttd_extended; 412399ca3a7SJohn Levon uintptr_t ttd_kthread; 4137c478bd9Sstevel@tonic-gate trap_trace_ctl_t ttd_ttc[NCPU]; 4147c478bd9Sstevel@tonic-gate } ttrace_dcmd_t; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate #if defined(__amd64) 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 4197c478bd9Sstevel@tonic-gate #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n" 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate static void 4227c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx)); 4277c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9)); 4287c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp)); 4297c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12)); 4307c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15)); 431ae115bc7Smrj mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs)); 432ae115bc7Smrj mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err)); 433ae115bc7Smrj mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl)); 434ae115bc7Smrj mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2); 43574ecdb51SJohn Levon mdb_printf(" %3s: %16lx %3s: %16lx\n", 43674ecdb51SJohn Levon "fsb", regs->__r_fsbase, 43774ecdb51SJohn Levon "gsb", regs->__r_gsbase); 4387c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate #else 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 4447c478bd9Sstevel@tonic-gate #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n" 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate static void 4477c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 4487c478bd9Sstevel@tonic-gate { 4497c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds)); 4527c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp)); 4537c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax)); 4547c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err), 4557c478bd9Sstevel@tonic-gate DUMP(pc), DUMP(cs)); 4567c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss), 4577c478bd9Sstevel@tonic-gate "cr2", rec->ttr_cr2); 4587c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate #endif /* __amd64 */ 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate int 4647c478bd9Sstevel@tonic-gate ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd) 4657c478bd9Sstevel@tonic-gate { 4667c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4677c478bd9Sstevel@tonic-gate processorid_t cpu = -1, i; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 4707c478bd9Sstevel@tonic-gate if (addr >= dcmd->ttd_ttc[i].ttc_first && 4717c478bd9Sstevel@tonic-gate addr < dcmd->ttd_ttc[i].ttc_limit) { 4727c478bd9Sstevel@tonic-gate cpu = i; 4737c478bd9Sstevel@tonic-gate break; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (cpu == -1) { 4787c478bd9Sstevel@tonic-gate mdb_warn("couldn't find %p in any trap trace ctl\n", addr); 4797c478bd9Sstevel@tonic-gate return (WALK_ERR); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu) 4837c478bd9Sstevel@tonic-gate return (WALK_NEXT); 4847c478bd9Sstevel@tonic-gate 485399ca3a7SJohn Levon if (dcmd->ttd_kthread != 0 && 486399ca3a7SJohn Levon dcmd->ttd_kthread != rec->ttr_curthread) 487399ca3a7SJohn Levon return (WALK_NEXT); 488399ca3a7SJohn Levon 4897c478bd9Sstevel@tonic-gate mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) { 4927c478bd9Sstevel@tonic-gate if (rec->ttr_marker != ttrace_hdlr[i].t_marker) 4937c478bd9Sstevel@tonic-gate continue; 4947c478bd9Sstevel@tonic-gate mdb_printf("%4s ", ttrace_hdlr[i].t_name); 4957c478bd9Sstevel@tonic-gate if (ttrace_hdlr[i].t_hdlr(rec) == -1) 4967c478bd9Sstevel@tonic-gate return (WALK_ERR); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate mdb_printf(" %a\n", regs->r_pc); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate if (dcmd->ttd_extended == FALSE) 5027c478bd9Sstevel@tonic-gate return (WALK_NEXT); 5037c478bd9Sstevel@tonic-gate 504f34a7178SJoe Bonasera if (rec->ttr_marker == TT_INTERRUPT) 505ae115bc7Smrj ttrace_intr_detail(rec); 506ae115bc7Smrj else 5077c478bd9Sstevel@tonic-gate ttrace_dumpregs(rec); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (rec->ttr_sdepth > 0) { 5107c478bd9Sstevel@tonic-gate for (i = 0; i < rec->ttr_sdepth; i++) { 5117c478bd9Sstevel@tonic-gate if (i >= TTR_STACK_DEPTH) { 5127c478bd9Sstevel@tonic-gate mdb_printf("%17s*** invalid ttr_sdepth (is %d, " 5137c478bd9Sstevel@tonic-gate "should be <= %d)\n", " ", rec->ttr_sdepth, 5147c478bd9Sstevel@tonic-gate TTR_STACK_DEPTH); 5157c478bd9Sstevel@tonic-gate break; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate mdb_printf("\n"); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate return (WALK_NEXT); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate int 5277c478bd9Sstevel@tonic-gate ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate ttrace_dcmd_t dcmd; 5307c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttc = dcmd.ttd_ttc; 5317c478bd9Sstevel@tonic-gate trap_trace_rec_t rec; 5327c478bd9Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 5357c478bd9Sstevel@tonic-gate return (WALK_ERR); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate bzero(&dcmd, sizeof (dcmd)); 5387c478bd9Sstevel@tonic-gate dcmd.ttd_cpu = -1; 5397c478bd9Sstevel@tonic-gate dcmd.ttd_extended = FALSE; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { 5427c478bd9Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 5437c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 5447c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 548399ca3a7SJohn Levon 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, 549399ca3a7SJohn Levon 't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc) 5507c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 5537c478bd9Sstevel@tonic-gate mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", 554ae115bc7Smrj "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", 5557c478bd9Sstevel@tonic-gate " EIP"); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 5597c478bd9Sstevel@tonic-gate if (addr >= NCPU) { 5607c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), addr) == -1) { 5617c478bd9Sstevel@tonic-gate mdb_warn("couldn't read trap trace record " 5627c478bd9Sstevel@tonic-gate "at %p", addr); 5637c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) 5677c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate return (DCMD_OK); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate dcmd.ttd_cpu = addr; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate 5747ff178cdSJimmy Vetayases if (mdb_readvar(&use_apix, "apix_enable") == -1) { 5757ff178cdSJimmy Vetayases mdb_warn("failed to read apix_enable"); 5767ff178cdSJimmy Vetayases use_apix = 0; 5777ff178cdSJimmy Vetayases } 5787ff178cdSJimmy Vetayases 5797ff178cdSJimmy Vetayases if (use_apix) { 5807ff178cdSJimmy Vetayases if (mdb_readvar(&d_apixs, "apixs") == -1) { 5817ff178cdSJimmy Vetayases mdb_warn("\nfailed to read apixs."); 5827ff178cdSJimmy Vetayases return (DCMD_ERR); 5837ff178cdSJimmy Vetayases } 5847ff178cdSJimmy Vetayases /* change to apix ttrace interrupt handler */ 5857ff178cdSJimmy Vetayases ttrace_hdlr[4].t_hdlr = ttrace_apix_interrupt; 5867ff178cdSJimmy Vetayases } 5877ff178cdSJimmy Vetayases 5887c478bd9Sstevel@tonic-gate if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { 5897c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk 'ttrace'"); 5907c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate return (DCMD_OK); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5977c478bd9Sstevel@tonic-gate int 5987c478bd9Sstevel@tonic-gate mutex_owner_init(mdb_walk_state_t *wsp) 5997c478bd9Sstevel@tonic-gate { 6007c478bd9Sstevel@tonic-gate return (WALK_NEXT); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate int 6047c478bd9Sstevel@tonic-gate mutex_owner_step(mdb_walk_state_t *wsp) 6057c478bd9Sstevel@tonic-gate { 6067c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 6077c478bd9Sstevel@tonic-gate mutex_impl_t mtx; 6087c478bd9Sstevel@tonic-gate uintptr_t owner; 6097c478bd9Sstevel@tonic-gate kthread_t thr; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 6127c478bd9Sstevel@tonic-gate return (WALK_ERR); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 6157c478bd9Sstevel@tonic-gate return (WALK_DONE); 6167c478bd9Sstevel@tonic-gate 617*892ad162SToomas Soome if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == 0) 6187c478bd9Sstevel@tonic-gate return (WALK_DONE); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate if (mdb_vread(&thr, sizeof (thr), owner) != -1) 6217c478bd9Sstevel@tonic-gate (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate return (WALK_DONE); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate static void 6277c478bd9Sstevel@tonic-gate gate_desc_dump(gate_desc_t *gate, const char *label, int header) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate const char *lastnm; 6307c478bd9Sstevel@tonic-gate uint_t lastval; 6317c478bd9Sstevel@tonic-gate char type[4]; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate switch (gate->sgd_type) { 6347c478bd9Sstevel@tonic-gate case SDT_SYSIGT: 6357c478bd9Sstevel@tonic-gate strcpy(type, "int"); 6367c478bd9Sstevel@tonic-gate break; 6377c478bd9Sstevel@tonic-gate case SDT_SYSTGT: 6387c478bd9Sstevel@tonic-gate strcpy(type, "trp"); 6397c478bd9Sstevel@tonic-gate break; 6407c478bd9Sstevel@tonic-gate case SDT_SYSTASKGT: 6417c478bd9Sstevel@tonic-gate strcpy(type, "tsk"); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate default: 6447c478bd9Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate #if defined(__amd64) 6487c478bd9Sstevel@tonic-gate lastnm = "IST"; 6497c478bd9Sstevel@tonic-gate lastval = gate->sgd_ist; 6507c478bd9Sstevel@tonic-gate #else 6517c478bd9Sstevel@tonic-gate lastnm = "STK"; 6527c478bd9Sstevel@tonic-gate lastval = gate->sgd_stkcpy; 6537c478bd9Sstevel@tonic-gate #endif 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (header) { 6567c478bd9Sstevel@tonic-gate mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> " 6577c478bd9Sstevel@tonic-gate "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label), 6587c478bd9Sstevel@tonic-gate "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate mdb_printf("%s", label); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if (gate->sgd_type == SDT_SYSTASKGT) 6647c478bd9Sstevel@tonic-gate mdb_printf("%-30s ", "-"); 6657c478bd9Sstevel@tonic-gate else 6667c478bd9Sstevel@tonic-gate mdb_printf("%-30a ", GATESEG_GETOFFSET(gate)); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector, 6697c478bd9Sstevel@tonic-gate gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6737c478bd9Sstevel@tonic-gate static int 6747c478bd9Sstevel@tonic-gate gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6757c478bd9Sstevel@tonic-gate { 6767c478bd9Sstevel@tonic-gate gate_desc_t gate; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 6797c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 6827c478bd9Sstevel@tonic-gate sizeof (gate_desc_t)) { 6837c478bd9Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", addr); 6847c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags)); 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate return (DCMD_OK); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6937c478bd9Sstevel@tonic-gate static int 6947c478bd9Sstevel@tonic-gate idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6957c478bd9Sstevel@tonic-gate { 6967c478bd9Sstevel@tonic-gate int i; 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 699ac19272fSjosephb GElf_Sym idt0_va; 700ac19272fSjosephb gate_desc_t *idt0; 7017c478bd9Sstevel@tonic-gate 702ac19272fSjosephb if (mdb_lookup_by_name("idt0", &idt0_va) < 0) { 703ac19272fSjosephb mdb_warn("failed to find VA of idt0"); 7047c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 707ac19272fSjosephb addr = idt0_va.st_value; 708ac19272fSjosephb if (mdb_vread(&idt0, sizeof (idt0), addr) != sizeof (idt0)) { 709ac19272fSjosephb mdb_warn("failed to read idt0 at %p\n", addr); 710ac19272fSjosephb return (DCMD_ERR); 711ac19272fSjosephb } 712ac19272fSjosephb 713ac19272fSjosephb addr = (uintptr_t)idt0; 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) { 7177c478bd9Sstevel@tonic-gate gate_desc_t gate; 7187c478bd9Sstevel@tonic-gate char label[6]; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 7217c478bd9Sstevel@tonic-gate sizeof (gate_desc_t)) { 7227c478bd9Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", 7237c478bd9Sstevel@tonic-gate addr); 7247c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate (void) mdb_snprintf(label, sizeof (label), "%3d: ", i); 7287c478bd9Sstevel@tonic-gate gate_desc_dump(&gate, label, i == 0); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate return (DCMD_OK); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 734ae115bc7Smrj static void 735ae115bc7Smrj htables_help(void) 736ae115bc7Smrj { 737ae115bc7Smrj mdb_printf( 738ae115bc7Smrj "Given a (hat_t *), generates the list of all (htable_t *)s\n" 739ae115bc7Smrj "that correspond to that address space\n"); 740ae115bc7Smrj } 741ae115bc7Smrj 742ae115bc7Smrj static void 743ae115bc7Smrj report_maps_help(void) 744ae115bc7Smrj { 745ae115bc7Smrj mdb_printf( 746ae115bc7Smrj "Given a PFN, report HAT structures that map the page, or use\n" 747ae115bc7Smrj "the page as a pagetable.\n" 748ae115bc7Smrj "\n" 749843e1988Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 750ae115bc7Smrj } 751ae115bc7Smrj 752ae115bc7Smrj static void 753ae115bc7Smrj ptable_help(void) 754ae115bc7Smrj { 755ae115bc7Smrj mdb_printf( 756ae115bc7Smrj "Given a PFN holding a page table, print its contents, and\n" 757ae115bc7Smrj "the address of the corresponding htable structure.\n" 758ae115bc7Smrj "\n" 75974ecdb51SJohn Levon "-m Interpret the PFN as an MFN (machine frame number)\n" 76074ecdb51SJohn Levon "-l force page table level (3 is top)\n"); 76174ecdb51SJohn Levon } 76274ecdb51SJohn Levon 76374ecdb51SJohn Levon static void 76474ecdb51SJohn Levon ptmap_help(void) 76574ecdb51SJohn Levon { 76674ecdb51SJohn Levon mdb_printf( 76774ecdb51SJohn Levon "Report all mappings represented by the page table hierarchy\n" 76874ecdb51SJohn Levon "rooted at the given cr3 value / physical address.\n" 76974ecdb51SJohn Levon "\n" 77074ecdb51SJohn Levon "-w run ::whatis on mapping start addresses\n"); 771ae115bc7Smrj } 772ae115bc7Smrj 773f7b98820SBryan Cantrill /* 774f7b98820SBryan Cantrill * NSEC_SHIFT is replicated here (it is not defined in a header file), 775f7b98820SBryan Cantrill * but for amusement, the reader is directed to the comment that explains 776f7b98820SBryan Cantrill * the rationale for this particular value on x86. Spoiler: the value is 777f7b98820SBryan Cantrill * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice 778f7b98820SBryan Cantrill * in that comment sounds too familiar, it's because your author also wrote 779f7b98820SBryan Cantrill * that code -- some fifteen years prior to this writing in 2011...) 780f7b98820SBryan Cantrill */ 781f7b98820SBryan Cantrill #define NSEC_SHIFT 5 782f7b98820SBryan Cantrill 783f7b98820SBryan Cantrill /*ARGSUSED*/ 784f7b98820SBryan Cantrill static int 785f7b98820SBryan Cantrill scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 786f7b98820SBryan Cantrill { 787f7b98820SBryan Cantrill uint32_t nsec_scale; 788f7b98820SBryan Cantrill hrtime_t tsc = addr, hrt; 789f7b98820SBryan Cantrill unsigned int *tscp = (unsigned int *)&tsc; 790f7b98820SBryan Cantrill uintptr_t scalehrtimef; 791f7b98820SBryan Cantrill uint64_t scale; 792f7b98820SBryan Cantrill GElf_Sym sym; 793f7b98820SBryan Cantrill 794f7b98820SBryan Cantrill if (!(flags & DCMD_ADDRSPEC)) { 795f7b98820SBryan Cantrill if (argc != 1) 796f7b98820SBryan Cantrill return (DCMD_USAGE); 797f7b98820SBryan Cantrill 798f7b98820SBryan Cantrill switch (argv[0].a_type) { 799f7b98820SBryan Cantrill case MDB_TYPE_STRING: 800f7b98820SBryan Cantrill tsc = mdb_strtoull(argv[0].a_un.a_str); 801f7b98820SBryan Cantrill break; 802f7b98820SBryan Cantrill case MDB_TYPE_IMMEDIATE: 803f7b98820SBryan Cantrill tsc = argv[0].a_un.a_val; 804f7b98820SBryan Cantrill break; 805f7b98820SBryan Cantrill default: 806f7b98820SBryan Cantrill return (DCMD_USAGE); 807f7b98820SBryan Cantrill } 808f7b98820SBryan Cantrill } 809f7b98820SBryan Cantrill 810f7b98820SBryan Cantrill if (mdb_readsym(&scalehrtimef, 811f7b98820SBryan Cantrill sizeof (scalehrtimef), "scalehrtimef") == -1) { 812f7b98820SBryan Cantrill mdb_warn("couldn't read 'scalehrtimef'"); 813f7b98820SBryan Cantrill return (DCMD_ERR); 814f7b98820SBryan Cantrill } 815f7b98820SBryan Cantrill 816f7b98820SBryan Cantrill if (mdb_lookup_by_name("tsc_scalehrtime", &sym) == -1) { 817f7b98820SBryan Cantrill mdb_warn("couldn't find 'tsc_scalehrtime'"); 818f7b98820SBryan Cantrill return (DCMD_ERR); 819f7b98820SBryan Cantrill } 820f7b98820SBryan Cantrill 821f7b98820SBryan Cantrill if (sym.st_value != scalehrtimef) { 822f7b98820SBryan Cantrill mdb_warn("::scalehrtime requires that scalehrtimef " 823f7b98820SBryan Cantrill "be set to tsc_scalehrtime\n"); 824f7b98820SBryan Cantrill return (DCMD_ERR); 825f7b98820SBryan Cantrill } 826f7b98820SBryan Cantrill 827f7b98820SBryan Cantrill if (mdb_readsym(&nsec_scale, sizeof (nsec_scale), "nsec_scale") == -1) { 828f7b98820SBryan Cantrill mdb_warn("couldn't read 'nsec_scale'"); 829f7b98820SBryan Cantrill return (DCMD_ERR); 830f7b98820SBryan Cantrill } 831f7b98820SBryan Cantrill 832f7b98820SBryan Cantrill scale = (uint64_t)nsec_scale; 833f7b98820SBryan Cantrill 834f7b98820SBryan Cantrill hrt = ((uint64_t)tscp[1] * scale) << NSEC_SHIFT; 835f7b98820SBryan Cantrill hrt += ((uint64_t)tscp[0] * scale) >> (32 - NSEC_SHIFT); 836f7b98820SBryan Cantrill 837f7b98820SBryan Cantrill mdb_printf("0x%llx\n", hrt); 838f7b98820SBryan Cantrill 839f7b98820SBryan Cantrill return (DCMD_OK); 840f7b98820SBryan Cantrill } 841f7b98820SBryan Cantrill 84229f78cfaSRobert Mustacchi /* 84329f78cfaSRobert Mustacchi * The x86 feature set is implemented as a bitmap array. That bitmap array is 84429f78cfaSRobert Mustacchi * stored across a number of uchars based on the BT_SIZEOFMAP(NUM_X86_FEATURES) 84529f78cfaSRobert Mustacchi * macro. We have the names for each of these features in unix's text segment 84629f78cfaSRobert Mustacchi * so we do not have to duplicate them and instead just look them up. 84729f78cfaSRobert Mustacchi */ 84829f78cfaSRobert Mustacchi /*ARGSUSED*/ 84929f78cfaSRobert Mustacchi static int 85029f78cfaSRobert Mustacchi x86_featureset_cmd(uintptr_t addr, uint_t flags, int argc, 85129f78cfaSRobert Mustacchi const mdb_arg_t *argv) 85229f78cfaSRobert Mustacchi { 85329f78cfaSRobert Mustacchi void *fset; 85429f78cfaSRobert Mustacchi GElf_Sym sym; 85529f78cfaSRobert Mustacchi uintptr_t nptr; 85629f78cfaSRobert Mustacchi char name[128]; 85729f78cfaSRobert Mustacchi int ii; 85829f78cfaSRobert Mustacchi 85929f78cfaSRobert Mustacchi size_t sz = sizeof (uchar_t) * BT_SIZEOFMAP(NUM_X86_FEATURES); 86029f78cfaSRobert Mustacchi 86129f78cfaSRobert Mustacchi if (argc != 0) 86229f78cfaSRobert Mustacchi return (DCMD_USAGE); 86329f78cfaSRobert Mustacchi 86429f78cfaSRobert Mustacchi if (mdb_lookup_by_name("x86_feature_names", &sym) == -1) { 86529f78cfaSRobert Mustacchi mdb_warn("couldn't find x86_feature_names"); 86629f78cfaSRobert Mustacchi return (DCMD_ERR); 86729f78cfaSRobert Mustacchi } 86829f78cfaSRobert Mustacchi 86929f78cfaSRobert Mustacchi fset = mdb_zalloc(sz, UM_NOSLEEP); 87029f78cfaSRobert Mustacchi if (fset == NULL) { 87129f78cfaSRobert Mustacchi mdb_warn("failed to allocate memory for x86_featureset"); 87229f78cfaSRobert Mustacchi return (DCMD_ERR); 87329f78cfaSRobert Mustacchi } 87429f78cfaSRobert Mustacchi 87529f78cfaSRobert Mustacchi if (mdb_readvar(fset, "x86_featureset") != sz) { 87629f78cfaSRobert Mustacchi mdb_warn("failed to read x86_featureset"); 87729f78cfaSRobert Mustacchi mdb_free(fset, sz); 87829f78cfaSRobert Mustacchi return (DCMD_ERR); 87929f78cfaSRobert Mustacchi } 88029f78cfaSRobert Mustacchi 88129f78cfaSRobert Mustacchi for (ii = 0; ii < NUM_X86_FEATURES; ii++) { 88229f78cfaSRobert Mustacchi if (!BT_TEST((ulong_t *)fset, ii)) 88329f78cfaSRobert Mustacchi continue; 88429f78cfaSRobert Mustacchi 88529f78cfaSRobert Mustacchi if (mdb_vread(&nptr, sizeof (char *), sym.st_value + 88629f78cfaSRobert Mustacchi sizeof (void *) * ii) != sizeof (char *)) { 88729f78cfaSRobert Mustacchi mdb_warn("failed to read feature array %d", ii); 88829f78cfaSRobert Mustacchi mdb_free(fset, sz); 88929f78cfaSRobert Mustacchi return (DCMD_ERR); 89029f78cfaSRobert Mustacchi } 89129f78cfaSRobert Mustacchi 89229f78cfaSRobert Mustacchi if (mdb_readstr(name, sizeof (name), nptr) == -1) { 89329f78cfaSRobert Mustacchi mdb_warn("failed to read feature %d", ii); 89429f78cfaSRobert Mustacchi mdb_free(fset, sz); 89529f78cfaSRobert Mustacchi return (DCMD_ERR); 89629f78cfaSRobert Mustacchi } 89729f78cfaSRobert Mustacchi mdb_printf("%s\n", name); 89829f78cfaSRobert Mustacchi } 89929f78cfaSRobert Mustacchi 90029f78cfaSRobert Mustacchi mdb_free(fset, sz); 90129f78cfaSRobert Mustacchi return (DCMD_OK); 90229f78cfaSRobert Mustacchi } 90329f78cfaSRobert Mustacchi 904799823bbSRobert Mustacchi #ifdef _KMDB 905799823bbSRobert Mustacchi /* ARGSUSED */ 906799823bbSRobert Mustacchi static int 907309b04b8SJohn Levon sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 908799823bbSRobert Mustacchi { 909399ca3a7SJohn Levon ulong_t cr0, cr2, cr3, cr4; 910309b04b8SJohn Levon desctbr_t gdtr; 911309b04b8SJohn Levon 912799823bbSRobert Mustacchi static const mdb_bitmask_t cr0_flag_bits[] = { 913799823bbSRobert Mustacchi { "PE", CR0_PE, CR0_PE }, 914799823bbSRobert Mustacchi { "MP", CR0_MP, CR0_MP }, 915799823bbSRobert Mustacchi { "EM", CR0_EM, CR0_EM }, 916799823bbSRobert Mustacchi { "TS", CR0_TS, CR0_TS }, 917799823bbSRobert Mustacchi { "ET", CR0_ET, CR0_ET }, 918799823bbSRobert Mustacchi { "NE", CR0_NE, CR0_NE }, 919799823bbSRobert Mustacchi { "WP", CR0_WP, CR0_WP }, 920799823bbSRobert Mustacchi { "AM", CR0_AM, CR0_AM }, 921799823bbSRobert Mustacchi { "NW", CR0_NW, CR0_NW }, 922799823bbSRobert Mustacchi { "CD", CR0_CD, CR0_CD }, 923799823bbSRobert Mustacchi { "PG", CR0_PG, CR0_PG }, 924799823bbSRobert Mustacchi { NULL, 0, 0 } 925799823bbSRobert Mustacchi }; 926799823bbSRobert Mustacchi 927399ca3a7SJohn Levon static const mdb_bitmask_t cr3_flag_bits[] = { 928399ca3a7SJohn Levon { "PCD", CR3_PCD, CR3_PCD }, 929399ca3a7SJohn Levon { "PWT", CR3_PWT, CR3_PWT }, 930399ca3a7SJohn Levon { NULL, 0, 0, } 931399ca3a7SJohn Levon }; 932399ca3a7SJohn Levon 933799823bbSRobert Mustacchi static const mdb_bitmask_t cr4_flag_bits[] = { 934799823bbSRobert Mustacchi { "VME", CR4_VME, CR4_VME }, 935799823bbSRobert Mustacchi { "PVI", CR4_PVI, CR4_PVI }, 936799823bbSRobert Mustacchi { "TSD", CR4_TSD, CR4_TSD }, 937799823bbSRobert Mustacchi { "DE", CR4_DE, CR4_DE }, 938799823bbSRobert Mustacchi { "PSE", CR4_PSE, CR4_PSE }, 939799823bbSRobert Mustacchi { "PAE", CR4_PAE, CR4_PAE }, 940799823bbSRobert Mustacchi { "MCE", CR4_MCE, CR4_MCE }, 941799823bbSRobert Mustacchi { "PGE", CR4_PGE, CR4_PGE }, 942799823bbSRobert Mustacchi { "PCE", CR4_PCE, CR4_PCE }, 943799823bbSRobert Mustacchi { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR }, 944799823bbSRobert Mustacchi { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT }, 945799823bbSRobert Mustacchi { "VMXE", CR4_VMXE, CR4_VMXE }, 946799823bbSRobert Mustacchi { "SMXE", CR4_SMXE, CR4_SMXE }, 947399ca3a7SJohn Levon { "PCIDE", CR4_PCIDE, CR4_PCIDE }, 948799823bbSRobert Mustacchi { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE }, 949799823bbSRobert Mustacchi { "SMEP", CR4_SMEP, CR4_SMEP }, 9503ce2fcdcSRobert Mustacchi { "SMAP", CR4_SMAP, CR4_SMAP }, 951799823bbSRobert Mustacchi { NULL, 0, 0 } 952799823bbSRobert Mustacchi }; 953799823bbSRobert Mustacchi 954799823bbSRobert Mustacchi cr0 = kmdb_unix_getcr0(); 955399ca3a7SJohn Levon cr2 = kmdb_unix_getcr2(); 956399ca3a7SJohn Levon cr3 = kmdb_unix_getcr3(); 957799823bbSRobert Mustacchi cr4 = kmdb_unix_getcr4(); 958309b04b8SJohn Levon 959309b04b8SJohn Levon kmdb_unix_getgdtr(&gdtr); 960309b04b8SJohn Levon 96174ecdb51SJohn Levon mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits); 96274ecdb51SJohn Levon mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2); 963399ca3a7SJohn Levon 964399ca3a7SJohn Levon if ((cr4 & CR4_PCIDE)) { 96574ecdb51SJohn Levon mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3, 966399ca3a7SJohn Levon cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET); 967399ca3a7SJohn Levon } else { 96874ecdb51SJohn Levon mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3, 969399ca3a7SJohn Levon cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits); 970399ca3a7SJohn Levon } 971399ca3a7SJohn Levon 97274ecdb51SJohn Levon mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits); 973399ca3a7SJohn Levon 974309b04b8SJohn Levon mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n", 975309b04b8SJohn Levon gdtr.dtr_base, gdtr.dtr_limit); 976309b04b8SJohn Levon 977799823bbSRobert Mustacchi return (DCMD_OK); 978799823bbSRobert Mustacchi } 979799823bbSRobert Mustacchi #endif 980799823bbSRobert Mustacchi 9817c478bd9Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = { 9827c478bd9Sstevel@tonic-gate { "gate_desc", ":", "dump a gate descriptor", gate_desc }, 9837c478bd9Sstevel@tonic-gate { "idt", ":[-v]", "dump an IDT", idt }, 984399ca3a7SJohn Levon { "ttrace", "[-x] [-t kthread]", "dump trap trace buffers", ttrace }, 9857c478bd9Sstevel@tonic-gate { "vatopfn", ":[-a as]", "translate address to physical page", 9867c478bd9Sstevel@tonic-gate va2pfn_dcmd }, 987ae115bc7Smrj { "report_maps", ":[-m]", 988ae115bc7Smrj "Given PFN, report mappings / page table usage", 989ae115bc7Smrj report_maps_dcmd, report_maps_help }, 990ae115bc7Smrj { "htables", "", "Given hat_t *, lists all its htable_t * values", 991ae115bc7Smrj htables_dcmd, htables_help }, 99274ecdb51SJohn Levon { "ptable", ":[-lm]", "Given PFN, dump contents of a page table", 993ae115bc7Smrj ptable_dcmd, ptable_help }, 99474ecdb51SJohn Levon { "ptmap", ":", "Given a cr3 value, dump all mappings", 99574ecdb51SJohn Levon ptmap_dcmd, ptmap_help }, 99674ecdb51SJohn Levon { "pte", ":[-l N]", "print human readable page table entry", 9977c478bd9Sstevel@tonic-gate pte_dcmd }, 998843e1988Sjohnlev { "pfntomfn", ":", "convert physical page to hypervisor machine page", 999843e1988Sjohnlev pfntomfn_dcmd }, 1000843e1988Sjohnlev { "mfntopfn", ":", "convert hypervisor machine page to physical page", 1001843e1988Sjohnlev mfntopfn_dcmd }, 10027c478bd9Sstevel@tonic-gate { "memseg_list", ":", "show memseg list", memseg_list }, 1003f7b98820SBryan Cantrill { "scalehrtime", ":", 1004f7b98820SBryan Cantrill "scale an unscaled high-res time", scalehrtime_cmd }, 100529f78cfaSRobert Mustacchi { "x86_featureset", NULL, "dump the x86_featureset vector", 100629f78cfaSRobert Mustacchi x86_featureset_cmd }, 1007799823bbSRobert Mustacchi #ifdef _KMDB 1008309b04b8SJohn Levon { "sysregs", NULL, "dump system registers", sysregs_dcmd }, 1009799823bbSRobert Mustacchi #endif 10107c478bd9Sstevel@tonic-gate { NULL } 10117c478bd9Sstevel@tonic-gate }; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate static const mdb_walker_t walkers[] = { 10147c478bd9Sstevel@tonic-gate { "ttrace", "walks trap trace buffers in reverse chronological order", 10157c478bd9Sstevel@tonic-gate ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 10167c478bd9Sstevel@tonic-gate { "mutex_owner", "walks the owner of a mutex", 10177c478bd9Sstevel@tonic-gate mutex_owner_init, mutex_owner_step }, 10187c478bd9Sstevel@tonic-gate { "memseg", "walk the memseg structures", 10197c478bd9Sstevel@tonic-gate memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 10207c478bd9Sstevel@tonic-gate { NULL } 10217c478bd9Sstevel@tonic-gate }; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate const mdb_modinfo_t * 10267c478bd9Sstevel@tonic-gate _mdb_init(void) 10277c478bd9Sstevel@tonic-gate { 10287c478bd9Sstevel@tonic-gate return (&modinfo); 10297c478bd9Sstevel@tonic-gate } 1030843e1988Sjohnlev 1031843e1988Sjohnlev void 1032843e1988Sjohnlev _mdb_fini(void) 1033843e1988Sjohnlev { 1034843e1988Sjohnlev free_mmu(); 1035843e1988Sjohnlev } 1036