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.
239c3024a3SHans Rosenfeld  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
249c3024a3SHans Rosenfeld  * Copyright 2019 Joyent, Inc.
25f7b98820SBryan Cantrill  */
26f7b98820SBryan Cantrill 
277c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
287c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
299c3024a3SHans Rosenfeld #include <mdb/mdb_x86util.h>
307c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/traptrace.h>
33ae115bc7Smrj #include <sys/x_call.h>
34f34a7178SJoe Bonasera #include <sys/xc_levels.h>
357c478bd9Sstevel@tonic-gate #include <sys/avintr.h>
367c478bd9Sstevel@tonic-gate #include <sys/systm.h>
377c478bd9Sstevel@tonic-gate #include <sys/trap.h>
387c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
397c478bd9Sstevel@tonic-gate #include <sys/mutex_impl.h>
407c478bd9Sstevel@tonic-gate #include "i86mmu.h"
41799823bbSRobert Mustacchi #include "unix_sup.h"
427ff178cdSJimmy Vetayases #include <sys/apix.h>
4329f78cfaSRobert Mustacchi #include <sys/x86_archext.h>
4429f78cfaSRobert Mustacchi #include <sys/bitmap.h>
45799823bbSRobert Mustacchi #include <sys/controlregs.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	TT_HDLR_WIDTH	17
487c478bd9Sstevel@tonic-gate 
497ff178cdSJimmy Vetayases 
507ff178cdSJimmy Vetayases /* apix only */
517ff178cdSJimmy Vetayases static apix_impl_t *d_apixs[NCPU];
527ff178cdSJimmy Vetayases static int use_apix = 0;
537ff178cdSJimmy Vetayases 
547c478bd9Sstevel@tonic-gate static int
ttrace_ttr_size_check(void)557c478bd9Sstevel@tonic-gate ttrace_ttr_size_check(void)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	mdb_ctf_id_t ttrtid;
587c478bd9Sstevel@tonic-gate 	ssize_t ttr_size;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 ||
617c478bd9Sstevel@tonic-gate 	    mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) {
627c478bd9Sstevel@tonic-gate 		mdb_warn("failed to determine size of trap_trace_rec_t; "
637c478bd9Sstevel@tonic-gate 		    "non-TRAPTRACE kernel?\n");
647c478bd9Sstevel@tonic-gate 		return (0);
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if ((ttr_size = mdb_ctf_type_size(ttrtid)) !=
687c478bd9Sstevel@tonic-gate 	    sizeof (trap_trace_rec_t)) {
697c478bd9Sstevel@tonic-gate 		/*
707c478bd9Sstevel@tonic-gate 		 * On Intel machines, this will happen when TTR_STACK_DEPTH
717c478bd9Sstevel@tonic-gate 		 * is changed.  This code could be smarter, and could
727c478bd9Sstevel@tonic-gate 		 * dynamically adapt to different depths, but not until a
737c478bd9Sstevel@tonic-gate 		 * need for such adaptation is demonstrated.
747c478bd9Sstevel@tonic-gate 		 */
757c478bd9Sstevel@tonic-gate 		mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't "
767c478bd9Sstevel@tonic-gate 		    "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t));
777c478bd9Sstevel@tonic-gate 		return (0);
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	return (1);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate int
ttrace_walk_init(mdb_walk_state_t * wsp)847c478bd9Sstevel@tonic-gate ttrace_walk_init(mdb_walk_state_t *wsp)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	trap_trace_ctl_t *ttcp;
877c478bd9Sstevel@tonic-gate 	size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
887c478bd9Sstevel@tonic-gate 	int i;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if (!ttrace_ttr_size_check())
917c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	ttcp = mdb_zalloc(ttc_size, UM_SLEEP);
947c478bd9Sstevel@tonic-gate 
95892ad162SToomas Soome 	if (wsp->walk_addr != 0) {
967c478bd9Sstevel@tonic-gate 		mdb_warn("ttrace only supports global walks\n");
977c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
987c478bd9Sstevel@tonic-gate 	}
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) {
1017c478bd9Sstevel@tonic-gate 		mdb_warn("symbol 'trap_trace_ctl' not found; "
1027c478bd9Sstevel@tonic-gate 		    "non-TRAPTRACE kernel?\n");
1037c478bd9Sstevel@tonic-gate 		mdb_free(ttcp, ttc_size);
1047c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * We'll poach the ttc_current pointer (which isn't used for
1097c478bd9Sstevel@tonic-gate 	 * anything) to store a pointer to our current TRAPTRACE record.
1107c478bd9Sstevel@tonic-gate 	 * This allows us to only keep the array of trap_trace_ctl structures
1117c478bd9Sstevel@tonic-gate 	 * as our walker state (ttc_current may be the only kernel data
1127c478bd9Sstevel@tonic-gate 	 * structure member added exclusively to make writing the mdb walker
1137c478bd9Sstevel@tonic-gate 	 * a little easier).
1147c478bd9Sstevel@tonic-gate 	 */
1157c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++) {
1167c478bd9Sstevel@tonic-gate 		trap_trace_ctl_t *ttc = &ttcp[i];
1177c478bd9Sstevel@tonic-gate 
118892ad162SToomas Soome 		if (ttc->ttc_first == 0)
1197c478bd9Sstevel@tonic-gate 			continue;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		/*
1227c478bd9Sstevel@tonic-gate 		 * Assign ttc_current to be the last completed record.
1237c478bd9Sstevel@tonic-gate 		 * Note that the error checking (i.e. in the ttc_next ==
1247c478bd9Sstevel@tonic-gate 		 * ttc_first case) is performed in the step function.
1257c478bd9Sstevel@tonic-gate 		 */
1267c478bd9Sstevel@tonic-gate 		ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t);
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	wsp->walk_data = ttcp;
1307c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate int
ttrace_walk_step(mdb_walk_state_t * wsp)1347c478bd9Sstevel@tonic-gate ttrace_walk_step(mdb_walk_state_t *wsp)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc;
1377c478bd9Sstevel@tonic-gate 	trap_trace_rec_t rec;
1387c478bd9Sstevel@tonic-gate 	int rval, i, recsize = sizeof (trap_trace_rec_t);
1397c478bd9Sstevel@tonic-gate 	hrtime_t latest = 0;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	/*
1427c478bd9Sstevel@tonic-gate 	 * Loop through the CPUs, looking for the latest trap trace record
1437c478bd9Sstevel@tonic-gate 	 * (we want to walk through the trap trace records in reverse
1447c478bd9Sstevel@tonic-gate 	 * chronological order).
1457c478bd9Sstevel@tonic-gate 	 */
1467c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++) {
1477c478bd9Sstevel@tonic-gate 		ttc = &ttcp[i];
1487c478bd9Sstevel@tonic-gate 
149892ad162SToomas Soome 		if (ttc->ttc_current == 0)
1507c478bd9Sstevel@tonic-gate 			continue;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 		if (ttc->ttc_current < ttc->ttc_first)
1537c478bd9Sstevel@tonic-gate 			ttc->ttc_current = ttc->ttc_limit - recsize;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) {
1567c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read rec at %p", ttc->ttc_current);
1577c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		if (rec.ttr_stamp > latest) {
1617c478bd9Sstevel@tonic-gate 			latest = rec.ttr_stamp;
1627c478bd9Sstevel@tonic-gate 			latest_ttc = ttc;
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (latest == 0)
1677c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	ttc = latest_ttc;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) {
1727c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read rec at %p", ttc->ttc_current);
1737c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (ttc->ttc_current == ttc->ttc_next)
179892ad162SToomas Soome 		ttc->ttc_current = 0;
1807c478bd9Sstevel@tonic-gate 	else
1817c478bd9Sstevel@tonic-gate 		ttc->ttc_current -= sizeof (trap_trace_rec_t);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	return (rval);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate void
ttrace_walk_fini(mdb_walk_state_t * wsp)1877c478bd9Sstevel@tonic-gate ttrace_walk_fini(mdb_walk_state_t *wsp)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU);
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static int
ttrace_syscall(trap_trace_rec_t * rec)1937c478bd9Sstevel@tonic-gate ttrace_syscall(trap_trace_rec_t *rec)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
1967c478bd9Sstevel@tonic-gate 	int sysnum = rec->ttr_sysnum;
1977c478bd9Sstevel@tonic-gate 	uintptr_t addr;
1987c478bd9Sstevel@tonic-gate 	struct sysent sys;
1997c478bd9Sstevel@tonic-gate 
200ae115bc7Smrj 	mdb_printf("%-3x", sysnum);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	if (rec->ttr_sysnum > NSYSCALL) {
203ae115bc7Smrj 		mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum);
2047c478bd9Sstevel@tonic-gate 		return (0);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (mdb_lookup_by_name("sysent", &sym) == -1) {
2087c478bd9Sstevel@tonic-gate 		mdb_warn("\ncouldn't find 'sysent'");
2097c478bd9Sstevel@tonic-gate 		return (-1);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if (addr >= (uintptr_t)sym.st_value + sym.st_size) {
2157c478bd9Sstevel@tonic-gate 		mdb_warn("\nsysnum %d out-of-range\n", sysnum);
2167c478bd9Sstevel@tonic-gate 		return (-1);
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (mdb_vread(&sys, sizeof (sys), addr) == -1) {
2207c478bd9Sstevel@tonic-gate 		mdb_warn("\nfailed to read sysent at %p", addr);
2217c478bd9Sstevel@tonic-gate 		return (-1);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
224ae115bc7Smrj 	mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static int
ttrace_interrupt(trap_trace_rec_t * rec)2307c478bd9Sstevel@tonic-gate ttrace_interrupt(trap_trace_rec_t *rec)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2337c478bd9Sstevel@tonic-gate 	uintptr_t addr;
2347c478bd9Sstevel@tonic-gate 	struct av_head hd;
2357c478bd9Sstevel@tonic-gate 	struct autovec av;
2367c478bd9Sstevel@tonic-gate 
237ae115bc7Smrj 	switch (rec->ttr_regs.r_trapno) {
238ae115bc7Smrj 	case T_SOFTINT:
239ae115bc7Smrj 		mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)");
2407c478bd9Sstevel@tonic-gate 		return (0);
241ae115bc7Smrj 	default:
242ae115bc7Smrj 		break;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
245ae115bc7Smrj 	mdb_printf("%-3x ", rec->ttr_vector);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	if (mdb_lookup_by_name("autovect", &sym) == -1) {
2487c478bd9Sstevel@tonic-gate 		mdb_warn("\ncouldn't find 'autovect'");
2497c478bd9Sstevel@tonic-gate 		return (-1);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	addr = (uintptr_t)sym.st_value +
2537c478bd9Sstevel@tonic-gate 	    rec->ttr_vector * sizeof (struct av_head);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (addr >= (uintptr_t)sym.st_value + sym.st_size) {
2567c478bd9Sstevel@tonic-gate 		mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector);
2577c478bd9Sstevel@tonic-gate 		return (-1);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hd, sizeof (hd), addr) == -1) {
2617c478bd9Sstevel@tonic-gate 		mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector);
2627c478bd9Sstevel@tonic-gate 		return (-1);
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (hd.avh_link == NULL) {
266ae115bc7Smrj 		if (rec->ttr_ipl == XC_CPUPOKE_PIL)
267ae115bc7Smrj 			mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)");
268ae115bc7Smrj 		else
269ae115bc7Smrj 			mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)");
2707c478bd9Sstevel@tonic-gate 	} else {
2717c478bd9Sstevel@tonic-gate 		if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) {
2727c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read autovec at %p",
2737c478bd9Sstevel@tonic-gate 			    (uintptr_t)hd.avh_link);
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	return (0);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827ff178cdSJimmy Vetayases static int
ttrace_apix_interrupt(trap_trace_rec_t * rec)2837ff178cdSJimmy Vetayases ttrace_apix_interrupt(trap_trace_rec_t *rec)
2847ff178cdSJimmy Vetayases {
2857ff178cdSJimmy Vetayases 	struct autovec av;
2867ff178cdSJimmy Vetayases 	apix_impl_t apix;
2877ff178cdSJimmy Vetayases 	apix_vector_t apix_vector;
2887ff178cdSJimmy Vetayases 
2897ff178cdSJimmy Vetayases 	switch (rec->ttr_regs.r_trapno) {
2907ff178cdSJimmy Vetayases 	case T_SOFTINT:
2917ff178cdSJimmy Vetayases 		mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)");
2927ff178cdSJimmy Vetayases 		return (0);
2937ff178cdSJimmy Vetayases 	default:
2947ff178cdSJimmy Vetayases 		break;
2957ff178cdSJimmy Vetayases 	}
2967ff178cdSJimmy Vetayases 
2977ff178cdSJimmy Vetayases 	mdb_printf("%-3x ", rec->ttr_vector);
2987ff178cdSJimmy Vetayases 
2997ff178cdSJimmy Vetayases 	/* Read the per CPU apix entry */
3007ff178cdSJimmy Vetayases 	if (mdb_vread(&apix, sizeof (apix_impl_t),
3017ff178cdSJimmy Vetayases 	    (uintptr_t)d_apixs[rec->ttr_cpuid]) == -1) {
3027ff178cdSJimmy Vetayases 		mdb_warn("\ncouldn't read apix[%d]", rec->ttr_cpuid);
3037ff178cdSJimmy Vetayases 		return (-1);
3047ff178cdSJimmy Vetayases 	}
3057ff178cdSJimmy Vetayases 	if (mdb_vread(&apix_vector, sizeof (apix_vector_t),
3067ff178cdSJimmy Vetayases 	    (uintptr_t)apix.x_vectbl[rec->ttr_vector]) == -1) {
3077ff178cdSJimmy Vetayases 		mdb_warn("\ncouldn't read apix_vector_t[%d]", rec->ttr_vector);
3087ff178cdSJimmy Vetayases 		return (-1);
3097ff178cdSJimmy Vetayases 	}
3107ff178cdSJimmy Vetayases 	if (apix_vector.v_share == 0) {
3117ff178cdSJimmy Vetayases 		if (rec->ttr_ipl == XC_CPUPOKE_PIL)
3127ff178cdSJimmy Vetayases 			mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)");
3137ff178cdSJimmy Vetayases 		else
3147ff178cdSJimmy Vetayases 			mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)");
3157ff178cdSJimmy Vetayases 	} else {
3167ff178cdSJimmy Vetayases 		if (mdb_vread(&av, sizeof (struct autovec),
3177ff178cdSJimmy Vetayases 		    (uintptr_t)(apix_vector.v_autovect)) == -1) {
3187ff178cdSJimmy Vetayases 			mdb_warn("couldn't read autovec at %p",
3197ff178cdSJimmy Vetayases 			    (uintptr_t)apix_vector.v_autovect);
3207ff178cdSJimmy Vetayases 		}
3217ff178cdSJimmy Vetayases 
3227ff178cdSJimmy Vetayases 		mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector);
3237ff178cdSJimmy Vetayases 	}
3247ff178cdSJimmy Vetayases 
3257ff178cdSJimmy Vetayases 	return (0);
3267ff178cdSJimmy Vetayases }
3277ff178cdSJimmy Vetayases 
3287ff178cdSJimmy Vetayases 
3297c478bd9Sstevel@tonic-gate static struct {
3307c478bd9Sstevel@tonic-gate 	int tt_trapno;
3317c478bd9Sstevel@tonic-gate 	char *tt_name;
3327c478bd9Sstevel@tonic-gate } ttrace_traps[] = {
3337c478bd9Sstevel@tonic-gate 	{ T_ZERODIV,	"divide-error" },
3347c478bd9Sstevel@tonic-gate 	{ T_SGLSTP,	"debug-exception" },
3357c478bd9Sstevel@tonic-gate 	{ T_NMIFLT,	"nmi-interrupt" },
3367c478bd9Sstevel@tonic-gate 	{ T_BPTFLT,	"breakpoint" },
3377c478bd9Sstevel@tonic-gate 	{ T_OVFLW,	"into-overflow" },
3387c478bd9Sstevel@tonic-gate 	{ T_BOUNDFLT,	"bound-exceeded" },
3397c478bd9Sstevel@tonic-gate 	{ T_ILLINST,	"invalid-opcode" },
3407c478bd9Sstevel@tonic-gate 	{ T_NOEXTFLT,	"device-not-avail" },
3417c478bd9Sstevel@tonic-gate 	{ T_DBLFLT,	"double-fault" },
3427c478bd9Sstevel@tonic-gate 	{ T_EXTOVRFLT,	"segment-overrun" },
3437c478bd9Sstevel@tonic-gate 	{ T_TSSFLT,	"invalid-tss" },
3447c478bd9Sstevel@tonic-gate 	{ T_SEGFLT,	"segment-not-pres" },
3457c478bd9Sstevel@tonic-gate 	{ T_STKFLT,	"stack-fault" },
3467c478bd9Sstevel@tonic-gate 	{ T_GPFLT,	"general-protectn" },
3477c478bd9Sstevel@tonic-gate 	{ T_PGFLT,	"page-fault" },
3487c478bd9Sstevel@tonic-gate 	{ T_EXTERRFLT,	"error-fault" },
3497c478bd9Sstevel@tonic-gate 	{ T_ALIGNMENT,	"alignment-check" },
3507c478bd9Sstevel@tonic-gate 	{ T_MCE,	"machine-check" },
3517c478bd9Sstevel@tonic-gate 	{ T_SIMDFPE,	"sse-exception" },
352ae115bc7Smrj 
353ae115bc7Smrj 	{ T_DBGENTR,	"debug-enter" },
354ae115bc7Smrj 	{ T_FASTTRAP,	"fasttrap-0xd2" },
355ae115bc7Smrj 	{ T_SYSCALLINT,	"syscall-0x91" },
356ae115bc7Smrj 	{ T_DTRACE_RET,	"dtrace-ret" },
357ae115bc7Smrj 	{ T_SOFTINT,	"softint" },
358ae115bc7Smrj 	{ T_INTERRUPT,	"interrupt" },
359ae115bc7Smrj 	{ T_FAULT,	"fault" },
360ae115bc7Smrj 	{ T_AST,	"ast" },
361ae115bc7Smrj 	{ T_SYSCALL,	"syscall" },
362ae115bc7Smrj 
3637c478bd9Sstevel@tonic-gate 	{ 0,		NULL }
3647c478bd9Sstevel@tonic-gate };
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate static int
ttrace_trap(trap_trace_rec_t * rec)3677c478bd9Sstevel@tonic-gate ttrace_trap(trap_trace_rec_t *rec)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	int i;
3707c478bd9Sstevel@tonic-gate 
371ae115bc7Smrj 	if (rec->ttr_regs.r_trapno == T_AST)
372ae115bc7Smrj 		mdb_printf("%-3s ", "-");
373ae115bc7Smrj 	else
374ae115bc7Smrj 		mdb_printf("%-3x ", rec->ttr_regs.r_trapno);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	for (i = 0; ttrace_traps[i].tt_name != NULL; i++) {
3777c478bd9Sstevel@tonic-gate 		if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno)
3787c478bd9Sstevel@tonic-gate 			break;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (ttrace_traps[i].tt_name == NULL)
3827c478bd9Sstevel@tonic-gate 		mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)");
3837c478bd9Sstevel@tonic-gate 	else
3847c478bd9Sstevel@tonic-gate 		mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return (0);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
389ae115bc7Smrj static void
ttrace_intr_detail(trap_trace_rec_t * rec)390ae115bc7Smrj ttrace_intr_detail(trap_trace_rec_t *rec)
391ae115bc7Smrj {
392ae115bc7Smrj 	mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector,
393ae115bc7Smrj 	    rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl);
394ae115bc7Smrj }
395ae115bc7Smrj 
3967c478bd9Sstevel@tonic-gate static struct {
3977c478bd9Sstevel@tonic-gate 	uchar_t t_marker;
3987c478bd9Sstevel@tonic-gate 	char *t_name;
3997c478bd9Sstevel@tonic-gate 	int (*t_hdlr)(trap_trace_rec_t *);
4007c478bd9Sstevel@tonic-gate } ttrace_hdlr[] = {
4017c478bd9Sstevel@tonic-gate 	{ TT_SYSCALL, "sysc", ttrace_syscall },
4027c478bd9Sstevel@tonic-gate 	{ TT_SYSENTER, "syse", ttrace_syscall },
4037c478bd9Sstevel@tonic-gate 	{ TT_SYSC, "asys", ttrace_syscall },
4047c478bd9Sstevel@tonic-gate 	{ TT_SYSC64, "sc64", ttrace_syscall },
4057c478bd9Sstevel@tonic-gate 	{ TT_INTERRUPT, "intr", ttrace_interrupt },
4067c478bd9Sstevel@tonic-gate 	{ TT_TRAP, "trap", ttrace_trap },
407ae115bc7Smrj 	{ TT_EVENT, "evnt", ttrace_trap },
4087c478bd9Sstevel@tonic-gate 	{ 0, NULL, NULL }
4097c478bd9Sstevel@tonic-gate };
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate typedef struct ttrace_dcmd {
4127c478bd9Sstevel@tonic-gate 	processorid_t ttd_cpu;
4137c478bd9Sstevel@tonic-gate 	uint_t ttd_extended;
414399ca3a7SJohn Levon 	uintptr_t ttd_kthread;
4157c478bd9Sstevel@tonic-gate 	trap_trace_ctl_t ttd_ttc[NCPU];
4167c478bd9Sstevel@tonic-gate } ttrace_dcmd_t;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate #if defined(__amd64)
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate #define	DUMP(reg) #reg, regs->r_##reg
4217c478bd9Sstevel@tonic-gate #define	THREEREGS	"         %3s: %16lx %3s: %16lx %3s: %16lx\n"
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate static void
ttrace_dumpregs(trap_trace_rec_t * rec)4247c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	struct regs *regs = &rec->ttr_regs;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
4297c478bd9Sstevel@tonic-gate 	mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
4307c478bd9Sstevel@tonic-gate 	mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
4317c478bd9Sstevel@tonic-gate 	mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
4327c478bd9Sstevel@tonic-gate 	mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
433ae115bc7Smrj 	mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
434ae115bc7Smrj 	mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
435ae115bc7Smrj 	mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
436ae115bc7Smrj 	mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);
43774ecdb51SJohn Levon 	mdb_printf("         %3s: %16lx %3s: %16lx\n",
43874ecdb51SJohn Levon 	    "fsb", regs->__r_fsbase,
43974ecdb51SJohn Levon 	    "gsb", regs->__r_gsbase);
4407c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate #else
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate #define	DUMP(reg) #reg, regs->r_##reg
4467c478bd9Sstevel@tonic-gate #define	FOURREGS	"         %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate static void
ttrace_dumpregs(trap_trace_rec_t * rec)4497c478bd9Sstevel@tonic-gate ttrace_dumpregs(trap_trace_rec_t *rec)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	struct regs *regs = &rec->ttr_regs;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
4547c478bd9Sstevel@tonic-gate 	mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
4557c478bd9Sstevel@tonic-gate 	mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
4567c478bd9Sstevel@tonic-gate 	mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
4577c478bd9Sstevel@tonic-gate 	    DUMP(pc), DUMP(cs));
4587c478bd9Sstevel@tonic-gate 	mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
4597c478bd9Sstevel@tonic-gate 	    "cr2", rec->ttr_cr2);
4607c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate #endif	/* __amd64 */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate int
ttrace_walk(uintptr_t addr,trap_trace_rec_t * rec,ttrace_dcmd_t * dcmd)4667c478bd9Sstevel@tonic-gate ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd)
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate 	struct regs *regs = &rec->ttr_regs;
4697c478bd9Sstevel@tonic-gate 	processorid_t cpu = -1, i;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++) {
4727c478bd9Sstevel@tonic-gate 		if (addr >= dcmd->ttd_ttc[i].ttc_first &&
4737c478bd9Sstevel@tonic-gate 		    addr < dcmd->ttd_ttc[i].ttc_limit) {
4747c478bd9Sstevel@tonic-gate 			cpu = i;
4757c478bd9Sstevel@tonic-gate 			break;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if (cpu == -1) {
4807c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
4817c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
4857c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
4867c478bd9Sstevel@tonic-gate 
487399ca3a7SJohn Levon 	if (dcmd->ttd_kthread != 0 &&
488399ca3a7SJohn Levon 	    dcmd->ttd_kthread != rec->ttr_curthread)
489399ca3a7SJohn Levon 		return (WALK_NEXT);
490399ca3a7SJohn Levon 
4917c478bd9Sstevel@tonic-gate 	mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
4947c478bd9Sstevel@tonic-gate 		if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
4957c478bd9Sstevel@tonic-gate 			continue;
4967c478bd9Sstevel@tonic-gate 		mdb_printf("%4s ", ttrace_hdlr[i].t_name);
4977c478bd9Sstevel@tonic-gate 		if (ttrace_hdlr[i].t_hdlr(rec) == -1)
4987c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
501ae115bc7Smrj 	mdb_printf(" %a\n", regs->r_pc);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (dcmd->ttd_extended == FALSE)
5047c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
5057c478bd9Sstevel@tonic-gate 
506f34a7178SJoe Bonasera 	if (rec->ttr_marker == TT_INTERRUPT)
507ae115bc7Smrj 		ttrace_intr_detail(rec);
508ae115bc7Smrj 	else
509ae115bc7Smrj 		ttrace_dumpregs(rec);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	if (rec->ttr_sdepth > 0) {
5127c478bd9Sstevel@tonic-gate 		for (i = 0; i < rec->ttr_sdepth; i++) {
5137c478bd9Sstevel@tonic-gate 			if (i >= TTR_STACK_DEPTH) {
5147c478bd9Sstevel@tonic-gate 				mdb_printf("%17s*** invalid ttr_sdepth (is %d, "
5157c478bd9Sstevel@tonic-gate 				    "should be <= %d)\n", " ", rec->ttr_sdepth,
5167c478bd9Sstevel@tonic-gate 				    TTR_STACK_DEPTH);
5177c478bd9Sstevel@tonic-gate 				break;
5187c478bd9Sstevel@tonic-gate 			}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 			mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]);
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate int
ttrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5297c478bd9Sstevel@tonic-gate ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	ttrace_dcmd_t dcmd;
5327c478bd9Sstevel@tonic-gate 	trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
5337c478bd9Sstevel@tonic-gate 	trap_trace_rec_t rec;
5347c478bd9Sstevel@tonic-gate 	size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (!ttrace_ttr_size_check())
5377c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	bzero(&dcmd, sizeof (dcmd));
5407c478bd9Sstevel@tonic-gate 	dcmd.ttd_cpu = -1;
5417c478bd9Sstevel@tonic-gate 	dcmd.ttd_extended = FALSE;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
5447c478bd9Sstevel@tonic-gate 		mdb_warn("symbol 'trap_trace_ctl' not found; "
5457c478bd9Sstevel@tonic-gate 		    "non-TRAPTRACE kernel?\n");
5467c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
550399ca3a7SJohn Levon 	    'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended,
551399ca3a7SJohn Levon 	    't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc)
5527c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
5557c478bd9Sstevel@tonic-gate 		mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
556ae115bc7Smrj 		    "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
557ae115bc7Smrj 		    " EIP");
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
5617c478bd9Sstevel@tonic-gate 		if (addr >= NCPU) {
5627c478bd9Sstevel@tonic-gate 			if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
5637c478bd9Sstevel@tonic-gate 				mdb_warn("couldn't read trap trace record "
5647c478bd9Sstevel@tonic-gate 				    "at %p", addr);
5657c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
5667c478bd9Sstevel@tonic-gate 			}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 			if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
5697c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 		dcmd.ttd_cpu = addr;
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767ff178cdSJimmy Vetayases 	if (mdb_readvar(&use_apix, "apix_enable") == -1) {
5777ff178cdSJimmy Vetayases 		mdb_warn("failed to read apix_enable");
5787ff178cdSJimmy Vetayases 		use_apix = 0;
5797ff178cdSJimmy Vetayases 	}
5807ff178cdSJimmy Vetayases 
5817ff178cdSJimmy Vetayases 	if (use_apix) {
5827ff178cdSJimmy Vetayases 		if (mdb_readvar(&d_apixs, "apixs") == -1) {
5837ff178cdSJimmy Vetayases 			mdb_warn("\nfailed to read apixs.");
5847ff178cdSJimmy Vetayases 			return (DCMD_ERR);
5857ff178cdSJimmy Vetayases 		}
5867ff178cdSJimmy Vetayases 		/* change to apix ttrace interrupt handler */
5877ff178cdSJimmy Vetayases 		ttrace_hdlr[4].t_hdlr = ttrace_apix_interrupt;
5887ff178cdSJimmy Vetayases 	}
5897ff178cdSJimmy Vetayases 
5907c478bd9Sstevel@tonic-gate 	if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) {
5917c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk 'ttrace'");
5927c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5997c478bd9Sstevel@tonic-gate int
mutex_owner_init(mdb_walk_state_t * wsp)6007c478bd9Sstevel@tonic-gate mutex_owner_init(mdb_walk_state_t *wsp)
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate int
mutex_owner_step(mdb_walk_state_t * wsp)6067c478bd9Sstevel@tonic-gate mutex_owner_step(mdb_walk_state_t *wsp)
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
6097c478bd9Sstevel@tonic-gate 	mutex_impl_t mtx;
6107c478bd9Sstevel@tonic-gate 	uintptr_t owner;
6117c478bd9Sstevel@tonic-gate 	kthread_t thr;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	if (mdb_vread(&mtx, sizeof (mtx), addr) == -1)
6147c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (!MUTEX_TYPE_ADAPTIVE(&mtx))
6177c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
6187c478bd9Sstevel@tonic-gate 
619892ad162SToomas Soome 	if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == 0)
6207c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (mdb_vread(&thr, sizeof (thr), owner) != -1)
6237c478bd9Sstevel@tonic-gate 		(void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	return (WALK_DONE);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate static void
gate_desc_dump(gate_desc_t * gate,const char * label,int header)6297c478bd9Sstevel@tonic-gate gate_desc_dump(gate_desc_t *gate, const char *label, int header)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	const char *lastnm;
6327c478bd9Sstevel@tonic-gate 	uint_t lastval;
6337c478bd9Sstevel@tonic-gate 	char type[4];
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	switch (gate->sgd_type) {
6367c478bd9Sstevel@tonic-gate 	case SDT_SYSIGT:
6377c478bd9Sstevel@tonic-gate 		strcpy(type, "int");
6387c478bd9Sstevel@tonic-gate 		break;
6397c478bd9Sstevel@tonic-gate 	case SDT_SYSTGT:
6407c478bd9Sstevel@tonic-gate 		strcpy(type, "trp");
6417c478bd9Sstevel@tonic-gate 		break;
6427c478bd9Sstevel@tonic-gate 	case SDT_SYSTASKGT:
6437c478bd9Sstevel@tonic-gate 		strcpy(type, "tsk");
6447c478bd9Sstevel@tonic-gate 		break;
6457c478bd9Sstevel@tonic-gate 	default:
6467c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate #if defined(__amd64)
6507c478bd9Sstevel@tonic-gate 	lastnm = "IST";
6517c478bd9Sstevel@tonic-gate 	lastval = gate->sgd_ist;
6527c478bd9Sstevel@tonic-gate #else
6537c478bd9Sstevel@tonic-gate 	lastnm = "STK";
6547c478bd9Sstevel@tonic-gate 	lastval = gate->sgd_stkcpy;
6557c478bd9Sstevel@tonic-gate #endif
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	if (header) {
6587c478bd9Sstevel@tonic-gate 		mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> "
6597c478bd9Sstevel@tonic-gate 		    "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label),
6607c478bd9Sstevel@tonic-gate 		    "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	mdb_printf("%s", label);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if (gate->sgd_type == SDT_SYSTASKGT)
6667c478bd9Sstevel@tonic-gate 		mdb_printf("%-30s ", "-");
6677c478bd9Sstevel@tonic-gate 	else
6687c478bd9Sstevel@tonic-gate 		mdb_printf("%-30a ", GATESEG_GETOFFSET(gate));
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	mdb_printf("%4x  %d  %c %3s %2x\n", gate->sgd_selector,
6717c478bd9Sstevel@tonic-gate 	    gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6757c478bd9Sstevel@tonic-gate static int
gate_desc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6767c478bd9Sstevel@tonic-gate gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	gate_desc_t gate;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
6817c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (mdb_vread(&gate, sizeof (gate_desc_t), addr) !=
6847c478bd9Sstevel@tonic-gate 	    sizeof (gate_desc_t)) {
6857c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read gate descriptor at %p\n", addr);
6867c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags));
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6957c478bd9Sstevel@tonic-gate static int
idt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6967c478bd9Sstevel@tonic-gate idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	int i;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
701ac19272fSjosephb 		GElf_Sym idt0_va;
702ac19272fSjosephb 		gate_desc_t *idt0;
7037c478bd9Sstevel@tonic-gate 
704ac19272fSjosephb 		if (mdb_lookup_by_name("idt0", &idt0_va) < 0) {
705ac19272fSjosephb 			mdb_warn("failed to find VA of idt0");
7067c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7077c478bd9Sstevel@tonic-gate 		}
7087c478bd9Sstevel@tonic-gate 
709ac19272fSjosephb 		addr = idt0_va.st_value;
710ac19272fSjosephb 		if (mdb_vread(&idt0, sizeof (idt0), addr) != sizeof (idt0)) {
711ac19272fSjosephb 			mdb_warn("failed to read idt0 at %p\n", addr);
712ac19272fSjosephb 			return (DCMD_ERR);
713ac19272fSjosephb 		}
714ac19272fSjosephb 
715ac19272fSjosephb 		addr = (uintptr_t)idt0;
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) {
7197c478bd9Sstevel@tonic-gate 		gate_desc_t gate;
7207c478bd9Sstevel@tonic-gate 		char label[6];
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		if (mdb_vread(&gate, sizeof (gate_desc_t), addr) !=
7237c478bd9Sstevel@tonic-gate 		    sizeof (gate_desc_t)) {
7247c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read gate descriptor at %p\n",
7257c478bd9Sstevel@tonic-gate 			    addr);
7267c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(label, sizeof (label), "%3d: ", i);
7307c478bd9Sstevel@tonic-gate 		gate_desc_dump(&gate, label, i == 0);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
736ae115bc7Smrj static void
htables_help(void)737ae115bc7Smrj htables_help(void)
738ae115bc7Smrj {
739ae115bc7Smrj 	mdb_printf(
740ae115bc7Smrj 	    "Given a (hat_t *), generates the list of all (htable_t *)s\n"
741ae115bc7Smrj 	    "that correspond to that address space\n");
742ae115bc7Smrj }
743ae115bc7Smrj 
744ae115bc7Smrj static void
report_maps_help(void)745ae115bc7Smrj report_maps_help(void)
746ae115bc7Smrj {
747ae115bc7Smrj 	mdb_printf(
748ae115bc7Smrj 	    "Given a PFN, report HAT structures that map the page, or use\n"
749ae115bc7Smrj 	    "the page as a pagetable.\n"
750ae115bc7Smrj 	    "\n"
751843e1988Sjohnlev 	    "-m Interpret the PFN as an MFN (machine frame number)\n");
752ae115bc7Smrj }
753ae115bc7Smrj 
754ae115bc7Smrj static void
ptable_help(void)755ae115bc7Smrj ptable_help(void)
756ae115bc7Smrj {
757ae115bc7Smrj 	mdb_printf(
758ae115bc7Smrj 	    "Given a PFN holding a page table, print its contents, and\n"
759ae115bc7Smrj 	    "the address of the corresponding htable structure.\n"
760ae115bc7Smrj 	    "\n"
76174ecdb51SJohn Levon 	    "-m Interpret the PFN as an MFN (machine frame number)\n"
76274ecdb51SJohn Levon 	    "-l force page table level (3 is top)\n");
76374ecdb51SJohn Levon }
76474ecdb51SJohn Levon 
76574ecdb51SJohn Levon static void
ptmap_help(void)76674ecdb51SJohn Levon ptmap_help(void)
76774ecdb51SJohn Levon {
76874ecdb51SJohn Levon 	mdb_printf(
76974ecdb51SJohn Levon 	    "Report all mappings represented by the page table hierarchy\n"
77074ecdb51SJohn Levon 	    "rooted at the given cr3 value / physical address.\n"
77174ecdb51SJohn Levon 	    "\n"
77274ecdb51SJohn Levon 	    "-w run ::whatis on mapping start addresses\n");
773ae115bc7Smrj }
774ae115bc7Smrj 
775adabf612SBryan Cantrill static const char *const scalehrtime_desc =
776adabf612SBryan Cantrill 	"Scales a timestamp from ticks to nanoseconds. Unscaled timestamps\n"
777adabf612SBryan Cantrill 	"are used as both a quick way of accumulating relative time (as for\n"
778adabf612SBryan Cantrill 	"usage) and as a quick way of getting the absolute current time.\n"
779adabf612SBryan Cantrill 	"These uses require slightly different scaling algorithms. By\n"
780adabf612SBryan Cantrill 	"default, if a specified time is greater than half of the unscaled\n"
781adabf612SBryan Cantrill 	"time at the last tick (that is, if the unscaled time represents\n"
782adabf612SBryan Cantrill 	"more than half the time since boot), the timestamp is assumed to\n"
783adabf612SBryan Cantrill 	"be absolute, and the scaling algorithm used mimics that which the\n"
784adabf612SBryan Cantrill 	"kernel uses in gethrtime(). Otherwise, the timestamp is assumed to\n"
785adabf612SBryan Cantrill 	"be relative, and the algorithm mimics scalehrtime(). This behavior\n"
786adabf612SBryan Cantrill 	"can be overridden by forcing the unscaled time to be interpreted\n"
787adabf612SBryan Cantrill 	"as relative (via -r) or absolute (via -a).\n";
788adabf612SBryan Cantrill 
789adabf612SBryan Cantrill static void
scalehrtime_help(void)790adabf612SBryan Cantrill scalehrtime_help(void)
791adabf612SBryan Cantrill {
792adabf612SBryan Cantrill 	mdb_printf("%s", scalehrtime_desc);
793adabf612SBryan Cantrill }
794adabf612SBryan Cantrill 
795f7b98820SBryan Cantrill /*
796f7b98820SBryan Cantrill  * NSEC_SHIFT is replicated here (it is not defined in a header file),
797f7b98820SBryan Cantrill  * but for amusement, the reader is directed to the comment that explains
798f7b98820SBryan Cantrill  * the rationale for this particular value on x86.  Spoiler:  the value is
799f7b98820SBryan Cantrill  * selected to accommodate 60 MHz Pentiums!  (And a confession:  if the voice
800f7b98820SBryan Cantrill  * in that comment sounds too familiar, it's because your author also wrote
801f7b98820SBryan Cantrill  * that code -- some fifteen years prior to this writing in 2011...)
802f7b98820SBryan Cantrill  */
803f7b98820SBryan Cantrill #define	NSEC_SHIFT 5
804f7b98820SBryan Cantrill 
805f7b98820SBryan Cantrill /*ARGSUSED*/
806f7b98820SBryan Cantrill static int
scalehrtime_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)807a8ea0c9dSJohn Levon scalehrtime_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
808f7b98820SBryan Cantrill {
809f7b98820SBryan Cantrill 	uint32_t nsec_scale;
810adabf612SBryan Cantrill 	hrtime_t tsc = addr, hrt, tsc_last, base, mult = 1;
811f7b98820SBryan Cantrill 	unsigned int *tscp = (unsigned int *)&tsc;
812f7b98820SBryan Cantrill 	uintptr_t scalehrtimef;
813f7b98820SBryan Cantrill 	uint64_t scale;
814f7b98820SBryan Cantrill 	GElf_Sym sym;
815adabf612SBryan Cantrill 	int expected = !(flags & DCMD_ADDRSPEC);
816adabf612SBryan Cantrill 	uint_t absolute = FALSE, relative = FALSE;
817f7b98820SBryan Cantrill 
818adabf612SBryan Cantrill 	if (mdb_getopts(argc, argv,
819adabf612SBryan Cantrill 	    'a', MDB_OPT_SETBITS, TRUE, &absolute,
820adabf612SBryan Cantrill 	    'r', MDB_OPT_SETBITS, TRUE, &relative, NULL) != argc - expected)
821adabf612SBryan Cantrill 		return (DCMD_USAGE);
822adabf612SBryan Cantrill 
823adabf612SBryan Cantrill 	if (absolute && relative) {
824adabf612SBryan Cantrill 		mdb_warn("can't specify both -a and -r\n");
825adabf612SBryan Cantrill 		return (DCMD_USAGE);
826adabf612SBryan Cantrill 	}
827f7b98820SBryan Cantrill 
828adabf612SBryan Cantrill 	if (expected == 1) {
829adabf612SBryan Cantrill 		switch (argv[argc - 1].a_type) {
830f7b98820SBryan Cantrill 		case MDB_TYPE_STRING:
831adabf612SBryan Cantrill 			tsc = mdb_strtoull(argv[argc - 1].a_un.a_str);
832f7b98820SBryan Cantrill 			break;
833f7b98820SBryan Cantrill 		case MDB_TYPE_IMMEDIATE:
834adabf612SBryan Cantrill 			tsc = argv[argc - 1].a_un.a_val;
835f7b98820SBryan Cantrill 			break;
836f7b98820SBryan Cantrill 		default:
837f7b98820SBryan Cantrill 			return (DCMD_USAGE);
838f7b98820SBryan Cantrill 		}
839f7b98820SBryan Cantrill 	}
840f7b98820SBryan Cantrill 
841f7b98820SBryan Cantrill 	if (mdb_readsym(&scalehrtimef,
842f7b98820SBryan Cantrill 	    sizeof (scalehrtimef), "scalehrtimef") == -1) {
843f7b98820SBryan Cantrill 		mdb_warn("couldn't read 'scalehrtimef'");
844f7b98820SBryan Cantrill 		return (DCMD_ERR);
845f7b98820SBryan Cantrill 	}
846f7b98820SBryan Cantrill 
847f7b98820SBryan Cantrill 	if (mdb_lookup_by_name("tsc_scalehrtime", &sym) == -1) {
848f7b98820SBryan Cantrill 		mdb_warn("couldn't find 'tsc_scalehrtime'");
849f7b98820SBryan Cantrill 		return (DCMD_ERR);
850f7b98820SBryan Cantrill 	}
851f7b98820SBryan Cantrill 
852f7b98820SBryan Cantrill 	if (sym.st_value != scalehrtimef) {
853f7b98820SBryan Cantrill 		mdb_warn("::scalehrtime requires that scalehrtimef "
854f7b98820SBryan Cantrill 		    "be set to tsc_scalehrtime\n");
855f7b98820SBryan Cantrill 		return (DCMD_ERR);
856f7b98820SBryan Cantrill 	}
857f7b98820SBryan Cantrill 
858f7b98820SBryan Cantrill 	if (mdb_readsym(&nsec_scale, sizeof (nsec_scale), "nsec_scale") == -1) {
859f7b98820SBryan Cantrill 		mdb_warn("couldn't read 'nsec_scale'");
860f7b98820SBryan Cantrill 		return (DCMD_ERR);
861f7b98820SBryan Cantrill 	}
862f7b98820SBryan Cantrill 
863adabf612SBryan Cantrill 	if (mdb_readsym(&tsc_last, sizeof (tsc_last), "tsc_last") == -1) {
864adabf612SBryan Cantrill 		mdb_warn("couldn't read 'tsc_last'");
865adabf612SBryan Cantrill 		return (DCMD_ERR);
866adabf612SBryan Cantrill 	}
867adabf612SBryan Cantrill 
868adabf612SBryan Cantrill 	if (mdb_readsym(&base, sizeof (base), "tsc_hrtime_base") == -1) {
869adabf612SBryan Cantrill 		mdb_warn("couldn't read 'tsc_hrtime_base'");
870adabf612SBryan Cantrill 		return (DCMD_ERR);
871adabf612SBryan Cantrill 	}
872adabf612SBryan Cantrill 
873adabf612SBryan Cantrill 	/*
874adabf612SBryan Cantrill 	 * If our time is greater than half of tsc_last, we will take our
875adabf612SBryan Cantrill 	 * delta against tsc_last, convert it, and add that to (or subtract it
876adabf612SBryan Cantrill 	 * from) tsc_hrtime_base.  This mimics what the kernel actually does
877adabf612SBryan Cantrill 	 * in gethrtime() (modulo the tsc_sync_tick_delta) and gets us a much
878adabf612SBryan Cantrill 	 * higher precision result than trying to convert a large tsc value.
879adabf612SBryan Cantrill 	 */
880adabf612SBryan Cantrill 	if (absolute || (tsc > (tsc_last >> 1) && !relative)) {
881adabf612SBryan Cantrill 		if (tsc > tsc_last) {
882adabf612SBryan Cantrill 			tsc = tsc - tsc_last;
883adabf612SBryan Cantrill 		} else {
884adabf612SBryan Cantrill 			tsc = tsc_last - tsc;
885adabf612SBryan Cantrill 			mult = -1;
886adabf612SBryan Cantrill 		}
887adabf612SBryan Cantrill 	} else {
888adabf612SBryan Cantrill 		base = 0;
889adabf612SBryan Cantrill 	}
890adabf612SBryan Cantrill 
891f7b98820SBryan Cantrill 	scale = (uint64_t)nsec_scale;
892f7b98820SBryan Cantrill 
893f7b98820SBryan Cantrill 	hrt = ((uint64_t)tscp[1] * scale) << NSEC_SHIFT;
894f7b98820SBryan Cantrill 	hrt += ((uint64_t)tscp[0] * scale) >> (32 - NSEC_SHIFT);
895f7b98820SBryan Cantrill 
896adabf612SBryan Cantrill 	mdb_printf("0x%llx\n", base + (hrt * mult));
897f7b98820SBryan Cantrill 
898f7b98820SBryan Cantrill 	return (DCMD_OK);
899f7b98820SBryan Cantrill }
900f7b98820SBryan Cantrill 
90129f78cfaSRobert Mustacchi /*
90229f78cfaSRobert Mustacchi  * The x86 feature set is implemented as a bitmap array. That bitmap array is
90329f78cfaSRobert Mustacchi  * stored across a number of uchars based on the BT_SIZEOFMAP(NUM_X86_FEATURES)
90429f78cfaSRobert Mustacchi  * macro. We have the names for each of these features in unix's text segment
90529f78cfaSRobert Mustacchi  * so we do not have to duplicate them and instead just look them up.
90629f78cfaSRobert Mustacchi  */
90729f78cfaSRobert Mustacchi /*ARGSUSED*/
90829f78cfaSRobert Mustacchi static int
x86_featureset_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)909a8ea0c9dSJohn Levon x86_featureset_dcmd(uintptr_t addr, uint_t flags, int argc,
91029f78cfaSRobert Mustacchi     const mdb_arg_t *argv)
91129f78cfaSRobert Mustacchi {
91229f78cfaSRobert Mustacchi 	void *fset;
91329f78cfaSRobert Mustacchi 	GElf_Sym sym;
91429f78cfaSRobert Mustacchi 	uintptr_t nptr;
91529f78cfaSRobert Mustacchi 	char name[128];
91629f78cfaSRobert Mustacchi 	int ii;
91729f78cfaSRobert Mustacchi 
91829f78cfaSRobert Mustacchi 	size_t sz = sizeof (uchar_t) * BT_SIZEOFMAP(NUM_X86_FEATURES);
91929f78cfaSRobert Mustacchi 
92029f78cfaSRobert Mustacchi 	if (argc != 0)
92129f78cfaSRobert Mustacchi 		return (DCMD_USAGE);
92229f78cfaSRobert Mustacchi 
92329f78cfaSRobert Mustacchi 	if (mdb_lookup_by_name("x86_feature_names", &sym) == -1) {
92429f78cfaSRobert Mustacchi 		mdb_warn("couldn't find x86_feature_names");
92529f78cfaSRobert Mustacchi 		return (DCMD_ERR);
92629f78cfaSRobert Mustacchi 	}
92729f78cfaSRobert Mustacchi 
92829f78cfaSRobert Mustacchi 	fset = mdb_zalloc(sz, UM_NOSLEEP);
92929f78cfaSRobert Mustacchi 	if (fset == NULL) {
93029f78cfaSRobert Mustacchi 		mdb_warn("failed to allocate memory for x86_featureset");
93129f78cfaSRobert Mustacchi 		return (DCMD_ERR);
93229f78cfaSRobert Mustacchi 	}
93329f78cfaSRobert Mustacchi 
934*c280e5aaSRichard Lowe 	if (flags & DCMD_ADDRSPEC) {
935*c280e5aaSRichard Lowe 		if (mdb_vread(fset, sz, addr) != sz) {
936*c280e5aaSRichard Lowe 			mdb_warn("failed to read x86_featureset from %p", addr);
937*c280e5aaSRichard Lowe 			mdb_free(fset, sz);
938*c280e5aaSRichard Lowe 			return (DCMD_ERR);
939*c280e5aaSRichard Lowe 		}
940*c280e5aaSRichard Lowe 	} else {
941*c280e5aaSRichard Lowe 		if (mdb_readvar(fset, "x86_featureset") != sz) {
942*c280e5aaSRichard Lowe 			mdb_warn("failed to read x86_featureset");
943*c280e5aaSRichard Lowe 			mdb_free(fset, sz);
944*c280e5aaSRichard Lowe 			return (DCMD_ERR);
945*c280e5aaSRichard Lowe 		}
94629f78cfaSRobert Mustacchi 	}
94729f78cfaSRobert Mustacchi 
94829f78cfaSRobert Mustacchi 	for (ii = 0; ii < NUM_X86_FEATURES; ii++) {
94929f78cfaSRobert Mustacchi 		if (!BT_TEST((ulong_t *)fset, ii))
95029f78cfaSRobert Mustacchi 			continue;
95129f78cfaSRobert Mustacchi 
95229f78cfaSRobert Mustacchi 		if (mdb_vread(&nptr, sizeof (char *), sym.st_value +
95329f78cfaSRobert Mustacchi 		    sizeof (void *) * ii) != sizeof (char *)) {
95429f78cfaSRobert Mustacchi 			mdb_warn("failed to read feature array %d", ii);
95529f78cfaSRobert Mustacchi 			mdb_free(fset, sz);
95629f78cfaSRobert Mustacchi 			return (DCMD_ERR);
95729f78cfaSRobert Mustacchi 		}
95829f78cfaSRobert Mustacchi 
95929f78cfaSRobert Mustacchi 		if (mdb_readstr(name, sizeof (name), nptr) == -1) {
960*c280e5aaSRichard Lowe 			mdb_printf("unknown feature 0x%x\n", ii);
961*c280e5aaSRichard Lowe 		} else {
962*c280e5aaSRichard Lowe 			mdb_printf("%s\n", name);
96329f78cfaSRobert Mustacchi 		}
96429f78cfaSRobert Mustacchi 	}
96529f78cfaSRobert Mustacchi 
96629f78cfaSRobert Mustacchi 	mdb_free(fset, sz);
96729f78cfaSRobert Mustacchi 	return (DCMD_OK);
96829f78cfaSRobert Mustacchi }
96929f78cfaSRobert Mustacchi 
970799823bbSRobert Mustacchi #ifdef _KMDB
971799823bbSRobert Mustacchi /* ARGSUSED */
972799823bbSRobert Mustacchi static int
sysregs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)973309b04b8SJohn Levon sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
974799823bbSRobert Mustacchi {
9759c3024a3SHans Rosenfeld 	struct sysregs sregs = { 0 };
976309b04b8SJohn Levon 	desctbr_t gdtr;
9779c3024a3SHans Rosenfeld 	boolean_t longmode = B_FALSE;
978309b04b8SJohn Levon 
9799c3024a3SHans Rosenfeld #ifdef __amd64
9809c3024a3SHans Rosenfeld 	longmode = B_TRUE;
9819c3024a3SHans Rosenfeld #endif
982309b04b8SJohn Levon 
9839c3024a3SHans Rosenfeld 	sregs.sr_cr0 = kmdb_unix_getcr0();
9849c3024a3SHans Rosenfeld 	sregs.sr_cr2 = kmdb_unix_getcr2();
9859c3024a3SHans Rosenfeld 	sregs.sr_cr3 = kmdb_unix_getcr3();
9869c3024a3SHans Rosenfeld 	sregs.sr_cr4 = kmdb_unix_getcr4();
987399ca3a7SJohn Levon 
9889c3024a3SHans Rosenfeld 	kmdb_unix_getgdtr(&gdtr);
9899c3024a3SHans Rosenfeld 	sregs.sr_gdtr.d_base = gdtr.dtr_base;
9909c3024a3SHans Rosenfeld 	sregs.sr_gdtr.d_lim = gdtr.dtr_limit;
991399ca3a7SJohn Levon 
9929c3024a3SHans Rosenfeld 	mdb_x86_print_sysregs(&sregs, longmode);
993309b04b8SJohn Levon 
994799823bbSRobert Mustacchi 	return (DCMD_OK);
995799823bbSRobert Mustacchi }
996799823bbSRobert Mustacchi #endif
997799823bbSRobert Mustacchi 
998a8ea0c9dSJohn Levon extern void xcall_help(void);
999a8ea0c9dSJohn Levon extern int xcall_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
1000a8ea0c9dSJohn Levon 
10017c478bd9Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
10027c478bd9Sstevel@tonic-gate 	{ "gate_desc", ":", "dump a gate descriptor", gate_desc },
10037c478bd9Sstevel@tonic-gate 	{ "idt", ":[-v]", "dump an IDT", idt },
1004399ca3a7SJohn Levon 	{ "ttrace", "[-x] [-t kthread]", "dump trap trace buffers", ttrace },
10057c478bd9Sstevel@tonic-gate 	{ "vatopfn", ":[-a as]", "translate address to physical page",
10067c478bd9Sstevel@tonic-gate 	    va2pfn_dcmd },
1007ae115bc7Smrj 	{ "report_maps", ":[-m]",
1008ae115bc7Smrj 	    "Given PFN, report mappings / page table usage",
1009ae115bc7Smrj 	    report_maps_dcmd, report_maps_help },
1010ae115bc7Smrj 	{ "htables", "", "Given hat_t *, lists all its htable_t * values",
1011ae115bc7Smrj 	    htables_dcmd, htables_help },
101274ecdb51SJohn Levon 	{ "ptable", ":[-lm]", "Given PFN, dump contents of a page table",
1013ae115bc7Smrj 	    ptable_dcmd, ptable_help },
101474ecdb51SJohn Levon 	{ "ptmap", ":", "Given a cr3 value, dump all mappings",
101574ecdb51SJohn Levon 	    ptmap_dcmd, ptmap_help },
101674ecdb51SJohn Levon 	{ "pte", ":[-l N]", "print human readable page table entry",
10177c478bd9Sstevel@tonic-gate 	    pte_dcmd },
1018843e1988Sjohnlev 	{ "pfntomfn", ":", "convert physical page to hypervisor machine page",
1019843e1988Sjohnlev 	    pfntomfn_dcmd },
1020843e1988Sjohnlev 	{ "mfntopfn", ":", "convert hypervisor machine page to physical page",
1021843e1988Sjohnlev 	    mfntopfn_dcmd },
10227c478bd9Sstevel@tonic-gate 	{ "memseg_list", ":", "show memseg list", memseg_list },
1023adabf612SBryan Cantrill 	{ "scalehrtime", ":[-a|-r]", "scale an unscaled high-res time",
1024a8ea0c9dSJohn Levon 	    scalehrtime_dcmd, scalehrtime_help },
1025*c280e5aaSRichard Lowe 	{ "x86_featureset", ":", "dump the x86_featureset vector",
1026a8ea0c9dSJohn Levon 		x86_featureset_dcmd },
1027a8ea0c9dSJohn Levon 	{ "xcall", ":", "print CPU cross-call state", xcall_dcmd, xcall_help },
1028799823bbSRobert Mustacchi #ifdef _KMDB
1029309b04b8SJohn Levon 	{ "sysregs", NULL, "dump system registers", sysregs_dcmd },
1030799823bbSRobert Mustacchi #endif
10317c478bd9Sstevel@tonic-gate 	{ NULL }
10327c478bd9Sstevel@tonic-gate };
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
10357c478bd9Sstevel@tonic-gate 	{ "ttrace", "walks trap trace buffers in reverse chronological order",
10367c478bd9Sstevel@tonic-gate 		ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
10377c478bd9Sstevel@tonic-gate 	{ "mutex_owner", "walks the owner of a mutex",
10387c478bd9Sstevel@tonic-gate 		mutex_owner_init, mutex_owner_step },
10397c478bd9Sstevel@tonic-gate 	{ "memseg", "walk the memseg structures",
10407c478bd9Sstevel@tonic-gate 		memseg_walk_init, memseg_walk_step, memseg_walk_fini },
10417c478bd9Sstevel@tonic-gate 	{ NULL }
10427c478bd9Sstevel@tonic-gate };
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)10477c478bd9Sstevel@tonic-gate _mdb_init(void)
10487c478bd9Sstevel@tonic-gate {
10497c478bd9Sstevel@tonic-gate 	return (&modinfo);
10507c478bd9Sstevel@tonic-gate }
1051843e1988Sjohnlev 
1052843e1988Sjohnlev void
_mdb_fini(void)1053843e1988Sjohnlev _mdb_fini(void)
1054843e1988Sjohnlev {
1055843e1988Sjohnlev 	free_mmu();
1056843e1988Sjohnlev }
1057