summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/mdb/Makefile.kmdb.files1
-rw-r--r--usr/src/cmd/mdb/Makefile.libstandctf2
-rw-r--r--usr/src/cmd/mdb/Makefile.mdb1
-rw-r--r--usr/src/cmd/mdb/common/libstandctf/mapfile7
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb.c17
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb.h3
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c5
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.c590
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.h27
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_main.c23
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_proc.c18
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_tab.c2
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_target_impl.h9
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_typedef.c773
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_typedef.h32
-rw-r--r--usr/src/cmd/mdb/intel/mdb/kvm_isadep.c22
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c54
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c22
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c58
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c22
-rw-r--r--usr/src/cmd/mdb/test/README18
-rw-r--r--usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh2
-rw-r--r--usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh2
-rw-r--r--usr/src/cmd/mdb/test/exit-e/tst.output.ksh1
-rw-r--r--usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out1
-rw-r--r--usr/src/cmd/mdb/test/exit-e/tst.simple.ksh1
-rw-r--r--usr/src/cmd/mdb/test/mtest.sh235
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badmodel.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.extraargs.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.noargs.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.nomodel.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.noname.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/err.typeexists.ksh1
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb4
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out5
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb4
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out6
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh22
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb27
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out26
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb27
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out26
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.dellist.mdb3
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb1
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.libctype.ksh6
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out4
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.models.ksh11
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.struct.mdb6
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out10
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb4
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out5
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.structvla.mdb4
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out6
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.union.mdb6
-rw-r--r--usr/src/cmd/mdb/test/typedef/tst.union.mdb.out12
74 files changed, 2179 insertions, 19 deletions
diff --git a/usr/src/cmd/mdb/Makefile.kmdb.files b/usr/src/cmd/mdb/Makefile.kmdb.files
index 3c5983de21..a82206d42c 100644
--- a/usr/src/cmd/mdb/Makefile.kmdb.files
+++ b/usr/src/cmd/mdb/Makefile.kmdb.files
@@ -84,6 +84,7 @@ KMDBSRCS += \
mdb_target.c \
kmdb_terminfo.c \
mdb_termio.c \
+ mdb_typedef.c \
mdb_umem.c \
kmdb_umemglue.c \
mdb_value.c \
diff --git a/usr/src/cmd/mdb/Makefile.libstandctf b/usr/src/cmd/mdb/Makefile.libstandctf
index 7d4c8fbf0d..b5dce2d926 100644
--- a/usr/src/cmd/mdb/Makefile.libstandctf
+++ b/usr/src/cmd/mdb/Makefile.libstandctf
@@ -43,7 +43,7 @@ MAPFILE = ../../../common/libstandctf/mapfile
$(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.
diff --git a/usr/src/cmd/mdb/Makefile.mdb b/usr/src/cmd/mdb/Makefile.mdb
index f331a43fda..9d1d7b4d6c 100644
--- a/usr/src/cmd/mdb/Makefile.mdb
+++ b/usr/src/cmd/mdb/Makefile.mdb
@@ -85,6 +85,7 @@ SRCS += \
mdb_target.c \
mdb_tdb.c \
mdb_termio.c \
+ mdb_typedef.c \
mdb_umem.c \
mdb_value.c \
mdb_vcb.c \
diff --git a/usr/src/cmd/mdb/common/libstandctf/mapfile b/usr/src/cmd/mdb/common/libstandctf/mapfile
index e72c2ddbcf..63b2ec06ee 100644
--- a/usr/src/cmd/mdb/common/libstandctf/mapfile
+++ b/usr/src/cmd/mdb/common/libstandctf/mapfile
@@ -20,6 +20,9 @@
#
# CDDL HEADER END
#
+#
+# Copyright (c) 2012, Joyent, Inc.
+#
#
# MAPFILE HEADER START
@@ -40,15 +43,19 @@ $mapfile_version 2
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;
diff --git a/usr/src/cmd/mdb/common/mdb/mdb.c b/usr/src/cmd/mdb/common/mdb/mdb.c
index 5c74c71772..5c1c5fc84a 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb.c
@@ -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 @@ mdb_create(const char *execname, const char *arg0)
(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_destroy(void)
mdb_intr_disable();
+ mdb_ctf_synthetics_fini();
+
mdb_macalias_destroy();
/*
@@ -899,6 +908,8 @@ mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
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 @@ mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
} 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();
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb.h b/usr/src/cmd/mdb/common/mdb/mdb.h
index dc91906295..7f712ad340 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb.h
@@ -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 @@ typedef struct mdb {
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 */
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index 4a7b39fd57..add7845c68 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -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 @@ const mdb_dcmd_t mdb_dcmd_builtins[] = {
{ "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 },
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
index 3181f8290c..3b545a08ff 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
@@ -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 @@ typedef struct mbr_info {
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 @@ name_to_type(mdb_tgt_t *t, const char *cname, ctf_id_t *idp)
/*
* 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 @@ name_to_type(mdb_tgt_t *t, const char *cname, ctf_id_t *idp)
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 @@ mdb_ctf_type_iter(const char *object, mdb_ctf_type_f *cb, void *data)
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 @@ mdb_ctf_bufopen(const void *ctf_va, size_t ctf_size, const void *sym_va,
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);
+}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.h b/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
index 05b56a381a..2396145299 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
@@ -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 const char *mdb_ctf_enum_name(mdb_ctf_id_t, int);
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_open(const char *, int *); /* Internal */
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
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_main.c b/usr/src/cmd/mdb/common/mdb/mdb_main.c
index 41535f4643..90e048bb82 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_main.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c
@@ -323,10 +323,12 @@ usage(int status)
{
mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
"[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
- "[-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 @@ main(int argc, char *argv[], char *envp[])
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 @@ main(int argc, char *argv[], char *envp[])
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 @@ main(int argc, char *argv[], char *envp[])
/*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 @@ tcreate:
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);
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_proc.c b/usr/src/cmd/mdb/common/mdb/mdb_proc.c
index 1b7cdc544b..667bfe8c47 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_proc.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_proc.c
@@ -4505,6 +4505,14 @@ pt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
*/
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 @@ pt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r)
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
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_tab.c b/usr/src/cmd/mdb/common/mdb/mdb_tab.c
index b06b5db680..8b43ecdb12 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_tab.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_tab.c
@@ -579,6 +579,8 @@ mdb_tab_complete_type(mdb_tab_cookie_t *mcp, const char *name, uint_t flags)
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);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h b/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h
index ecc5331a1e..7f78bc4879 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_target_impl.h
@@ -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 @@ extern long mdb_tgt_nop(); /* Return 0 for success */
#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 */
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_typedef.c b/usr/src/cmd/mdb/common/mdb/mdb_typedef.c
new file mode 100644
index 0000000000..be6411596c
--- /dev/null
+++ b/usr/src/cmd/mdb/common/mdb/mdb_typedef.c
@@ -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);
+}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_typedef.h b/usr/src/cmd/mdb/common/mdb/mdb_typedef.h
new file mode 100644
index 0000000000..25721f8b9f
--- /dev/null
+++ b/usr/src/cmd/mdb/common/mdb/mdb_typedef.h
@@ -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 */
diff --git a/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c b/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c
index 84db05c117..db04cb7a31 100644
--- a/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c
+++ b/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c
@@ -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 @@ kt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
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 @@ kt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r)
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);
}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
index c1bb17104f..432f22210c 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
@@ -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 @@ const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
{ "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 @@ const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
{ "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 }
};
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
index addb37e19f..43db94741b 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
@@ -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 @@ const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "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 @@ const mdb_tgt_regdesc_t mdb_ia32_kregs[] = {
{ "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 }
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
index 29dd1682d1..75dd430c7d 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
@@ -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 },
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
index bca8445d86..b532dc9149 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
@@ -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 @@ const mdb_tgt_regdesc_t pt_regdesc[] = {
{ "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 }
};
diff --git a/usr/src/cmd/mdb/test/README b/usr/src/cmd/mdb/test/README
new file mode 100644
index 0000000000..28127e5916
--- /dev/null
+++ b/usr/src/cmd/mdb/test/README
@@ -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.
diff --git a/usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh b/usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh
new file mode 100644
index 0000000000..de50faeb01
--- /dev/null
+++ b/usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh
@@ -0,0 +1,2 @@
+$MDB -e '::typegraph'
+exit $?
diff --git a/usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh b/usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh
new file mode 100644
index 0000000000..038f121b26
--- /dev/null
+++ b/usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh
@@ -0,0 +1,2 @@
+$MDB -e '::commandthatdoesnotexist'
+exit $?
diff --git a/usr/src/cmd/mdb/test/exit-e/tst.output.ksh b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh
new file mode 100644
index 0000000000..13b5db072d
--- /dev/null
+++ b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh
@@ -0,0 +1 @@
+$MDB -e '0t2 << 0t10=K'
diff --git a/usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out
new file mode 100644
index 0000000000..7a38ab6e65
--- /dev/null
+++ b/usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out
@@ -0,0 +1 @@
+ 800
diff --git a/usr/src/cmd/mdb/test/exit-e/tst.simple.ksh b/usr/src/cmd/mdb/test/exit-e/tst.simple.ksh
new file mode 100644
index 0000000000..4c8a3c58ad
--- /dev/null
+++ b/usr/src/cmd/mdb/test/exit-e/tst.simple.ksh
@@ -0,0 +1 @@
+$MDB -e '::dcmds'
diff --git a/usr/src/cmd/mdb/test/mtest.sh b/usr/src/cmd/mdb/test/mtest.sh
new file mode 100644
index 0000000000..f21d0faa21
--- /dev/null
+++ b/usr/src/cmd/mdb/test/mtest.sh
@@ -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 ]]
diff --git a/usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh b/usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh
new file mode 100644
index 0000000000..f297cf99f1
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef lp32; ::typedef uint8_t 42foo'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh b/usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh
new file mode 100644
index 0000000000..5c7582b89c
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef lp32; ::typedef uint8_t %foo'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badmodel.ksh b/usr/src/cmd/mdb/test/typedef/err.badmodel.ksh
new file mode 100644
index 0000000000..28d6cf05a5
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badmodel.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c LLP64'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh
new file mode 100644
index 0000000000..3543aab1df
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; {} void {**white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh
new file mode 100644
index 0000000000..ec41576179
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[-3]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh
new file mode 100644
index 0000000000..b91094ae44
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh
new file mode 100644
index 0000000000..4fe23fcee2
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh
new file mode 100644
index 0000000000..9fe7e77200
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone7]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh
new file mode 100644
index 0000000000..d50d8e3fb9
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct uintptr_t stone[7]; void **white;" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh
new file mode 100644
index 0000000000..4b20fac8c5
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **white; " gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh
new file mode 100644
index 0000000000..9fd82a01cc
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh
new file mode 100644
index 0000000000..e1e4eacf13
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { void; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh
new file mode 100644
index 0000000000..9ab93a792f
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **white }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh
new file mode 100644
index 0000000000..450b35ade2
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct uintptr_t stone[7]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh
new file mode 100644
index 0000000000..789caf63b0
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef struct { uintptr_t stone[7]; void **white; } gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh
new file mode 100644
index 0000000000..c00aca88fb
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[7]; void **stone; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh
new file mode 100644
index 0000000000..a678d136b6
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[]; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh b/usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh
new file mode 100644
index 0000000000..7999c97a5a
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "struct { uintptr_t stone[0]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh b/usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh
new file mode 100644
index 0000000000..57a82a7752
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "union { int foo; uintptr_t stone[]; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.extraargs.ksh b/usr/src/cmd/mdb/test/typedef/err.extraargs.ksh
new file mode 100644
index 0000000000..510797265b
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.extraargs.ksh
@@ -0,0 +1 @@
+$MDB -e "::typedef -c lp32; ::typedef uint8_t rm_t extra_t"
diff --git a/usr/src/cmd/mdb/test/typedef/err.noargs.ksh b/usr/src/cmd/mdb/test/typedef/err.noargs.ksh
new file mode 100644
index 0000000000..77eeacc5f2
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.noargs.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef'
diff --git a/usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh b/usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh
new file mode 100644
index 0000000000..9a5e1a1fcc
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c lp32; ::typedef "{ uintptr_t stone[7]; void **white; }" gift_t'
diff --git a/usr/src/cmd/mdb/test/typedef/err.nomodel.ksh b/usr/src/cmd/mdb/test/typedef/err.nomodel.ksh
new file mode 100644
index 0000000000..4614ac23d6
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.nomodel.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef -c'
diff --git a/usr/src/cmd/mdb/test/typedef/err.noname.ksh b/usr/src/cmd/mdb/test/typedef/err.noname.ksh
new file mode 100644
index 0000000000..04ebca1204
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.noname.ksh
@@ -0,0 +1 @@
+$MDB -e '::typedef int'
diff --git a/usr/src/cmd/mdb/test/typedef/err.typeexists.ksh b/usr/src/cmd/mdb/test/typedef/err.typeexists.ksh
new file mode 100644
index 0000000000..a1158cd830
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/err.typeexists.ksh
@@ -0,0 +1 @@
+$MDB /lib/libc.so -e '::typedef uint8_t uint16_t'
diff --git a/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb
new file mode 100644
index 0000000000..27de9428c6
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb
@@ -0,0 +1,4 @@
+::typedef -c lp32
+::typedef "struct { uintptr_t stone[7]; void **white; }" gift_t
+::sizeof gift_t
+::print -at gift_t
diff --git a/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out
new file mode 100644
index 0000000000..605e0facfc
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out
@@ -0,0 +1,5 @@
+sizeof (gift_t) = 0x28
+0 gift_t {
+ 0 uintptr_t [7] stone
+ 20 void **white
+}
diff --git a/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb
new file mode 100644
index 0000000000..1aa17b5366
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb
@@ -0,0 +1,4 @@
+::typedef -c lp64
+::typedef "union { int frodo; char sam; long gandalf; }" ringbearer_t;
+::sizeof ringbearer_t
+::print -at ringbearer_t
diff --git a/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out
new file mode 100644
index 0000000000..0a762dc1f8
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out
@@ -0,0 +1,6 @@
+sizeof (ringbearer_t) = 8
+0 ringbearer_t {
+ 0 int frodo
+ 0 char sam
+ 0 long gandalf
+}
diff --git a/usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh b/usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh
new file mode 100644
index 0000000000..1abf7540ce
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh
@@ -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 ]]
diff --git a/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb
new file mode 100644
index 0000000000..12c28075a8
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out
new file mode 100644
index 0000000000..792f42fbf2
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb
new file mode 100644
index 0000000000..5ae94cdea0
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out
new file mode 100644
index 0000000000..83b85b943a
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.dellist.mdb b/usr/src/cmd/mdb/test/typedef/tst.dellist.mdb
new file mode 100644
index 0000000000..e9009d7b68
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.dellist.mdb
@@ -0,0 +1,3 @@
+::typdef -c lp32
+::typedef -d
+::typedef -l
diff --git a/usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb b/usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb
new file mode 100644
index 0000000000..6c7505ac1c
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb
@@ -0,0 +1 @@
+::typedef -l
diff --git a/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh
new file mode 100644
index 0000000000..cf517cf937
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh
@@ -0,0 +1,6 @@
+$MDB /lib/libc.so <<EOF
+::typedef uint8_t rm_t
+::typedef -l
+::print -at rm_t
+::sizeof rm_t
+EOF
diff --git a/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out
new file mode 100644
index 0000000000..d37ffafbfb
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out
@@ -0,0 +1,4 @@
+uint8_t
+rm_t
+0 rm_t
+sizeof (rm_t) = 1
diff --git a/usr/src/cmd/mdb/test/typedef/tst.models.ksh b/usr/src/cmd/mdb/test/typedef/tst.models.ksh
new file mode 100644
index 0000000000..8537ec443c
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.models.ksh
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.struct.mdb b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb
new file mode 100644
index 0000000000..2e0206e7ec
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out
new file mode 100644
index 0000000000..9a7d801742
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out
@@ -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
+}
diff --git a/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb
new file mode 100644
index 0000000000..85b3068e00
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out
new file mode 100644
index 0000000000..a6f4823ad1
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out
@@ -0,0 +1,5 @@
+sizeof (list_t) = 0x10
+0 list_t {
+ 0 struct list *prev
+ 8 struct list *next
+}
diff --git a/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb
new file mode 100644
index 0000000000..27cd56c186
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out
new file mode 100644
index 0000000000..0a0d3d4029
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out
@@ -0,0 +1,6 @@
+sizeof (gift_t) = 0x28
+0 gift_t {
+ 0 uintptr_t [7] stone
+ 20 void **white
+ 28 char [0] owner
+}
diff --git a/usr/src/cmd/mdb/test/typedef/tst.union.mdb b/usr/src/cmd/mdb/test/typedef/tst.union.mdb
new file mode 100644
index 0000000000..966446caee
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.union.mdb
@@ -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
diff --git a/usr/src/cmd/mdb/test/typedef/tst.union.mdb.out b/usr/src/cmd/mdb/test/typedef/tst.union.mdb.out
new file mode 100644
index 0000000000..2afc2eabb9
--- /dev/null
+++ b/usr/src/cmd/mdb/test/typedef/tst.union.mdb.out
@@ -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
+}