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 /* 22*f34a7178SJoe Bonasera * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 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> 32*f34a7178SJoe 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" 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #define TT_HDLR_WIDTH 17 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate static int 437c478bd9Sstevel@tonic-gate ttrace_ttr_size_check(void) 447c478bd9Sstevel@tonic-gate { 457c478bd9Sstevel@tonic-gate mdb_ctf_id_t ttrtid; 467c478bd9Sstevel@tonic-gate ssize_t ttr_size; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || 497c478bd9Sstevel@tonic-gate mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { 507c478bd9Sstevel@tonic-gate mdb_warn("failed to determine size of trap_trace_rec_t; " 517c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 527c478bd9Sstevel@tonic-gate return (0); 537c478bd9Sstevel@tonic-gate } 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate if ((ttr_size = mdb_ctf_type_size(ttrtid)) != 567c478bd9Sstevel@tonic-gate sizeof (trap_trace_rec_t)) { 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * On Intel machines, this will happen when TTR_STACK_DEPTH 597c478bd9Sstevel@tonic-gate * is changed. This code could be smarter, and could 607c478bd9Sstevel@tonic-gate * dynamically adapt to different depths, but not until a 617c478bd9Sstevel@tonic-gate * need for such adaptation is demonstrated. 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " 647c478bd9Sstevel@tonic-gate "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); 657c478bd9Sstevel@tonic-gate return (0); 667c478bd9Sstevel@tonic-gate } 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate return (1); 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate int 727c478bd9Sstevel@tonic-gate ttrace_walk_init(mdb_walk_state_t *wsp) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttcp; 757c478bd9Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 767c478bd9Sstevel@tonic-gate int i; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 797c478bd9Sstevel@tonic-gate return (WALK_ERR); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate ttcp = mdb_zalloc(ttc_size, UM_SLEEP); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 847c478bd9Sstevel@tonic-gate mdb_warn("ttrace only supports global walks\n"); 857c478bd9Sstevel@tonic-gate return (WALK_ERR); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { 897c478bd9Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 907c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 917c478bd9Sstevel@tonic-gate mdb_free(ttcp, ttc_size); 927c478bd9Sstevel@tonic-gate return (WALK_ERR); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * We'll poach the ttc_current pointer (which isn't used for 977c478bd9Sstevel@tonic-gate * anything) to store a pointer to our current TRAPTRACE record. 987c478bd9Sstevel@tonic-gate * This allows us to only keep the array of trap_trace_ctl structures 997c478bd9Sstevel@tonic-gate * as our walker state (ttc_current may be the only kernel data 1007c478bd9Sstevel@tonic-gate * structure member added exclusively to make writing the mdb walker 1017c478bd9Sstevel@tonic-gate * a little easier). 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1047c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttc = &ttcp[i]; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate if (ttc->ttc_first == NULL) 1077c478bd9Sstevel@tonic-gate continue; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Assign ttc_current to be the last completed record. 1117c478bd9Sstevel@tonic-gate * Note that the error checking (i.e. in the ttc_next == 1127c478bd9Sstevel@tonic-gate * ttc_first case) is performed in the step function. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate wsp->walk_data = ttcp; 1187c478bd9Sstevel@tonic-gate return (WALK_NEXT); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate int 1227c478bd9Sstevel@tonic-gate ttrace_walk_step(mdb_walk_state_t *wsp) 1237c478bd9Sstevel@tonic-gate { 1247c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc; 1257c478bd9Sstevel@tonic-gate trap_trace_rec_t rec; 1267c478bd9Sstevel@tonic-gate int rval, i, recsize = sizeof (trap_trace_rec_t); 1277c478bd9Sstevel@tonic-gate hrtime_t latest = 0; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * Loop through the CPUs, looking for the latest trap trace record 1317c478bd9Sstevel@tonic-gate * (we want to walk through the trap trace records in reverse 1327c478bd9Sstevel@tonic-gate * chronological order). 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1357c478bd9Sstevel@tonic-gate ttc = &ttcp[i]; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (ttc->ttc_current == NULL) 1387c478bd9Sstevel@tonic-gate continue; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate if (ttc->ttc_current < ttc->ttc_first) 1417c478bd9Sstevel@tonic-gate ttc->ttc_current = ttc->ttc_limit - recsize; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1447c478bd9Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1457c478bd9Sstevel@tonic-gate return (WALK_ERR); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate if (rec.ttr_stamp > latest) { 1497c478bd9Sstevel@tonic-gate latest = rec.ttr_stamp; 1507c478bd9Sstevel@tonic-gate latest_ttc = ttc; 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (latest == 0) 1557c478bd9Sstevel@tonic-gate return (WALK_DONE); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate ttc = latest_ttc; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 1607c478bd9Sstevel@tonic-gate mdb_warn("couldn't read rec at %p", ttc->ttc_current); 1617c478bd9Sstevel@tonic-gate return (WALK_ERR); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate if (ttc->ttc_current == ttc->ttc_next) 1677c478bd9Sstevel@tonic-gate ttc->ttc_current = NULL; 1687c478bd9Sstevel@tonic-gate else 1697c478bd9Sstevel@tonic-gate ttc->ttc_current -= sizeof (trap_trace_rec_t); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate return (rval); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate void 1757c478bd9Sstevel@tonic-gate ttrace_walk_fini(mdb_walk_state_t *wsp) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static int 1817c478bd9Sstevel@tonic-gate ttrace_syscall(trap_trace_rec_t *rec) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate GElf_Sym sym; 1847c478bd9Sstevel@tonic-gate int sysnum = rec->ttr_sysnum; 1857c478bd9Sstevel@tonic-gate uintptr_t addr; 1867c478bd9Sstevel@tonic-gate struct sysent sys; 1877c478bd9Sstevel@tonic-gate 188ae115bc7Smrj mdb_printf("%-3x", sysnum); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate if (rec->ttr_sysnum > NSYSCALL) { 1917c478bd9Sstevel@tonic-gate mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum); 1927c478bd9Sstevel@tonic-gate return (0); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("sysent", &sym) == -1) { 1967c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't find 'sysent'"); 1977c478bd9Sstevel@tonic-gate return (-1); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent); 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2037c478bd9Sstevel@tonic-gate mdb_warn("\nsysnum %d out-of-range\n", sysnum); 2047c478bd9Sstevel@tonic-gate return (-1); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (mdb_vread(&sys, sizeof (sys), addr) == -1) { 2087c478bd9Sstevel@tonic-gate mdb_warn("\nfailed to read sysent at %p", addr); 2097c478bd9Sstevel@tonic-gate return (-1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate return (0); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate static int 2187c478bd9Sstevel@tonic-gate ttrace_interrupt(trap_trace_rec_t *rec) 2197c478bd9Sstevel@tonic-gate { 2207c478bd9Sstevel@tonic-gate GElf_Sym sym; 2217c478bd9Sstevel@tonic-gate uintptr_t addr; 2227c478bd9Sstevel@tonic-gate struct av_head hd; 2237c478bd9Sstevel@tonic-gate struct autovec av; 2247c478bd9Sstevel@tonic-gate 225ae115bc7Smrj switch (rec->ttr_regs.r_trapno) { 226ae115bc7Smrj case T_SOFTINT: 227ae115bc7Smrj mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 2287c478bd9Sstevel@tonic-gate return (0); 229ae115bc7Smrj default: 230ae115bc7Smrj break; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 233ae115bc7Smrj mdb_printf("%-3x ", rec->ttr_vector); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("autovect", &sym) == -1) { 2367c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't find 'autovect'"); 2377c478bd9Sstevel@tonic-gate return (-1); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value + 2417c478bd9Sstevel@tonic-gate rec->ttr_vector * sizeof (struct av_head); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 2447c478bd9Sstevel@tonic-gate mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector); 2457c478bd9Sstevel@tonic-gate return (-1); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (mdb_vread(&hd, sizeof (hd), addr) == -1) { 2497c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector); 2507c478bd9Sstevel@tonic-gate return (-1); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if (hd.avh_link == NULL) { 254ae115bc7Smrj if (rec->ttr_ipl == XC_CPUPOKE_PIL) 255ae115bc7Smrj mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 256ae115bc7Smrj else 2577c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 2587c478bd9Sstevel@tonic-gate } else { 2597c478bd9Sstevel@tonic-gate if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) { 2607c478bd9Sstevel@tonic-gate mdb_warn("couldn't read autovec at %p", 2617c478bd9Sstevel@tonic-gate (uintptr_t)hd.avh_link); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate return (0); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate static struct { 2717c478bd9Sstevel@tonic-gate int tt_trapno; 2727c478bd9Sstevel@tonic-gate char *tt_name; 2737c478bd9Sstevel@tonic-gate } ttrace_traps[] = { 2747c478bd9Sstevel@tonic-gate { T_ZERODIV, "divide-error" }, 2757c478bd9Sstevel@tonic-gate { T_SGLSTP, "debug-exception" }, 2767c478bd9Sstevel@tonic-gate { T_NMIFLT, "nmi-interrupt" }, 2777c478bd9Sstevel@tonic-gate { T_BPTFLT, "breakpoint" }, 2787c478bd9Sstevel@tonic-gate { T_OVFLW, "into-overflow" }, 2797c478bd9Sstevel@tonic-gate { T_BOUNDFLT, "bound-exceeded" }, 2807c478bd9Sstevel@tonic-gate { T_ILLINST, "invalid-opcode" }, 2817c478bd9Sstevel@tonic-gate { T_NOEXTFLT, "device-not-avail" }, 2827c478bd9Sstevel@tonic-gate { T_DBLFLT, "double-fault" }, 2837c478bd9Sstevel@tonic-gate { T_EXTOVRFLT, "segment-overrun" }, 2847c478bd9Sstevel@tonic-gate { T_TSSFLT, "invalid-tss" }, 2857c478bd9Sstevel@tonic-gate { T_SEGFLT, "segment-not-pres" }, 2867c478bd9Sstevel@tonic-gate { T_STKFLT, "stack-fault" }, 2877c478bd9Sstevel@tonic-gate { T_GPFLT, "general-protectn" }, 2887c478bd9Sstevel@tonic-gate { T_PGFLT, "page-fault" }, 2897c478bd9Sstevel@tonic-gate { T_EXTERRFLT, "error-fault" }, 2907c478bd9Sstevel@tonic-gate { T_ALIGNMENT, "alignment-check" }, 2917c478bd9Sstevel@tonic-gate { T_MCE, "machine-check" }, 2927c478bd9Sstevel@tonic-gate { T_SIMDFPE, "sse-exception" }, 293ae115bc7Smrj 294ae115bc7Smrj { T_DBGENTR, "debug-enter" }, 295ae115bc7Smrj { T_FASTTRAP, "fasttrap-0xd2" }, 296ae115bc7Smrj { T_SYSCALLINT, "syscall-0x91" }, 297ae115bc7Smrj { T_DTRACE_RET, "dtrace-ret" }, 298ae115bc7Smrj { T_SOFTINT, "softint" }, 299ae115bc7Smrj { T_INTERRUPT, "interrupt" }, 300ae115bc7Smrj { T_FAULT, "fault" }, 301ae115bc7Smrj { T_AST, "ast" }, 302ae115bc7Smrj { T_SYSCALL, "syscall" }, 303ae115bc7Smrj 3047c478bd9Sstevel@tonic-gate { 0, NULL } 3057c478bd9Sstevel@tonic-gate }; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate static int 3087c478bd9Sstevel@tonic-gate ttrace_trap(trap_trace_rec_t *rec) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate int i; 3117c478bd9Sstevel@tonic-gate 312ae115bc7Smrj if (rec->ttr_regs.r_trapno == T_AST) 313ae115bc7Smrj mdb_printf("%-3s ", "-"); 314ae115bc7Smrj else 315ae115bc7Smrj mdb_printf("%-3x ", rec->ttr_regs.r_trapno); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate for (i = 0; ttrace_traps[i].tt_name != NULL; i++) { 3187c478bd9Sstevel@tonic-gate if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno) 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate if (ttrace_traps[i].tt_name == NULL) 3237c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 3247c478bd9Sstevel@tonic-gate else 3257c478bd9Sstevel@tonic-gate mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate return (0); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 330ae115bc7Smrj static void 331ae115bc7Smrj ttrace_intr_detail(trap_trace_rec_t *rec) 332ae115bc7Smrj { 333ae115bc7Smrj mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector, 334ae115bc7Smrj rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl); 335ae115bc7Smrj } 336ae115bc7Smrj 337ae115bc7Smrj static struct { 3387c478bd9Sstevel@tonic-gate uchar_t t_marker; 3397c478bd9Sstevel@tonic-gate char *t_name; 3407c478bd9Sstevel@tonic-gate int (*t_hdlr)(trap_trace_rec_t *); 3417c478bd9Sstevel@tonic-gate } ttrace_hdlr[] = { 3427c478bd9Sstevel@tonic-gate { TT_SYSCALL, "sysc", ttrace_syscall }, 3437c478bd9Sstevel@tonic-gate { TT_SYSENTER, "syse", ttrace_syscall }, 3447c478bd9Sstevel@tonic-gate { TT_SYSC, "asys", ttrace_syscall }, 3457c478bd9Sstevel@tonic-gate { TT_SYSC64, "sc64", ttrace_syscall }, 3467c478bd9Sstevel@tonic-gate { TT_INTERRUPT, "intr", ttrace_interrupt }, 3477c478bd9Sstevel@tonic-gate { TT_TRAP, "trap", ttrace_trap }, 348ae115bc7Smrj { TT_EVENT, "evnt", ttrace_trap }, 3497c478bd9Sstevel@tonic-gate { 0, NULL, NULL } 3507c478bd9Sstevel@tonic-gate }; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate typedef struct ttrace_dcmd { 3537c478bd9Sstevel@tonic-gate processorid_t ttd_cpu; 3547c478bd9Sstevel@tonic-gate uint_t ttd_extended; 3557c478bd9Sstevel@tonic-gate trap_trace_ctl_t ttd_ttc[NCPU]; 3567c478bd9Sstevel@tonic-gate } ttrace_dcmd_t; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate #if defined(__amd64) 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 3617c478bd9Sstevel@tonic-gate #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n" 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate static void 3647c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx)); 3697c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9)); 3707c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp)); 3717c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12)); 3727c478bd9Sstevel@tonic-gate mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15)); 373ae115bc7Smrj mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs)); 374ae115bc7Smrj mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err)); 375ae115bc7Smrj mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl)); 376ae115bc7Smrj mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2); 3777c478bd9Sstevel@tonic-gate mdb_printf("\n"); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate #else 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate #define DUMP(reg) #reg, regs->r_##reg 3837c478bd9Sstevel@tonic-gate #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n" 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate static void 3867c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec) 3877c478bd9Sstevel@tonic-gate { 3887c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds)); 3917c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp)); 3927c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax)); 3937c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err), 3947c478bd9Sstevel@tonic-gate DUMP(pc), DUMP(cs)); 3957c478bd9Sstevel@tonic-gate mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss), 3967c478bd9Sstevel@tonic-gate "cr2", rec->ttr_cr2); 3977c478bd9Sstevel@tonic-gate mdb_printf("\n"); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate #endif /* __amd64 */ 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate int 4037c478bd9Sstevel@tonic-gate ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate struct regs *regs = &rec->ttr_regs; 4067c478bd9Sstevel@tonic-gate processorid_t cpu = -1, i; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 4097c478bd9Sstevel@tonic-gate if (addr >= dcmd->ttd_ttc[i].ttc_first && 4107c478bd9Sstevel@tonic-gate addr < dcmd->ttd_ttc[i].ttc_limit) { 4117c478bd9Sstevel@tonic-gate cpu = i; 4127c478bd9Sstevel@tonic-gate break; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if (cpu == -1) { 4177c478bd9Sstevel@tonic-gate mdb_warn("couldn't find %p in any trap trace ctl\n", addr); 4187c478bd9Sstevel@tonic-gate return (WALK_ERR); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu) 4227c478bd9Sstevel@tonic-gate return (WALK_NEXT); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) { 4277c478bd9Sstevel@tonic-gate if (rec->ttr_marker != ttrace_hdlr[i].t_marker) 4287c478bd9Sstevel@tonic-gate continue; 4297c478bd9Sstevel@tonic-gate mdb_printf("%4s ", ttrace_hdlr[i].t_name); 4307c478bd9Sstevel@tonic-gate if (ttrace_hdlr[i].t_hdlr(rec) == -1) 4317c478bd9Sstevel@tonic-gate return (WALK_ERR); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate mdb_printf(" %a\n", regs->r_pc); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (dcmd->ttd_extended == FALSE) 4377c478bd9Sstevel@tonic-gate return (WALK_NEXT); 4387c478bd9Sstevel@tonic-gate 439*f34a7178SJoe Bonasera if (rec->ttr_marker == TT_INTERRUPT) 440ae115bc7Smrj ttrace_intr_detail(rec); 441ae115bc7Smrj else 4427c478bd9Sstevel@tonic-gate ttrace_dumpregs(rec); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if (rec->ttr_sdepth > 0) { 4457c478bd9Sstevel@tonic-gate for (i = 0; i < rec->ttr_sdepth; i++) { 4467c478bd9Sstevel@tonic-gate if (i >= TTR_STACK_DEPTH) { 4477c478bd9Sstevel@tonic-gate mdb_printf("%17s*** invalid ttr_sdepth (is %d, " 4487c478bd9Sstevel@tonic-gate "should be <= %d)\n", " ", rec->ttr_sdepth, 4497c478bd9Sstevel@tonic-gate TTR_STACK_DEPTH); 4507c478bd9Sstevel@tonic-gate break; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate return (WALK_NEXT); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate int 4627c478bd9Sstevel@tonic-gate ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate ttrace_dcmd_t dcmd; 4657c478bd9Sstevel@tonic-gate trap_trace_ctl_t *ttc = dcmd.ttd_ttc; 4667c478bd9Sstevel@tonic-gate trap_trace_rec_t rec; 4677c478bd9Sstevel@tonic-gate size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (!ttrace_ttr_size_check()) 4707c478bd9Sstevel@tonic-gate return (WALK_ERR); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate bzero(&dcmd, sizeof (dcmd)); 4737c478bd9Sstevel@tonic-gate dcmd.ttd_cpu = -1; 4747c478bd9Sstevel@tonic-gate dcmd.ttd_extended = FALSE; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { 4777c478bd9Sstevel@tonic-gate mdb_warn("symbol 'trap_trace_ctl' not found; " 4787c478bd9Sstevel@tonic-gate "non-TRAPTRACE kernel?\n"); 4797c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 4837c478bd9Sstevel@tonic-gate 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc) 4847c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 4877c478bd9Sstevel@tonic-gate mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", 488ae115bc7Smrj "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", 4897c478bd9Sstevel@tonic-gate " EIP"); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 4937c478bd9Sstevel@tonic-gate if (addr >= NCPU) { 4947c478bd9Sstevel@tonic-gate if (mdb_vread(&rec, sizeof (rec), addr) == -1) { 4957c478bd9Sstevel@tonic-gate mdb_warn("couldn't read trap trace record " 4967c478bd9Sstevel@tonic-gate "at %p", addr); 4977c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) 5017c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate return (DCMD_OK); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate dcmd.ttd_cpu = addr; 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { 5097c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk 'ttrace'"); 5107c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate return (DCMD_OK); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5177c478bd9Sstevel@tonic-gate int 5187c478bd9Sstevel@tonic-gate mutex_owner_init(mdb_walk_state_t *wsp) 5197c478bd9Sstevel@tonic-gate { 5207c478bd9Sstevel@tonic-gate return (WALK_NEXT); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate int 5247c478bd9Sstevel@tonic-gate mutex_owner_step(mdb_walk_state_t *wsp) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 5277c478bd9Sstevel@tonic-gate mutex_impl_t mtx; 5287c478bd9Sstevel@tonic-gate uintptr_t owner; 5297c478bd9Sstevel@tonic-gate kthread_t thr; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 5327c478bd9Sstevel@tonic-gate return (WALK_ERR); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 5357c478bd9Sstevel@tonic-gate return (WALK_DONE); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL) 5387c478bd9Sstevel@tonic-gate return (WALK_DONE); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if (mdb_vread(&thr, sizeof (thr), owner) != -1) 5417c478bd9Sstevel@tonic-gate (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate return (WALK_DONE); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate static void 5477c478bd9Sstevel@tonic-gate gate_desc_dump(gate_desc_t *gate, const char *label, int header) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate const char *lastnm; 5507c478bd9Sstevel@tonic-gate uint_t lastval; 5517c478bd9Sstevel@tonic-gate char type[4]; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate switch (gate->sgd_type) { 5547c478bd9Sstevel@tonic-gate case SDT_SYSIGT: 5557c478bd9Sstevel@tonic-gate strcpy(type, "int"); 5567c478bd9Sstevel@tonic-gate break; 5577c478bd9Sstevel@tonic-gate case SDT_SYSTGT: 5587c478bd9Sstevel@tonic-gate strcpy(type, "trp"); 5597c478bd9Sstevel@tonic-gate break; 5607c478bd9Sstevel@tonic-gate case SDT_SYSTASKGT: 5617c478bd9Sstevel@tonic-gate strcpy(type, "tsk"); 5627c478bd9Sstevel@tonic-gate break; 5637c478bd9Sstevel@tonic-gate default: 5647c478bd9Sstevel@tonic-gate (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate #if defined(__amd64) 5687c478bd9Sstevel@tonic-gate lastnm = "IST"; 5697c478bd9Sstevel@tonic-gate lastval = gate->sgd_ist; 5707c478bd9Sstevel@tonic-gate #else 5717c478bd9Sstevel@tonic-gate lastnm = "STK"; 5727c478bd9Sstevel@tonic-gate lastval = gate->sgd_stkcpy; 5737c478bd9Sstevel@tonic-gate #endif 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if (header) { 5767c478bd9Sstevel@tonic-gate mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> " 5777c478bd9Sstevel@tonic-gate "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label), 5787c478bd9Sstevel@tonic-gate "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate mdb_printf("%s", label); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if (gate->sgd_type == SDT_SYSTASKGT) 5847c478bd9Sstevel@tonic-gate mdb_printf("%-30s ", "-"); 5857c478bd9Sstevel@tonic-gate else 5867c478bd9Sstevel@tonic-gate mdb_printf("%-30a ", GATESEG_GETOFFSET(gate)); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector, 5897c478bd9Sstevel@tonic-gate gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5937c478bd9Sstevel@tonic-gate static int 5947c478bd9Sstevel@tonic-gate gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate gate_desc_t gate; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 5997c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 6027c478bd9Sstevel@tonic-gate sizeof (gate_desc_t)) { 6037c478bd9Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", addr); 6047c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags)); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate return (DCMD_OK); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6137c478bd9Sstevel@tonic-gate static int 6147c478bd9Sstevel@tonic-gate idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate int i; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 619ac19272fSjosephb GElf_Sym idt0_va; 620ac19272fSjosephb gate_desc_t *idt0; 6217c478bd9Sstevel@tonic-gate 622ac19272fSjosephb if (mdb_lookup_by_name("idt0", &idt0_va) < 0) { 623ac19272fSjosephb mdb_warn("failed to find VA of idt0"); 6247c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 627ac19272fSjosephb addr = idt0_va.st_value; 628ac19272fSjosephb if (mdb_vread(&idt0, sizeof (idt0), addr) != sizeof (idt0)) { 629ac19272fSjosephb mdb_warn("failed to read idt0 at %p\n", addr); 630ac19272fSjosephb return (DCMD_ERR); 631ac19272fSjosephb } 632ac19272fSjosephb 633ac19272fSjosephb addr = (uintptr_t)idt0; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) { 6377c478bd9Sstevel@tonic-gate gate_desc_t gate; 6387c478bd9Sstevel@tonic-gate char label[6]; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 6417c478bd9Sstevel@tonic-gate sizeof (gate_desc_t)) { 6427c478bd9Sstevel@tonic-gate mdb_warn("failed to read gate descriptor at %p\n", 6437c478bd9Sstevel@tonic-gate addr); 6447c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate (void) mdb_snprintf(label, sizeof (label), "%3d: ", i); 6487c478bd9Sstevel@tonic-gate gate_desc_dump(&gate, label, i == 0); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate return (DCMD_OK); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 654ae115bc7Smrj static void 655ae115bc7Smrj htables_help(void) 656ae115bc7Smrj { 657ae115bc7Smrj mdb_printf( 658ae115bc7Smrj "Given a (hat_t *), generates the list of all (htable_t *)s\n" 659ae115bc7Smrj "that correspond to that address space\n"); 660ae115bc7Smrj } 661ae115bc7Smrj 662ae115bc7Smrj static void 663ae115bc7Smrj report_maps_help(void) 664ae115bc7Smrj { 665ae115bc7Smrj mdb_printf( 666ae115bc7Smrj "Given a PFN, report HAT structures that map the page, or use\n" 667ae115bc7Smrj "the page as a pagetable.\n" 668ae115bc7Smrj "\n" 669843e1988Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 670ae115bc7Smrj } 671ae115bc7Smrj 672ae115bc7Smrj static void 673ae115bc7Smrj ptable_help(void) 674ae115bc7Smrj { 675ae115bc7Smrj mdb_printf( 676ae115bc7Smrj "Given a PFN holding a page table, print its contents, and\n" 677ae115bc7Smrj "the address of the corresponding htable structure.\n" 678ae115bc7Smrj "\n" 679843e1988Sjohnlev "-m Interpret the PFN as an MFN (machine frame number)\n"); 680ae115bc7Smrj } 681ae115bc7Smrj 6827c478bd9Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = { 6837c478bd9Sstevel@tonic-gate { "gate_desc", ":", "dump a gate descriptor", gate_desc }, 6847c478bd9Sstevel@tonic-gate { "idt", ":[-v]", "dump an IDT", idt }, 6857c478bd9Sstevel@tonic-gate { "ttrace", "[-x]", "dump trap trace buffers", ttrace }, 6867c478bd9Sstevel@tonic-gate { "vatopfn", ":[-a as]", "translate address to physical page", 6877c478bd9Sstevel@tonic-gate va2pfn_dcmd }, 688ae115bc7Smrj { "report_maps", ":[-m]", 689ae115bc7Smrj "Given PFN, report mappings / page table usage", 690ae115bc7Smrj report_maps_dcmd, report_maps_help }, 691ae115bc7Smrj { "htables", "", "Given hat_t *, lists all its htable_t * values", 692ae115bc7Smrj htables_dcmd, htables_help }, 693ae115bc7Smrj { "ptable", ":[-m]", "Given PFN, dump contents of a page table", 694ae115bc7Smrj ptable_dcmd, ptable_help }, 6957c478bd9Sstevel@tonic-gate { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry", 6967c478bd9Sstevel@tonic-gate pte_dcmd }, 6977c478bd9Sstevel@tonic-gate { "page_num2pp", ":", "page frame number to page structure", 6987c478bd9Sstevel@tonic-gate page_num2pp }, 699843e1988Sjohnlev { "pfntomfn", ":", "convert physical page to hypervisor machine page", 700843e1988Sjohnlev pfntomfn_dcmd }, 701843e1988Sjohnlev { "mfntopfn", ":", "convert hypervisor machine page to physical page", 702843e1988Sjohnlev mfntopfn_dcmd }, 7037c478bd9Sstevel@tonic-gate { "memseg_list", ":", "show memseg list", memseg_list }, 7047c478bd9Sstevel@tonic-gate { NULL } 7057c478bd9Sstevel@tonic-gate }; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate static const mdb_walker_t walkers[] = { 7087c478bd9Sstevel@tonic-gate { "ttrace", "walks trap trace buffers in reverse chronological order", 7097c478bd9Sstevel@tonic-gate ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 7107c478bd9Sstevel@tonic-gate { "mutex_owner", "walks the owner of a mutex", 7117c478bd9Sstevel@tonic-gate mutex_owner_init, mutex_owner_step }, 7127c478bd9Sstevel@tonic-gate { "memseg", "walk the memseg structures", 7137c478bd9Sstevel@tonic-gate memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 7147c478bd9Sstevel@tonic-gate { NULL } 7157c478bd9Sstevel@tonic-gate }; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate const mdb_modinfo_t * 7207c478bd9Sstevel@tonic-gate _mdb_init(void) 7217c478bd9Sstevel@tonic-gate { 7227c478bd9Sstevel@tonic-gate return (&modinfo); 7237c478bd9Sstevel@tonic-gate } 724843e1988Sjohnlev 725843e1988Sjohnlev void 726843e1988Sjohnlev _mdb_fini(void) 727843e1988Sjohnlev { 728843e1988Sjohnlev free_mmu(); 729843e1988Sjohnlev } 730