changeset 14143:42d090a37218

3089 want ::typedef 3690 mdb on x86 should be able to print alternate register names 3688 Want mdb -e 3094 libctf should support removing a dynamic type 3095 libctf does not validate arrays correctly 3096 libctf does not validate function types correctly 3689 Want an mdb test suite driver Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Approved by: Gordon Ross <gwr@nexenta.com>
author Robert Mustacchi <rm@joyent.com>
date Wed, 03 Apr 2013 15:25:37 -0700
parents 20c0ad5cefdf
children 6f291eb437b9
files usr/src/cmd/mdb/Makefile.kmdb.files usr/src/cmd/mdb/Makefile.libstandctf usr/src/cmd/mdb/Makefile.mdb usr/src/cmd/mdb/common/libstandctf/mapfile usr/src/cmd/mdb/common/mdb/mdb.c usr/src/cmd/mdb/common/mdb/mdb.h usr/src/cmd/mdb/common/mdb/mdb_cmds.c usr/src/cmd/mdb/common/mdb/mdb_ctf.c usr/src/cmd/mdb/common/mdb/mdb_ctf.h usr/src/cmd/mdb/common/mdb/mdb_main.c usr/src/cmd/mdb/common/mdb/mdb_proc.c usr/src/cmd/mdb/common/mdb/mdb_tab.c usr/src/cmd/mdb/common/mdb/mdb_target_impl.h usr/src/cmd/mdb/common/mdb/mdb_typedef.c usr/src/cmd/mdb/common/mdb/mdb_typedef.h usr/src/cmd/mdb/intel/mdb/kvm_isadep.c usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c usr/src/cmd/mdb/test/README usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh usr/src/cmd/mdb/test/exit-e/tst.output.ksh usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out usr/src/cmd/mdb/test/exit-e/tst.simple.ksh usr/src/cmd/mdb/test/mtest.sh usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh usr/src/cmd/mdb/test/typedef/err.badmodel.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh usr/src/cmd/mdb/test/typedef/err.extraargs.ksh usr/src/cmd/mdb/test/typedef/err.noargs.ksh usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh usr/src/cmd/mdb/test/typedef/err.nomodel.ksh usr/src/cmd/mdb/test/typedef/err.noname.ksh usr/src/cmd/mdb/test/typedef/err.typeexists.ksh usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out usr/src/cmd/mdb/test/typedef/tst.dellist.mdb usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb usr/src/cmd/mdb/test/typedef/tst.libctype.ksh usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out usr/src/cmd/mdb/test/typedef/tst.models.ksh usr/src/cmd/mdb/test/typedef/tst.struct.mdb usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out usr/src/cmd/mdb/test/typedef/tst.structvla.mdb usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out usr/src/cmd/mdb/test/typedef/tst.union.mdb usr/src/cmd/mdb/test/typedef/tst.union.mdb.out usr/src/common/ctf/ctf_create.c usr/src/common/ctf/ctf_error.c usr/src/common/ctf/ctf_impl.h usr/src/common/ctf/ctf_open.c usr/src/lib/libctf/common/mapfile-vers usr/src/man/man1/mdb.1 usr/src/tools/findunref/exception_list.open usr/src/uts/common/sys/ctf_api.h
diffstat 82 files changed, 2405 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/Makefile.kmdb.files	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/Makefile.kmdb.files	Wed Apr 03 15:25:37 2013 -0700
@@ -84,6 +84,7 @@
 	mdb_target.c \
 	kmdb_terminfo.c \
 	mdb_termio.c \
+	mdb_typedef.c \
 	mdb_umem.c \
 	kmdb_umemglue.c \
 	mdb_value.c \
--- a/usr/src/cmd/mdb/Makefile.libstandctf	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/Makefile.libstandctf	Wed Apr 03 15:25:37 2013 -0700
@@ -43,7 +43,7 @@
 
 $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
 CPPFLAGS += -I$(SRC)/common/ctf -I../../../common -DCTF_OLD_VERSIONS -D_MDB \
-    -Dvsnprintf=ctf_vsnprintf
+    -Dvsnprintf=ctf_vsnprintf -Dassfail=kmdb_prom_assfail
 
 #
 # kmdb is a kernel module, so we'll use the kernel's build flags.
--- a/usr/src/cmd/mdb/Makefile.mdb	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/Makefile.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -85,6 +85,7 @@
 	mdb_target.c \
 	mdb_tdb.c \
 	mdb_termio.c \
+	mdb_typedef.c \
 	mdb_umem.c \
 	mdb_value.c \
 	mdb_vcb.c \
--- a/usr/src/cmd/mdb/common/libstandctf/mapfile	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/libstandctf/mapfile	Wed Apr 03 15:25:37 2013 -0700
@@ -20,6 +20,9 @@
 #
 # CDDL HEADER END
 #
+#
+# Copyright (c) 2012, Joyent, Inc.
+#
 
 #
 # MAPFILE HEADER START
