summaryrefslogtreecommitdiff
path: root/usr/src/cmd/mdb
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/mdb')
-rw-r--r--usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c2
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c7
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_create.c9
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_fmt.c6
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_kproc.c3
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_kvm.c2
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_main.c32
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_rawfile.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_target.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_target.h13
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile3
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix.c79
-rw-r--r--usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile3
-rw-r--r--usr/src/cmd/mdb/intel/Makefile.kmdb3
-rw-r--r--usr/src/cmd/mdb/intel/amd64/Makefile.kmdb5
-rw-r--r--usr/src/cmd/mdb/intel/amd64/mdb/Makefile17
-rw-r--r--usr/src/cmd/mdb/intel/kmdb/kaif.c34
-rw-r--r--usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c1
-rw-r--r--usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c1
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c35
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c1461
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c83
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_isautil.h7
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_kreg.h12
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_x86util.c215
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_x86util.h68
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c4
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c6
30 files changed, 1976 insertions, 157 deletions
diff --git a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
index 90fd098d1c..628503d179 100644
--- a/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
+++ b/usr/src/cmd/mdb/common/kmdb/kmdb_kvm.c
@@ -286,6 +286,8 @@ kmt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
case (uintptr_t)MDB_TGT_AS_IO:
return (set_errno(EINVAL));
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
if ((asp = (struct as *)kmt_read_kas(t)) == NULL)
return (-1); /* errno is set for us */
break;
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index b7b15aa507..10c622443a 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -2090,7 +2090,7 @@ cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
if (opt_f)
as = MDB_TGT_AS_FILE;
else
- as = MDB_TGT_AS_VIRT;
+ as = MDB_TGT_AS_VIRT_I;
if (opt_w == FALSE) {
n++;
@@ -2635,8 +2635,9 @@ tgt_status(const mdb_tgt_status_t *tsp)
return (DCMD_OK);
if (tsp->st_pc != 0) {
- if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
- buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
+ if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
+ MDB_TGT_AS_VIRT_I, buf, sizeof (buf), tsp->st_pc) !=
+ tsp->st_pc)
format = "target stopped at:\n%-#16a%8T%s\n";
else
format = "target stopped at %a:\n";
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_create.c b/usr/src/cmd/mdb/common/mdb/mdb_create.c
index ea30457ef0..86490bf825 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_create.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_create.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
#include <mdb/mdb.h>
#include <mdb/mdb_conf.h>
@@ -51,6 +53,11 @@ mdb_create_builtin_tgts(void)
if ((mp = mdb_module_load_builtin("mdb_raw")) != NULL)
mp->mod_tgt_ctor = mdb_rawfile_tgt_create;
+
+#ifdef __amd64
+ if ((mp = mdb_module_load_builtin("mdb_bhyve")) != NULL)
+ mp->mod_tgt_ctor = mdb_bhyve_tgt_create;
+#endif
}
void
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
index 662cf7bea5..6a745b2ac4 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
@@ -411,6 +411,9 @@ fmt_instr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
char buf[BUFSIZ];
uintptr_t naddr;
+ if (as == MDB_TGT_AS_VIRT)
+ as = MDB_TGT_AS_VIRT_I;
+
while (cnt-- != 0) {
naddr = mdb_dis_ins2str(mdb.m_disasm, t, as,
buf, sizeof (buf), addr);
@@ -431,6 +434,9 @@ fmt_dotinstr(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
uintptr_t naddr;
uint32_t i;
+ if (as == MDB_TGT_AS_VIRT)
+ as = MDB_TGT_AS_VIRT_I;
+
for (mdb_iob_clrflags(mdb.m_out, oflags); cnt-- != 0; addr = naddr) {
if (mdb_tgt_aread(t, as, &i, sizeof (i), addr) != sizeof (i)) {
warn("failed to read data from target");
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
index e13dcea53f..4eeb8ac708 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_kproc.c
@@ -553,7 +553,8 @@ kp_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
kp_data_t *kp = t->t_data;
physaddr_t pa;
- if (as != MDB_TGT_AS_VIRT)
+ if (as != MDB_TGT_AS_VIRT && as != MDB_TGT_AS_VIRT_I &&
+ as != MDB_TGT_AS_VIRT_S)
return (set_errno(EINVAL));
if ((pa = kvm_physaddr(kp->kp_cookie, kp->kp_as, va)) != -1ULL) {
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
index fe280c05c7..27ca238ca9 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_kvm.c
@@ -814,6 +814,8 @@ kt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap)
case (uintptr_t)MDB_TGT_AS_IO:
return (set_errno(EINVAL));
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
asp = kt->k_as;
break;
default:
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_main.c b/usr/src/cmd/mdb/common/mdb/mdb_main.c
index eea4b5b60e..8747464328 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_main.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c
@@ -322,12 +322,13 @@ static void
usage(int status)
{
mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
- "[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
+ "[-b VM] [-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
"[-R root] [-V dis-version] [-e expr] "
"[object [core] | core | suffix]\n\n",
mdb.m_pname);
mdb_iob_puts(mdb.m_err,
+ "\t-b attach to specified bhyve VM\n"
"\t-e evaluate expr and return status\n"
"\t-f force raw file debugging mode\n"
"\t-k force kernel debugging mode\n"
@@ -405,6 +406,19 @@ identify_xvm_file(const char *file, int *longmode)
}
#endif /* __x86 */
+#ifndef __amd64
+/*
+ * There is no bhyve target in a 32bit x86 or any SPARC mdb. This dummy helps
+ * keep the code simpler.
+ */
+/*ARGSUSED*/
+static int
+mdb_bhyve_tgt_create(mdb_tgt_t *t, int argc, const char *argv[])
+{
+ return (set_errno(EINVAL));
+}
+#endif
+
int
main(int argc, char *argv[], char *envp[])
{
@@ -424,6 +438,7 @@ main(int argc, char *argv[], char *envp[])
const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL;
const char *eflag = NULL;
int fflag = 0, Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0;
+ int bflag = 0;
int ttylike;
int longmode = 0;
@@ -513,8 +528,12 @@ main(int argc, char *argv[], char *envp[])
while (optind < argc) {
while ((c = getopt(argc, argv,
- "e:fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
+ "be:fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
switch (c) {
+ case 'b':
+ bflag++;
+ tgt_ctor = mdb_bhyve_tgt_create;
+ break;
case 'e':
if (eflag != NULL) {
warn("-e already specified\n");
@@ -830,6 +849,15 @@ main(int argc, char *argv[], char *envp[])
if (fflag)
goto tcreate; /* skip re-exec and just create target */
+ /* bhyve: directly create target, or re-exec in case of 32bit */
+ if (bflag) {
+#ifndef __amd64
+ goto reexec;
+#else
+ goto tcreate;
+#endif
+ }
+
/*
* If we just have an object file name, and that file doesn't
* exist, and it's a string of digits, infer it to be a
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c b/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
index 086639de74..d21ad0f38a 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_rawfile.c
@@ -143,6 +143,8 @@ rf_aread(mdb_tgt_t *t, mdb_tgt_as_t as, void *buf,
{
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
case (uintptr_t)MDB_TGT_AS_PHYS:
if (RF_CORE(t->t_data) != NULL)
return (rf_read(RF_CORE(t->t_data), buf, len, addr));
@@ -160,6 +162,8 @@ rf_awrite(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf,
{
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
case (uintptr_t)MDB_TGT_AS_PHYS:
if (RF_CORE(t->t_data) != NULL)
return (rf_write(RF_CORE(t->t_data), buf, len, addr));
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target.c b/usr/src/cmd/mdb/common/mdb/mdb_target.c
index 17aef0aac1..e0ae29bd99 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_target.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target.c
@@ -398,6 +398,8 @@ mdb_tgt_aread(mdb_tgt_t *t, mdb_tgt_as_t as,
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
return (t->t_ops->t_vread(t, buf, n, addr));
case (uintptr_t)MDB_TGT_AS_PHYS:
return (t->t_ops->t_pread(t, buf, n, addr));
@@ -421,6 +423,8 @@ mdb_tgt_awrite(mdb_tgt_t *t, mdb_tgt_as_t as,
switch ((uintptr_t)as) {
case (uintptr_t)MDB_TGT_AS_VIRT:
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
return (t->t_ops->t_vwrite(t, buf, n, addr));
case (uintptr_t)MDB_TGT_AS_PHYS:
return (t->t_ops->t_pwrite(t, buf, n, addr));
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target.h b/usr/src/cmd/mdb/common/mdb/mdb_target.h
index c36b85e2f3..e385caa38e 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_target.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target.h
@@ -64,6 +64,9 @@ extern int mdb_kvm_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_proc_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_kproc_tgt_create(mdb_tgt_t *, int, const char *[]);
extern int mdb_rawfile_tgt_create(mdb_tgt_t *, int, const char *[]);
+#ifdef __amd64
+extern int mdb_bhyve_tgt_create(mdb_tgt_t *, int, const char *[]);
+#endif
#else
extern int kmdb_kvm_create(mdb_tgt_t *, int, const char *[]);
#endif
@@ -139,10 +142,12 @@ typedef void * mdb_tgt_as_t; /* Opaque address space id */
typedef uint64_t mdb_tgt_addr_t; /* Generic unsigned address */
typedef uint64_t physaddr_t; /* Physical memory address */
-#define MDB_TGT_AS_VIRT ((mdb_tgt_as_t)-1L) /* Virtual address space */
-#define MDB_TGT_AS_PHYS ((mdb_tgt_as_t)-2L) /* Physical address space */
-#define MDB_TGT_AS_FILE ((mdb_tgt_as_t)-3L) /* Object file address space */
-#define MDB_TGT_AS_IO ((mdb_tgt_as_t)-4L) /* I/o address space */
+#define MDB_TGT_AS_VIRT ((mdb_tgt_as_t)-1L) /* Virtual address space: */
+#define MDB_TGT_AS_VIRT_I ((mdb_tgt_as_t)-2L) /* special case for code */
+#define MDB_TGT_AS_VIRT_S ((mdb_tgt_as_t)-3L) /* special case for stack */
+#define MDB_TGT_AS_PHYS ((mdb_tgt_as_t)-4L) /* Physical address space */
+#define MDB_TGT_AS_FILE ((mdb_tgt_as_t)-5L) /* Object file address space */
+#define MDB_TGT_AS_IO ((mdb_tgt_as_t)-6L) /* I/o address space */
extern ssize_t mdb_tgt_aread(mdb_tgt_t *, mdb_tgt_as_t,
void *, size_t, mdb_tgt_addr_t);
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile b/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
index efcfad5375..54bc62a086 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile
@@ -22,7 +22,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
MODULE = unix.so
MDBTGT = kvm
@@ -38,6 +38,7 @@ include ../../../../Makefile.module
CPPFLAGS += -DMP -D_MACHDEP
CPPFLAGS += -I../../../../common
+CPPFLAGS += -I../../../../intel
CPPFLAGS += -I$(SRC)/uts/i86pc
CPPFLAGS += -I$(SRC)/uts/intel
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
index e91321b235..c3b7e809e4 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
@@ -20,11 +20,13 @@
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2019 Joyent, Inc.
*/
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_x86util.h>
#include <sys/cpuvar.h>
#include <sys/systm.h>
#include <sys/traptrace.h>
@@ -963,73 +965,24 @@ x86_featureset_dcmd(uintptr_t addr, uint_t flags, int argc,
static int
sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
- ulong_t cr0, cr2, cr3, cr4;
+ struct sysregs sregs = { 0 };
desctbr_t gdtr;
+ boolean_t longmode = B_FALSE;
- static const mdb_bitmask_t cr0_flag_bits[] = {
- { "PE", CR0_PE, CR0_PE },
- { "MP", CR0_MP, CR0_MP },
- { "EM", CR0_EM, CR0_EM },
- { "TS", CR0_TS, CR0_TS },
- { "ET", CR0_ET, CR0_ET },
- { "NE", CR0_NE, CR0_NE },
- { "WP", CR0_WP, CR0_WP },
- { "AM", CR0_AM, CR0_AM },
- { "NW", CR0_NW, CR0_NW },
- { "CD", CR0_CD, CR0_CD },
- { "PG", CR0_PG, CR0_PG },
- { NULL, 0, 0 }
- };
-
- static const mdb_bitmask_t cr3_flag_bits[] = {
- { "PCD", CR3_PCD, CR3_PCD },
- { "PWT", CR3_PWT, CR3_PWT },
- { NULL, 0, 0, }
- };
-
- static const mdb_bitmask_t cr4_flag_bits[] = {
- { "VME", CR4_VME, CR4_VME },
- { "PVI", CR4_PVI, CR4_PVI },
- { "TSD", CR4_TSD, CR4_TSD },
- { "DE", CR4_DE, CR4_DE },
- { "PSE", CR4_PSE, CR4_PSE },
- { "PAE", CR4_PAE, CR4_PAE },
- { "MCE", CR4_MCE, CR4_MCE },
- { "PGE", CR4_PGE, CR4_PGE },
- { "PCE", CR4_PCE, CR4_PCE },
- { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
- { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
- { "VMXE", CR4_VMXE, CR4_VMXE },
- { "SMXE", CR4_SMXE, CR4_SMXE },
- { "PCIDE", CR4_PCIDE, CR4_PCIDE },
- { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
- { "SMEP", CR4_SMEP, CR4_SMEP },
- { "SMAP", CR4_SMAP, CR4_SMAP },
- { NULL, 0, 0 }
- };
-
- cr0 = kmdb_unix_getcr0();
- cr2 = kmdb_unix_getcr2();
- cr3 = kmdb_unix_getcr3();
- cr4 = kmdb_unix_getcr4();
-
- kmdb_unix_getgdtr(&gdtr);
+#ifdef __amd64
+ longmode = B_TRUE;
+#endif
- mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
- mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
+ sregs.sr_cr0 = kmdb_unix_getcr0();
+ sregs.sr_cr2 = kmdb_unix_getcr2();
+ sregs.sr_cr3 = kmdb_unix_getcr3();
+ sregs.sr_cr4 = kmdb_unix_getcr4();
- if ((cr4 & CR4_PCIDE)) {
- mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3,
- cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET);
- } else {
- mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3,
- cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits);
- }
-
- mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
+ kmdb_unix_getgdtr(&gdtr);
+ sregs.sr_gdtr.d_base = gdtr.dtr_base;
+ sregs.sr_gdtr.d_lim = gdtr.dtr_limit;
- mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n",
- gdtr.dtr_base, gdtr.dtr_limit);
+ mdb_x86_print_sysregs(&sregs, longmode);
return (DCMD_OK);
}
diff --git a/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile b/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
index 32c1fe33fd..5854a1610e 100644
--- a/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
+++ b/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile
@@ -22,7 +22,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
MODULE = unix.so
MDBTGT = kvm
@@ -40,6 +40,7 @@ MODSRCS_DIR = ../../../../i86pc/modules/unix/
CPPFLAGS += -DMP -D_MACHDEP -D__xpv
CPPFLAGS += -I../../../../common
+CPPFLAGS += -I../../../../intel
CPPFLAGS += -I$(SRC)/uts/common
CPPFLAGS += -I$(SRC)/uts/i86xpv
CPPFLAGS += -I$(SRC)/uts/i86pc
diff --git a/usr/src/cmd/mdb/intel/Makefile.kmdb b/usr/src/cmd/mdb/intel/Makefile.kmdb
index 1e9efcbc83..6151a2e46a 100644
--- a/usr/src/cmd/mdb/intel/Makefile.kmdb
+++ b/usr/src/cmd/mdb/intel/Makefile.kmdb
@@ -22,7 +22,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2019, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
PROMSRCS += \
@@ -68,6 +68,7 @@ KMDBLIBS = $(STANDLIBS) ../mdb_ks/kmod/mdb_ks
MAPFILE_SOURCES = \
$(MAPFILE_SOURCES_COMMON) \
../../kmdb/kmdb_dpi_isadep.h \
+ ../../mdb/mdb_x86util.h \
$(MAPFILE_SOURCES_$(MACH))
%.o: ../../../../../uts/intel/promif/%.c
diff --git a/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb b/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
index 61cf1541a2..8cee9ff049 100644
--- a/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
+++ b/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb
@@ -22,6 +22,8 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
KMDBML += \
kaif_invoke.s \
@@ -29,6 +31,7 @@ KMDBML += \
KMDBSRCS += \
kmdb_makecontext.c \
- mdb_amd64util.c
+ mdb_amd64util.c \
+ mdb_x86util.c
SACPPFLAGS = -D__$(MACH64) -U__$(MACH)
diff --git a/usr/src/cmd/mdb/intel/amd64/mdb/Makefile b/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
index 3dfa7a34d5..918aa71ea1 100644
--- a/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
+++ b/usr/src/cmd/mdb/intel/amd64/mdb/Makefile
@@ -22,10 +22,15 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
SRCS = kvm_amd64dep.c \
kvm_isadep.c \
mdb_amd64util.c \
+ mdb_ia32util.c \
+ mdb_x86util.c \
+ mdb_bhyve.c \
proc_amd64dep.c
%.o: %.c
@@ -42,12 +47,14 @@ SRCS = kvm_amd64dep.c \
%.ln: ../../mdb/%.c
$(LINT.c) -c $<
-include ../../../../Makefile.cmd
-include ../../../../Makefile.cmd.64
-include ../../Makefile.amd64
-include ../../../Makefile.mdb
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/cmd/Makefile.cmd.64
+include $(SRC)/cmd/mdb/intel/Makefile.amd64
+include $(SRC)/cmd/mdb/Makefile.mdb
+include $(SRC)/Makefile.psm
CPPFLAGS += -I../../mdb
-LDLIBS += -lsaveargs
+
+LDLIBS += -lsaveargs -lvmm
install: all $(ISAEXEC) $(ROOTPROG64) $(ROOTLINK64)
diff --git a/usr/src/cmd/mdb/intel/kmdb/kaif.c b/usr/src/cmd/mdb/intel/kmdb/kaif.c
index 39cc9b620a..e4f80ad228 100644
--- a/usr/src/cmd/mdb/intel/kmdb/kaif.c
+++ b/usr/src/cmd/mdb/intel/kmdb/kaif.c
@@ -296,12 +296,12 @@ kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
return (set_errno(EMDB_TGTNOTSUP));
}
- if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, instrp,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
- if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_I, &bkpt,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
return (0);
@@ -310,8 +310,8 @@ kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
static int
kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
{
- if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
- sizeof (mdb_instr_t))
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_I, &instrp,
+ sizeof (mdb_instr_t), addr) != sizeof (mdb_instr_t))
return (-1); /* errno is set for us */
return (0);
@@ -486,7 +486,7 @@ kaif_step(void)
}
if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
- MDB_TGT_AS_VIRT, pc)) == pc) {
+ MDB_TGT_AS_VIRT_I, pc)) == pc) {
warn("failed to decode instruction at %a for step\n", pc);
return (set_errno(EINVAL));
}
@@ -498,8 +498,8 @@ kaif_step(void)
* versus their 64-bit counterparts.
*/
do {
- if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
- pc + pcoff) != sizeof (mdb_instr_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, &instr,
+ sizeof (mdb_instr_t), pc + pcoff) != sizeof (mdb_instr_t)) {
warn("failed to read at %p for step",
(void *)(pc + pcoff));
return (-1);
@@ -518,8 +518,8 @@ kaif_step(void)
return (set_errno(EMDB_TGTNOTSUP));
case M_ESC:
- if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
- pc + pcoff) != sizeof (mdb_instr_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_I, &instr,
+ sizeof (mdb_instr_t), pc + pcoff) != sizeof (mdb_instr_t)) {
warn("failed to read at %p for step",
(void *)(pc + pcoff));
return (-1);
@@ -568,8 +568,8 @@ kaif_step(void)
(void) kmdb_dpi_get_register("sp", &sp);
(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
- if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_aread(mdb.m_target, MDB_TGT_AS_VIRT_S, &newfl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to read " FLAGS_REG_NAME
" at %p for popfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
@@ -577,8 +577,8 @@ kaif_step(void)
fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
- if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_S, &fl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to update " FLAGS_REG_NAME
" at %p for popfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
@@ -617,8 +617,8 @@ kaif_step(void)
*/
(void) kmdb_dpi_get_register("sp", &sp);
- if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
- sp) != sizeof (kreg_t)) {
+ if (mdb_tgt_awrite(mdb.m_target, MDB_TGT_AS_VIRT_S, &oldfl,
+ sizeof (kreg_t), sp) != sizeof (kreg_t)) {
warn("failed to update pushed " FLAGS_REG_NAME
" at %p after pushfl step\n", (void *)sp);
return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
diff --git a/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
index f3352b6e21..0382c7e0fb 100644
--- a/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_amd64dep.c
@@ -46,6 +46,7 @@
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/kvm_isadep.h>
#include <mdb/mdb_kvm.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
index 2dfced82d3..7a6ecaeb6b 100644
--- a/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_ia32dep.c
@@ -45,6 +45,7 @@
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/kvm_isadep.h>
#include <mdb/mdb_kvm.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
index 14c81f47fd..7740a82d8f 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
@@ -39,6 +39,7 @@
#include <mdb/mdb_kreg_impl.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/mdb_ctf.h>
#include <mdb/mdb_err.h>
@@ -244,7 +245,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
while (fp != 0) {
int args_style = 0;
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) !=
+ sizeof (fr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -259,8 +261,9 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (advance_tortoise != 0) {
struct fr tfr;
- if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
- tortoise_fp) != sizeof (tfr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
+ sizeof (tfr), tortoise_fp) !=
+ sizeof (tfr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -330,7 +333,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
pc - s.st_value);
- if (mdb_tgt_vread(t, ins, insnsize, s.st_value) != insnsize)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, insnsize,
+ s.st_value) != insnsize)
argc = 0;
if ((argc != 0) &&
@@ -349,8 +353,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (args_style == SAVEARGS_STRUCT_ARGS)
size += sizeof (long);
- if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
- != size)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, fr_argv, size,
+ (fp - size)) != size)
return (-1); /* errno has been set for us */
/*
@@ -369,7 +373,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
sizeof (fr_argv) -
(reg_argc * sizeof (long)));
- if (mdb_tgt_vread(t, &fr_argv[reg_argc], size,
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S,
+ &fr_argv[reg_argc], size,
fp + sizeof (fr)) != size)
return (-1); /* errno has been set */
}
@@ -434,14 +439,15 @@ mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
fp = sp - 8;
else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
- if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
- pc + 1) == sizeof (curinstr) && curinstr ==
- M_MOVL_RBP)
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
+ sizeof (curinstr), pc + 1) == sizeof (curinstr) &&
+ curinstr == M_MOVL_RBP)
fp = sp;
}
}
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
+ sizeof (fr)) {
*p = fr.fr_savpc;
return (0);
}
@@ -476,8 +482,8 @@ mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
/* Skip the rex prefix, if any */
callpc = pc;
while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
- if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
- sizeof (curinstr))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
+ sizeof (curinstr), ++callpc) != sizeof (curinstr))
return (-1); /* errno is set for us */
}
@@ -486,7 +492,8 @@ mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
return (set_errno(EAGAIN));
}
- if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
+ npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT_I, pc);
+ if (npc == pc)
return (-1); /* errno is set for us */
*p = npc;
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
index f8c6097cef..b3f060bf05 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.h
@@ -22,12 +22,13 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_AMD64UTIL_H
#define _MDB_AMD64UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_target_impl.h>
@@ -35,8 +36,6 @@
extern "C" {
#endif
-typedef uchar_t mdb_instr_t;
-
extern const mdb_tgt_regdesc_t mdb_amd64_kregs[];
extern void mdb_amd64_printregs(const mdb_tgt_gregset_t *);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c b/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c
new file mode 100644
index 0000000000..9477bf5056
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_bhyve.c
@@ -0,0 +1,1461 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * bhyve target
+ *
+ * The bhyve target is used to examine and manipulate a bhyve VM. Access to
+ * a bhyve VM is provided by libvmm, which itself uses libvmmapi, which uses
+ * the vmm driver's ioctl interface to carry out requests.
+ *
+ * The bhyve target does not know about threads or processes, but it handles
+ * multiple vCPUs and can switch between them. Execution control is currently
+ * limited to completely stopping or resuming all vCPUs of a VM, or single-
+ * stepping a particular vCPU while all other vCPUs remain stopped. Breakpoints
+ * are not implemented yet, and as such step-out and step-over don't work yet.
+ * All known x86 instruction sets are support, legacy IA-16, IA-32 and AMD64.
+ * The current CPU instruction set is automatically determined by parsing the
+ * code segment (CS) attributes in the current vCPU.
+ *
+ * All of the VMs physical memory and device memory segments are mapped R/W
+ * into mdb's address space by libvmm. All accesses to those memory are
+ * facilitated through libvmm calls, which may include virtual address
+ * translation according to the current vCPU mode. Both real-mode and protected-
+ * mode segmentation are understood and used for translating virtual addresses
+ * into linear addresses, which may further be translated using 2-level, 3-level
+ * or 4-level paging.
+ *
+ * To handle disassembly and stack tracing properly when segmentation is used by
+ * a vCPU (always in real mode, sometimes in protected mode) the bhyve target
+ * has a notion of three virtual address spaces used for reading/writing memory:
+ * - MDB_TGT_AS_VIRT, the default virtual address space uses the DS segment
+ * by default, but this default can be changed with the ::defseg dcmd.
+ * - MDB_TGT_AS_VIRT_I, the virtual address space for instructions always
+ * uses the code segment (CS) for translation
+ * - MDB_TGT_AS_VIRT_S, the virtual address space for the stack always uses
+ * the stack segment (SS) for translation
+ *
+ * Register printing and stack tracing is using the common x86 ISA-specific code
+ * in IA-32 and AMD64 modes. There is no stack tracing for IA-16 mode yet.
+ *
+ * Todo:
+ * - support for breakpoint, step-out, and step-over
+ * - support for x86 stack tracing
+ */
+#include <mdb/mdb_conf.h>
+#include <mdb/mdb_err.h>
+#include <mdb/mdb_signal.h>
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_io_impl.h>
+#include <mdb/mdb_kreg_impl.h>
+#include <mdb/mdb_target_impl.h>
+#include <mdb/mdb_isautil.h>
+#include <mdb/mdb_amd64util.h>
+#include <mdb/mdb_ia32util.h>
+#include <mdb/mdb_x86util.h>
+#include <mdb/mdb.h>
+
+#include <sys/controlregs.h>
+#include <sys/debugreg.h>
+#include <sys/sysmacros.h>
+#include <sys/note.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <libvmm.h>
+
+#define MDB_DEF_PROMPT "[%<_cpuid>]> "
+
+typedef struct bhyve_data {
+ vmm_t *bd_vmm;
+ uint_t bd_curcpu;
+ int bd_defseg;
+
+ /* must be last */
+ char bd_name[];
+} bhyve_data_t;
+
+
+const mdb_tgt_regdesc_t bhyve_kregs[] = {
+ { "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
+ { "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "di", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
+ { "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "si", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
+ { "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "dx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "dh", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "dl", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
+ { "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "cx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "ch", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "cl", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r8", KREG_R8, MDB_TGT_R_EXPORT },
+ { "r8d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r8w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r8l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r9", KREG_R9, MDB_TGT_R_EXPORT },
+ { "r9d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r9w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r9l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rax", KREG_RAX, MDB_TGT_R_EXPORT },
+ { "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "ax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "ah", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "al", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
+ { "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "bx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "bh", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+ { "bl", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
+ { "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "bp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r10", KREG_R10, MDB_TGT_R_EXPORT },
+ { "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r11", KREG_R11, MDB_TGT_R_EXPORT },
+ { "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r12", KREG_R12, MDB_TGT_R_EXPORT },
+ { "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r13", KREG_R13, MDB_TGT_R_EXPORT },
+ { "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r14", KREG_R14, MDB_TGT_R_EXPORT },
+ { "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "r15", KREG_R15, MDB_TGT_R_EXPORT },
+ { "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "ds", KREG_DS, MDB_TGT_R_EXPORT },
+ { "es", KREG_ES, MDB_TGT_R_EXPORT },
+ { "fs", KREG_FS, MDB_TGT_R_EXPORT },
+ { "gs", KREG_GS, MDB_TGT_R_EXPORT },
+ { "rip", KREG_RIP, MDB_TGT_R_EXPORT },
+ { "cs", KREG_CS, MDB_TGT_R_EXPORT },
+ { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
+ { "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
+ { "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+ { "sp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+ { "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
+ { "ss", KREG_SS, MDB_TGT_R_EXPORT },
+ { "cr2", KREG_CR2, MDB_TGT_R_EXPORT },
+ { "cr3", KREG_CR3, MDB_TGT_R_EXPORT },
+ { NULL, 0, 0 }
+};
+
+static const char *segments[] = { "CS", "DS", "ES", "FS", "GS", "SS" };
+
+
+/*ARGSUSED*/
+static uintmax_t
+bhyve_cpuid_get(const mdb_var_t *v)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+
+ return (bd->bd_curcpu);
+}
+
+static const mdb_nv_disc_t bhyve_cpuid_disc = {
+ .disc_get = bhyve_cpuid_get
+};
+
+
+static uintmax_t
+bhyve_reg_get(const mdb_var_t *v)
+{
+ mdb_tgt_reg_t r = 0;
+
+ if (mdb_tgt_getareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), &r) == -1)
+ mdb_warn("failed to get %%%s register", mdb_nv_get_name(v));
+
+ return (r);
+}
+
+static void
+bhyve_reg_set(mdb_var_t *v, uintmax_t r)
+{
+ if (mdb_tgt_putareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), r) == -1)
+ mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v));
+}
+
+static const mdb_nv_disc_t bhyve_reg_disc = {
+ .disc_set = bhyve_reg_set,
+ .disc_get = bhyve_reg_get
+};
+
+static int
+bhyve_get_gregset(bhyve_data_t *bd, int cpu, mdb_tgt_gregset_t *gregs)
+{
+ vmm_desc_t fs, gs;
+
+ /*
+ * Register numbers to get, the order must match the definitions of
+ * KREG_* in mdb_kreg.h so that we get a proper mdb_tgt_gregset_t
+ * that the register printing functions will understand.
+ *
+ * There are a few fields in mdb_tgt_gregset_t that can't be accessed
+ * with vmm_get_regset(), either because they don't exist in bhyve or
+ * or because they need to be accessed with vmm_get_desc(). For these
+ * cases we ask for RAX instead and fill it with 0 or the real value,
+ * respectively.
+ */
+ static const int regnums[] = {
+ KREG_RAX, /* dummy for SAVFP */
+ KREG_RAX, /* dummy for SAVFP */
+ KREG_RDI,
+ KREG_RSI,
+ KREG_RDX,
+ KREG_RCX,
+ KREG_R8,
+ KREG_R9,
+ KREG_RAX,
+ KREG_RBX,
+ KREG_RBP,
+ KREG_R10,
+ KREG_R11,
+ KREG_R12,
+ KREG_R13,
+ KREG_R14,
+ KREG_R15,
+ KREG_RAX, /* dummy for FSBASE */
+ KREG_RAX, /* dummy for GSBASE */
+ KREG_RAX, /* dummy for KGSBASE */
+ KREG_CR2,
+ KREG_CR3,
+ KREG_DS,
+ KREG_ES,
+ KREG_FS,
+ KREG_GS,
+ KREG_RAX, /* dummy for TRAPNO */
+ KREG_RAX, /* dummy for ERR */
+ KREG_RIP,
+ KREG_CS,
+ KREG_RFLAGS,
+ KREG_RSP,
+ KREG_SS
+ };
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, KREG_NGREG, regnums,
+ &gregs->kregs[0]) != 0) {
+ mdb_warn("failed to get general-purpose registers for CPU %d",
+ cpu);
+ return (-1);
+ }
+
+ if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS, &fs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS, &gs) != 0) {
+ mdb_warn("failed to get FS/GS descriptors for CPU %d", cpu);
+ return (-1);
+ }
+
+ gregs->kregs[KREG_SAVFP] = 0;
+ gregs->kregs[KREG_SAVPC] = 0;
+ gregs->kregs[KREG_KGSBASE] = 0;
+ gregs->kregs[KREG_TRAPNO] = 0;
+ gregs->kregs[KREG_ERR] = 0;
+
+ gregs->kregs[KREG_FSBASE] = fs.vd_base;
+ gregs->kregs[KREG_GSBASE] = gs.vd_base;
+
+ return (0);
+}
+
+static int
+bhyve_cpuregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ mdb_tgt_gregset_t gregs;
+ int i;
+
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ if (bhyve_get_gregset(bd, cpu, &gregs) != 0)
+ return (DCMD_ERR);
+
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, cpu)) {
+ case VMM_ISA_64:
+ mdb_amd64_printregs(&gregs);
+ break;
+ case VMM_ISA_32:
+ case VMM_ISA_16:
+ mdb_ia32_printregs(&gregs);
+ break;
+ default:
+ mdb_warn("CPU %d mode unknown", cpu);
+ return (DCMD_ERR);
+ }
+
+ return (0);
+}
+
+static int
+bhyve_regs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ if ((flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ return (bhyve_cpuregs_dcmd(addr, flags, argc, argv));
+}
+
+static int
+bhyve_stack_common(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv, int vcpu, boolean_t verbose)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ void *arg = (void *)(uintptr_t)mdb.m_nargs;
+
+ mdb_tgt_gregset_t gregs;
+ mdb_tgt_stack_f *func;
+
+ if (vcpu == -1)
+ vcpu = bd->bd_curcpu;
+
+ if (flags & DCMD_ADDRSPEC) {
+ bzero(&gregs, sizeof (gregs));
+ gregs.kregs[KREG_RBP] = addr;
+ } else if (bhyve_get_gregset(bd, vcpu, &gregs) != 0)
+ return (DCMD_ERR);
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, vcpu)) {
+ case VMM_ISA_64:
+ func = verbose ? mdb_amd64_kvm_framev : mdb_amd64_kvm_frame;
+ (void) mdb_amd64_kvm_stack_iter(mdb.m_target, &gregs, func,
+ arg);
+ break;
+ case VMM_ISA_32:
+ func = verbose ? mdb_ia32_kvm_framev : mdb_amd64_kvm_frame;
+ (void) mdb_ia32_kvm_stack_iter(mdb.m_target, &gregs, func, arg);
+ break;
+ case VMM_ISA_16:
+ mdb_warn("IA16 stack tracing not implemented\n");
+ return (DCMD_ERR);
+ default:
+ mdb_warn("CPU %d mode unknown", vcpu);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+static int
+bhyve_cpustack_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ boolean_t verbose;
+ int i;
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (addr < vmm_ncpu(bd->bd_vmm)) {
+ cpu = (uint64_t)addr;
+ flags &= ~DCMD_ADDRSPEC;
+ }
+ }
+
+ i = mdb_getopts(argc, argv,
+ 'c', MDB_OPT_UINT64, &cpu,
+ 'v', MDB_OPT_SETBITS, 1, &verbose,
+ NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ return (bhyve_stack_common(addr, flags, argc, argv, cpu, verbose));
+}
+
+static int
+bhyve_stack_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_FALSE));
+}
+
+static int
+bhyve_stackv_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE));
+}
+
+static int
+bhyve_stackr_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE));
+}
+
+static int
+bhyve_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ vmm_mode_t mode;
+ vmm_isa_t isa;
+
+ static const char *modes[] = {
+ "unknown mode",
+ "real mode",
+ "protected mode, no PAE",
+ "protected mode, PAE",
+ "long mode"
+ };
+ static const char *isas[] = {
+ "unknown ISA",
+ "IA16",
+ "IA32",
+ "AMD64"
+ };
+
+ if ((flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ mode = vmm_vcpu_mode(bd->bd_vmm, bd->bd_curcpu);
+ isa = vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu);
+
+ mdb_printf("debugging live VM '%s'\n", bd->bd_name);
+ mdb_printf("VM memory size: %d MB\n",
+ vmm_memsize(bd->bd_vmm) / 1024 / 1024);
+ mdb_printf("vCPUs: %d\n", vmm_ncpu(bd->bd_vmm));
+ mdb_printf("current CPU: %d (%s, %s)\n", bd->bd_curcpu, modes[mode],
+ isas[isa]);
+ mdb_printf("default segment: %s",
+ segments[bd->bd_defseg - VMM_DESC_CS]);
+
+ return (DCMD_OK);
+}
+
+
+static int
+bhyve_sysregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ int ret = DCMD_ERR;
+ struct sysregs sregs;
+ int i;
+
+ /*
+ * This array must use the order of the elements of struct sysregs.
+ */
+ static const int regnums[] = {
+ VMM_REG_CR0,
+ VMM_REG_CR2,
+ VMM_REG_CR3,
+ VMM_REG_CR4,
+ VMM_REG_DR0,
+ VMM_REG_DR1,
+ VMM_REG_DR2,
+ VMM_REG_DR3,
+ VMM_REG_DR6,
+ VMM_REG_DR7,
+ VMM_REG_EFER,
+ VMM_REG_PDPTE0,
+ VMM_REG_PDPTE1,
+ VMM_REG_PDPTE2,
+ VMM_REG_PDPTE3,
+ VMM_REG_INTR_SHADOW
+ };
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums,
+ (uint64_t *)&sregs) != 0)
+ goto fail;
+
+ if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GDTR,
+ (vmm_desc_t *)&sregs.sr_gdtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_IDTR,
+ (vmm_desc_t *)&sregs.sr_idtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_LDTR,
+ (vmm_desc_t *)&sregs.sr_ldtr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_TR,
+ (vmm_desc_t *)&sregs.sr_tr) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_CS,
+ (vmm_desc_t *)&sregs.sr_cs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_DS,
+ (vmm_desc_t *)&sregs.sr_ds) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_ES,
+ (vmm_desc_t *)&sregs.sr_es) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS,
+ (vmm_desc_t *)&sregs.sr_fs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS,
+ (vmm_desc_t *)&sregs.sr_gs) != 0 ||
+ vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_SS,
+ (vmm_desc_t *)&sregs.sr_ss) != 0)
+ goto fail;
+
+ mdb_x86_print_sysregs(&sregs, vmm_vcpu_mode(bd->bd_vmm, cpu) ==
+ VMM_MODE_LONG);
+
+ ret = DCMD_OK;
+
+fail:
+ if (ret != DCMD_OK)
+ mdb_warn("failed to get system registers for CPU %d\n", cpu);
+ return (ret);
+}
+
+static int
+bhyve_dbgregs_dcmd(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ uint64_t cpu = bd->bd_curcpu;
+ int ret = DCMD_ERR;
+ vmm_desc_t gdtr, ldtr, idtr, tr, cs, ds, es, fs, gs, ss;
+ uint64_t *regvals;
+ int i;
+
+ /*
+ * This array must use the order of definitions set in libvmm.h
+ * to make GETREG() work.
+ */
+#define GETREG(r) (regvals[r - VMM_REG_DR0])
+ static const int regnums[] = {
+ VMM_REG_DR0,
+ VMM_REG_DR1,
+ VMM_REG_DR2,
+ VMM_REG_DR3,
+ VMM_REG_DR6,
+ VMM_REG_DR7,
+ };
+
+ static const mdb_bitmask_t dr6_flag_bits[] = {
+ { "DR0", DR_TRAP0, DR_TRAP0 },
+ { "DR1", DR_TRAP1, DR_TRAP1 },
+ { "DR2", DR_TRAP2, DR_TRAP2 },
+ { "DR3", DR_TRAP3, DR_TRAP3 },
+ { "debug reg", DR_ICEALSO, DR_ICEALSO },
+ { "single step", DR_SINGLESTEP, DR_SINGLESTEP },
+ { "task switch", DR_TASKSWITCH, DR_TASKSWITCH },
+ { NULL, 0, 0 }
+ };
+
+#define DR_RW(x, m) \
+ ((DR_RW_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE))
+#define DR_LEN(x, m) \
+ ((DR_LEN_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE))
+
+ static const mdb_bitmask_t dr7_flag_bits[] = {
+ { "L0", DR_ENABLE0, DR_LOCAL_ENABLE_MASK & DR_ENABLE0 },
+ { "G0", DR_ENABLE0, DR_GLOBAL_ENABLE_MASK & DR_ENABLE0 },
+ { "L1", DR_ENABLE1, DR_LOCAL_ENABLE_MASK & DR_ENABLE1 },
+ { "G1", DR_ENABLE1, DR_GLOBAL_ENABLE_MASK & DR_ENABLE1 },
+ { "L2", DR_ENABLE2, DR_LOCAL_ENABLE_MASK & DR_ENABLE2 },
+ { "G2", DR_ENABLE2, DR_GLOBAL_ENABLE_MASK & DR_ENABLE2 },
+ { "L3", DR_ENABLE3, DR_LOCAL_ENABLE_MASK & DR_ENABLE3 },
+ { "G3", DR_ENABLE3, DR_GLOBAL_ENABLE_MASK & DR_ENABLE3 },
+ { "LE", DR_LOCAL_SLOWDOWN, DR_LOCAL_SLOWDOWN },
+ { "GE", DR_GLOBAL_SLOWDOWN, DR_GLOBAL_SLOWDOWN },
+ { "RTM", DR_RTM, DR_RTM },
+ { "GD", DR_GENERAL_DETECT, DR_GENERAL_DETECT },
+ { "0:X", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_EXECUTE) },
+ { "0:W", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_WRITE) },
+ { "0:IO", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_IO_RW) },
+ { "0:RW", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_READ) },
+ { "1:X", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_EXECUTE) },
+ { "1:W", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_WRITE) },
+ { "1:IO", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_IO_RW) },
+ { "1:RW", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_READ) },
+ { "2:X", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_EXECUTE) },
+ { "2:W", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_WRITE) },
+ { "2:IO", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_IO_RW) },
+ { "2:RW", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_READ) },
+ { "3:X", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_EXECUTE) },
+ { "3:W", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_WRITE) },
+ { "3:IO", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_IO_RW) },
+ { "3:RW", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_READ) },
+ { "0:1", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_1) },
+ { "0:2", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_2) },
+ { "0:4", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_4) },
+ { "0:8", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_8) },
+ { "1:1", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_1) },
+ { "1:2", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_2) },
+ { "1:4", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_4) },
+ { "1:8", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_8) },
+ { "2:1", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_1) },
+ { "2:2", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_2) },
+ { "2:4", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_4) },
+ { "2:8", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_8) },
+ { "3:1", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_1) },
+ { "3:2", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_2) },
+ { "3:4", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_4) },
+ { "3:8", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_8) },
+ { NULL, 0, 0 },
+ };
+
+
+ if (flags & DCMD_ADDRSPEC) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ cpu = (uint64_t)addr;
+ }
+
+ i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ regvals = mdb_zalloc(ARRAY_SIZE(regnums) * sizeof (uint64_t), UM_SLEEP);
+
+ if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums,
+ regvals) != 0)
+ goto fail;
+
+ mdb_printf("%%dr0 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR0), GETREG(VMM_REG_DR0));
+ mdb_printf("%%dr1 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR1), GETREG(VMM_REG_DR1));
+ mdb_printf("%%dr2 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR2), GETREG(VMM_REG_DR2));
+ mdb_printf("%%dr3 = 0x%0?p %A\n",
+ GETREG(VMM_REG_DR3), GETREG(VMM_REG_DR3));
+ mdb_printf("%%dr6 = 0x%0lx <%b>\n",
+ GETREG(VMM_REG_DR6), GETREG(VMM_REG_DR6), dr6_flag_bits);
+ mdb_printf("%%dr7 = 0x%0lx <%b>\n",
+ GETREG(VMM_REG_DR7), GETREG(VMM_REG_DR7), dr7_flag_bits);
+#undef GETREG
+
+ ret = DCMD_OK;
+
+fail:
+ if (ret != DCMD_OK)
+ mdb_warn("failed to get debug registers for CPU %d\n", cpu);
+ mdb_free(regvals, ARRAY_SIZE(regnums) * sizeof (uint64_t));
+ return (ret);
+}
+
+static int
+bhyve_switch_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ size_t cpu = (int)addr;
+
+ if (!(flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ if (cpu >= vmm_ncpu(bd->bd_vmm)) {
+ mdb_warn("no such CPU\n");
+ return (DCMD_ERR);
+ }
+
+ bd->bd_curcpu = cpu;
+ return (DCMD_OK);
+
+}
+
+static int
+bhyve_seg2reg(const char *seg)
+{
+ if (strcasecmp(seg, "cs") == 0)
+ return (VMM_DESC_CS);
+ else if (strcasecmp(seg, "ds") == 0)
+ return (VMM_DESC_DS);
+ else if (strcasecmp(seg, "es") == 0)
+ return (VMM_DESC_ES);
+ else if (strcasecmp(seg, "fs") == 0)
+ return (VMM_DESC_FS);
+ else if (strcasecmp(seg, "gs") == 0)
+ return (VMM_DESC_GS);
+ else if (strcasecmp(seg, "ss") == 0)
+ return (VMM_DESC_SS);
+ else
+ return (-1);
+}
+
+static int
+bhyve_vtol_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ uint64_t laddr;
+ int i;
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+ }
+
+ if (vmm_vtol(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &laddr) != 0) {
+ if (errno == EFAULT)
+ (void) set_errno(EMDB_NOMAP);
+ return (DCMD_ERR);
+ }
+
+ if (flags & DCMD_PIPE_OUT)
+ mdb_printf("%llr\n", laddr);
+ else
+ mdb_printf("virtual %lr mapped to linear %llr\n", addr, laddr);
+
+ return (DCMD_OK);
+}
+
+static int
+bhyve_vtop_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ physaddr_t pa;
+ int i;
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+ }
+
+ if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &pa) == -1) {
+ mdb_warn("failed to get physical mapping");
+ return (DCMD_ERR);
+ }
+
+ if (flags & DCMD_PIPE_OUT)
+ mdb_printf("%llr\n", pa);
+ else
+ mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
+ return (DCMD_OK);
+}
+
+static int
+bhyve_defseg_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ bhyve_data_t *bd = mdb.m_target->t_data;
+ int segreg = bd->bd_defseg;
+ char *seg = "";
+ int i;
+
+ if (flags & DCMD_ADDRSPEC)
+ return (DCMD_USAGE);
+
+ i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL);
+
+ argc -= i;
+ argv += i;
+
+ if (i != 0) {
+ if (argc != 0)
+ return (DCMD_USAGE);
+
+ segreg = bhyve_seg2reg(seg);
+ if (segreg == -1)
+ return (DCMD_USAGE);
+
+ bd->bd_defseg = segreg;
+ }
+
+ mdb_printf("using segment %s for virtual to linear address translation",
+ segments[bd->bd_defseg - VMM_DESC_CS]);
+
+ return (DCMD_OK);
+}
+
+static const mdb_dcmd_t bhyve_dcmds[] = {
+ { "$c", NULL, "print stack backtrace", bhyve_stack_dcmd },
+ { "$C", NULL, "print stack backtrace", bhyve_stackv_dcmd },
+ { "$r", NULL, "print general-purpose registers", bhyve_regs_dcmd },
+ { "$?", NULL, "print status and registers", bhyve_regs_dcmd },
+ { ":x", ":", "change the active CPU", bhyve_switch_dcmd },
+ { "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a "
+ "specific CPU", bhyve_cpustack_dcmd },
+ { "cpuregs", "?[-c cpuid]", "print general-purpose registers for a "
+ "specific CPU", bhyve_cpuregs_dcmd },
+ { "dbgregs", "?[-c cpuid]", "print debug registers for a specific CPU",
+ bhyve_dbgregs_dcmd },
+ { "defseg", "?[-s segment]", "change the default segment used to "
+ "translate addresses", bhyve_defseg_dcmd },
+ { "regs", NULL, "print general-purpose registers", bhyve_regs_dcmd },
+ { "stack", NULL, "print stack backtrace", bhyve_stack_dcmd },
+ { "stackregs", NULL, "print stack backtrace and registers",
+ bhyve_stackr_dcmd },
+ { "status", NULL, "print summary of current target",
+ bhyve_status_dcmd },
+ { "sysregs", "?[-c cpuid]", "print system registers for a specific CPU",
+ bhyve_sysregs_dcmd },
+ { "switch", ":", "change the active CPU", bhyve_switch_dcmd },
+ { "vtol", ":[-s segment]", "print linear mapping of virtual address",
+ bhyve_vtol_dcmd },
+ { "vtop", ":[-s segment]", "print physical mapping of virtual "
+ "address", bhyve_vtop_dcmd },
+ { NULL }
+};
+
+
+/*
+ * t_setflags: change target flags
+ */
+static int
+bhyve_setflags(mdb_tgt_t *tgt, int flags)
+{
+ bhyve_data_t *bd = tgt->t_data;
+
+ if (((tgt->t_flags ^ flags) & MDB_TGT_F_RDWR) != 0) {
+ boolean_t writable = (flags & MDB_TGT_F_RDWR) != 0;
+
+ vmm_unmap(bd->bd_vmm);
+ if (vmm_map(bd->bd_vmm, writable) != 0) {
+ mdb_warn("failed to map guest memory");
+ return (set_errno(EMDB_TGT));
+ }
+ }
+
+ tgt->t_flags = flags;
+
+ return (0);
+}
+
+/*
+ * t_activate: activate target
+ */
+static void
+bhyve_activate(mdb_tgt_t *tgt)
+{
+ mdb_tgt_status_t *tsp = &tgt->t_status;
+ bhyve_data_t *bd = tgt->t_data;
+ const char *format;
+ char buf[BUFSIZ];
+
+ (void) mdb_set_prompt(MDB_DEF_PROMPT);
+
+ (void) mdb_tgt_register_dcmds(tgt, bhyve_dcmds, MDB_MOD_FORCE);
+ mdb_tgt_register_regvars(tgt, bhyve_kregs, &bhyve_reg_disc, 0);
+
+ (void) vmm_stop(bd->bd_vmm);
+
+ if (mdb_tgt_status(tgt, tsp) != 0)
+ return;
+
+ if (tsp->st_pc != 0) {
+ if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
+ MDB_TGT_AS_VIRT_I, buf, sizeof (buf), tsp->st_pc) !=
+ tsp->st_pc)
+ format = "target stopped at:\n%-#16a%8T%s\n";
+ else
+ format = "target stopped at %a:\n";
+ mdb_warn(format, tsp->st_pc, buf);
+ }
+}
+
+/*
+ * t_deactivate: deactivate target
+ */
+static void
+bhyve_deactivate(mdb_tgt_t *tgt)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ const mdb_tgt_regdesc_t *rd;
+ const mdb_dcmd_t *dc;
+
+ for (rd = bhyve_kregs; rd->rd_name != NULL; rd++) {
+ mdb_var_t *var;
+
+ if (!(rd->rd_flags & MDB_TGT_R_EXPORT))
+ continue; /* didn't export register as variable */
+
+ if ((var = mdb_nv_lookup(&mdb.m_nv, rd->rd_name)) != NULL) {
+ var->v_flags &= ~MDB_NV_PERSIST;
+ mdb_nv_remove(&mdb.m_nv, var);
+ }
+ }
+
+ for (dc = bhyve_dcmds; dc->dc_name != NULL; dc++)
+ if (mdb_module_remove_dcmd(tgt->t_module, dc->dc_name) == -1)
+ mdb_warn("failed to remove dcmd %s", dc->dc_name);
+
+ (void) vmm_cont(bd->bd_vmm);
+}
+
+/*
+ * t_name: return name of target
+ */
+static const char *
+bhyve_name(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return ("bhyve");
+}
+
+/*
+ * t_destroy: cleanup target private resources
+ */
+static void
+bhyve_destroy(mdb_tgt_t *tgt)
+{
+ bhyve_data_t *bd = tgt->t_data;
+
+ (void) vmm_cont(bd->bd_vmm);
+ vmm_unmap(bd->bd_vmm);
+ vmm_close_vm(bd->bd_vmm);
+ mdb_free(bd, sizeof (bhyve_data_t));
+ tgt->t_data = NULL;
+}
+
+/*
+ * t_isa: return name of target ISA
+ */
+const char *
+bhyve_isa(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return ("amd64");
+}
+
+/*
+ * t_dmodel: return target data model
+ */
+static int
+bhyve_dmodel(mdb_tgt_t *tgt)
+{
+ _NOTE(ARGUNUSED(tgt));
+
+ return (MDB_TGT_MODEL_LP64);
+}
+
+/*ARGSUSED*/
+static ssize_t
+bhyve_aread(mdb_tgt_t *tgt, mdb_tgt_as_t as, void *buf, size_t nbytes,
+ mdb_tgt_addr_t addr)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ ssize_t cnt;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_PHYS:
+ cnt = vmm_pread(bd->bd_vmm, buf, nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_FILE:
+ case (uintptr_t)MDB_TGT_AS_IO:
+ return (set_errno(EMDB_TGTNOTSUP));
+ }
+
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+
+ return (cnt);
+}
+
+/*ARGSUSED*/
+static ssize_t
+bhyve_awrite(mdb_tgt_t *tgt, mdb_tgt_as_t as, const void *buf, size_t nbytes,
+ mdb_tgt_addr_t addr)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ ssize_t cnt;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf,
+ nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_PHYS:
+ cnt = vmm_pwrite(bd->bd_vmm, buf, nbytes, addr);
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_FILE:
+ case (uintptr_t)MDB_TGT_AS_IO:
+ return (set_errno(EMDB_TGTNOTSUP));
+ }
+
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+
+ return (cnt);
+}
+
+/*
+ * t_vread: read from virtual memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_vread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr));
+}
+
+/*
+ * t_vwrite: write to virtual memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_vwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr));
+}
+
+/*
+ * t_pread: read from physical memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_pread(mdb_tgt_t *tgt, void *buf, size_t nbytes, physaddr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr));
+}
+
+/*
+ * t_pwrite: write to physical memory
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_pwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, physaddr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr));
+}
+
+/*
+ * t_fread: read from core/object file
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_fread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr));
+}
+
+/*
+ * t_fwrite: write to core/object file
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_fwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr));
+}
+
+/*
+ * t_ioread: read from I/O space
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_ioread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_aread(tgt, MDB_TGT_AS_IO, buf, nbytes, addr));
+}
+
+/*
+ * t_iowrite: write to I/O space
+ */
+/*ARGSUSED*/
+static ssize_t
+bhyve_iowrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr)
+{
+ return (bhyve_awrite(tgt, MDB_TGT_AS_IO, buf, nbytes, addr));
+}
+
+/*
+ * t_vtop: translate virtual to physical address
+ */
+static int
+bhyve_vtop(mdb_tgt_t *tgt, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pa)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int seg;
+
+ switch ((uintptr_t)as) {
+ case (uintptr_t)MDB_TGT_AS_VIRT:
+ seg = bd->bd_defseg;
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_I:
+ seg = VMM_DESC_CS;
+ break;
+
+ case (uintptr_t)MDB_TGT_AS_VIRT_S:
+ seg = VMM_DESC_SS;
+ break;
+
+ default:
+ return (set_errno(EINVAL));
+ }
+
+ if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, seg, va, pa) != 0) {
+ if (errno == EFAULT)
+ return (set_errno(EMDB_NOMAP));
+ else
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * t_status: get target status
+ */
+static int
+bhyve_status(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ mdb_tgt_reg_t rip;
+ vmm_desc_t cs;
+ int ret;
+
+ bzero(tsp, sizeof (mdb_tgt_status_t));
+
+ ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, KREG_RIP, &rip);
+ if (ret != 0) {
+ tsp->st_state = MDB_TGT_UNDEAD;
+ } else {
+ tsp->st_state = MDB_TGT_STOPPED;
+ tsp->st_pc = rip;
+ }
+
+ switch (vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu)) {
+ case VMM_ISA_16:
+ (void) mdb_dis_select("ia16");
+ break;
+ case VMM_ISA_32:
+ (void) mdb_dis_select("ia32");
+ break;
+ case VMM_ISA_64:
+ (void) mdb_dis_select("amd64");
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static void
+bhyve_sighdl(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *tgt)
+{
+ mdb_tgt_status_t *tsp = &tgt->t_status;
+ bhyve_data_t *bd = tgt->t_data;
+
+ switch (sig) {
+ case SIGINT:
+ /*
+ * vmm_stop() may fail if the VM was destroyed while we were
+ * waiting. This will be handled by mdb_tgt_status().
+ */
+ (void) vmm_stop(bd->bd_vmm);
+ (void) mdb_tgt_status(tgt, tsp);
+ break;
+ }
+}
+
+/*
+ * t_step: single-step target
+ */
+static int
+bhyve_step(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int ret;
+
+ ret = vmm_step(bd->bd_vmm, bd->bd_curcpu);
+ (void) mdb_tgt_status(tgt, tsp);
+
+ return (ret);
+}
+
+/*
+ * t_cont: continue target execution
+ *
+ * Catch SIGINT so that the target can be stopped with Ctrl-C.
+ */
+static int
+bhyve_cont(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ mdb_signal_f *intf;
+ void *intd;
+ int ret;
+
+ intf = mdb_signal_gethandler(SIGINT, &intd);
+ (void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)bhyve_sighdl, tgt);
+
+ if (ret = vmm_cont(bd->bd_vmm) != 0) {
+ mdb_warn("failed to continue target execution: %d", ret);
+ return (set_errno(EMDB_TGT));
+ }
+
+ tsp->st_state = MDB_TGT_RUNNING;
+ (void) pause();
+
+ (void) mdb_signal_sethandler(SIGINT, intf, intd);
+ (void) mdb_tgt_status(tgt, tsp);
+
+ return (ret);
+}
+
+static int
+bhyve_lookup_reg(mdb_tgt_t *tgt, const char *rname)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ const mdb_tgt_regdesc_t *rd;
+
+ for (rd = bhyve_kregs; rd->rd_name != NULL; rd++)
+ if (strcmp(rd->rd_name, rname) == 0)
+ return (rd->rd_num);
+
+ return (-1);
+}
+
+/*
+ * t_getareg: get the value of a single register
+ */
+static int
+bhyve_getareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname,
+ mdb_tgt_reg_t *rp)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int reg = bhyve_lookup_reg(tgt, rname);
+ int ret;
+
+ if (reg == -1)
+ return (set_errno(EMDB_BADREG));
+
+ ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, reg, rp);
+ if (ret == -1)
+ return (set_errno(EMDB_BADREG));
+
+ return (0);
+}
+
+/*
+ * t_putareg: set the value of a single register
+ */
+static int
+bhyve_putareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname,
+ mdb_tgt_reg_t r)
+{
+ bhyve_data_t *bd = tgt->t_data;
+ int reg = bhyve_lookup_reg(tgt, rname);
+ int ret;
+
+ if ((tgt->t_flags & MDB_TGT_F_RDWR) == 0)
+ return (set_errno(EMDB_TGTRDONLY));
+
+ if (reg == -1)
+ return (set_errno(EMDB_BADREG));
+
+ ret = vmm_setreg(bd->bd_vmm, bd->bd_curcpu, reg, r);
+ if (ret == -1)
+ return (set_errno(EMDB_BADREG));
+
+ return (0);
+}
+
+static const mdb_tgt_ops_t bhyve_ops = {
+ .t_setflags = bhyve_setflags,
+ .t_setcontext = (int (*)()) mdb_tgt_notsup,
+ .t_activate = bhyve_activate,
+ .t_deactivate = bhyve_deactivate,
+ .t_periodic = (void (*)()) mdb_tgt_nop,
+ .t_destroy = bhyve_destroy,
+ .t_name = bhyve_name,
+ .t_isa = bhyve_isa,
+ .t_platform = (const char *(*)()) mdb_conf_platform,
+ .t_uname = (int (*)()) mdb_tgt_notsup,
+ .t_dmodel = bhyve_dmodel,
+ .t_aread = bhyve_aread,
+ .t_awrite = bhyve_awrite,
+ .t_vread = bhyve_vread,
+ .t_vwrite = bhyve_vwrite,
+ .t_pread = bhyve_pread,
+ .t_pwrite = bhyve_pwrite,
+ .t_fread = bhyve_fread,
+ .t_fwrite = bhyve_fwrite,
+ .t_ioread = bhyve_ioread,
+ .t_iowrite = bhyve_iowrite,
+ .t_vtop = bhyve_vtop,
+ .t_lookup_by_name = (int (*)()) mdb_tgt_notsup,
+ .t_lookup_by_addr = (int (*)()) mdb_tgt_notsup,
+ .t_symbol_iter = (int (*)()) mdb_tgt_notsup,
+ .t_mapping_iter = (int (*)()) mdb_tgt_notsup,
+ .t_object_iter = (int (*)()) mdb_tgt_notsup,
+ .t_addr_to_map = (const mdb_map_t *(*)()) mdb_tgt_null,
+ .t_name_to_map = (const mdb_map_t *(*)()) mdb_tgt_null,
+ .t_addr_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null,
+ .t_name_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null,
+ .t_status = bhyve_status,
+ .t_run = (int (*)()) mdb_tgt_notsup,
+ .t_step = bhyve_step,
+ .t_step_out = (int (*)()) mdb_tgt_notsup,
+ .t_next = (int (*)()) mdb_tgt_notsup,
+ .t_cont = bhyve_cont,
+ .t_signal = (int (*)()) mdb_tgt_notsup,
+ .t_add_vbrkpt = (int (*)()) mdb_tgt_null,
+ .t_add_sbrkpt = (int (*)()) mdb_tgt_null,
+ .t_add_pwapt = (int (*)()) mdb_tgt_null,
+ .t_add_vwapt = (int (*)()) mdb_tgt_null,
+ .t_add_iowapt = (int (*)()) mdb_tgt_null,
+ .t_add_sysenter = (int (*)()) mdb_tgt_null,
+ .t_add_sysexit = (int (*)()) mdb_tgt_null,
+ .t_add_signal = (int (*)()) mdb_tgt_null,
+ .t_add_fault = (int (*)()) mdb_tgt_null,
+ .t_getareg = bhyve_getareg,
+ .t_putareg = bhyve_putareg,
+ .t_stack_iter = (int (*)()) mdb_tgt_notsup,
+ .t_auxv = (int (*)()) mdb_tgt_notsup
+};
+
+int
+mdb_bhyve_tgt_create(mdb_tgt_t *tgt, int argc, const char *argv[])
+{
+ bhyve_data_t *bd;
+ vmm_t *vmm = NULL;
+ boolean_t writable = (tgt->t_flags & MDB_TGT_F_RDWR) != 0;
+
+ if (argc != 1)
+ return (set_errno(EINVAL));
+
+ vmm = vmm_open_vm(argv[0]);
+ if (vmm == NULL) {
+ mdb_warn("failed to open %s", argv[0]);
+ return (set_errno(EMDB_TGT));
+ }
+
+ if (vmm_map(vmm, writable) != 0) {
+ mdb_warn("failed to map %s", argv[0]);
+ vmm_close_vm(vmm);
+ return (set_errno(EMDB_TGT));
+ }
+
+ bd = mdb_zalloc(sizeof (bhyve_data_t) + strlen(argv[0]) + 1, UM_SLEEP);
+ (void) strcpy(bd->bd_name, argv[0]);
+ bd->bd_vmm = vmm;
+ bd->bd_curcpu = 0;
+ bd->bd_defseg = VMM_DESC_DS;
+
+ tgt->t_ops = &bhyve_ops;
+ tgt->t_data = bd;
+ tgt->t_flags |= MDB_TGT_F_ASIO;
+
+ (void) mdb_nv_insert(&mdb.m_nv, "cpuid", &bhyve_cpuid_disc, 0,
+ MDB_NV_PERSIST | MDB_NV_RDONLY);
+
+ return (0);
+}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
index d6db4811b2..22e56a0eda 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
@@ -23,16 +23,18 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
+#include <sys/types32.h>
#include <sys/reg.h>
#include <sys/privregs.h>
#include <sys/stack.h>
#include <sys/frame.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/mdb_target_impl.h>
#include <mdb/mdb_kreg_impl.h>
@@ -41,10 +43,14 @@
#include <mdb/mdb_err.h>
#include <mdb/mdb.h>
+#ifndef __amd64
/*
* We also define an array of register names and their corresponding
* array indices. This is used by the getareg and putareg entry points,
* and also by our register variable discipline.
+ *
+ * When built into an amd64 mdb this won't be used as it's only a subset of
+ * mdb_amd64_kregs, hence the #ifdef.
*/
const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
@@ -87,6 +93,7 @@ const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
{ NULL, 0, 0 }
};
+#endif
void
mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
@@ -94,27 +101,27 @@ mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
const kreg_t *kregs = &gregs->kregs[0];
kreg_t eflags = kregs[KREG_EFLAGS];
- mdb_printf("%%cs = 0x%04x\t\t%%eax = 0x%0?p %A\n",
+ mdb_printf("%%cs = 0x%04x\t\t%%eax = 0x%08p %A\n",
kregs[KREG_CS], kregs[KREG_EAX], kregs[KREG_EAX]);
- mdb_printf("%%ds = 0x%04x\t\t%%ebx = 0x%0?p %A\n",
+ mdb_printf("%%ds = 0x%04x\t\t%%ebx = 0x%08p %A\n",
kregs[KREG_DS], kregs[KREG_EBX], kregs[KREG_EBX]);
- mdb_printf("%%ss = 0x%04x\t\t%%ecx = 0x%0?p %A\n",
+ mdb_printf("%%ss = 0x%04x\t\t%%ecx = 0x%08p %A\n",
kregs[KREG_SS], kregs[KREG_ECX], kregs[KREG_ECX]);
- mdb_printf("%%es = 0x%04x\t\t%%edx = 0x%0?p %A\n",
+ mdb_printf("%%es = 0x%04x\t\t%%edx = 0x%08p %A\n",
kregs[KREG_ES], kregs[KREG_EDX], kregs[KREG_EDX]);
- mdb_printf("%%fs = 0x%04x\t\t%%esi = 0x%0?p %A\n",
+ mdb_printf("%%fs = 0x%04x\t\t%%esi = 0x%08p %A\n",
kregs[KREG_FS], kregs[KREG_ESI], kregs[KREG_ESI]);
- mdb_printf("%%gs = 0x%04x\t\t%%edi = 0x%0?p %A\n\n",
+ mdb_printf("%%gs = 0x%04x\t\t%%edi = 0x%08p %A\n\n",
kregs[KREG_GS], kregs[KREG_EDI], kregs[KREG_EDI]);
- mdb_printf("%%eip = 0x%0?p %A\n", kregs[KREG_EIP], kregs[KREG_EIP]);
- mdb_printf("%%ebp = 0x%0?p\n", kregs[KREG_EBP]);
- mdb_printf("%%esp = 0x%0?p\n\n", kregs[KREG_ESP]);
+ mdb_printf("%%eip = 0x%08p %A\n", kregs[KREG_EIP], kregs[KREG_EIP]);
+ mdb_printf("%%ebp = 0x%08p\n", kregs[KREG_EBP]);
+ mdb_printf("%%esp = 0x%08p\n\n", kregs[KREG_ESP]);
mdb_printf("%%eflags = 0x%08x\n", eflags);
mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
@@ -138,8 +145,8 @@ mdb_ia32_printregs(const mdb_tgt_gregset_t *gregs)
(eflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
(eflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
-#ifndef _KMDB
- mdb_printf(" %%uesp = 0x%0?x\n", kregs[KREG_UESP]);
+#if !defined(__amd64) && !defined(_KMDB)
+ mdb_printf(" %%uesp = 0x%08x\n", kregs[KREG_UESP]);
#endif
mdb_printf("%%trapno = 0x%x\n", kregs[KREG_TRAPNO]);
mdb_printf(" %%err = 0x%x\n", kregs[KREG_ERR]);
@@ -166,7 +173,8 @@ kvm_argcount(mdb_tgt_t *t, uintptr_t eip, ssize_t size)
M_ADD_IMM8 = 0x83 /* ADD imm8 to r/m32 */
};
- if (mdb_tgt_vread(t, ins, sizeof (ins), eip) != sizeof (ins))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, sizeof (ins), eip) !=
+ sizeof (ins))
return (0);
if (ins[1] != M_MODRM_ESP)
@@ -185,7 +193,7 @@ kvm_argcount(mdb_tgt_t *t, uintptr_t eip, ssize_t size)
n = 0;
}
- return (MIN((ssize_t)n, size) / sizeof (long));
+ return (MIN((ssize_t)n, size) / sizeof (uint32_t));
}
int
@@ -198,9 +206,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
int err;
struct fr {
- uintptr_t fr_savfp;
- uintptr_t fr_savpc;
- long fr_argv[32];
+ uintptr32_t fr_savfp;
+ uintptr32_t fr_savpc;
+ uint32_t fr_argv[32];
} fr;
uintptr_t fp = gsp->kregs[KREG_EBP];
@@ -226,9 +234,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
err = EMDB_STKALIGN;
goto badfp;
}
- if ((size = mdb_tgt_vread(t, &fr, sizeof (fr), fp)) >=
- (ssize_t)(2 * sizeof (uintptr_t))) {
- size -= (ssize_t)(2 * sizeof (uintptr_t));
+ if ((size = mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr,
+ sizeof (fr), fp)) >= (ssize_t)(2 * sizeof (uintptr32_t))) {
+ size -= (ssize_t)(2 * sizeof (uintptr32_t));
argc = kvm_argcount(t, fr.fr_savpc, size);
} else {
err = EMDB_NOMAP;
@@ -245,8 +253,9 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
if (advance_tortoise != 0) {
struct fr tfr;
- if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
- tortoise_fp) != sizeof (tfr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
+ sizeof (tfr), tortoise_fp) !=
+ sizeof (tfr)) {
err = EMDB_NOMAP;
goto badfp;
}
@@ -262,7 +271,8 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
advance_tortoise = !advance_tortoise;
- if (got_pc && func(arg, pc, argc, fr.fr_argv, &gregs) != 0)
+ if (got_pc &&
+ func(arg, pc, argc, (const long *)fr.fr_argv, &gregs) != 0)
break;
kregs[KREG_ESP] = kregs[KREG_EBP];
@@ -294,6 +304,12 @@ badfp:
return (set_errno(err));
}
+#ifndef __amd64
+/*
+ * The functions mdb_ia32_step_out and mdb_ia32_next haven't yet been adapted
+ * to work when built for an amd64 mdb. They are unused by the amd64-only bhyve
+ * target, hence the #ifdef.
+ */
/*
* Determine the return address for the current frame. Typically this is the
* fr_savpc value from the current frame, but we also perform some special
@@ -321,7 +337,8 @@ mdb_ia32_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
fp = sp;
}
- if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
+ sizeof (fr)) {
*p = fr.fr_savpc;
return (0);
}
@@ -372,7 +389,8 @@ mdb_ia32_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
* read the subsequent Mod/RM byte to perform additional decoding.
*/
if (curinstr == M_CALL_REG) {
- if (mdb_tgt_vread(t, &m, sizeof (m), pc + 1) != sizeof (m))
+ if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &m, sizeof (m), pc + 1)
+ != sizeof (m))
return (-1); /* errno is set for us */
/*
@@ -404,13 +422,16 @@ mdb_ia32_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
return (set_errno(EAGAIN));
}
+#endif
/*ARGSUSED*/
int
-mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
+mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *largv,
const mdb_tgt_gregset_t *gregs)
{
- argc = MIN(argc, (uint_t)arglim);
+ const uint32_t *argv = (const uint32_t *)largv;
+
+ argc = MIN(argc, (uintptr_t)arglim);
mdb_printf("%a(", pc);
if (argc != 0) {
@@ -424,11 +445,13 @@ mdb_ia32_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
}
int
-mdb_ia32_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
+mdb_ia32_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *largv,
const mdb_tgt_gregset_t *gregs)
{
- argc = MIN(argc, (uint_t)arglim);
- mdb_printf("%0?lr %a(", gregs->kregs[KREG_EBP], pc);
+ const uint32_t *argv = (const uint32_t *)largv;
+
+ argc = MIN(argc, (uintptr_t)arglim);
+ mdb_printf("%08lr %a(", gregs->kregs[KREG_EBP], pc);
if (argc != 0) {
mdb_printf("%lr", *argv++);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
index 597b234b3e..1645b86d8d 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.h
@@ -22,12 +22,13 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_IA32UTIL_H
#define _MDB_IA32UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_target_impl.h>
@@ -35,8 +36,6 @@
extern "C" {
#endif
-typedef uchar_t mdb_instr_t;
-
extern const mdb_tgt_regdesc_t mdb_ia32_kregs[];
extern void mdb_ia32_printregs(const mdb_tgt_gregset_t *);
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h b/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
index b6d17e1045..237e6663ae 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_isautil.h
@@ -23,16 +23,19 @@
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
+ */
#ifndef _MDB_ISAUTIL_H
#define _MDB_ISAUTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
+typedef uchar_t mdb_instr_t;
+
#ifdef __amd64
#include <mdb/mdb_amd64util.h>
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h b/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
index a3edf864d7..3db7d6a1d6 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_kreg.h
@@ -75,6 +75,7 @@ typedef uint32_t kreg_t;
#define KREG_ES KDIREG_ES
#define KREG_FS KDIREG_FS
#define KREG_GS KDIREG_GS
+#define KREG_FSBASE KDIREG_FSBASE
#define KREG_GSBASE KDIREG_GSBASE
#define KREG_KGSBASE KDIREG_KGSBASE
#define KREG_TRAPNO KDIREG_TRAPNO
@@ -91,6 +92,17 @@ typedef uint32_t kreg_t;
#define KREG_SP KREG_RSP
#define KREG_FP KREG_RBP
+#define KREG_EAX KREG_RAX
+#define KREG_EBX KREG_RBX
+#define KREG_ECX KREG_RCX
+#define KREG_EDX KREG_RDX
+#define KREG_ESI KREG_RSI
+#define KREG_EDI KREG_RDI
+#define KREG_EBP KREG_RBP
+#define KREG_ESP KREG_RSP
+#define KREG_EFLAGS KREG_RFLAGS
+#define KREG_EIP KREG_RIP
+
#else /* __amd64 */
#define KREG_SAVFP KDIREG_SAVFP
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c
new file mode 100644
index 0000000000..a01ee6cffb
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.c
@@ -0,0 +1,215 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * ISA-independent utility functions for the x86 architecture
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_x86util.h>
+
+#include <sys/controlregs.h>
+#include <inttypes.h>
+
+#define MMU_PAGESHIFT 12
+#define MMU_PAGESIZE (1 << MMU_PAGESHIFT)
+#define MMU_PAGEOFFSET (MMU_PAGESIZE - 1)
+#define MMU_PAGEMASK (~MMU_PAGEOFFSET)
+
+#ifndef _KMDB
+static void
+mdb_x86_print_desc(const char *name, const mdb_x86_desc_t *desc, uint_t width)
+{
+ const char *type;
+ const mdb_bitmask_t *bits;
+
+ static const mdb_bitmask_t mem_desc_flag_bits[] = {
+ { "P", 0x80, 0x80 },
+ { "16b", 0x6000, 0x0 },
+ { "32b", 0x6000, 0x4000 },
+ { "64b", 0x6000, 0x2000 },
+ { "G", 0x8000, 0x8000 },
+ { "A", 0x1, 0x1 },
+ { NULL, 0, 0 },
+ };
+
+ static const char *mem_desc_types[] = {
+ "data, up, read-only",
+ "data, up, read-write",
+ "data, down, read-only",
+ "data, down, read-write",
+ "code, non-conforming, execute-only",
+ "code, non-conforming, execute-read",
+ "code, conforming, execute-only",
+ "code, conforming, execute-read"
+ };
+
+ static const mdb_bitmask_t sys_desc_flag_bits[] = {
+ { "P", 0x80, 0x80 },
+ { "16b", 0x6000, 0x0 },
+ { "32b", 0x6000, 0x4000 },
+ { "64b", 0x6000, 0x2000 },
+ { "G", 0x8000, 0x8000 },
+ { NULL, 0, 0 },
+ };
+
+ static const char *sys_desc_types[] = {
+ "reserved",
+ "16b TSS, available",
+ "LDT",
+ "16b TSS, busy",
+ "16b call gate",
+ "task gate",
+ "16b interrupt gate",
+ "16b trap gate",
+ "reserved",
+ "32b/64b TSS, available",
+ "reserved",
+ "32b/64b TSS, busy",
+ "32b/64b call gate",
+ "reserved",
+ "32b/64b interrupt gate"
+ "32b/64b trap gate",
+ };
+
+ if (desc->d_acc & 0x10) {
+ type = mem_desc_types[(desc->d_acc >> 1) & 7];
+ bits = mem_desc_flag_bits;
+ } else {
+ type = sys_desc_types[desc->d_acc & 0xf];
+ bits = sys_desc_flag_bits;
+ }
+
+ mdb_printf("%%%s = 0x%0*lx/0x%0*x 0x%05x "
+ "<%susable, %s, dpl %d, flags: %b>\n",
+ name, width, desc->d_base, width / 2, desc->d_lim, desc->d_acc,
+ (desc->d_acc >> 16) & 1 ? "un" : "", type,
+ (desc->d_acc >> 5) & 3, desc->d_acc, bits);
+}
+#endif
+
+void
+mdb_x86_print_sysregs(struct sysregs *sregs, boolean_t long_mode)
+{
+ const uint_t width =
+ 2 * (long_mode ? sizeof (uint64_t) : sizeof (uint32_t));
+
+
+#ifndef _KMDB
+ static const mdb_bitmask_t efer_flag_bits[] = {
+ { "SCE", AMD_EFER_SCE, AMD_EFER_SCE },
+ { "LME", AMD_EFER_LME, AMD_EFER_LME },
+ { "LMA", AMD_EFER_LMA, AMD_EFER_LMA },
+ { "NXE", AMD_EFER_NXE, AMD_EFER_NXE },
+ { "SVME", AMD_EFER_SVME, AMD_EFER_SVME },
+ { "LMSLE", AMD_EFER_LMSLE, AMD_EFER_LMSLE },
+ { "FFXSR", AMD_EFER_FFXSR, AMD_EFER_FFXSR },
+ { "TCE", AMD_EFER_TCE, AMD_EFER_TCE },
+ { NULL, 0, 0 }
+ };
+#endif
+
+ static const mdb_bitmask_t cr0_flag_bits[] = {
+ { "PE", CR0_PE, CR0_PE },
+ { "MP", CR0_MP, CR0_MP },
+ { "EM", CR0_EM, CR0_EM },
+ { "TS", CR0_TS, CR0_TS },
+ { "ET", CR0_ET, CR0_ET },
+ { "NE", CR0_NE, CR0_NE },
+ { "WP", CR0_WP, CR0_WP },
+ { "AM", CR0_AM, CR0_AM },
+ { "NW", CR0_NW, CR0_NW },
+ { "CD", CR0_CD, CR0_CD },
+ { "PG", CR0_PG, CR0_PG },
+ { NULL, 0, 0 }
+ };
+
+ static const mdb_bitmask_t cr3_flag_bits[] = {
+ { "PCD", CR3_PCD, CR3_PCD },
+ { "PWT", CR3_PWT, CR3_PWT },
+ { NULL, 0, 0, }
+ };
+
+ static const mdb_bitmask_t cr4_flag_bits[] = {
+ { "VME", CR4_VME, CR4_VME },
+ { "PVI", CR4_PVI, CR4_PVI },
+ { "TSD", CR4_TSD, CR4_TSD },
+ { "DE", CR4_DE, CR4_DE },
+ { "PSE", CR4_PSE, CR4_PSE },
+ { "PAE", CR4_PAE, CR4_PAE },
+ { "MCE", CR4_MCE, CR4_MCE },
+ { "PGE", CR4_PGE, CR4_PGE },
+ { "PCE", CR4_PCE, CR4_PCE },
+ { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
+ { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
+ { "UMIP", CR4_UMIP, CR4_UMIP },
+ { "VMXE", CR4_VMXE, CR4_VMXE },
+ { "SMXE", CR4_SMXE, CR4_SMXE },
+ { "FSGSBASE", CR4_FSGSBASE, CR4_FSGSBASE },
+ { "PCIDE", CR4_PCIDE, CR4_PCIDE },
+ { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
+ { "SMEP", CR4_SMEP, CR4_SMEP },
+ { "SMAP", CR4_SMAP, CR4_SMAP },
+ { "PKE", CR4_PKE, CR4_PKE },
+ { NULL, 0, 0 }
+ };
+
+#ifndef _KMDB
+ mdb_printf("%%efer = 0x%0lx <%b>\n",
+ sregs->sr_efer, sregs->sr_efer, efer_flag_bits);
+#endif
+ mdb_printf("%%cr0 = 0x%0lx <%b>\n",
+ sregs->sr_cr0, sregs->sr_cr0, cr0_flag_bits);
+ mdb_printf("%%cr2 = 0x%0*x <%a>\n", width,
+ sregs->sr_cr2, sregs->sr_cr2);
+ mdb_printf("%%cr3 = 0x%0lx <pfn:0x%lx ",
+ sregs->sr_cr3, sregs->sr_cr3 >> MMU_PAGESHIFT);
+ if (sregs->sr_cr4 & CR4_PCIDE)
+ mdb_printf("pcid:%lu>\n", sregs->sr_cr3 & MMU_PAGEOFFSET);
+ else
+ mdb_printf("flags:%b>\n", sregs->sr_cr3, cr3_flag_bits);
+ mdb_printf("%%cr4 = 0x%0lx <%b>\n",
+ sregs->sr_cr4, sregs->sr_cr4, cr4_flag_bits);
+
+#ifndef _KMDB
+ mdb_printf("\n");
+ mdb_printf("%%pdpte0 = 0x%0?lx\t%%pdpte2 = 0x%0?lx\n",
+ sregs->sr_pdpte0, sregs->sr_pdpte2);
+ mdb_printf("%%pdpte1 = 0x%0?lx\t%%pdpte3 = 0x%0?lx\n",
+ sregs->sr_pdpte1, sregs->sr_pdpte3);
+ mdb_printf("\n");
+
+ mdb_printf("%%gdtr = 0x%0*lx/0x%hx\n",
+ width, sregs->sr_gdtr.d_base, sregs->sr_gdtr.d_lim);
+#else
+ mdb_printf("%%gdtr.base = 0x%0*lx, %%gdtr.limit = 0x%hx\n",
+ width, sregs->sr_gdtr.d_base, sregs->sr_gdtr.d_lim);
+#endif
+#ifndef _KMDB
+ mdb_printf("%%idtr = 0x%0*lx/0x%hx\n",
+ width, sregs->sr_idtr.d_base, sregs->sr_idtr.d_lim);
+ mdb_x86_print_desc("ldtr", &sregs->sr_ldtr, width);
+ mdb_x86_print_desc("tr ", &sregs->sr_tr, width);
+ mdb_x86_print_desc("cs ", &sregs->sr_cs, width);
+ mdb_x86_print_desc("ss ", &sregs->sr_ss, width);
+ mdb_x86_print_desc("ds ", &sregs->sr_ds, width);
+ mdb_x86_print_desc("es ", &sregs->sr_es, width);
+ mdb_x86_print_desc("fs ", &sregs->sr_fs, width);
+ mdb_x86_print_desc("gs ", &sregs->sr_gs, width);
+
+ mdb_printf("%%intr_shadow = 0x%lx\n",
+ sregs->sr_intr_shadow);
+#endif
+}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h
new file mode 100644
index 0000000000..7641595d2a
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_x86util.h
@@ -0,0 +1,68 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#ifndef _MDB_X86UTIL_H
+#define _MDB_X86UTIL_H
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mdb_x86_desc {
+ uint64_t d_base;
+ uint32_t d_lim;
+ uint32_t d_acc;
+} mdb_x86_desc_t;
+
+struct sysregs {
+ uint64_t sr_cr0;
+ uint64_t sr_cr2;
+ uint64_t sr_cr3;
+ uint64_t sr_cr4;
+ uint64_t sr_dr0;
+ uint64_t sr_dr1;
+ uint64_t sr_dr2;
+ uint64_t sr_dr3;
+ uint64_t sr_dr6;
+ uint64_t sr_dr7;
+ uint64_t sr_efer;
+ uint64_t sr_pdpte0;
+ uint64_t sr_pdpte1;
+ uint64_t sr_pdpte2;
+ uint64_t sr_pdpte3;
+ uint64_t sr_intr_shadow;
+ mdb_x86_desc_t sr_gdtr;
+ mdb_x86_desc_t sr_idtr;
+ mdb_x86_desc_t sr_ldtr;
+ mdb_x86_desc_t sr_tr;
+ mdb_x86_desc_t sr_cs;
+ mdb_x86_desc_t sr_ss;
+ mdb_x86_desc_t sr_ds;
+ mdb_x86_desc_t sr_es;
+ mdb_x86_desc_t sr_fs;
+ mdb_x86_desc_t sr_gs;
+};
+
+extern void mdb_x86_print_sysregs(struct sysregs *, boolean_t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MDB_X86UTIL_H */
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
index cb613e2f0c..b19498b96e 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
@@ -38,6 +38,7 @@
#include <mdb/mdb_proc.h>
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_err.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_amd64util.h>
#include <mdb/mdb.h>
@@ -144,7 +145,8 @@ pt_read_instr(mdb_tgt_t *t)
const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
uint8_t ret = 0;
- (void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[REG_RIP]);
+ (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret),
+ psp->pr_reg[REG_RIP]);
return (ret);
}
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
index 7f505b950f..c03a73f31e 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
@@ -24,8 +24,8 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
* Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
+ * Copyright 2018 Joyent, Inc.
*/
/*
@@ -38,6 +38,7 @@
#include <mdb/mdb_proc.h>
#include <mdb/mdb_kreg.h>
#include <mdb/mdb_err.h>
+#include <mdb/mdb_isautil.h>
#include <mdb/mdb_ia32util.h>
#include <mdb/mdb.h>
@@ -99,7 +100,8 @@ pt_read_instr(mdb_tgt_t *t)
const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
uint8_t ret = 0;
- (void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[EIP]);
+ (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret),
+ psp->pr_reg[EIP]);
return (ret);
}