From 0a47c91c895e274dd0990009919e30e984364a8b Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Wed, 3 Apr 2013 15:25:37 -0700 Subject: [PATCH] 3089 want ::typedef 3690 mdb on x86 should be able to print alternate register names 3688 Want mdb -e 3094 libctf should support removing a dynamic type 3095 libctf does not validate arrays correctly 3096 libctf does not validate function types correctly 3689 Want an mdb test suite driver Reviewed by: Richard Lowe Reviewed by: Eric Schrock Approved by: Gordon Ross --- usr/src/cmd/mdb/Makefile.kmdb.files | 1 + usr/src/cmd/mdb/Makefile.libstandctf | 2 +- usr/src/cmd/mdb/Makefile.mdb | 1 + usr/src/cmd/mdb/common/libstandctf/mapfile | 7 + usr/src/cmd/mdb/common/mdb/mdb.c | 17 +- usr/src/cmd/mdb/common/mdb/mdb.h | 3 + usr/src/cmd/mdb/common/mdb/mdb_cmds.c | 5 +- usr/src/cmd/mdb/common/mdb/mdb_ctf.c | 590 +++++++++++++++- usr/src/cmd/mdb/common/mdb/mdb_ctf.h | 27 + usr/src/cmd/mdb/common/mdb/mdb_main.c | 23 +- usr/src/cmd/mdb/common/mdb/mdb_proc.c | 18 + usr/src/cmd/mdb/common/mdb/mdb_tab.c | 2 + usr/src/cmd/mdb/common/mdb/mdb_target_impl.h | 9 +- usr/src/cmd/mdb/common/mdb/mdb_typedef.c | 773 +++++++++++++++++++++ usr/src/cmd/mdb/common/mdb/mdb_typedef.h | 32 + usr/src/cmd/mdb/intel/mdb/kvm_isadep.c | 22 +- usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c | 54 ++ usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c | 22 +- usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c | 58 +- usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c | 22 +- usr/src/cmd/mdb/test/README | 18 + usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh | 2 + usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh | 2 + usr/src/cmd/mdb/test/exit-e/tst.output.ksh | 1 + usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out | 1 + usr/src/cmd/mdb/test/exit-e/tst.simple.ksh | 1 + usr/src/cmd/mdb/test/mtest.sh | 235 +++++++ usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh | 1 + .../cmd/mdb/test/typedef/err.badid-leadschar.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.badmodel.ksh | 1 + .../mdb/test/typedef/err.badstruct-extrabraces.ksh | 1 + .../mdb/test/typedef/err.badstruct-neglenarr.ksh | 1 + .../test/typedef/err.badstruct-noarrayclose.ksh | 1 + .../mdb/test/typedef/err.badstruct-noarraylen.ksh | 1 + .../mdb/test/typedef/err.badstruct-noarrayopen.ksh | 1 + .../mdb/test/typedef/err.badstruct-nobraces.ksh | 1 + .../test/typedef/err.badstruct-noclosebrace.ksh | 1 + .../mdb/test/typedef/err.badstruct-nomembers.ksh | 1 + .../mdb/test/typedef/err.badstruct-nomemname.ksh | 1 + .../mdb/test/typedef/err.badstruct-nomemsemi.ksh | 1 + .../mdb/test/typedef/err.badstruct-noopenbrace.ksh | 1 + .../mdb/test/typedef/err.badstruct-noquotes.ksh | 1 + .../mdb/test/typedef/err.badstruct-repmemname.ksh | 1 + .../cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh | 1 + .../mdb/test/typedef/err.badstruct-zerolenarr.ksh | 1 + .../cmd/mdb/test/typedef/err.badunion-hasvla.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.extraargs.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.noargs.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.nomodel.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.noname.ksh | 1 + usr/src/cmd/mdb/test/typedef/err.typeexists.ksh | 1 + usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb | 4 + .../cmd/mdb/test/typedef/tst.anonstruct.mdb.out | 5 + usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb | 4 + usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out | 6 + usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh | 22 + usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb | 27 + .../cmd/mdb/test/typedef/tst.deftypes32.mdb.out | 26 + usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb | 27 + .../cmd/mdb/test/typedef/tst.deftypes64.mdb.out | 26 + usr/src/cmd/mdb/test/typedef/tst.dellist.mdb | 3 + usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb | 1 + usr/src/cmd/mdb/test/typedef/tst.libctype.ksh | 6 + usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out | 4 + usr/src/cmd/mdb/test/typedef/tst.models.ksh | 11 + usr/src/cmd/mdb/test/typedef/tst.struct.mdb | 6 + usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out | 10 + usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb | 4 + .../cmd/mdb/test/typedef/tst.structselfref.mdb.out | 5 + usr/src/cmd/mdb/test/typedef/tst.structvla.mdb | 4 + usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out | 6 + usr/src/cmd/mdb/test/typedef/tst.union.mdb | 6 + usr/src/cmd/mdb/test/typedef/tst.union.mdb.out | 12 + usr/src/common/ctf/ctf_create.c | 190 ++++- usr/src/common/ctf/ctf_error.c | 7 +- usr/src/common/ctf/ctf_impl.h | 10 +- usr/src/common/ctf/ctf_open.c | 13 +- usr/src/lib/libctf/common/mapfile-vers | 1 + usr/src/man/man1/mdb.1 | 17 +- usr/src/tools/findunref/exception_list.open | 1 + usr/src/uts/common/sys/ctf_api.h | 7 +- 82 files changed, 2405 insertions(+), 39 deletions(-) create mode 100644 usr/src/cmd/mdb/common/mdb/mdb_typedef.c create mode 100644 usr/src/cmd/mdb/common/mdb/mdb_typedef.h create mode 100644 usr/src/cmd/mdb/test/README create mode 100644 usr/src/cmd/mdb/test/exit-e/err.cmdbadopt.ksh create mode 100644 usr/src/cmd/mdb/test/exit-e/err.enocmd.ksh create mode 100644 usr/src/cmd/mdb/test/exit-e/tst.output.ksh create mode 100644 usr/src/cmd/mdb/test/exit-e/tst.output.ksh.out create mode 100644 usr/src/cmd/mdb/test/exit-e/tst.simple.ksh create mode 100644 usr/src/cmd/mdb/test/mtest.sh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badid-leadnum.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badid-leadschar.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badmodel.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-extrabraces.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-neglenarr.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayclose.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noarraylen.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noarrayopen.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-nobraces.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noclosebrace.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-nomembers.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-nomemname.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-nomemsemi.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noopenbrace.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-noquotes.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-repmemname.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-vlaonly.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badstruct-zerolenarr.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.badunion-hasvla.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.extraargs.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.noargs.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.nokeyword.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.nomodel.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.noname.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/err.typeexists.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.anonstruct.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.anonunion.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.cleanupstruct.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.deftypes32.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.deftypes64.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.dellist.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.emptylist.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.libctype.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/tst.libctype.ksh.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.models.ksh create mode 100644 usr/src/cmd/mdb/test/typedef/tst.struct.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.struct.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.structselfref.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.structvla.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.structvla.mdb.out create mode 100644 usr/src/cmd/mdb/test/typedef/tst.union.mdb create mode 100644 usr/src/cmd/mdb/test/typedef/tst.union.mdb.out 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 #include #include +#include #ifdef _KMDB #include #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 #include #include +#include #include #ifdef _KMDB #include @@ -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 @@ -67,6 +67,7 @@ #include #include #include +#include #ifdef _KMDB #include #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 @@ -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 #include #include @@ -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 +#include +#include +#include + +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 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("%OPTIONS%\n"); + (void) mdb_inc_indent(2); + mdb_printf("%s", typedef_opts); + (void) mdb_dec_indent(2); + mdb_printf("%EXAMPLES%\n"); + (void) mdb_inc_indent(2); + mdb_printf("%s", typedef_examps); + (void) mdb_dec_indent(2); + mdb_printf("%INTRINSICS%\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 + +#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 @@ -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 #include @@ -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 <&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 <&1 + exit 1 +fi + +$MDB < $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 <&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 +} diff --git a/usr/src/common/ctf/ctf_create.c b/usr/src/common/ctf/ctf_create.c index a4f3df34e8..239d166f44 100644 --- a/usr/src/common/ctf/ctf_create.c +++ b/usr/src/common/ctf/ctf_create.c @@ -24,13 +24,15 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013, Joyent, Inc. All rights reserved. + */ #include #include #include #include +#include /* * This static string is used as the template for initially populating a @@ -167,6 +169,51 @@ ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) } /* + * Only types of dyanmic CTF containers contain reference counts. These + * containers are marked RD/WR. Because of that we basically make this a no-op + * for compatability with non-dynamic CTF sections. This is also a no-op for + * types which are not dynamic types. It is the responsibility of the caller to + * make sure it is a valid type. We help that caller out on debug builds. + * + * Note that the reference counts are not maintained for types that are not + * within this container. In other words if we have a type in a parent, that + * will not have its reference count increased. On the flip side, the parent + * will not be allowed to remove dynamic types if it has children. + */ +static void +ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid) +{ + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); + + if (dtd == NULL) + return; + + if (!(fp->ctf_flags & LCTF_RDWR)) + return; + + dtd->dtd_ref++; +} + +/* + * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the + * caller should ensure that this is already a valid type. + */ +static void +ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid) +{ + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); + + if (dtd == NULL) + return; + + if (!(fp->ctf_flags & LCTF_RDWR)) + return; + + ASSERT(dtd->dtd_ref >= 1); + dtd->dtd_ref--; +} + +/* * If the specified CTF container is writable and has been modified, reload * this container with the updated type definitions. In order to make this * code and the rest of libctf as simple as possible, we perform updates by @@ -180,6 +227,10 @@ ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp * constant for the caller, so after ctf_bufopen() returns, we use bcopy to * swap the interior of the old and new ctf_file_t's, and then free the old. + * + * Note that the lists of dynamic types stays around and the resulting container + * is still writeable. Furthermore, the reference counts that are on the dtd's + * are still valid. */ int ctf_update(ctf_file_t *fp) @@ -432,6 +483,7 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; ctf_dmdef_t *dmd, *nmd; size_t len; + int kind, i; for (p = *q; p != NULL; p = p->dtd_hash) { if (p != dtd) @@ -443,7 +495,8 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) if (p != NULL) *q = p->dtd_hash; - switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { + kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); + switch (kind) { case CTF_K_STRUCT: case CTF_K_UNION: case CTF_K_ENUM: @@ -454,14 +507,33 @@ ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) ctf_free(dmd->dmd_name, len); fp->ctf_dtstrlen -= len; } + if (kind != CTF_K_ENUM) + ctf_ref_dec(fp, dmd->dmd_type); nmd = ctf_list_next(dmd); ctf_free(dmd, sizeof (ctf_dmdef_t)); } break; case CTF_K_FUNCTION: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++) + if (dtd->dtd_u.dtu_argv[i] != 0) + ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]); ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); break; + case CTF_K_ARRAY: + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); + break; + case CTF_K_TYPEDEF: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + break; + case CTF_K_POINTER: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + ctf_ref_dec(fp, dtd->dtd_data.ctt_type); + break; } if (dtd->dtd_name) { @@ -495,7 +567,9 @@ ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) * Discard all of the dynamic type definitions that have been added to the * container since the last call to ctf_update(). We locate such types by * scanning the list and deleting elements that have type IDs greater than - * ctf_dtoldid, which is set by ctf_update(), above. + * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly + * with our reference counting schemes, we must delete the dynamic list in + * reverse. */ int ctf_discard(ctf_file_t *fp) @@ -508,11 +582,11 @@ ctf_discard(ctf_file_t *fp) if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ - for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { + for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { if (dtd->dtd_type <= fp->ctf_dtoldid) continue; /* skip types that have been committed */ - ntd = ctf_list_next(dtd); + ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } @@ -614,6 +688,8 @@ ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ + ctf_ref_inc(fp, ref); + dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); dtd->dtd_data.ctt_type = (ushort_t)ref; @@ -645,16 +721,29 @@ ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) { ctf_dtdef_t *dtd; ctf_id_t type; + ctf_file_t *fpd; if (arp == NULL) return (ctf_set_errno(fp, EINVAL)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && + ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && + ctf_dtd_lookup(fp, arp->ctr_index) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); dtd->dtd_data.ctt_size = 0; dtd->dtd_u.dtu_arr = *arp; + ctf_ref_inc(fp, arp->ctr_contents); + ctf_ref_inc(fp, arp->ctr_index); return (type); } @@ -662,6 +751,7 @@ ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) int ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) { + ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) @@ -670,8 +760,22 @@ ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) return (ctf_set_errno(fp, ECTF_BADID)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && + ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + fpd = fp; + if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && + ctf_dtd_lookup(fp, arp->ctr_index) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); + ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); fp->ctf_flags |= LCTF_DIRTY; dtd->dtd_u.dtu_arr = *arp; + ctf_ref_inc(fp, arp->ctr_contents); + ctf_ref_inc(fp, arp->ctr_index); return (0); } @@ -683,7 +787,9 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, ctf_dtdef_t *dtd; ctf_id_t type; uint_t vlen; + int i; ctf_id_t *vdat = NULL; + ctf_file_t *fpd; if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || (ctc->ctc_argc != 0 && argv == NULL)) @@ -696,6 +802,18 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, if (vlen > CTF_MAX_VLEN) return (ctf_set_errno(fp, EOVERFLOW)); + fpd = fp; + if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL && + ctf_dtd_lookup(fp, ctc->ctc_return) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + + for (i = 0; i < ctc->ctc_argc; i++) { + fpd = fp; + if (ctf_lookup_by_id(&fpd, argv[i]) == NULL && + ctf_dtd_lookup(fp, argv[i]) == NULL) + return (ctf_set_errno(fp, ECTF_BADID)); + } + if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) return (ctf_set_errno(fp, EAGAIN)); @@ -707,6 +825,10 @@ ctf_add_function(ctf_file_t *fp, uint_t flag, dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; + ctf_ref_inc(fp, ctc->ctc_return); + for (i = 0; i < ctc->ctc_argc; i++) + ctf_ref_inc(fp, argv[i]); + bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); if (ctc->ctc_flags & CTF_FUNC_VARARG) vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ @@ -825,8 +947,11 @@ ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) { ctf_dtdef_t *dtd; ctf_id_t type; + ctf_file_t *fpd; - if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) + fpd = fp; + if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL && + ctf_dtd_lookup(fp, ref) == NULL)) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) @@ -834,6 +959,7 @@ ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); dtd->dtd_data.ctt_type = (ushort_t)ref; + ctf_ref_inc(fp, ref); return (type); } @@ -1008,6 +1134,45 @@ ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) if (s != NULL) fp->ctf_dtstrlen += strlen(s) + 1; + ctf_ref_inc(fp, type); + fp->ctf_flags |= LCTF_DIRTY; + return (0); +} + +/* + * This removes a type from the dynamic section. This will fail if the type is + * referenced by another type. Note that the CTF ID is never reused currently by + * CTF. Note that if this container is a parent container then we just outright + * refuse to remove the type. There currently is no notion of searching for the + * ctf_dtdef_t in parent containers. If there is, then this constraint could + * become finer grained. + */ +int +ctf_delete_type(ctf_file_t *fp, ctf_id_t type) +{ + ctf_file_t *fpd; + ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); + + if (!(fp->ctf_flags & LCTF_RDWR)) + return (ctf_set_errno(fp, ECTF_RDONLY)); + + /* + * We want to give as useful an errno as possible. That means that we + * want to distinguish between a type which does not exist and one for + * which the type is not dynamic. + */ + fpd = fp; + if (ctf_lookup_by_id(&fpd, type) == NULL && + ctf_dtd_lookup(fp, type) == NULL) + return (CTF_ERR); /* errno is set for us */ + + if (dtd == NULL) + return (ctf_set_errno(fp, ECTF_NOTDYN)); + + if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1) + return (ctf_set_errno(fp, ECTF_REFERENCED)); + + ctf_dtd_delete(fp, dtd); fp->ctf_flags |= LCTF_DIRTY; return (0); } @@ -1103,6 +1268,9 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) ctf_hash_t *hp; ctf_helem_t *hep; + if (dst_fp == src_fp) + return (src_type); + if (!(dst_fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(dst_fp, ECTF_RDONLY)); @@ -1313,6 +1481,14 @@ ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) if (errs) return (CTF_ERR); /* errno is set for us */ + + /* + * Now that we know that we can't fail, we go through and bump + * all the reference counts on the member types. + */ + for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); + dmd != NULL; dmd = ctf_list_next(dmd)) + ctf_ref_inc(dst_fp, dmd->dmd_type); break; } diff --git a/usr/src/common/ctf/ctf_error.c b/usr/src/common/ctf/ctf_error.c index 888c6c848b..fe3d0de0cb 100644 --- a/usr/src/common/ctf/ctf_error.c +++ b/usr/src/common/ctf/ctf_error.c @@ -23,8 +23,9 @@ * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012, Joyent, Inc. + */ #include @@ -73,6 +74,8 @@ static const char *const _ctf_errlist[] = { "Limit on number of dynamic types reached", /* ECTF_FULL */ "Duplicate member name definition", /* ECTF_DUPMEMBER */ "Conflicting type is already defined", /* ECTF_CONFLICT */ + "Type has outstanding references", /* ECTF_REFERENCED */ + "Type is not a dynamic type" /* ECTF_NOTDYN */ }; static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]); diff --git a/usr/src/common/ctf/ctf_impl.h b/usr/src/common/ctf/ctf_impl.h index 99990806a3..f56fa6a005 100644 --- a/usr/src/common/ctf/ctf_impl.h +++ b/usr/src/common/ctf/ctf_impl.h @@ -24,12 +24,13 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ #ifndef _CTF_IMPL_H #define _CTF_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -149,6 +150,7 @@ typedef struct ctf_dtdef { char *dtd_name; /* name associated with definition (if any) */ ctf_id_t dtd_type; /* type identifier for this definition */ ctf_type_t dtd_data; /* type node (see ) */ + int dtd_ref; /* recfount for dyanmic types */ union { ctf_list_t dtu_members; /* struct, union, or enum */ ctf_arinfo_t dtu_arr; /* array */ @@ -269,7 +271,9 @@ enum { ECTF_DTFULL, /* CTF type is full (no more members allowed) */ ECTF_FULL, /* CTF container is full */ ECTF_DUPMEMBER, /* duplicate member name definition */ - ECTF_CONFLICT /* conflicting type definition present */ + ECTF_CONFLICT, /* conflicting type definition present */ + ECTF_REFERENCED, /* type has outstanding references */ + ECTF_NOTDYN /* type is not a dynamic type */ }; extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *, diff --git a/usr/src/common/ctf/ctf_open.c b/usr/src/common/ctf/ctf_open.c index e49a4cb329..2148389fff 100644 --- a/usr/src/common/ctf/ctf_open.c +++ b/usr/src/common/ctf/ctf_open.c @@ -24,8 +24,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ #include #include @@ -810,8 +811,12 @@ ctf_close(ctf_file_t *fp) if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); - for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { - ntd = ctf_list_next(dtd); + /* + * Note, to work properly with reference counting on the dynamic + * section, we must delete the list in reverse. + */ + for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { + ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } diff --git a/usr/src/lib/libctf/common/mapfile-vers b/usr/src/lib/libctf/common/mapfile-vers index c218edc37c..0873de319e 100644 --- a/usr/src/lib/libctf/common/mapfile-vers +++ b/usr/src/lib/libctf/common/mapfile-vers @@ -60,6 +60,7 @@ SYMBOL_VERSION SUNWprivate_1.2 { ctf_add_union; ctf_add_volatile; ctf_create; + ctf_delete_type; ctf_discard; ctf_enum_value; ctf_label_info; diff --git a/usr/src/man/man1/mdb.1 b/usr/src/man/man1/mdb.1 index a64d145527..f3a084d151 100644 --- a/usr/src/man/man1/mdb.1 +++ b/usr/src/man/man1/mdb.1 @@ -1,9 +1,10 @@ '\" te .\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved. +.\" Copyright (c) 2012, Joyent, Inc. All Rights Reserved. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH MDB 1 "Nov 30, 2005" +.TH MDB 1 "Oct 05, 2012" .SH NAME mdb \- modular debugger .SH SYNOPSIS @@ -11,7 +12,7 @@ mdb \- modular debugger .nf \fBmdb\fR [\fB-fkmuwyAFKMSUW\fR] [\(+-o \fIoption\fR] [\fB-p\fR \fIpid\fR] [\fB-s\fR \fIdistance\fR] [\fB-I\fR \fIpath\fR] [\fB-L\fR \fIpath\fR] [\fB-P\fR \fIprompt\fR] [\fB-R\fR \fIroot\fR] - [\fB-V\fR \fIdis-version\fR] [object [core] | core | suffix] + [\fB-V\fR \fIdis-version\fR] [\fB-e\fR \fIexpr\fR] [object [core] | core | suffix] .fi .SH DESCRIPTION @@ -3716,6 +3717,18 @@ system or an operating system crash dump. .sp .ne 2 .na +\fB\fB-e\fR \fIexpr\fR\fR +.ad +.RS 15n +Causes \fBmdb\fR to ignore standard input and instead evaluate the \fBmdb\fR +expression \fIexpr\fR. Upon completing evaluation, \fBmdb\fR terminates and +returns a status code. A non-zero return code from \fBmdb\fR indicates that +either \fBmdb\fR or the evaluation of \fIexpr\fR failed. +.RE + +.sp +.ne 2 +.na \fB\fB-f\fR\fR .ad .RS 15n diff --git a/usr/src/tools/findunref/exception_list.open b/usr/src/tools/findunref/exception_list.open index 6e298428e7..d0ed727e90 100644 --- a/usr/src/tools/findunref/exception_list.open +++ b/usr/src/tools/findunref/exception_list.open @@ -264,3 +264,4 @@ # ld tests which are not currently delivered # ./usr/src/cmd/sgs/test +./usr/src/cmd/mdb/test diff --git a/usr/src/uts/common/sys/ctf_api.h b/usr/src/uts/common/sys/ctf_api.h index 17b0b7262e..c08acf1950 100644 --- a/usr/src/uts/common/sys/ctf_api.h +++ b/usr/src/uts/common/sys/ctf_api.h @@ -23,6 +23,9 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ /* * This header file defines the interfaces available from the CTF debugger @@ -40,8 +43,6 @@ #ifndef _CTF_API_H #define _CTF_API_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -223,6 +224,8 @@ extern int ctf_add_member(ctf_file_t *, ctf_id_t, const char *, ctf_id_t); extern int ctf_set_array(ctf_file_t *, ctf_id_t, const ctf_arinfo_t *); +extern int ctf_delete_type(ctf_file_t *, ctf_id_t); + extern int ctf_update(ctf_file_t *); extern int ctf_discard(ctf_file_t *); extern int ctf_write(ctf_file_t *, int); -- 2.11.4.GIT