@@ -40,15 +43,19 @@
 SYMBOL_SCOPE {
 	global:
 		ctf_add_array;
+		ctf_add_float;
+		ctf_add_integer;
 		ctf_add_member;
 		ctf_add_pointer;
 		ctf_add_struct;
+		ctf_add_type;
 		ctf_add_typedef;
 		ctf_add_union;
 		ctf_array_info;
 		ctf_bufopen;
 		ctf_close;
 		ctf_create;
+		ctf_delete_type;
 		ctf_discard;
 		ctf_enum_iter;
 		ctf_enum_name;
--- a/usr/src/cmd/mdb/common/mdb/mdb.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb.c	Wed Apr 03 15:25:37 2013 -0700
@@ -22,7 +22,6 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
 /*
  * Copyright (c) 2012 by Delphix. All rights reserved.
  * Copyright (c) 2012 Joyent, Inc. All rights reserved.
@@ -72,6 +71,7 @@
 #include <mdb/mdb_err.h>
 #include <mdb/mdb_lex.h>
 #include <mdb/mdb_io.h>
+#include <mdb/mdb_ctf.h>
 #ifdef _KMDB
 #include <kmdb/kmdb_module.h>
 #endif
@@ -555,6 +555,13 @@
 	(void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update,
 	    NULL);
 
+	/*
+	 * The call to ctf_create that this does can in fact fail, but that's
+	 * okay. All of the ctf functions that might use the synthetic types
+	 * make sure that this is safe.
+	 */
+	(void) mdb_ctf_synthetics_init();
+
 #ifdef _KMDB
 	(void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP);
 #endif
@@ -577,6 +584,8 @@
 
 	mdb_intr_disable();
 
+	mdb_ctf_synthetics_fini();
+
 	mdb_macalias_destroy();
 
 	/*
@@ -899,6 +908,8 @@
 				    flags | DCMD_PIPE_OUT, &cp->c_argv,
 				    &cp->c_addrv, cp->c_vcbs);
 
+				mdb.m_lastret = status;
+
 				ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
 				ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
 			} else {
@@ -943,8 +954,8 @@
 
 		} else {
 			mdb_intr_enable();
-			(void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags,
-			    &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
+			mdb.m_lastret = mdb_call_idcmd(cp->c_dcmd, addr, count,
+			    flags, &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
 			mdb_intr_disable();
 		}
 
--- a/usr/src/cmd/mdb/common/mdb/mdb.h	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb.h	Wed Apr 03 15:25:37 2013 -0700
@@ -43,6 +43,7 @@
 #include <mdb/mdb_modapi.h>
 #include <mdb/mdb_list.h>
 #include <mdb/mdb_vcb.h>
+#include <mdb/mdb_ctf.h>
 #include <mdb/mdb_tab.h>
 #ifdef _KMDB
 #include <kmdb/kmdb_wr.h>
@@ -181,6 +182,8 @@
 	char **m_env;		/* Current environment */
 	mdb_list_t m_cblist;	/* List of callbacks */
 	mdb_nv_t m_macaliases;	/* Name/value hash of ADB macro aliases */
+	ctf_file_t *m_synth;	/* Container for synthetic types */
+	int m_lastret;		/* Result of running the last command */
 #ifdef _KMDB
 	struct dpi_ops *m_dpi;	/* DPI ops vector */
 	struct kdi *m_kdi;	/* KDI ops vector */
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c	Wed Apr 03 15:25:37 2013 -0700
@@ -26,7 +26,7 @@
 
 /*
  * Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2012 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
  */
 
 #include <sys/elf.h>
@@ -67,6 +67,7 @@
 #include <mdb/mdb_whatis_impl.h>
 #include <mdb/mdb_macalias.h>
 #include <mdb/mdb_tab.h>
+#include <mdb/mdb_typedef.h>
 #ifdef _KMDB
 #include <kmdb/kmdb_kdi.h>
 #endif
@@ -2978,6 +2979,8 @@
 	{ "status", NULL, "print summary of current target", cmd_notsup },
 	{ "term", NULL, "display current terminal type", cmd_term },
 	{ "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset },
+	{ "typedef", "[-c model | -d | -l | -r file ] [type] [name]",
+		"create synthetic types", cmd_typedef, cmd_typedef_help },
 	{ "unset", "[name ...]", "unset variables", cmd_unset },
 	{ "vars", "[-npt]", "print listing of variables", cmd_vars },
 	{ "version", NULL, "print debugger version string", cmd_version },
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c	Wed Apr 03 15:25:37 2013 -0700
@@ -24,6 +24,7 @@
  */
 /*
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  */
 
 #include <mdb/mdb_ctf.h>
@@ -71,6 +72,125 @@
 	mdb_ctf_id_t *mbr_typep;
 } mbr_info_t;
 
+typedef struct synth_intrinsic {
+	const char *syn_name;
+	ctf_encoding_t syn_enc;
+	uint_t syn_kind;
+} synth_intrinsic_t;
+
+typedef struct synth_typedef {
+	const char *syt_src;
+	const char *syt_targ;
+} synth_typedef_t;
+
+/*
+ * As part of our support for synthetic types via ::typedef, we define a core
+ * set of types.
+ */
+static const synth_intrinsic_t synth_builtins32[] = {
+{ "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER },
+{ "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER },
+{ "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER },
+{ "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT },
+{ "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT },
+{ "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT },
+{ "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT },
+{ "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT },
+{ "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT },
+{ "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT },
+{ "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT },
+{ "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT },
+{ NULL, { 0, 0, 0}, 0 }
+};
+
+static const synth_intrinsic_t synth_builtins64[] = {
+{ "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER },
+{ "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER },
+{ "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER },
+{ "signed long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER },
+{ "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER },
+{ "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER },
+{ "unsigned long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER },
+{ "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER },
+{ "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT },
+{ "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT },
+{ "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT },
+{ "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT },
+{ "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT },
+{ "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT },
+{ "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT },
+{ "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT },
+{ "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT },
+{ NULL, { 0, 0, 0 }, 0 }
+};
+
+static const synth_typedef_t synth_typedefs32[] = {
+{ "char", "int8_t" },
+{ "short", "int16_t" },
+{ "int", "int32_t" },
+{ "long long", "int64_t" },
+{ "int", "intptr_t" },
+{ "unsigned char", "uint8_t" },
+{ "unsigned short", "uint16_t" },
+{ "unsigned", "uint32_t" },
+{ "unsigned long long", "uint64_t" },
+{ "unsigned char", "uchar_t" },
+{ "unsigned short", "ushort_t" },
+{ "unsigned", "uint_t" },
+{ "unsigned long", "ulong_t" },
+{ "unsigned long long", "u_longlong_t" },
+{ "int", "ptrdiff_t" },
+{ "unsigned", "uintptr_t" },
+{ NULL, NULL }
+};
+
+static const synth_typedef_t synth_typedefs64[] = {
+{ "char", "int8_t" },
+{ "short", "int16_t" },
+{ "int", "int32_t" },
+{ "long", "int64_t" },
+{ "long", "intptr_t" },
+{ "unsigned char", "uint8_t" },
+{ "unsigned short", "uint16_t" },
+{ "unsigned", "uint32_t" },
+{ "unsigned long", "uint64_t" },
+{ "unsigned char", "uchar_t" },
+{ "unsigned short", "ushort_t" },
+{ "unsigned", "uint_t" },
+{ "unsigned long", "ulong_t" },
+{ "unsigned long long", "u_longlong_t" },
+{ "long", "ptrdiff_t" },
+{ "unsigned long", "uintptr_t" },
+{ NULL, NULL }
+};
+
 static void
 set_ctf_id(mdb_ctf_id_t *p, ctf_file_t *fp, ctf_id_t id)
 {
@@ -146,6 +266,7 @@
 	/*
 	 * Attempt to look up the name in the primary object file.  If this
 	 * fails and the name was unscoped, search all remaining object files.
+	 * Finally, search the synthetic types.
 	 */
 	if (((fp = mdb_tgt_name_to_ctf(t, object)) == NULL ||
 	    (id = ctf_lookup_by_name(fp, name)) == CTF_ERR ||
@@ -162,6 +283,10 @@
 		if (arg.tn_id != CTF_ERR) {
 			fp = arg.tn_fp;
 			id = arg.tn_id;
+		} else if (mdb.m_synth != NULL) {
+			if ((id = ctf_lookup_by_name(mdb.m_synth,
+			    name)) != CTF_ERR)
+				fp = mdb.m_synth;
 		}
 	}
 
@@ -675,7 +800,12 @@
 	int ret;
 	type_iter_t ti;
 
-	if ((fp = mdb_tgt_name_to_ctf(t, object)) == NULL)
+	if (object == MDB_CTF_SYNTHETIC_ITER)
+		fp = mdb.m_synth;
+	else
+		fp = mdb_tgt_name_to_ctf(t, object);
+
+	if (fp == NULL)
 		return (-1);
 
 	ti.ti_cb = cb;
@@ -1553,3 +1683,461 @@
 
 	return (ctf_bufopen(&ctdata, &symtab, &strtab, errp));
 }
+
+int
+mdb_ctf_synthetics_init(void)
+{
+	int err;
+
+	if ((mdb.m_synth = ctf_create(&err)) == NULL)
+		return (set_errno(ctf_to_errno(err)));
+
+	return (0);
+}
+
+void
+mdb_ctf_synthetics_fini(void)
+{
+	if (mdb.m_synth == NULL)
+		return;
+
+	ctf_close(mdb.m_synth);
+	mdb.m_synth = NULL;
+}
+
+int
+mdb_ctf_synthetics_create_base(int kind)
+{
+	const synth_intrinsic_t *synp;
+	const synth_typedef_t *sytp;
+	int err;
+	ctf_id_t id;
+	ctf_file_t *cp = mdb.m_synth;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	switch (kind) {
+	case SYNTHETIC_ILP32:
+		synp = synth_builtins32;
+		sytp = synth_typedefs32;
+		break;
+	case SYNTHETIC_LP64:
+		synp = synth_builtins64;
+		sytp = synth_typedefs64;
+		break;
+	default:
+		mdb_dprintf(MDB_DBG_CTF, "invalid type of intrinsic: %d\n",
+		    kind);
+		return (1);
+	}
+
+	err = 0;
+	for (; synp->syn_name != NULL; synp++) {
+		if (synp->syn_kind == CTF_K_INTEGER) {
+			err = ctf_add_integer(cp, CTF_ADD_ROOT, synp->syn_name,
+			    &synp->syn_enc);
+		} else {
+			err = ctf_add_float(cp, CTF_ADD_ROOT, synp->syn_name,
+			    &synp->syn_enc);
+		}
+
+		if (err == CTF_ERR) {
+			mdb_dprintf(MDB_DBG_CTF, "couldn't add synthetic "
+			    "type: %s\n", synp->syn_name);
+			goto discard;
+		}
+	}
+
+	if (ctf_update(cp) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types\n");
+		goto discard;
+	}
+
+	for (; sytp->syt_src != NULL; sytp++) {
+		id = ctf_lookup_by_name(cp, sytp->syt_src);
+		if (id == CTF_ERR) {
+			mdb_dprintf(MDB_DBG_CTF, "cailed to lookup %s: %s\n",
+			    sytp->syt_src, ctf_errmsg(ctf_errno(cp)));
+			goto discard;
+		}
+		if (ctf_add_typedef(cp, CTF_ADD_ROOT, sytp->syt_targ, id) ==
+		    CTF_ERR) {
+			mdb_dprintf(MDB_DBG_CTF, "couldn't add typedef %s "
+			    "%s: %s\n", sytp->syt_targ, sytp->syt_src,
+			    ctf_errmsg(ctf_errno(cp)));
+			goto discard;
+		}
+	}
+
+	if (ctf_update(cp) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types\n");
+		goto discard;
+	}
+
+	return (0);
+
+discard:
+	err = set_errno(ctf_to_errno(ctf_errno(cp)));
+	(void) ctf_discard(cp);
+	return (err);
+}
+
+int
+mdb_ctf_synthetics_reset(void)
+{
+	mdb_ctf_synthetics_fini();
+	return (mdb_ctf_synthetics_init());
+}
+
+int
+mdb_ctf_add_typedef(const char *name, const mdb_ctf_id_t *p, mdb_ctf_id_t *new)
+{
+	ctf_id_t rid;
+	mdb_ctf_id_t tid;
+	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	if (mdb_ctf_lookup_by_name(name, &tid) == 0) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add type %s: a type "
+		    "with that name already exists\n", name);
+		return (set_errno(EEXIST));
+	}
+
+	rid = ctf_add_type(mdb.m_synth, mcip->mci_fp, mcip->mci_id);
+	if (rid == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add reference type: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+	rid = ctf_add_typedef(mdb.m_synth, CTF_ADD_ROOT, name, rid);
+	if (rid == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add typedef: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (new != NULL)
+		set_ctf_id(new, mdb.m_synth, rid);
+
+	return (0);
+}
+
+int
+mdb_ctf_add_struct(const char *name, mdb_ctf_id_t *rid)
+{
+	mdb_ctf_id_t tid;
+	ctf_id_t id;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	if (name != NULL && mdb_ctf_lookup_by_name(name, &tid) == 0) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add type %s: a type "
+		    "with that name already exists\n", name);
+		return (set_errno(EEXIST));
+	}
+
+	if ((id = ctf_add_struct(mdb.m_synth, CTF_ADD_ROOT, name)) ==
+	    CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add struct: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (rid != NULL)
+		set_ctf_id(rid, mdb.m_synth, id);
+
+	return (0);
+}
+
+int
+mdb_ctf_add_union(const char *name, mdb_ctf_id_t *rid)
+{
+	mdb_ctf_id_t tid;
+	ctf_id_t id;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	if (name != NULL && mdb_ctf_lookup_by_name(name, &tid) == 0) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add type %s: a type "
+		    "with that name already exists\n", name);
+		return (set_errno(EEXIST));
+	}
+
+	if ((id = ctf_add_union(mdb.m_synth, CTF_ADD_ROOT, name)) ==
+	    CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add union: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (rid != NULL)
+		set_ctf_id(rid, mdb.m_synth, id);
+
+	return (0);
+}
+
+int
+mdb_ctf_add_member(const mdb_ctf_id_t *p, const char *name,
+    const mdb_ctf_id_t *mtype, mdb_ctf_id_t *rid)
+{
+	ctf_id_t id, mtid;
+	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
+	mdb_ctf_impl_t *mcim = (mdb_ctf_impl_t *)mtype;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (DCMD_ERR);
+	}
+
+	if (mcip->mci_fp != mdb.m_synth) {
+		mdb_dprintf(MDB_DBG_CTF, "requested to add member to a type "
+		    "that wasn't created from a synthetic\n");
+		return (set_errno(EINVAL));
+	}
+
+	mtid = ctf_add_type(mdb.m_synth, mcim->mci_fp, mcim->mci_id);
+	if (mtid == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add member type: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	id = ctf_add_member(mdb.m_synth, mcip->mci_id, name, mtid);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add member %s: %s\n",
+		    name, ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (rid != NULL)
+		set_ctf_id(rid, mdb.m_synth, id);
+
+	return (0);
+}
+
+int
+mdb_ctf_add_array(const mdb_ctf_arinfo_t *marp, mdb_ctf_id_t *rid)
+{
+	mdb_ctf_impl_t *mcip;
+	ctf_arinfo_t car;
+	ctf_id_t id;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	car.ctr_nelems = marp->mta_nelems;
+
+	mcip = (mdb_ctf_impl_t *)&marp->mta_contents;
+	id = ctf_add_type(mdb.m_synth, mcip->mci_fp, mcip->mci_id);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add member type: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+	car.ctr_contents = id;
+
+	mcip = (mdb_ctf_impl_t *)&marp->mta_index;
+	id = ctf_add_type(mdb.m_synth, mcip->mci_fp, mcip->mci_id);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add member type: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+	car.ctr_index = id;
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	id = ctf_add_array(mdb.m_synth, CTF_ADD_ROOT, &car);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (rid != NULL)
+		set_ctf_id(rid, mdb.m_synth, id);
+
+	return (0);
+}
+
+int
+mdb_ctf_add_pointer(const mdb_ctf_id_t *p, mdb_ctf_id_t *rid)
+{
+	ctf_id_t id;
+	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)p;
+
+	if (mdb.m_synth == NULL) {
+		mdb_printf("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	id = ctf_add_type(mdb.m_synth, mcip->mci_fp, mcip->mci_id);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add pointer type: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+
+	id = ctf_add_pointer(mdb.m_synth, CTF_ADD_ROOT, id);
+	if (id == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add pointer: %s\n",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+
+	if (rid != NULL)
+		set_ctf_id(rid, mdb.m_synth, id);
+
+	return (0);
+}
+
+int
+mdb_ctf_type_delete(const mdb_ctf_id_t *id)
+{
+	int ret;
+
+	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)id;
+
+	if (mcip->mci_fp != mdb.m_synth) {
+		mdb_warn("bad ctf_file_t, expected synth container\n");
+		return (1);
+	}
+
+	ret = ctf_delete_type(mcip->mci_fp, mcip->mci_id);
+	if (ret != 0) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to delete synthetic type: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	if (ctf_update(mdb.m_synth) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types: %s",
+		    ctf_errmsg(ctf_errno(mdb.m_synth)));
+		return (set_errno(ctf_to_errno(ctf_errno(mdb.m_synth))));
+	}
+
+	return (0);
+}
+
+static int
+mdb_ctf_synthetics_file_cb(mdb_ctf_id_t id, void *arg)
+{
+	ctf_file_t *targ = arg;
+	mdb_ctf_impl_t *mcip = (mdb_ctf_impl_t *)&id;
+
+	if (ctf_add_type(targ, mcip->mci_fp, mcip->mci_id) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to add type %d: %s\n",
+		    mcip->mci_id, ctf_errmsg(ctf_errno(mcip->mci_fp)));
+		return (set_errno(ctf_to_errno(ctf_errno(mcip->mci_fp))));
+	}
+
+	return (0);
+}
+
+int
+mdb_ctf_synthetics_from_file(const char *file)
+{
+	ctf_file_t *fp, *syn = mdb.m_synth;
+	int ret;
+	type_iter_t ti;
+
+	if (syn == NULL) {
+		mdb_warn("synthetic types disabled: ctf create failed\n");
+		return (1);
+	}
+
+	if ((fp = mdb_ctf_open(file, &ret)) == NULL) {
+		mdb_warn("failed to parse ctf data in %s", file);
+		return (1);
+	}
+
+	ret = DCMD_OK;
+	ti.ti_fp = fp;
+	ti.ti_arg = syn;
+	ti.ti_cb = mdb_ctf_synthetics_file_cb;
+	if (ctf_type_iter(fp, type_iter_cb, &ti) == CTF_ERR) {
+		ret = set_errno(ctf_to_errno(ctf_errno(fp)));
+		mdb_warn("failed to add types");
+		goto cleanup;
+	}
+
+	if (ctf_update(syn) == CTF_ERR) {
+		mdb_dprintf(MDB_DBG_CTF, "failed to update synthetic types\n");
+		ret = set_errno(ctf_to_errno(ctf_errno(fp)));
+	}
+
+cleanup:
+	ctf_close(fp);
+	if (ret != 0)
+		(void) ctf_discard(syn);
+	return (ret);
+}
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.h	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.h	Wed Apr 03 15:25:37 2013 -0700
@@ -24,6 +24,7 @@
  */
 /*
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  */
 
 #ifndef	_MDB_CTF_H
@@ -101,6 +102,29 @@
 extern int mdb_ctf_member_iter(mdb_ctf_id_t, mdb_ctf_member_f *, void *);
 extern int mdb_ctf_enum_iter(mdb_ctf_id_t, mdb_ctf_enum_f *, void *);
 extern int mdb_ctf_type_iter(const char *, mdb_ctf_type_f *, void *);
+extern int mdb_ctf_type_delete(const mdb_ctf_id_t *);
+
+/*
+ * Special values for mdb_ctf_type_iter.
+ */
+#define	MDB_CTF_SYNTHETIC_ITER	(const char *)(-1L)
+
+#define	SYNTHETIC_ILP32	1
+#define	SYNTHETIC_LP64	2
+extern int mdb_ctf_synthetics_create_base(int);
+extern int mdb_ctf_synthetics_reset(void);
+
+/*
+ * Synthetic creation routines
+ */
+extern int mdb_ctf_add_typedef(const char *, const mdb_ctf_id_t *,
+    mdb_ctf_id_t *);
+extern int mdb_ctf_add_struct(const char *, mdb_ctf_id_t *);
+extern int mdb_ctf_add_union(const char *, mdb_ctf_id_t *);
+extern int mdb_ctf_add_member(const mdb_ctf_id_t *, const char *,
+    const mdb_ctf_id_t *, mdb_ctf_id_t *);
+extern int mdb_ctf_add_array(const mdb_ctf_arinfo_t *, mdb_ctf_id_t *);
+extern int mdb_ctf_add_pointer(const mdb_ctf_id_t *, mdb_ctf_id_t *);
 
 /* utility stuff */
 extern ctf_id_t mdb_ctf_type_id(mdb_ctf_id_t);
@@ -128,6 +152,9 @@
 extern ctf_file_t *mdb_ctf_bufopen(const void *, size_t,	/* Internal */
     const void *, Shdr *, const void *, Shdr *, int *);
 extern void mdb_ctf_close(ctf_file_t *fp);			/* Internal */
+extern int mdb_ctf_synthetics_init(void);			/* Internal */
+extern void mdb_ctf_synthetics_fini(void);			/* Internal */
+extern int mdb_ctf_synthetics_from_file(const char *);		/* Internal */
 
 #endif
 
--- a/usr/src/cmd/mdb/common/mdb/mdb_main.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c	Wed Apr 03 15:25:37 2013 -0700
@@ -323,10 +323,12 @@
 {
 	mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
 	    "[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
-	    "[-R root] [-V dis-version] [object [core] | core | suffix]\n\n",
+	    "[-R root] [-V dis-version] [-e expr] "
+	    "[object [core] | core | suffix]\n\n",
 	    mdb.m_pname);
 
 	mdb_iob_puts(mdb.m_err,
+	    "\t-e evaluate expr and return status\n"
 	    "\t-f force raw file debugging mode\n"
 	    "\t-k force kernel debugging mode\n"
 	    "\t-m disable demand-loading of module symbols\n"
@@ -420,6 +422,7 @@
 	char *p;
 
 	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 ttylike;
@@ -508,8 +511,15 @@
 
 	while (optind < argc) {
 		while ((c = getopt(argc, argv,
-		    "fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
+		    "e:fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
 			switch (c) {
+			case 'e':
+				if (eflag != NULL) {
+					warn("-e already specified\n");
+					terminate(2);
+				}
+				eflag = optarg;
+				break;
 			case 'f':
 				fflag++;
 				tgt_ctor = mdb_rawfile_tgt_create;
@@ -691,6 +701,12 @@
 		/*NOTREACHED*/
 	}
 
+	if (eflag != NULL) {
+		IOP_CLOSE(in_io);
+		in_io = mdb_strio_create(eflag);
+		mdb.m_lastret = 0;
+	}
+
 	/*
 	 * If standard input appears to have tty attributes, attempt to
 	 * initialize a terminal i/o backend on top of stdin and stdout.
@@ -1079,7 +1095,8 @@
 		continue;
 	}
 
-	terminate((status == MDB_ERR_QUIT || status == 0) ? 0 : 1);
+	terminate((status == MDB_ERR_QUIT || status == 0) ?
+	    (eflag != NULL && mdb.m_lastret != 0 ? 1 : 0) : 1);
 	/*NOTREACHED*/
 	return (0);
 
--- a/usr/src/cmd/mdb/common/mdb/mdb_proc.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_proc.c	Wed Apr 03 15:25:37 2013 -0700
@@ -4505,6 +4505,14 @@
 			 */
 			if (PTL_GETREGS(t, tid, grs) == 0) {
 				*rp = r | (ulong_t)grs[rd_num];
+				if (rd_flags & MDB_TGT_R_32)
+					*rp &= 0xffffffffULL;
+				else if (rd_flags & MDB_TGT_R_16)
+					*rp &= 0xffffULL;
+				else if (rd_flags & MDB_TGT_R_8H)
+					*rp = (*rp & 0xff00ULL) >> 8;
+				else if (rd_flags & MDB_TGT_R_8L)
+					*rp &= 0xffULL;
 				return (0);
 			}
 			return (-1);
@@ -4531,6 +4539,16 @@
 		ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval);
 
 		if (!MDB_TGT_R_IS_FP(rd_flags)) {
+
+			if (rd_flags & MDB_TGT_R_32)
+				r &= 0xffffffffULL;
+			else if (rd_flags & MDB_TGT_R_16)
+				r &= 0xffffULL;
+			else if (rd_flags & MDB_TGT_R_8H)
+				r = (r & 0xffULL) << 8;
+			else if (rd_flags & MDB_TGT_R_8L)
+				r &= 0xffULL;
+
 #if defined(__sparc) && defined(_ILP32)
 			/*
 			 * If we are debugging on 32-bit SPARC, the globals and
--- a/usr/src/cmd/mdb/common/mdb/mdb_tab.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_tab.c	Wed Apr 03 15:25:37 2013 -0700
@@ -579,6 +579,8 @@
 		mdb_tab_setmbase(mcp, name);
 
 	(void) mdb_tgt_object_iter(t, mdb_tab_complete_module, mcp);
+	(void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, tab_complete_type,
+	    mcp);
 	return (0);
 }
 
--- a/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h	Wed Apr 03 15:25:37 2013 -0700
@@ -22,12 +22,13 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef	_MDB_TARGET_IMPL_H
 #define	_MDB_TARGET_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <mdb/mdb_target.h>
 #include <mdb/mdb_module.h>
 #include <mdb/mdb_list.h>
@@ -250,6 +251,10 @@
 #define	MDB_TGT_R_FPQ		0x040	/* Quad-precision floating-point */
 #define	MDB_TGT_R_FPU		0x080	/* FPU control/status register */
 #define	MDB_TGT_R_RDONLY	0x100	/* Register is read-only */
+#define	MDB_TGT_R_32		0x200	/* 32-bit version of register */
+#define	MDB_TGT_R_16		0x400	/* 16-bit version of register */
+#define	MDB_TGT_R_8H		0x800	/* upper half of a 16-bit reg */
+#define	MDB_TGT_R_8L		0x1000	/* lower half of a 16-bit reg */
 
 #define	MDB_TGT_R_IS_FP(f)	((f) & 0xf0) /* Test MDB_TGT_R_FP* bits */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/mdb/mdb_typedef.c	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,773 @@
+/*
+ * 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 (c) 2013 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * ::typedef exists to allow a user to create and import auxiliary CTF
+ * information for the currently running target. ::typedef is similar to the C
+ * typedef keyword. However, ::typedef has no illusions of grandeur. It is not a
+ * standards complaint version of C's typedef. For specifics on what it does and
+ * does not support, please see the help message for ::typedef later on in this
+ * file.
+ *
+ * In addition to allowing the user to create types, it has a notion of a
+ * built-in set of types that a compiler might provide. Currently ::typedef
+ * supports both the standard illumos 32-bit and 64-bit environments, mainly
+ * LP32 and LP64. These are not present by default; it is up to the user to
+ * request that they be inserted.
+ *
+ * To facilitate this, ::typedef adds all of its type information to an
+ * auxiliary CTF container that is a part of the global mdb state. This is
+ * abstracted away from ::typedef by the mdb_ctf_* apis. This container is
+ * referred to as the synthetic container, as it holds these synthetic types.
+ * The synthetic container does not have a parent CTF container. This is rather
+ * important to its operation, as a user can end up referencing types that come
+ * from many different such containers (eg. different kernel modules). As such,
+ * whenever a type is referenced that we do not know about, we search all of the
+ * CTF containers that mdb knows about it. If we find it, then that type is
+ * imported (along with all of its dependent types) into the synthetic
+ * container.
+ *
+ * Finally, ::typedef can source CTF information from external files with the -r
+ * option. This will copy in every type from their container into the synthetic
+ * container, because of this the parent and child relationship between
+ * containers with parents cannot be maintained.
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_list.h>
+#include <mdb/mdb_nv.h>
+
+struct parse_node;
+
+#define	PN_F_POINTER	0x01
+#define	PN_F_ARRAY	0x02
+
+typedef struct parse_node {
+	mdb_list_t		pn_list;	/* list entry, must be first */
+	char			*pn_type;	/* name of base type */
+	char			*pn_name;	/* name of the member */
+	int			pn_flags;	/* flags */
+	int			pn_nptrs;	/* number of pointers */
+	int			pn_asub;	/* value of array subscript */
+} parse_node_t;
+
+typedef struct parse_root {
+	mdb_list_t	pr_nodes;	/* list of members */
+	int		pr_kind;	/* CTF_K_* */
+	const char	*pr_name;	/* entity name */
+	const char	*pr_tname;	/* entity typedef */
+} parse_root_t;
+
+static int
+typedef_valid_identifier(const char *str)
+{
+	/*
+	 * We can't use the standard ctype.h functions because those aren't
+	 * necessairly available in kmdb. On the flip side, we only care about
+	 * ascii characters here so that isn't too bad.
+	 *
+	 * C Identifiers have to start with a letter or a _. Afterwards they can
+	 * be alphanumeric or an _.
+	 */
+
+	if (*str == '\0')
+		return (1);
+
+	if (*str != '_' &&
+	    (*str < 'A' || *str > 'Z') &&
+	    (*str < 'a' || *str > 'z'))
+		return (1);
+	str++;
+
+	while (*str != '\0') {
+		if (*str != '_' &&
+		    (*str < '0' || *str > '9') &&
+		    (*str < 'A' || *str > 'Z') &&
+		    (*str < 'a' || *str > 'z'))
+			return (1);
+		str++;
+	}
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+typedef_list_cb(mdb_ctf_id_t id, void *arg)
+{
+	char buf[MDB_SYM_NAMLEN];
+
+	/*
+	 * The user may have created an anonymous structure or union as part of
+	 * running ::typedef. If this is the case, we passed a NULL pointer for
+	 * the name into the ctf routines. When we go back and ask for the name
+	 * of that, ctf goes through and loops through all the declarations.
+	 * This, however correctly, gives us back something undesirable to the
+	 * user, eg. the name is simply 'struct' and 'union'. Because a typedef
+	 * will always have a non-anonymous name for that, we instead opt to
+	 * not include these anonymous names. ctf usefully includes a space as
+	 * part of that name.
+	 */
+	(void) mdb_ctf_type_name(id, buf, sizeof (buf));
+	if (strcmp("struct ", buf) != 0 && strcmp("union ", buf) != 0)
+		mdb_printf("%s\n", buf);
+	return (0);
+}
+
+static char *
+typedef_join_strings(int nstr, const mdb_arg_t *args, int flags)
+{
+	int i, size = 0;
+	char *ret, *sptr;
+
+	for (i = 0; i <= nstr; i++) {
+		/* Always account for the space or the null terminator */
+		size += strlen(args[i].a_un.a_str) + 1;
+	}
+	ret = mdb_alloc(sizeof (char) * size, flags);
+	if (ret == NULL)
+		return (NULL);
+	sptr = ret;
+	for (i = 0; i <= nstr; i++) {
+		(void) strcpy(sptr, args[i].a_un.a_str);
+		sptr += strlen(args[i].a_un.a_str);
+		*sptr = ' ';
+		sptr++;
+	}
+	*sptr = '\0';
+
+	return (ret);
+}
+
+static int
+typedef_list(void)
+{
+	(void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, typedef_list_cb,
+	    NULL);
+	return (DCMD_OK);
+}
+
+static int
+typedef_destroy(void)
+{
+	if (mdb_ctf_synthetics_reset() != 0) {
+		mdb_warn("failed to reset synthetic types");
+		return (DCMD_ERR);
+	}
+	return (DCMD_OK);
+}
+
+/*
+ * We've been asked to create the basic types that exist. We accept the
+ * following strings to indicate what we should create.
+ * - LP32, ILP32 (case insensitive)
+ * - LP64
+ */
+static int
+typedef_create(const char *arg)
+{
+	int kind;
+
+	if (strcasecmp(arg, "LP32") == 0 || strcasecmp(arg, "ILP32") == 0) {
+		kind = SYNTHETIC_ILP32;
+	} else if (strcasecmp(arg, "LP64") == 0) {
+		kind = SYNTHETIC_LP64;
+	} else {
+		mdb_printf("invalid data model: %s\n", arg);
+		return (DCMD_USAGE);
+	}
+
+	if (mdb_ctf_synthetics_create_base(kind) != 0) {
+		mdb_printf("failed to create intrinsic types, maybe "
+		    "they already exist\n");
+		return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
+
+/*
+ * Search the current arguments for a complete member declaration. This function
+ * modifies the value of defn based on what's necessary for parsing. It returns
+ * the appropriate parse node in pnp.
+ */
+static int
+typedef_parse_member(char *defn, char **next, parse_node_t **pnp)
+{
+	char *c, *name, *array;
+	int nptrs = 0;
+	parse_node_t *pn;
+
+	c = strchr(defn, ';');
+	if (c == NULL) {
+		mdb_printf("Cannot find semi-colon to delineate the end "
+		    "of a member.\n");
+		return (DCMD_ERR);
+	}
+	*c = '\0';
+	*next = c + 1;
+
+	c = strrchr(defn, ' ');
+	if (c == NULL) {
+		mdb_printf("Missing both a name and a type declaration for "
+		    "a member. Instead, found '%s'\n", defn);
+		return (DCMD_ERR);
+	}
+	*c = '\0';
+	name = c + 1;
+	c--;
+	while (*c == '*' || *c == ' ') {
+		if (*c == '*')
+			nptrs++;
+		c--;
+	}
+	*(c + 1) = '\0';
+
+	pn = mdb_zalloc(sizeof (parse_node_t), UM_SLEEP | UM_GC);
+	pn->pn_type = defn;
+
+	/*
+	 * Go through and prepare the name field. Note that we still have to
+	 * check if this is a pointer or an array. We also need to strip the
+	 * ending semi-colon.
+	 */
+	while (*name == '*') {
+		name++;
+		nptrs++;
+	}
+
+	if ((c = strchr(name, '[')) != NULL) {
+		array = c;
+		if ((c = strchr(array, ']')) == NULL) {
+			mdb_printf("Found the beginning of an array size "
+			    "but no closing ']' in %s\n", array);
+			return (DCMD_ERR);
+		}
+		*array = '\0';
+		array++;
+		*c = '\0';
+		pn->pn_flags |= PN_F_ARRAY;
+		pn->pn_asub = mdb_strtoull(array);
+		if (pn->pn_asub < 0) {
+			mdb_printf("Array lengths cannot be negative\n");
+			return (DCMD_ERR);
+		}
+	}
+
+	if (typedef_valid_identifier(name) != 0) {
+		mdb_printf("The name %s is not a valid C identifier.\n",
+		    name);
+		return (DCMD_ERR);
+	}
+
+	if (nptrs) {
+		pn->pn_flags |= PN_F_POINTER;
+		pn->pn_nptrs = nptrs;
+	}
+	pn->pn_name = name;
+
+	*pnp = pn;
+	return (DCMD_OK);
+}
+
+/*
+ * We're going to parse out our types here. Note that we are not strictly
+ * speaking a truely ANSI C compliant parser. Currently we support normal
+ * declarations except for the following:
+ *   o function pointers
+ *   o bit-fields
+ */
+static int
+typedef_parse(char *defn, const char *name, parse_root_t **prp)
+{
+	int len, ret;
+	const char *kind, *basename;
+	char *c, *brace;
+	parse_root_t *pr;
+	parse_node_t *pn;
+	mdb_ctf_id_t id;
+
+	pr = mdb_zalloc(sizeof (parse_root_t), UM_SLEEP | UM_GC);
+	basename = defn;
+
+	c = strchr(defn, ' ');
+	if (c == NULL) {
+		mdb_printf("Invalid structure definition. Structure "
+		    "must start with either 'struct {' or 'union {'\n");
+		return (DCMD_ERR);
+	}
+	*c = '\0';
+
+	if (strcmp(defn, "struct") == 0)
+		pr->pr_kind = CTF_K_STRUCT;
+	else if (strcmp(defn, "union") == 0)
+		pr->pr_kind = CTF_K_UNION;
+	else {
+		mdb_printf("Invalid start of definition. "
+		    "Expected 'struct' or 'union'. "
+		    "Found: '%s'\n", defn);
+		return (DCMD_ERR);
+	}
+
+	/*
+	 * We transform this back to a space so we can validate that a
+	 * non-anonymous struct or union name is valid.
+	 */
+	*c = ' ';
+
+	kind = defn;
+	defn = c + 1;
+	while (*defn == ' ')
+		defn++;
+
+	/* Check whether this is anonymous or not */
+	if (*defn != '{') {
+		brace = strchr(defn, '{');
+		c = brace;
+		if (c == NULL) {
+			mdb_printf("Missing opening brace for %s definition. "
+			    "Expected '{'. "
+			    "Found: '%c'\n", kind, *defn);
+			return (DCMD_ERR);
+		}
+		*c = '\0';
+		c--;
+		while (*c == ' ')
+			c--;
+		*(c+1) = '\0';
+		if (typedef_valid_identifier(defn) != 0) {
+			mdb_printf("The name %s is not a valid C identifier.\n",
+			    defn);
+			return (DCMD_ERR);
+		}
+
+		if (mdb_ctf_lookup_by_name(basename, &id) != CTF_ERR) {
+			mdb_printf("type name %s already in use\n", basename);
+			return (DCMD_ERR);
+		}
+
+		pr->pr_name = defn;
+		defn = brace;
+	} else {
+		pr->pr_name = NULL;
+	}
+
+	defn++;
+	while (*defn == ' ')
+		defn++;
+
+	len = strlen(defn);
+	if (defn[len-1] != '}') {
+		mdb_printf("Missing closing brace for %s declaration. "
+		    "Expected '}'.\n");
+		return (DCMD_ERR);
+	}
+	defn[len-1] = '\0';
+
+	/*
+	 * Start walking all the arguments, looking for a terminating semicolon
+	 * for type definitions.
+	 */
+	for (;;) {
+		ret = typedef_parse_member(defn, &c, &pn);
+		if (ret == DCMD_ERR)
+			return (DCMD_ERR);
+
+		mdb_list_append(&pr->pr_nodes, pn);
+
+		while (*c == ' ')
+			c++;
+
+		if (*c == '\0')
+			break;
+
+		defn = c;
+	}
+
+	pr->pr_tname = name;
+	*prp = pr;
+
+	return (DCMD_OK);
+}
+
+/*
+ * Make sure that none of the member names overlap and that the type names don't
+ * already exist. If we have an array entry that is a VLA, make sure it is the
+ * last member and not the only member.
+ */
+static int
+typedef_validate(parse_root_t *pr)
+{
+	mdb_nv_t nv;
+	parse_node_t *pn;
+	mdb_ctf_id_t id;
+	int count = 0;
+
+	(void) mdb_nv_create(&nv, UM_SLEEP | UM_GC);
+	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
+	    pn = mdb_list_next(pn)) {
+		count++;
+		if (mdb_nv_lookup(&nv, pn->pn_name) != NULL) {
+			mdb_printf("duplicate name detected: %s\n",
+			    pn->pn_name);
+			return (DCMD_ERR);
+		}
+
+		/*
+		 * Our parse tree won't go away before the nv, so it's simpler
+		 * to just mark everything external.
+		 */
+		(void) mdb_nv_insert(&nv, pn->pn_name, NULL, 0, MDB_NV_EXTNAME);
+
+		if (pn->pn_flags & PN_F_ARRAY && pn->pn_asub == 0) {
+			if (pr->pr_kind != CTF_K_STRUCT) {
+				mdb_printf("Flexible array members are only "
+				    "valid in structs.\n");
+				return (DCMD_ERR);
+			}
+
+			if (&pn->pn_list != pr->pr_nodes.ml_prev) {
+				mdb_printf("Flexible array entries are only "
+				    "allowed to be the last entry in a "
+				    "struct\n");
+				return (DCMD_ERR);
+			}
+
+			if (count == 1) {
+				mdb_printf("Structs must have members aside "
+				    "from a flexible member\n");
+				return (DCMD_ERR);
+			}
+		}
+	}
+
+	if (mdb_ctf_lookup_by_name(pr->pr_tname, &id) != CTF_ERR) {
+		mdb_printf("typedef name %s already exists\n", pr->pr_tname);
+		return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
+
+static int
+typedef_add(parse_root_t *pr)
+{
+	parse_node_t *pn;
+	mdb_ctf_id_t id, aid, tid, pid;
+	mdb_ctf_arinfo_t ar;
+	int ii;
+
+	/* Pre-flight checks */
+	if (typedef_validate(pr) == DCMD_ERR)
+		return (DCMD_ERR);
+
+	if (pr->pr_kind == CTF_K_STRUCT) {
+		if (mdb_ctf_add_struct(pr->pr_name, &id) != 0) {
+			mdb_printf("failed to create struct for %s\n",
+			    pr->pr_tname);
+			return (DCMD_ERR);
+		}
+	} else {
+		if (mdb_ctf_add_union(pr->pr_name, &id) != 0) {
+			mdb_printf("failed to create union for %s\n",
+			    pr->pr_tname);
+			return (DCMD_ERR);
+		}
+	}
+
+	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
+	    pn = mdb_list_next(pn)) {
+
+		if (mdb_ctf_lookup_by_name(pn->pn_type, &tid) == CTF_ERR) {
+			mdb_printf("failed to add member %s: type %s does "
+			    "not exist\n", pn->pn_name, pn->pn_type);
+			goto destroy;
+		}
+
+		if (pn->pn_flags & PN_F_POINTER) {
+			for (ii = 0; ii < pn->pn_nptrs; ii++) {
+				if (mdb_ctf_add_pointer(&tid,
+				    &pid) != 0) {
+					mdb_printf("failed to add a pointer "
+					    "type as part of member: %s\n",
+					    pn->pn_name);
+					goto destroy;
+				}
+				tid = pid;
+			}
+		}
+
+		if (pn->pn_flags & PN_F_ARRAY) {
+			if (mdb_ctf_lookup_by_name("long", &aid) != 0) {
+				mdb_printf("failed to lookup the type 'long' "
+				    "for array indexes, are you running mdb "
+				    "without a target or using ::typedef -c?");
+				goto destroy;
+			}
+
+			ar.mta_contents = tid;
+			ar.mta_index = aid;
+			ar.mta_nelems = pn->pn_asub;
+
+			if (mdb_ctf_add_array(&ar, &tid) != 0) {
+				mdb_printf("failed to create array type for "
+				    "memeber%s\n", pn->pn_name);
+				goto destroy;
+			}
+		}
+
+		if (mdb_ctf_add_member(&id, pn->pn_name, &tid, NULL) ==
+		    CTF_ERR) {
+			mdb_printf("failed to create member %s\n",
+			    pn->pn_name);
+			goto destroy;
+		}
+	}
+
+	if (mdb_ctf_add_typedef(pr->pr_tname, &id, NULL) != 0) {
+		mdb_printf("failed to add typedef for %s\n",
+		    pr->pr_tname);
+		goto destroy;
+	}
+
+	return (DCMD_OK);
+
+destroy:
+	return (mdb_ctf_type_delete(&id));
+}
+
+static int
+typedef_readfile(const char *file)
+{
+	int ret;
+
+	ret = mdb_ctf_synthetics_from_file(file);
+	if (ret != DCMD_OK)
+		mdb_warn("failed to create synthetics from file\n");
+	return (ret);
+}
+
+/* ARGSUSED */
+int
+cmd_typedef(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	mdb_ctf_id_t id;
+	int i;
+	int destroy = 0, list = 0;
+	const char *cmode = NULL, *rfile = NULL;
+	const char *dst, *src;
+	char *dup;
+	parse_root_t *pr;
+
+	if (flags & DCMD_ADDRSPEC)
+		return (DCMD_USAGE);
+
+	i = mdb_getopts(argc, argv,
+	    'd', MDB_OPT_SETBITS, TRUE, &destroy,
+	    'l', MDB_OPT_SETBITS, TRUE, &list,
+	    'c', MDB_OPT_STR, &cmode,
+	    'r', MDB_OPT_STR, &rfile, NULL);
+
+	argc -= i;
+	argv += i;
+
+	/*
+	 * All our options are mutually exclusive currently.
+	 */
+	i = 0;
+	if (destroy)
+		i++;
+	if (cmode != NULL)
+		i++;
+	if (list)
+		i++;
+	if (rfile != NULL)
+		i++;
+	if (i > 1)
+		return (DCMD_USAGE);
+
+	if ((destroy || cmode != NULL || list || rfile != NULL) && argc != 0)
+		return (DCMD_USAGE);
+
+	if (destroy)
+		return (typedef_destroy());
+
+	if (cmode)
+		return (typedef_create(cmode));
+
+	if (list)
+		return (typedef_list());
+
+	if (rfile)
+		return (typedef_readfile(rfile));
+
+	if (argc < 2)
+		return (DCMD_USAGE);
+
+	/*
+	 * Check to see if we are defining a struct or union. Note that we have
+	 * to distinguish between struct foo and struct {. All typedef structs
+	 * are annonymous structs that are only known by their typedef name. The
+	 * same is true with unions. The problem that we have to deal with is
+	 * that the ';' character in mdb causes mdb to begin another command. To
+	 * work around that fact we require users to put the whole struct
+	 * definition in a pair of "" or ''.
+	 */
+	if (argc == 2 && strchr(argv[0].a_un.a_str, '{') != NULL) {
+		dup = mdb_alloc(strlen(argv[0].a_un.a_str) + 1,
+		    UM_GC | UM_SLEEP);
+		(void) strcpy(dup, argv[0].a_un.a_str);
+		if (typedef_parse(dup, argv[1].a_un.a_str, &pr) == DCMD_ERR)
+			return (DCMD_ERR);
+		if (typedef_add(pr) == DCMD_ERR)
+			return (DCMD_ERR);
+
+		return (DCMD_OK);
+	}
+
+	/*
+	 * Someone could give us something like struct foobar or unsigned int or
+	 * even long double imaginary. In this case we end up conjoining all
+	 * arguments except the last one into one large string that we look up.
+	 */
+	if (argc - 1 == 1) {
+		src = argv[0].a_un.a_str;
+	} else {
+		src = typedef_join_strings(argc - 2, argv, UM_GC | UM_SLEEP);
+	}
+
+	dst = argv[argc-1].a_un.a_str;
+
+	if (mdb_ctf_lookup_by_name(dst, &id) != -1) {
+		mdb_printf("%s already exists\n", dst);
+		return (DCMD_ERR);
+	}
+
+	if (mdb_ctf_lookup_by_name(src, &id) != 0)  {
+		mdb_printf("%s does not exist\n", src);
+		return (DCMD_ERR);
+	}
+
+	if (mdb_ctf_add_typedef(dst, &id, NULL) != 0) {
+		mdb_printf("failed to create typedef\n");
+		return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
+
+static char typedef_desc[] =
+"::typedef operates like the C typedef keyword and creates a synthetic type\n"
+"that is usable across mdb just like a type that is embedded in CTF data.\n"
+"This includes familiar dcmds like ::print as well as mdb's tab completion\n"
+"engine. The \"type\" argument can either be a named structure or union\n"
+"declaration, like \"struct proc { int p_id; }\" declartion, an anonymous\n"
+"structure or union declaration, like \"struct { int count; }\", or simply\n"
+"the name of an existing type, like \"uint64_t\". Either form may refer to\n"
+"other types already defined in CTF or a previous ::typedef invocation. When\n"
+"debugging binaries without CTF, definitions for intrinsic types may be\n"
+"created using the -c option. See the OPTIONS section for more information.\n"
+"If a named struct or union is used, then a type will be created for it just\n"
+"like in C. This may be used to mimic a forward declaration and an example of\n"
+"this is in the EXAMPLES section. Regardless of whether a struct or union is\n"
+"anonymous or named, the \"name\" argument is always required.\n"
+"\n"
+"When declaring anonymous structures and unions, the entire definition must\n"
+"be enclosed within \"\" or ''. The ';' is used by mdb to separate commands\n"
+"in a similar fashion to the shell. The ';' cannot be escaped, therefore\n"
+"quoting your argument is necessary. See the EXAMPLES sections for examples\n"
+"of what this looks like.\n"
+"\n"
+"All member and type names must be valid C identifiers. They must start with\n"
+"an underscore or a letter. Subsequent characters are allowed to be letters,\n"
+"numbers, or an underscore.\n"
+"\n"
+"Declaring arrays and any number of pointers in anonymous structures is \n"
+"supported. However the following C features are not supported: \n"
+"  o function pointers (use a void * instead)\n"
+"  o bitfields (use an integer of the appropriate size instead)\n"
+"  o packed structures (all structures currently use their natural alignment)\n"
+"\n"
+"::typedef also allows you to read type definitions from a file. Definitions\n"
+"can be read from any ELF file that has a CTF section that libctf can parse.\n"
+"You can check if a file has such a section with elfdump(1). If a binary or\n"
+"core dump does not have any type information, but you do have it elsewhere,\n"
+"then you can use ::typedef -r to read in that type information.\n"
+"\n";
+
+static char typedef_opts[] =
+"  -c model   create intrinsic types based on the specified data model.\n"
+"             The INTRINSICS section lists the built-in types and typedefs.\n"
+"             The following data models are supported:\n"
+"                 o LP64  - Traditional illumos 64-bit program\n"
+"                 o LP32  - Traditional illumos 32-bit program.\n"
+"                 o ILP32 - An alternate name for LP32.\n"
+"  -d         delete all synthetic types\n"
+"  -l         list all synthetic types\n"
+"  -r file    import type definitions (CTF) from another ELF file\n"
+"\n";
+
+static char typedef_examps[] =
+"  ::typedef -c LP64\n"
+"  ::typedef uint64_t bender_t\n"
+"  ::typedef struct proc new_proc_t\n"
+"  ::typedef \"union { int frodo; char sam; long gandalf; }\" ringbearer_t;\n"
+"  ::typedef \"struct { uintptr_t stone[7]; void **white; }\" gift_t\n"
+"  ::typedef \"struct list { struct list *l_next; struct list *l_prev; }\" "
+"list_t\n"
+"  ::typedef -r /var/tmp/qemu-system-x86_64\n"
+"\n";
+
+static char typedef_intrins[] =
+"The following C types and <stdint.h> typedefs are provided when \n"
+"::typedef -c is used\n"
+"\n"
+"       signed              unsigned              void\n"
+"       char                short                 int\n"
+"       long                long long             signed char\n"
+"       signed short        signed int            signed long\n"
+"       singed long long    unsigned char         unsigned short\n"
+"       unsigned int        unsigned long         unsigned long long\n"
+"       _Bool               float                 double\n"
+"       long double         float imaginary       double imaginary\n"
+"       long double imaginary                     float complex\n"
+"       double complex                            long double complex\n"
+"\n"
+"       int8_t              int16_t               int32_t\n"
+"       int64_t             intptr_t              uint8_t\n"
+"       uint16_t            uint32_t              uint64_t\n"
+"       uchar_t             ushort_t              uint_t\n"
+"       ulong_t             u_longlong_t          ptrdiff_t\n"
+"       uintptr_t\n"
+"\n";
+
+void
+cmd_typedef_help(void)
+{
+	mdb_printf("%s", typedef_desc);
+	(void) mdb_dec_indent(2);
+	mdb_printf("%<b>OPTIONS%</b>\n");
+	(void) mdb_inc_indent(2);
+	mdb_printf("%s", typedef_opts);
+	(void) mdb_dec_indent(2);
+	mdb_printf("%<b>EXAMPLES%</b>\n");
+	(void) mdb_inc_indent(2);
+	mdb_printf("%s", typedef_examps);
+	(void) mdb_dec_indent(2);
+	mdb_printf("%<b>INTRINSICS%</b>\n");
+	(void) mdb_inc_indent(2);
+	mdb_printf("%s", typedef_intrins);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/mdb/mdb_typedef.h	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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 (c) 2012 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef	_MDB_TYPEDEF_H
+#define	_MDB_TYPEDEF_H
+
+#include <mdb/mdb_modapi.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int cmd_typedef(uintptr_t, uint_t, int, const mdb_arg_t *);
+void cmd_typedef_help(void);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _MDB_TYPEDEF_H */
--- a/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c	Wed Apr 03 15:25:37 2013 -0700
@@ -22,8 +22,9 @@
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 /*
  * Libkvm Kernel Target Intel component
@@ -57,6 +58,14 @@
 	for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) {
 		if (strcmp(rname, rdp->rd_name) == 0) {
 			*rp = kt->k_regs->kregs[rdp->rd_num];
+			if (rdp->rd_flags & MDB_TGT_R_32)
+				*rp &= 0xffffffffULL;
+			else if (rdp->rd_flags & MDB_TGT_R_16)
+				*rp &= 0xffffULL;
+			else if (rdp->rd_flags & MDB_TGT_R_8H)
+				*rp = (*rp & 0xff00ULL) >> 8;
+			else if (rdp->rd_flags & MDB_TGT_R_8L)
+				*rp &= 0xffULL;
 			return (0);
 		}
 	}
@@ -75,6 +84,15 @@
 
 	for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) {
 		if (strcmp(rname, rdp->rd_name) == 0) {
+			if (rdp->rd_flags & MDB_TGT_R_32)
+				r &= 0xffffffffULL;
+			else if (rdp->rd_flags & MDB_TGT_R_16)
+				r &= 0xffffULL;
+			else if (rdp->rd_flags & MDB_TGT_R_8H)
+				r = (r & 0xffULL) << 8;
+			else if (rdp->rd_flags & MDB_TGT_R_8L)
+				r &= 0xffULL;
+
 			kt->k_regs->kregs[rdp->rd_num] = (kreg_t)r;
 			return (0);
 		}
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c	Wed Apr 03 15:25:37 2013 -0700
@@ -25,6 +25,7 @@
  */
 /*
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
@@ -53,20 +54,69 @@
 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
 	{ "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 },
@@ -76,7 +126,11 @@
 	{ "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 },
 	{ NULL, 0, 0 }
 };
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c	Wed Apr 03 15:25:37 2013 -0700
@@ -22,8 +22,9 @@
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/reg.h>
@@ -48,13 +49,29 @@
 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
 	{ "eax", KREG_EAX, MDB_TGT_R_EXPORT },
+	{ "ax", KREG_EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ah", KREG_EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "al", KREG_EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "ebx", KREG_EBX, MDB_TGT_R_EXPORT },
+	{ "bx", KREG_EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "bh", KREG_EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "bl", KREG_EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "ecx", KREG_ECX, MDB_TGT_R_EXPORT },
+	{ "cx", KREG_ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ch", KREG_ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "cl", KREG_ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "edx", KREG_EDX, MDB_TGT_R_EXPORT },
+	{ "dx", KREG_EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "dh", KREG_EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "dl", KREG_EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "esi", KREG_ESI, MDB_TGT_R_EXPORT },
+	{ "si", KREG_ESI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "edi", KREG_EDI, MDB_TGT_R_EXPORT },
+	{ "di",	EDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "ebp", KREG_EBP, MDB_TGT_R_EXPORT },
+	{ "bp", KREG_EBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "esp", KREG_ESP, MDB_TGT_R_EXPORT },
+	{ "sp", KREG_ESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
@@ -64,6 +81,7 @@
 	{ "eflags", KREG_EFLAGS, MDB_TGT_R_EXPORT },
 	{ "eip", KREG_EIP, MDB_TGT_R_EXPORT },
 	{ "uesp", KREG_UESP, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
+	{ "usp", KREG_UESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
 	{ NULL, 0, 0 }
--- a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c	Wed Apr 03 15:25:37 2013 -0700
@@ -23,8 +23,9 @@
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 /*
  * User Process Target Intel 32-bit component
@@ -46,26 +47,79 @@
 
 const mdb_tgt_regdesc_t pt_regdesc[] = {
 	{ "r15",	REG_R15,	MDB_TGT_R_EXPORT },
+	{ "r15d",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r15w",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r15l",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r14",	REG_R14,	MDB_TGT_R_EXPORT },
+	{ "r14d",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r14w",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r14l",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r13",	REG_R13,	MDB_TGT_R_EXPORT },
+	{ "r13d",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r13w",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r13l",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r12",	REG_R12,	MDB_TGT_R_EXPORT },
+	{ "r12d",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r12w",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r12l",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r11",	REG_R11,	MDB_TGT_R_EXPORT },
+	{ "r11d",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r11w",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r11l",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r10",	REG_R10,	MDB_TGT_R_EXPORT },
+	{ "r10d",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r10w",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r10l",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r9",		REG_R9,		MDB_TGT_R_EXPORT },
+	{ "r9d",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r9w",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r9l",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "r8",		REG_R8,		MDB_TGT_R_EXPORT },
+	{ "r8d",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "r8w",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "r8l",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rdi",	REG_RDI,	MDB_TGT_R_EXPORT },
+	{ "edi",	REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "di",		REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "dil",	REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rsi",	REG_RSI,	MDB_TGT_R_EXPORT },
+	{ "esi",	REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "si",		REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "sil",	REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rbp",	REG_RBP,	MDB_TGT_R_EXPORT },
+	{ "ebp",	REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "bp",		REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "bpl",	REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rbx",	REG_RBX,	MDB_TGT_R_EXPORT },
+	{ "ebx",	REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "bx",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "bh",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "bl",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rdx",	REG_RDX,	MDB_TGT_R_EXPORT },
+	{ "edx",	REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "dx",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "dh",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "dl",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rcx",	REG_RCX,	MDB_TGT_R_EXPORT },
+	{ "ecx",	REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "cx",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ch",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "cl",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "rax",	REG_RAX,	MDB_TGT_R_EXPORT },
+	{ "eax",	REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "ax",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ah",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "al",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "trapno",	REG_TRAPNO,	MDB_TGT_R_EXPORT },
 	{ "err",	REG_ERR,	MDB_TGT_R_EXPORT },
 	{ "rip",	REG_RIP,	MDB_TGT_R_EXPORT },
 	{ "cs",		REG_CS,		MDB_TGT_R_EXPORT },
 	{ "rflags",	REG_RFL,	MDB_TGT_R_EXPORT },
+	{ "eflags",	REG_RFL,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
 	{ "rsp",	REG_RSP,	MDB_TGT_R_EXPORT },
+	{ "esp",	REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
+	{ "sp",		REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "spl",	REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "ss",		REG_SS,		MDB_TGT_R_EXPORT },
 	{ "fs",		REG_FS,		MDB_TGT_R_EXPORT },
 	{ "gs",		REG_GS,		MDB_TGT_R_EXPORT },
--- a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c	Wed Apr 03 15:25:37 2013 -0700
@@ -23,8 +23,9 @@
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 /*
  * User Process Target Intel 32-bit component
@@ -50,19 +51,36 @@
 	{ "es", ES, MDB_TGT_R_EXPORT },
 	{ "ds", DS, MDB_TGT_R_EXPORT },
 	{ "edi", EDI, MDB_TGT_R_EXPORT },
+	{ "di",	EDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "esi", ESI, MDB_TGT_R_EXPORT },
+	{ "si", ESI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "ebp", EBP, MDB_TGT_R_EXPORT },
+	{ "bp", EBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "kesp", ESP, MDB_TGT_R_EXPORT },
+	{ "ksp", ESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "ebx", EBX, MDB_TGT_R_EXPORT },
+	{ "bx", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "bh", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "bl", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "edx", EDX, MDB_TGT_R_EXPORT },
+	{ "dx", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "dh", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "dl", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "ecx", ECX, MDB_TGT_R_EXPORT },
+	{ "cx", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ch", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "cl", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "eax", EAX, MDB_TGT_R_EXPORT },
+	{ "ax", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
+	{ "ah", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
+	{ "al", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
 	{ "trapno", TRAPNO, MDB_TGT_R_EXPORT },
 	{ "err", ERR, MDB_TGT_R_EXPORT },
 	{ "eip", EIP, MDB_TGT_R_EXPORT },
 	{ "cs", CS, MDB_TGT_R_EXPORT },
 	{ "eflags", EFL, MDB_TGT_R_EXPORT },
 	{ "esp", UESP, MDB_TGT_R_EXPORT },
+	{ "sp", UESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
 	{ "ss", SS, MDB_TGT_R_EXPORT },
 	{ NULL, 0, 0 }
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/README	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,18 @@
+MDB Test suite
+
+This provides a primordial version of a test suite for mdb. To run the tests,
+run mtest. Tests exist in various subdirectories. The name of the test is
+important.
+
+A test must start with either:
+
+ o tst - Indicating that it should exit zero
+ o err - Indicating that it should exit non-zero
+
+A test must end with either:
+
+ o mdb - Indicating that the file should be passed as standard input to mdb
+ o ksh - Indicating that it should be run with ksh
+
+A test may have an optional .out file which if present indicates that the test
+should pass if and only if its standard ouput matches its standar error.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,2 @@
+$MDB -e '::typegraph'
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,2 @@
+$MDB -e '::commandthatdoesnotexist'
+exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '0t2 << 0t10=K'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+                800             
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/exit-e/tst.simple.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::dcmds'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/mtest.sh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,235 @@
+#!/bin/bash
+#
+# 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 2012 (c), Joyent, Inc.
+#
+
+#
+# mdb test driver
+#
+unalias -a
+shopt -s xpg_echo
+#set -o xtrace
+
+mt_arg0=$(basename $0)
+mt_ksh="/usr/bin/ksh"
+mt_mdb="/usr/bin/mdb"
+mt_outdir=
+mt_keep=
+mt_all=
+mt_tests=
+mt_tnum=0
+mt_tfail=0
+mt_tsuc=0
+
+function usage
+{
+	local msg="$*"
+	[[ -z "$msg" ]] || echo "$msg" 2>&1
+	cat <<USAGE >&2
+Usage: $mt_arg0  [ -o dir ] [ -k ] [ -m executable ] [ -a | test ... ]
+
+	-o dir		Sets 'dir' as the output directory
+	-a		Runs all tests, ignores tests passed in
+	-k		Keep output from all tests, not just failures
+	-m 		mdb binary to test
+USAGE
+	exit 2
+}
+
+function fatal
+{
+	local msg="$*"
+	[[ -z "$msg" ]] && msg="failed"
+	echo "$mt_arg0: $msg" >&2
+	exit 1
+}
+
+function setup_outdir
+{
+	mt_outdir="$mt_outdir/$mt_arg0.$$"
+	mkdir -p $mt_outdir || fatal "failed to make output dir $mt_outdir"
+}
+
+function run_single
+{
+	local name=$1
+	local expect base ext exe command odir res reason input
+
+	[[ -z "$name" ]] && fail "missing test to run"
+	base=${name##*/}
+	ext=${base##*.}
+	expect=${base%%.*}
+	odir="$mt_outdir/current"
+	[[ -z "$ext" ]] && fatal "found test without ext: $name"
+	[[ -z "$expect" ]] && fatal "found test without prefix: $name"
+
+	case "$ext" in
+	"ksh")
+		command="$mt_ksh $name"
+		;;
+	"mdb")
+		command="$mt_mdb"
+		input="$name"
+		;;
+	"out")
+		#
+		# This is the file format for checking output against.
+		#
+		return 0
+		;;
+	*)
+		echo "skipping test $name (unknown extensino)"
+		return 0
+		;;
+	esac
+
+	echo "Executing test $name ... \c"
+	mkdir -p "$odir" >/dev/null || fatal "can't make output directory"
+	if [[ -z "$input" ]]; then
+		MDB=$mt_mdb $command > "$odir/stdout" 2>"$odir/stderr"
+		res=$?
+	else
+		MDB=$mt_mdb $command < $input > "$odir/stdout" 2>"$odir/stderr"
+		res=$?
+	fi
+
+	if [[ -f "$name.out" ]] && ! diff "$name.out" "$odir/stdout" >/dev/null; then
+		cp $name.out $odir/$base.out
+		reason="stdout mismatch"
+	elif [[ "$expect" == "tst" && $res -ne 0 ]]; then
+		reason="test exited $res, not zero"
+	elif [[ "$expect" == "err" && $res -eq 0 ]]; then
+		reason="test exited $res, not non-zero"
+	fi
+
+	if [[ -n "$reason" ]]; then
+		echo "$reason"
+		((mt_tfail++))
+		mv "$odir" "$mt_outdir/failure.$mt_tfail" || fatal \
+		    "failed to move test output directory"
+		cp "$name" "$mt_outdir/failure.$mt_tfail/test" || fatal \
+		    "failed to copy test into output directory"
+	else
+		echo "passed"
+		((mt_tsuc++))
+		mv "$odir" "$mt_outdir/success.$mt_tsuc" || fatal \
+		    "failed to move test directory"	
+	fi
+
+	((mt_tnum++))
+}
+
+function run_all
+{
+	local tests t
+	
+	tests=$(find . -type f -name '[tst,err]*.*.[ksh,mdb]*')
+	for t in $tests; do
+		run_single $t
+	done
+}
+
+function welcome
+{
+	cat <<WELCOME
+Starting tests...
+mtest target: $mt_mdb
+output directory: $mt_outdir
+WELCOME
+}
+
+function cleanup
+{
+	[[ -n "$mt_keep" ]] && return
+	rm -rf "$mt_outdir"/success.* || fatal \
+	     "failed to remove successful test cases"
+	if [[ $mt_tfail -eq 0 ]]; then
+		rmdir "$mt_outdir" || fatal \
+		    "failed to remove test output directory"
+	fi
+}
+
+function goodbye
+{
+	cat <<EOF
+
+-------------
+Results
+-------------
+
+Tests passed: $mt_tsuc
+Tests failed: $mt_tfail
+Tests ran:    $mt_tnum
+
+EOF
+	if [[ $mt_tfail  -eq 0 ]]; then
+		echo "Congrats, mdb isn't completely broken, the tests pass".
+	else
+		echo "Some tests failed, you have some work to do."
+	fi
+}
+
+while getopts ":ahko:m:" c $@; do
+	case "$c" in
+	a)
+		mt_all="y"
+		;;
+	k)
+		mt_keep="y"
+		;;
+	m)
+		mt_mdb="$OPTARG"
+		;;
+	o)
+		mt_outdir="$OPTARG"
+		;;
+	h)
+		usage
+		;;
+	:)
+		usage "option requires an argument -- $OPTARG"
+		;;
+	*)
+		usage "invalid option -- $OPTARG"
+		;;
+	esac
+done
+
+shift $((OPTIND-1))
+
+[[ -z "$mt_all" && $# == 0 ]] && usage "no tests to run"
+
+[[ -x "$mt_mdb" ]] || fatal "unable to execute mdb binary: $mt_mdb"
+
+[[ -z "$mt_outdir" ]] && mt_outdir=/var/tmp
+
+setup_outdir
+welcome
+
+if [[ ! -z "$mt_all" ]]; then
+	run_all
+else
+	for t in $@; do
+		[[ -f $t ]] || fatal "cannot find test $t"
+		run_single $t		
+	done
+fi
+
+goodbye
+cleanup
+
+#
+# Exit 1 if we have tests that return non-zero
+#
+[[ $mt_tfai -eq 0 ]]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef lp32; ::typedef uint8_t 42foo'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef lp32; ::typedef uint8_t %foo'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badmodel.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c LLP64'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; {} void {**white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[-3]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone7]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct uintptr_t stone[7]; void **white;" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **white; " gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { void; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **white }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct  uintptr_t stone[7]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef struct { uintptr_t stone[7]; void **white; } gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **stone; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[]; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[0]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "union { int foo; uintptr_t stone[]; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.extraargs.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e "::typedef -c lp32; ::typedef uint8_t rm_t extra_t"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.noargs.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c lp32; ::typedef "{ uintptr_t stone[7]; void **white; }" gift_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.nomodel.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef -c'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.noname.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB -e '::typedef int'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/err.typeexists.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+$MDB /lib/libc.so -e '::typedef uint8_t uint16_t'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,4 @@
+::typedef -c lp32
+::typedef "struct { uintptr_t stone[7]; void **white; }" gift_t
+::sizeof gift_t
+::print -at gift_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,5 @@
+sizeof (gift_t) = 0x28
+0 gift_t {
+    0 uintptr_t [7] stone 
+    20 void **white 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,4 @@
+::typedef -c lp64
+::typedef "union { int frodo; char sam; long gandalf; }" ringbearer_t;
+::sizeof ringbearer_t
+::print -at ringbearer_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,6 @@
+sizeof (ringbearer_t) = 8
+0 ringbearer_t {
+    0 int frodo 
+    0 char sam 
+    0 long gandalf 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,22 @@
+#
+# One of the problems that we can encounter involves trying to typedef a struct
+# that has an error in it. The problem here is that we actually create the type
+# itself for the struct before we add members. So what we need is something that
+# will fail validation. So here we go!
+#
+
+TMPFILE="/tmp/$(mktemp mtest.XXXXXX)"
+if [[ -z "$TMPFILE" ]]; then
+	echo "Failed to get a temp file" 2>&1
+	exit 1
+fi
+
+$MDB <<EOF
+::typedef "struct foo { int r; }" foo_t
+::typedef -l ! cat > $TMPFILE
+EOF
+
+DATA=$(cat $TMPFILE)
+rm -f $TMPFILE
+
+[[ -z $DATA ]]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,27 @@
+::typedef -c LP32
+::sizeof int8_t
+::sizeof int16_t
+::sizeof int32_t
+::sizeof int64_t
+::sizeof uint8_t
+::sizeof uint16_t
+::sizeof uint32_t
+::sizeof uint64_t
+::sizeof intptr_t
+::sizeof uintptr_t
+::sizeof uchar_t
+::sizeof ushort_t
+::sizeof uint_t
+::sizeof ulong_t
+::sizeof u_longlong_t
+::sizeof ptrdiff_t
+::sizeof signed
+::sizeof unsigned
+::sizeof void
+::sizeof char
+::sizeof short
+::sizeof int
+::sizeof long
+::sizeof _Bool
+::sizeof float
+::sizeof double
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,26 @@
+sizeof (int8_t) = 1
+sizeof (int16_t) = 2
+sizeof (int32_t) = 4
+sizeof (int64_t) = 8
+sizeof (uint8_t) = 1
+sizeof (uint16_t) = 2
+sizeof (uint32_t) = 4
+sizeof (uint64_t) = 8
+sizeof (intptr_t) = 4
+sizeof (uintptr_t) = 4
+sizeof (uchar_t) = 1
+sizeof (ushort_t) = 2
+sizeof (uint_t) = 4
+sizeof (ulong_t) = 4
+sizeof (u_longlong_t) = 8
+sizeof (ptrdiff_t) = 4
+sizeof (signed) = 4
+sizeof (unsigned) = 4
+sizeof (void) = 0
+sizeof (char) = 1
+sizeof (short) = 2
+sizeof (int) = 4
+sizeof (long) = 4
+sizeof (_Bool) = 1
+sizeof (float) = 4
+sizeof (double) = 8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,27 @@
+::typedef -c LP64
+::sizeof int8_t
+::sizeof int16_t
+::sizeof int32_t
+::sizeof int64_t
+::sizeof uint8_t
+::sizeof uint16_t
+::sizeof uint32_t
+::sizeof uint64_t
+::sizeof intptr_t
+::sizeof uintptr_t
+::sizeof uchar_t
+::sizeof ushort_t
+::sizeof uint_t
+::sizeof ulong_t
+::sizeof u_longlong_t
+::sizeof ptrdiff_t
+::sizeof signed
+::sizeof unsigned
+::sizeof void
+::sizeof char
+::sizeof short
+::sizeof int
+::sizeof long
+::sizeof _Bool
+::sizeof float
+::sizeof double
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,26 @@
+sizeof (int8_t) = 1
+sizeof (int16_t) = 2
+sizeof (int32_t) = 4
+sizeof (int64_t) = 8
+sizeof (uint8_t) = 1
+sizeof (uint16_t) = 2
+sizeof (uint32_t) = 4
+sizeof (uint64_t) = 8
+sizeof (intptr_t) = 8
+sizeof (uintptr_t) = 8
+sizeof (uchar_t) = 1
+sizeof (ushort_t) = 2
+sizeof (uint_t) = 4
+sizeof (ulong_t) = 8
+sizeof (u_longlong_t) = 8
+sizeof (ptrdiff_t) = 8
+sizeof (signed) = 4
+sizeof (unsigned) = 4
+sizeof (void) = 0
+sizeof (char) = 1
+sizeof (short) = 2
+sizeof (int) = 4
+sizeof (long) = 8
+sizeof (_Bool) = 1
+sizeof (float) = 4
+sizeof (double) = 8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.dellist.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,3 @@
+::typdef -c lp32
+::typedef -d
+::typedef -l
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,1 @@
+::typedef -l
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,6 @@
+$MDB /lib/libc.so <<EOF
+::typedef uint8_t rm_t
+::typedef -l
+::print -at rm_t
+::sizeof rm_t
+EOF
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,4 @@
+uint8_t
+rm_t
+0 rm_t 
+sizeof (rm_t) = 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.models.ksh	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,11 @@
+lp64m="lp64 Lp64 LP64 lP64"
+lp32m="lp32 Lp32 LP32 lP32"
+ilp32m="ilp32 ilP32 iLp32 iLP32 Ilp32 IlP32 ILp32 ILP32"
+for m in $lp64m $lp32m $ilp32m; do
+	$MDB -e "::typedef -c $m"
+	if [[ ! $? -eq 0 ]]; then
+		echo "failed to create model $m" 2>&1
+		exit 1
+	fi
+done
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,6 @@
+::typedef -c lp32
+::typedef "struct gift { uintptr_t stone[7]; void **white; }" gift_t
+::sizeof gift_t
+::print -at gift_t
+::sizeof struct gift
+::print -at struct gift
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,10 @@
+sizeof (gift_t) = 0x28
+0 gift_t {
+    0 uintptr_t [7] stone 
+    20 void **white 
+}
+sizeof (struct gift) = 0x28
+0 struct gift {
+    0 uintptr_t [7] stone 
+    20 void **white 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,4 @@
+::typedef -c lp32
+::typedef "struct list { struct list *prev; struct list *next; }" list_t
+::sizeof list_t
+::print -at list_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,5 @@
+sizeof (list_t) = 0x10
+0 list_t {
+    0 struct list *prev 
+    8 struct list *next 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,4 @@
+::typedef -c lp32
+::typedef "struct gift { uintptr_t stone[7]; void **white; char owner[]; }" gift_t
+::sizeof gift_t
+::print -at gift_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,6 @@
+sizeof (gift_t) = 0x28
+0 gift_t {
+    0 uintptr_t [7] stone 
+    20 void **white 
+    28 char [0] owner 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.union.mdb	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,6 @@
+::typedef -c lp64
+::typedef "union ringbearer { int frodo; char sam; long gandalf; }" ringbearer_t;
+::sizeof ringbearer_t
+::print -at ringbearer_t
+::sizeof union ringbearer
+::print -at union ringbearer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/test/typedef/tst.union.mdb.out	Wed Apr 03 15:25:37 2013 -0700
@@ -0,0 +1,12 @@
+sizeof (ringbearer_t) = 8
+0 ringbearer_t {
+    0 int frodo 
+    0 char sam 
+    0 long gandalf 
+}
+sizeof (union ringbearer) = 8
+0 union ringbearer {
+    0 int frodo 
+    0 char sam 
+    0 long gandalf 
+}
--- a/usr/src/common/ctf/ctf_create.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/common/ctf/ctf_create.c	Wed Apr 03 15:25:37 2013 -0700
@@ -24,13 +24,15 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #include <sys/sysmacros.h>
 #include <sys/param.h>
 #include <sys/mman.h>
 #include <ctf_impl.h>
+#include <sys/debug.h>
 
 /*
  * This static string is used as the template for initially populating a
@@ -167,6 +169,51 @@
 }
 
 /*
+ * Only types of dyanmic CTF containers contain reference counts. These
+ * containers are marked RD/WR. Because of that we basically make this a no-op
+ * for compatability with non-dynamic CTF sections. This is also a no-op for
+ * types which are not dynamic types. It is the responsibility of the caller to
+ * make sure it is a valid type. We help that caller out on debug builds.
+ *
+ * Note that the reference counts are not maintained for types that are not
+ * within this container. In other words if we have a type in a parent, that
+ * will not have its reference count increased. On the flip side, the parent
+ * will not be allowed to remove dynamic types if it has children.
+ */
+static void
+ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid)
+{
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+	if (dtd == NULL)
+		return;
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return;
+
+	dtd->dtd_ref++;
+}
+
+/*
+ * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the
+ * caller should ensure that this is already a valid type.
+ */
+static void
+ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid)
+{
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+	if (dtd == NULL)
+		return;
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return;
+
+	ASSERT(dtd->dtd_ref >= 1);
+	dtd->dtd_ref--;
+}
+
+/*
  * If the specified CTF container is writable and has been modified, reload
  * this container with the updated type definitions.  In order to make this
  * code and the rest of libctf as simple as possible, we perform updates by
@@ -180,6 +227,10 @@
  * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp
  * constant for the caller, so after ctf_bufopen() returns, we use bcopy to
  * swap the interior of the old and new ctf_file_t's, and then free the old.
+ *
+ * Note that the lists of dynamic types stays around and the resulting container
+ * is still writeable. Furthermore, the reference counts that are on the dtd's
+ * are still valid.
  */
 int
 ctf_update(ctf_file_t *fp)
@@ -432,6 +483,7 @@
 	ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
 	ctf_dmdef_t *dmd, *nmd;
 	size_t len;
+	int kind, i;
 
 	for (p = *q; p != NULL; p = p->dtd_hash) {
 		if (p != dtd)
@@ -443,7 +495,8 @@
 	if (p != NULL)
 		*q = p->dtd_hash;
 
-	switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) {
+	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+	switch (kind) {
 	case CTF_K_STRUCT:
 	case CTF_K_UNION:
 	case CTF_K_ENUM:
@@ -454,14 +507,33 @@
 				ctf_free(dmd->dmd_name, len);
 				fp->ctf_dtstrlen -= len;
 			}
+			if (kind != CTF_K_ENUM)
+				ctf_ref_dec(fp, dmd->dmd_type);
 			nmd = ctf_list_next(dmd);
 			ctf_free(dmd, sizeof (ctf_dmdef_t));
 		}
 		break;
 	case CTF_K_FUNCTION:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++)
+			if (dtd->dtd_u.dtu_argv[i] != 0)
+				ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]);
 		ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
 		    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
 		break;
+	case CTF_K_ARRAY:
+		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
+		break;
+	case CTF_K_TYPEDEF:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		break;
+	case CTF_K_POINTER:
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		break;
 	}
 
 	if (dtd->dtd_name) {
@@ -495,7 +567,9 @@
  * Discard all of the dynamic type definitions that have been added to the
  * container since the last call to ctf_update().  We locate such types by
  * scanning the list and deleting elements that have type IDs greater than
- * ctf_dtoldid, which is set by ctf_update(), above.
+ * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly
+ * with our reference counting schemes, we must delete the dynamic list in
+ * reverse.
  */
 int
 ctf_discard(ctf_file_t *fp)
@@ -508,11 +582,11 @@
 	if (!(fp->ctf_flags & LCTF_DIRTY))
 		return (0); /* no update required */
 
-	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
 		if (dtd->dtd_type <= fp->ctf_dtoldid)
 			continue; /* skip types that have been committed */
 
-		ntd = ctf_list_next(dtd);
+		ntd = ctf_list_prev(dtd);
 		ctf_dtd_delete(fp, dtd);
 	}
 
@@ -614,6 +688,8 @@
 	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
 		return (CTF_ERR); /* errno is set for us */
 
+	ctf_ref_inc(fp, ref);
+
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
 	dtd->dtd_data.ctt_type = (ushort_t)ref;
 
@@ -645,16 +721,29 @@
 {
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
+	ctf_file_t *fpd;
 
 	if (arp == NULL)
 		return (ctf_set_errno(fp, EINVAL));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
 	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
 		return (CTF_ERR); /* errno is set for us */
 
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0);
 	dtd->dtd_data.ctt_size = 0;
 	dtd->dtd_u.dtu_arr = *arp;
+	ctf_ref_inc(fp, arp->ctr_contents);
+	ctf_ref_inc(fp, arp->ctr_index);
 
 	return (type);
 }
@@ -662,6 +751,7 @@
 int
 ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
 {
+	ctf_file_t *fpd;
 	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
 
 	if (!(fp->ctf_flags & LCTF_RDWR))
@@ -670,8 +760,22 @@
 	if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
 		return (ctf_set_errno(fp, ECTF_BADID));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
 	fp->ctf_flags |= LCTF_DIRTY;
 	dtd->dtd_u.dtu_arr = *arp;
+	ctf_ref_inc(fp, arp->ctr_contents);
+	ctf_ref_inc(fp, arp->ctr_index);
 
 	return (0);
 }
@@ -683,7 +787,9 @@
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
 	uint_t vlen;
+	int i;
 	ctf_id_t *vdat = NULL;
+	ctf_file_t *fpd;
 
 	if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 ||
 	    (ctc->ctc_argc != 0 && argv == NULL))
@@ -696,6 +802,18 @@
 	if (vlen > CTF_MAX_VLEN)
 		return (ctf_set_errno(fp, EOVERFLOW));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL &&
+	    ctf_dtd_lookup(fp, ctc->ctc_return) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	for (i = 0; i < ctc->ctc_argc; i++) {
+		fpd = fp;
+		if (ctf_lookup_by_id(&fpd, argv[i]) == NULL &&
+		    ctf_dtd_lookup(fp, argv[i]) == NULL)
+			return (ctf_set_errno(fp, ECTF_BADID));
+	}
+
 	if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL)
 		return (ctf_set_errno(fp, EAGAIN));
 
@@ -707,6 +825,10 @@
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen);
 	dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return;
 
+	ctf_ref_inc(fp, ctc->ctc_return);
+	for (i = 0; i < ctc->ctc_argc; i++)
+		ctf_ref_inc(fp, argv[i]);
+
 	bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc);
 	if (ctc->ctc_flags & CTF_FUNC_VARARG)
 		vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */
@@ -825,8 +947,11 @@
 {
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
+	ctf_file_t *fpd;
 
-	if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+	fpd = fp;
+	if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL &&
+	    ctf_dtd_lookup(fp, ref) == NULL))
 		return (ctf_set_errno(fp, EINVAL));
 
 	if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
@@ -834,6 +959,7 @@
 
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0);
 	dtd->dtd_data.ctt_type = (ushort_t)ref;
+	ctf_ref_inc(fp, ref);
 
 	return (type);
 }
@@ -1008,6 +1134,45 @@
 	if (s != NULL)
 		fp->ctf_dtstrlen += strlen(s) + 1;
 
+	ctf_ref_inc(fp, type);
+	fp->ctf_flags |= LCTF_DIRTY;
+	return (0);
+}
+
+/*
+ * This removes a type from the dynamic section. This will fail if the type is
+ * referenced by another type. Note that the CTF ID is never reused currently by
+ * CTF. Note that if this container is a parent container then we just outright
+ * refuse to remove the type. There currently is no notion of searching for the
+ * ctf_dtdef_t in parent containers. If there is, then this constraint could
+ * become finer grained.
+ */
+int
+ctf_delete_type(ctf_file_t *fp, ctf_id_t type)
+{
+	ctf_file_t *fpd;
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return (ctf_set_errno(fp, ECTF_RDONLY));
+
+	/*
+	 * We want to give as useful an errno as possible. That means that we
+	 * want to distinguish between a type which does not exist and one for
+	 * which the type is not dynamic.
+	 */
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, type) == NULL &&
+	    ctf_dtd_lookup(fp, type) == NULL)
+		return (CTF_ERR); /* errno is set for us */
+
+	if (dtd == NULL)
+		return (ctf_set_errno(fp, ECTF_NOTDYN));
+
+	if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1)
+		return (ctf_set_errno(fp, ECTF_REFERENCED));
+
+	ctf_dtd_delete(fp, dtd);
 	fp->ctf_flags |= LCTF_DIRTY;
 	return (0);
 }
@@ -1103,6 +1268,9 @@
 	ctf_hash_t *hp;
 	ctf_helem_t *hep;
 
+	if (dst_fp == src_fp)
+		return (src_type);
+
 	if (!(dst_fp->ctf_flags & LCTF_RDWR))
 		return (ctf_set_errno(dst_fp, ECTF_RDONLY));
 
@@ -1313,6 +1481,14 @@
 
 		if (errs)
 			return (CTF_ERR); /* errno is set for us */
+
+		/*
+		 * Now that we know that we can't fail, we go through and bump
+		 * all the reference counts on the member types.
+		 */
+		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+		    dmd != NULL; dmd = ctf_list_next(dmd))
+			ctf_ref_inc(dst_fp, dmd->dmd_type);
 		break;
 	}
 
--- a/usr/src/common/ctf/ctf_error.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/common/ctf/ctf_error.c	Wed Apr 03 15:25:37 2013 -0700
@@ -23,8 +23,9 @@
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.
+ */
 
 #include <ctf_impl.h>
 
@@ -73,6 +74,8 @@
 	"Limit on number of dynamic types reached",	 /* ECTF_FULL */
 	"Duplicate member name definition",		 /* ECTF_DUPMEMBER */
 	"Conflicting type is already defined",		 /* ECTF_CONFLICT */
+	"Type has outstanding references",		 /* ECTF_REFERENCED */
+	"Type is not a dynamic type"			 /* ECTF_NOTDYN */
 };
 
 static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);
--- a/usr/src/common/ctf/ctf_impl.h	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/common/ctf/ctf_impl.h	Wed Apr 03 15:25:37 2013 -0700
@@ -24,12 +24,13 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef	_CTF_IMPL_H
 #define	_CTF_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/sysmacros.h>
@@ -149,6 +150,7 @@
 	char *dtd_name;		/* name associated with definition (if any) */
 	ctf_id_t dtd_type;	/* type identifier for this definition */
 	ctf_type_t dtd_data;	/* type node (see <sys/ctf.h>) */
+	int dtd_ref;		/* recfount for dyanmic types */
 	union {
 		ctf_list_t dtu_members;	/* struct, union, or enum */
 		ctf_arinfo_t dtu_arr;	/* array */
@@ -269,7 +271,9 @@
 	ECTF_DTFULL,		/* CTF type is full (no more members allowed) */
 	ECTF_FULL,		/* CTF container is full */
 	ECTF_DUPMEMBER,		/* duplicate member name definition */
-	ECTF_CONFLICT		/* conflicting type definition present */
+	ECTF_CONFLICT,		/* conflicting type definition present */
+	ECTF_REFERENCED,	/* type has outstanding references */
+	ECTF_NOTDYN		/* type is not a dynamic type */
 };
 
 extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *,
--- a/usr/src/common/ctf/ctf_open.c	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/common/ctf/ctf_open.c	Wed Apr 03 15:25:37 2013 -0700
@@ -24,8 +24,9 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 #include <ctf_impl.h>
 #include <sys/mman.h>
@@ -810,8 +811,12 @@
 	if (fp->ctf_parent != NULL)
 		ctf_close(fp->ctf_parent);
 
-	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
-		ntd = ctf_list_next(dtd);
+	/*
+	 * Note, to work properly with reference counting on the dynamic
+	 * section, we must delete the list in reverse.
+	 */
+	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+		ntd = ctf_list_prev(dtd);
 		ctf_dtd_delete(fp, dtd);
 	}
 
--- a/usr/src/lib/libctf/common/mapfile-vers	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/lib/libctf/common/mapfile-vers	Wed Apr 03 15:25:37 2013 -0700
@@ -60,6 +60,7 @@
 	ctf_add_union;
 	ctf_add_volatile;
 	ctf_create;
+	ctf_delete_type;
 	ctf_discard;
 	ctf_enum_value;
 	ctf_label_info;
--- a/usr/src/man/man1/mdb.1	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/man/man1/mdb.1	Wed Apr 03 15:25:37 2013 -0700
@@ -1,9 +1,10 @@
 '\" te
 .\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2012, Joyent, Inc. All Rights Reserved.
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH MDB 1 "Nov 30, 2005"
+.TH MDB 1 "Oct 05, 2012"
 .SH NAME
 mdb \- modular debugger
 .SH SYNOPSIS
@@ -11,7 +12,7 @@
 .nf
 \fBmdb\fR [\fB-fkmuwyAFKMSUW\fR] [\(+-o \fIoption\fR] [\fB-p\fR \fIpid\fR] [\fB-s\fR \fIdistance\fR]
      [\fB-I\fR \fIpath\fR] [\fB-L\fR \fIpath\fR] [\fB-P\fR \fIprompt\fR] [\fB-R\fR \fIroot\fR]
-     [\fB-V\fR \fIdis-version\fR] [object [core] | core | suffix]
+     [\fB-V\fR \fIdis-version\fR] [\fB-e\fR \fIexpr\fR] [object [core] | core | suffix]
 .fi
 
 .SH DESCRIPTION
@@ -3716,6 +3717,18 @@
 .sp
 .ne 2
 .na
+\fB\fB-e\fR \fIexpr\fR\fR
+.ad
+.RS 15n
+Causes \fBmdb\fR to ignore standard input and instead evaluate the \fBmdb\fR
+expression \fIexpr\fR. Upon completing evaluation, \fBmdb\fR terminates and
+returns a status code. A non-zero return code from \fBmdb\fR indicates that
+either \fBmdb\fR or the evaluation of \fIexpr\fR failed.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fB-f\fR\fR
 .ad
 .RS 15n
--- a/usr/src/tools/findunref/exception_list.open	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/tools/findunref/exception_list.open	Wed Apr 03 15:25:37 2013 -0700
@@ -264,3 +264,4 @@
 # ld tests which are not currently delivered
 #
 ./usr/src/cmd/sgs/test
+./usr/src/cmd/mdb/test
--- a/usr/src/uts/common/sys/ctf_api.h	Wed Jul 17 17:05:07 2013 -0700
+++ b/usr/src/uts/common/sys/ctf_api.h	Wed Apr 03 15:25:37 2013 -0700
@@ -23,6 +23,9 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 /*
  * This header file defines the interfaces available from the CTF debugger
@@ -40,8 +43,6 @@
 #ifndef	_CTF_API_H
 #define	_CTF_API_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/elf.h>
@@ -223,6 +224,8 @@
 
 extern int ctf_set_array(ctf_file_t *, ctf_id_t, const ctf_arinfo_t *);
 
+extern int ctf_delete_type(ctf_file_t *, ctf_id_t);
+
 extern int ctf_update(ctf_file_t *);
 extern int ctf_discard(ctf_file_t *);
 extern int ctf_write(ctf_file_t *, int);