Print this page
8956 Implement KPTI
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
9210 remove KMDB branch debugging support
9211 ::crregs could do with cr2/cr3 support
9209 ::ttrace should be able to filter by thread
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2015 Joyent, Inc.
  24  */
  25 
  26 #include <mdb/mdb_modapi.h>
  27 #include <mdb/mdb_ctf.h>
  28 #include <sys/cpuvar.h>
  29 #include <sys/systm.h>
  30 #include <sys/traptrace.h>
  31 #include <sys/x_call.h>
  32 #include <sys/xc_levels.h>
  33 #include <sys/avintr.h>
  34 #include <sys/systm.h>
  35 #include <sys/trap.h>
  36 #include <sys/mutex.h>
  37 #include <sys/mutex_impl.h>
  38 #include "i86mmu.h"
  39 #include "unix_sup.h"
  40 #include <sys/apix.h>
  41 #include <sys/x86_archext.h>
  42 #include <sys/bitmap.h>
  43 #include <sys/controlregs.h>


 392 }
 393 
 394 static struct {
 395         uchar_t t_marker;
 396         char *t_name;
 397         int (*t_hdlr)(trap_trace_rec_t *);
 398 } ttrace_hdlr[] = {
 399         { TT_SYSCALL, "sysc", ttrace_syscall },
 400         { TT_SYSENTER, "syse", ttrace_syscall },
 401         { TT_SYSC, "asys", ttrace_syscall },
 402         { TT_SYSC64, "sc64", ttrace_syscall },
 403         { TT_INTERRUPT, "intr", ttrace_interrupt },
 404         { TT_TRAP, "trap", ttrace_trap },
 405         { TT_EVENT, "evnt", ttrace_trap },
 406         { 0, NULL, NULL }
 407 };
 408 
 409 typedef struct ttrace_dcmd {
 410         processorid_t ttd_cpu;
 411         uint_t ttd_extended;

 412         trap_trace_ctl_t ttd_ttc[NCPU];
 413 } ttrace_dcmd_t;
 414 
 415 #if defined(__amd64)
 416 
 417 #define DUMP(reg) #reg, regs->r_##reg
 418 #define THREEREGS       "         %3s: %16lx %3s: %16lx %3s: %16lx\n"
 419 
 420 static void
 421 ttrace_dumpregs(trap_trace_rec_t *rec)
 422 {
 423         struct regs *regs = &rec->ttr_regs;
 424 
 425         mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
 426         mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
 427         mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
 428         mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
 429         mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
 430         mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
 431         mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
 432         mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
 433         mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);



 434         mdb_printf("\n");
 435 }
 436 
 437 #else
 438 
 439 #define DUMP(reg) #reg, regs->r_##reg
 440 #define FOURREGS        "         %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
 441 
 442 static void
 443 ttrace_dumpregs(trap_trace_rec_t *rec)
 444 {
 445         struct regs *regs = &rec->ttr_regs;
 446 
 447         mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
 448         mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
 449         mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
 450         mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
 451             DUMP(pc), DUMP(cs));
 452         mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
 453             "cr2", rec->ttr_cr2);


 461 {
 462         struct regs *regs = &rec->ttr_regs;
 463         processorid_t cpu = -1, i;
 464 
 465         for (i = 0; i < NCPU; i++) {
 466                 if (addr >= dcmd->ttd_ttc[i].ttc_first &&
 467                     addr < dcmd->ttd_ttc[i].ttc_limit) {
 468                         cpu = i;
 469                         break;
 470                 }
 471         }
 472 
 473         if (cpu == -1) {
 474                 mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
 475                 return (WALK_ERR);
 476         }
 477 
 478         if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
 479                 return (WALK_NEXT);
 480 




 481         mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
 482 
 483         for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
 484                 if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
 485                         continue;
 486                 mdb_printf("%4s ", ttrace_hdlr[i].t_name);
 487                 if (ttrace_hdlr[i].t_hdlr(rec) == -1)
 488                         return (WALK_ERR);
 489         }
 490 
 491         mdb_printf(" %a\n", regs->r_pc);
 492 
 493         if (dcmd->ttd_extended == FALSE)
 494                 return (WALK_NEXT);
 495 
 496         if (rec->ttr_marker == TT_INTERRUPT)
 497                 ttrace_intr_detail(rec);
 498         else
 499                 ttrace_dumpregs(rec);
 500 


 520 {
 521         ttrace_dcmd_t dcmd;
 522         trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
 523         trap_trace_rec_t rec;
 524         size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
 525 
 526         if (!ttrace_ttr_size_check())
 527                 return (WALK_ERR);
 528 
 529         bzero(&dcmd, sizeof (dcmd));
 530         dcmd.ttd_cpu = -1;
 531         dcmd.ttd_extended = FALSE;
 532 
 533         if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
 534                 mdb_warn("symbol 'trap_trace_ctl' not found; "
 535                     "non-TRAPTRACE kernel?\n");
 536                 return (DCMD_ERR);
 537         }
 538 
 539         if (mdb_getopts(argc, argv,
 540             'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc)

 541                 return (DCMD_USAGE);
 542 
 543         if (DCMD_HDRSPEC(flags)) {
 544                 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
 545                     "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
 546                     " EIP");
 547         }
 548 
 549         if (flags & DCMD_ADDRSPEC) {
 550                 if (addr >= NCPU) {
 551                         if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
 552                                 mdb_warn("couldn't read trap trace record "
 553                                     "at %p", addr);
 554                                 return (DCMD_ERR);
 555                         }
 556 
 557                         if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
 558                                 return (DCMD_ERR);
 559 
 560                         return (DCMD_OK);


 730             "that correspond to that address space\n");
 731 }
 732 
 733 static void
 734 report_maps_help(void)
 735 {
 736         mdb_printf(
 737             "Given a PFN, report HAT structures that map the page, or use\n"
 738             "the page as a pagetable.\n"
 739             "\n"
 740             "-m Interpret the PFN as an MFN (machine frame number)\n");
 741 }
 742 
 743 static void
 744 ptable_help(void)
 745 {
 746         mdb_printf(
 747             "Given a PFN holding a page table, print its contents, and\n"
 748             "the address of the corresponding htable structure.\n"
 749             "\n"
 750             "-m Interpret the PFN as an MFN (machine frame number)\n");

 751 }
 752 










 753 /*
 754  * NSEC_SHIFT is replicated here (it is not defined in a header file),
 755  * but for amusement, the reader is directed to the comment that explains
 756  * the rationale for this particular value on x86.  Spoiler:  the value is
 757  * selected to accommodate 60 MHz Pentiums!  (And a confession:  if the voice
 758  * in that comment sounds too familiar, it's because your author also wrote
 759  * that code -- some fifteen years prior to this writing in 2011...)
 760  */
 761 #define NSEC_SHIFT 5
 762 
 763 /*ARGSUSED*/
 764 static int
 765 scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 766 {
 767         uint32_t nsec_scale;
 768         hrtime_t tsc = addr, hrt;
 769         unsigned int *tscp = (unsigned int *)&tsc;
 770         uintptr_t scalehrtimef;
 771         uint64_t scale;
 772         GElf_Sym sym;


 869                         return (DCMD_ERR);
 870                 }
 871 
 872                 if (mdb_readstr(name, sizeof (name), nptr) == -1) {
 873                         mdb_warn("failed to read feature %d", ii);
 874                         mdb_free(fset, sz);
 875                         return (DCMD_ERR);
 876                 }
 877                 mdb_printf("%s\n", name);
 878         }
 879 
 880         mdb_free(fset, sz);
 881         return (DCMD_OK);
 882 }
 883 
 884 #ifdef _KMDB
 885 /* ARGSUSED */
 886 static int
 887 crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 888 {
 889         ulong_t cr0, cr4;
 890         static const mdb_bitmask_t cr0_flag_bits[] = {
 891                 { "PE",         CR0_PE,         CR0_PE },
 892                 { "MP",         CR0_MP,         CR0_MP },
 893                 { "EM",         CR0_EM,         CR0_EM },
 894                 { "TS",         CR0_TS,         CR0_TS },
 895                 { "ET",         CR0_ET,         CR0_ET },
 896                 { "NE",         CR0_NE,         CR0_NE },
 897                 { "WP",         CR0_WP,         CR0_WP },
 898                 { "AM",         CR0_AM,         CR0_AM },
 899                 { "NW",         CR0_NW,         CR0_NW },
 900                 { "CD",         CR0_CD,         CR0_CD },
 901                 { "PG",         CR0_PG,         CR0_PG },
 902                 { NULL,         0,              0 }
 903         };
 904 






 905         static const mdb_bitmask_t cr4_flag_bits[] = {
 906                 { "VME",        CR4_VME,        CR4_VME },
 907                 { "PVI",        CR4_PVI,        CR4_PVI },
 908                 { "TSD",        CR4_TSD,        CR4_TSD },
 909                 { "DE",         CR4_DE,         CR4_DE },
 910                 { "PSE",        CR4_PSE,        CR4_PSE },
 911                 { "PAE",        CR4_PAE,        CR4_PAE },
 912                 { "MCE",        CR4_MCE,        CR4_MCE },
 913                 { "PGE",        CR4_PGE,        CR4_PGE },
 914                 { "PCE",        CR4_PCE,        CR4_PCE },
 915                 { "OSFXSR",     CR4_OSFXSR,     CR4_OSFXSR },
 916                 { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
 917                 { "VMXE",       CR4_VMXE,       CR4_VMXE },
 918                 { "SMXE",       CR4_SMXE,       CR4_SMXE },

 919                 { "OSXSAVE",    CR4_OSXSAVE,    CR4_OSXSAVE },
 920                 { "SMEP",       CR4_SMEP,       CR4_SMEP },
 921                 { "SMAP",       CR4_SMAP,       CR4_SMAP },
 922                 { NULL,         0,              0 }
 923         };
 924 
 925         cr0 = kmdb_unix_getcr0();


 926         cr4 = kmdb_unix_getcr4();
 927         mdb_printf("%%cr0 = 0x%08x <%b>\n", cr0, cr0, cr0_flag_bits);
 928         mdb_printf("%%cr4 = 0x%08x <%b>\n", cr4, cr4, cr4_flag_bits);











 929         return (DCMD_OK);
 930 }
 931 #endif
 932 
 933 static const mdb_dcmd_t dcmds[] = {
 934         { "gate_desc", ":", "dump a gate descriptor", gate_desc },
 935         { "idt", ":[-v]", "dump an IDT", idt },
 936         { "ttrace", "[-x]", "dump trap trace buffers", ttrace },
 937         { "vatopfn", ":[-a as]", "translate address to physical page",
 938             va2pfn_dcmd },
 939         { "report_maps", ":[-m]",
 940             "Given PFN, report mappings / page table usage",
 941             report_maps_dcmd, report_maps_help },
 942         { "htables", "", "Given hat_t *, lists all its htable_t * values",
 943             htables_dcmd, htables_help },
 944         { "ptable", ":[-m]", "Given PFN, dump contents of a page table",
 945             ptable_dcmd, ptable_help },
 946         { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry",


 947             pte_dcmd },
 948         { "pfntomfn", ":", "convert physical page to hypervisor machine page",
 949             pfntomfn_dcmd },
 950         { "mfntopfn", ":", "convert hypervisor machine page to physical page",
 951             mfntopfn_dcmd },
 952         { "memseg_list", ":", "show memseg list", memseg_list },
 953         { "scalehrtime", ":",
 954             "scale an unscaled high-res time", scalehrtime_cmd },
 955         { "x86_featureset", NULL, "dump the x86_featureset vector",
 956                 x86_featureset_cmd },
 957 #ifdef _KMDB
 958         { "crregs", NULL, "dump control registers", crregs_dcmd },
 959 #endif
 960         { NULL }
 961 };
 962 
 963 static const mdb_walker_t walkers[] = {
 964         { "ttrace", "walks trap trace buffers in reverse chronological order",
 965                 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
 966         { "mutex_owner", "walks the owner of a mutex",


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Joyent, Inc.
  24  */
  25 
  26 #include <mdb/mdb_modapi.h>
  27 #include <mdb/mdb_ctf.h>
  28 #include <sys/cpuvar.h>
  29 #include <sys/systm.h>
  30 #include <sys/traptrace.h>
  31 #include <sys/x_call.h>
  32 #include <sys/xc_levels.h>
  33 #include <sys/avintr.h>
  34 #include <sys/systm.h>
  35 #include <sys/trap.h>
  36 #include <sys/mutex.h>
  37 #include <sys/mutex_impl.h>
  38 #include "i86mmu.h"
  39 #include "unix_sup.h"
  40 #include <sys/apix.h>
  41 #include <sys/x86_archext.h>
  42 #include <sys/bitmap.h>
  43 #include <sys/controlregs.h>


 392 }
 393 
 394 static struct {
 395         uchar_t t_marker;
 396         char *t_name;
 397         int (*t_hdlr)(trap_trace_rec_t *);
 398 } ttrace_hdlr[] = {
 399         { TT_SYSCALL, "sysc", ttrace_syscall },
 400         { TT_SYSENTER, "syse", ttrace_syscall },
 401         { TT_SYSC, "asys", ttrace_syscall },
 402         { TT_SYSC64, "sc64", ttrace_syscall },
 403         { TT_INTERRUPT, "intr", ttrace_interrupt },
 404         { TT_TRAP, "trap", ttrace_trap },
 405         { TT_EVENT, "evnt", ttrace_trap },
 406         { 0, NULL, NULL }
 407 };
 408 
 409 typedef struct ttrace_dcmd {
 410         processorid_t ttd_cpu;
 411         uint_t ttd_extended;
 412         uintptr_t ttd_kthread;
 413         trap_trace_ctl_t ttd_ttc[NCPU];
 414 } ttrace_dcmd_t;
 415 
 416 #if defined(__amd64)
 417 
 418 #define DUMP(reg) #reg, regs->r_##reg
 419 #define THREEREGS       "         %3s: %16lx %3s: %16lx %3s: %16lx\n"
 420 
 421 static void
 422 ttrace_dumpregs(trap_trace_rec_t *rec)
 423 {
 424         struct regs *regs = &rec->ttr_regs;
 425 
 426         mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
 427         mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
 428         mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
 429         mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
 430         mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
 431         mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
 432         mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
 433         mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
 434         mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);
 435         mdb_printf("         %3s: %16lx %3s: %16lx\n",
 436             "fsb", regs->__r_fsbase,
 437             "gsb", regs->__r_gsbase);
 438         mdb_printf("\n");
 439 }
 440 
 441 #else
 442 
 443 #define DUMP(reg) #reg, regs->r_##reg
 444 #define FOURREGS        "         %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
 445 
 446 static void
 447 ttrace_dumpregs(trap_trace_rec_t *rec)
 448 {
 449         struct regs *regs = &rec->ttr_regs;
 450 
 451         mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
 452         mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
 453         mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
 454         mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
 455             DUMP(pc), DUMP(cs));
 456         mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
 457             "cr2", rec->ttr_cr2);


 465 {
 466         struct regs *regs = &rec->ttr_regs;
 467         processorid_t cpu = -1, i;
 468 
 469         for (i = 0; i < NCPU; i++) {
 470                 if (addr >= dcmd->ttd_ttc[i].ttc_first &&
 471                     addr < dcmd->ttd_ttc[i].ttc_limit) {
 472                         cpu = i;
 473                         break;
 474                 }
 475         }
 476 
 477         if (cpu == -1) {
 478                 mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
 479                 return (WALK_ERR);
 480         }
 481 
 482         if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
 483                 return (WALK_NEXT);
 484 
 485         if (dcmd->ttd_kthread != 0 &&
 486             dcmd->ttd_kthread != rec->ttr_curthread)
 487                 return (WALK_NEXT);
 488 
 489         mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
 490 
 491         for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
 492                 if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
 493                         continue;
 494                 mdb_printf("%4s ", ttrace_hdlr[i].t_name);
 495                 if (ttrace_hdlr[i].t_hdlr(rec) == -1)
 496                         return (WALK_ERR);
 497         }
 498 
 499         mdb_printf(" %a\n", regs->r_pc);
 500 
 501         if (dcmd->ttd_extended == FALSE)
 502                 return (WALK_NEXT);
 503 
 504         if (rec->ttr_marker == TT_INTERRUPT)
 505                 ttrace_intr_detail(rec);
 506         else
 507                 ttrace_dumpregs(rec);
 508 


 528 {
 529         ttrace_dcmd_t dcmd;
 530         trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
 531         trap_trace_rec_t rec;
 532         size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
 533 
 534         if (!ttrace_ttr_size_check())
 535                 return (WALK_ERR);
 536 
 537         bzero(&dcmd, sizeof (dcmd));
 538         dcmd.ttd_cpu = -1;
 539         dcmd.ttd_extended = FALSE;
 540 
 541         if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
 542                 mdb_warn("symbol 'trap_trace_ctl' not found; "
 543                     "non-TRAPTRACE kernel?\n");
 544                 return (DCMD_ERR);
 545         }
 546 
 547         if (mdb_getopts(argc, argv,
 548             'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended,
 549             't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc)
 550                 return (DCMD_USAGE);
 551 
 552         if (DCMD_HDRSPEC(flags)) {
 553                 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
 554                     "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
 555                     " EIP");
 556         }
 557 
 558         if (flags & DCMD_ADDRSPEC) {
 559                 if (addr >= NCPU) {
 560                         if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
 561                                 mdb_warn("couldn't read trap trace record "
 562                                     "at %p", addr);
 563                                 return (DCMD_ERR);
 564                         }
 565 
 566                         if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
 567                                 return (DCMD_ERR);
 568 
 569                         return (DCMD_OK);


 739             "that correspond to that address space\n");
 740 }
 741 
 742 static void
 743 report_maps_help(void)
 744 {
 745         mdb_printf(
 746             "Given a PFN, report HAT structures that map the page, or use\n"
 747             "the page as a pagetable.\n"
 748             "\n"
 749             "-m Interpret the PFN as an MFN (machine frame number)\n");
 750 }
 751 
 752 static void
 753 ptable_help(void)
 754 {
 755         mdb_printf(
 756             "Given a PFN holding a page table, print its contents, and\n"
 757             "the address of the corresponding htable structure.\n"
 758             "\n"
 759             "-m Interpret the PFN as an MFN (machine frame number)\n"
 760             "-l force page table level (3 is top)\n");
 761 }
 762 
 763 static void
 764 ptmap_help(void)
 765 {
 766         mdb_printf(
 767             "Report all mappings represented by the page table hierarchy\n"
 768             "rooted at the given cr3 value / physical address.\n"
 769             "\n"
 770             "-w run ::whatis on mapping start addresses\n");
 771 }
 772 
 773 /*
 774  * NSEC_SHIFT is replicated here (it is not defined in a header file),
 775  * but for amusement, the reader is directed to the comment that explains
 776  * the rationale for this particular value on x86.  Spoiler:  the value is
 777  * selected to accommodate 60 MHz Pentiums!  (And a confession:  if the voice
 778  * in that comment sounds too familiar, it's because your author also wrote
 779  * that code -- some fifteen years prior to this writing in 2011...)
 780  */
 781 #define NSEC_SHIFT 5
 782 
 783 /*ARGSUSED*/
 784 static int
 785 scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 786 {
 787         uint32_t nsec_scale;
 788         hrtime_t tsc = addr, hrt;
 789         unsigned int *tscp = (unsigned int *)&tsc;
 790         uintptr_t scalehrtimef;
 791         uint64_t scale;
 792         GElf_Sym sym;


 889                         return (DCMD_ERR);
 890                 }
 891 
 892                 if (mdb_readstr(name, sizeof (name), nptr) == -1) {
 893                         mdb_warn("failed to read feature %d", ii);
 894                         mdb_free(fset, sz);
 895                         return (DCMD_ERR);
 896                 }
 897                 mdb_printf("%s\n", name);
 898         }
 899 
 900         mdb_free(fset, sz);
 901         return (DCMD_OK);
 902 }
 903 
 904 #ifdef _KMDB
 905 /* ARGSUSED */
 906 static int
 907 crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 908 {
 909         ulong_t cr0, cr2, cr3, cr4;
 910         static const mdb_bitmask_t cr0_flag_bits[] = {
 911                 { "PE",         CR0_PE,         CR0_PE },
 912                 { "MP",         CR0_MP,         CR0_MP },
 913                 { "EM",         CR0_EM,         CR0_EM },
 914                 { "TS",         CR0_TS,         CR0_TS },
 915                 { "ET",         CR0_ET,         CR0_ET },
 916                 { "NE",         CR0_NE,         CR0_NE },
 917                 { "WP",         CR0_WP,         CR0_WP },
 918                 { "AM",         CR0_AM,         CR0_AM },
 919                 { "NW",         CR0_NW,         CR0_NW },
 920                 { "CD",         CR0_CD,         CR0_CD },
 921                 { "PG",         CR0_PG,         CR0_PG },
 922                 { NULL,         0,              0 }
 923         };
 924 
 925         static const mdb_bitmask_t cr3_flag_bits[] = {
 926                 { "PCD",        CR3_PCD,        CR3_PCD },
 927                 { "PWT",        CR3_PWT,        CR3_PWT },
 928                 { NULL,         0,              0, }
 929         };
 930 
 931         static const mdb_bitmask_t cr4_flag_bits[] = {
 932                 { "VME",        CR4_VME,        CR4_VME },
 933                 { "PVI",        CR4_PVI,        CR4_PVI },
 934                 { "TSD",        CR4_TSD,        CR4_TSD },
 935                 { "DE",         CR4_DE,         CR4_DE },
 936                 { "PSE",        CR4_PSE,        CR4_PSE },
 937                 { "PAE",        CR4_PAE,        CR4_PAE },
 938                 { "MCE",        CR4_MCE,        CR4_MCE },
 939                 { "PGE",        CR4_PGE,        CR4_PGE },
 940                 { "PCE",        CR4_PCE,        CR4_PCE },
 941                 { "OSFXSR",     CR4_OSFXSR,     CR4_OSFXSR },
 942                 { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
 943                 { "VMXE",       CR4_VMXE,       CR4_VMXE },
 944                 { "SMXE",       CR4_SMXE,       CR4_SMXE },
 945                 { "PCIDE",      CR4_PCIDE,      CR4_PCIDE },
 946                 { "OSXSAVE",    CR4_OSXSAVE,    CR4_OSXSAVE },
 947                 { "SMEP",       CR4_SMEP,       CR4_SMEP },
 948                 { "SMAP",       CR4_SMAP,       CR4_SMAP },
 949                 { NULL,         0,              0 }
 950         };
 951 
 952         cr0 = kmdb_unix_getcr0();
 953         cr2 = kmdb_unix_getcr2();
 954         cr3 = kmdb_unix_getcr3();
 955         cr4 = kmdb_unix_getcr4();
 956         mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
 957         mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
 958 
 959         if ((cr4 & CR4_PCIDE)) {
 960                 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3,
 961                     cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET);
 962         } else {
 963                 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3,
 964                     cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits);
 965         }
 966 
 967         mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
 968 
 969         return (DCMD_OK);
 970 }
 971 #endif
 972 
 973 static const mdb_dcmd_t dcmds[] = {
 974         { "gate_desc", ":", "dump a gate descriptor", gate_desc },
 975         { "idt", ":[-v]", "dump an IDT", idt },
 976         { "ttrace", "[-x] [-t kthread]", "dump trap trace buffers", ttrace },
 977         { "vatopfn", ":[-a as]", "translate address to physical page",
 978             va2pfn_dcmd },
 979         { "report_maps", ":[-m]",
 980             "Given PFN, report mappings / page table usage",
 981             report_maps_dcmd, report_maps_help },
 982         { "htables", "", "Given hat_t *, lists all its htable_t * values",
 983             htables_dcmd, htables_help },
 984         { "ptable", ":[-lm]", "Given PFN, dump contents of a page table",
 985             ptable_dcmd, ptable_help },
 986         { "ptmap", ":", "Given a cr3 value, dump all mappings",
 987             ptmap_dcmd, ptmap_help },
 988         { "pte", ":[-l N]", "print human readable page table entry",
 989             pte_dcmd },
 990         { "pfntomfn", ":", "convert physical page to hypervisor machine page",
 991             pfntomfn_dcmd },
 992         { "mfntopfn", ":", "convert hypervisor machine page to physical page",
 993             mfntopfn_dcmd },
 994         { "memseg_list", ":", "show memseg list", memseg_list },
 995         { "scalehrtime", ":",
 996             "scale an unscaled high-res time", scalehrtime_cmd },
 997         { "x86_featureset", NULL, "dump the x86_featureset vector",
 998                 x86_featureset_cmd },
 999 #ifdef _KMDB
1000         { "crregs", NULL, "dump control registers", crregs_dcmd },
1001 #endif
1002         { NULL }
1003 };
1004 
1005 static const mdb_walker_t walkers[] = {
1006         { "ttrace", "walks trap trace buffers in reverse chronological order",
1007                 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
1008         { "mutex_owner", "walks the owner of a mutex",