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