Mercurial > illumos > illumos-gate
changeset 13688:32dde9989090
2701 Add tab completion support for mdb
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Darren Reed <darrenr@fastmail.net>
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
author | Matt Amdur <matt.amdur@delphix.com> |
---|---|
date | Fri, 11 May 2012 22:38:13 -0400 |
parents | 72ce76fa37fb |
children | 125d1b3a6fa8 |
files | usr/src/cmd/mdb/Makefile.kmdb.files usr/src/cmd/mdb/Makefile.mdb usr/src/cmd/mdb/common/mdb/mdb.c usr/src/cmd/mdb/common/mdb/mdb.h usr/src/cmd/mdb/common/mdb/mdb_cmds.c usr/src/cmd/mdb/common/mdb/mdb_modapi.h usr/src/cmd/mdb/common/mdb/mdb_module.c usr/src/cmd/mdb/common/mdb/mdb_module.h usr/src/cmd/mdb/common/mdb/mdb_module_load.c usr/src/cmd/mdb/common/mdb/mdb_print.c usr/src/cmd/mdb/common/mdb/mdb_print.h usr/src/cmd/mdb/common/mdb/mdb_tab.c usr/src/cmd/mdb/common/mdb/mdb_tab.h usr/src/cmd/mdb/common/mdb/mdb_termio.c usr/src/cmd/mdb/common/mdb/mdb_whatis.c |
diffstat | 15 files changed, 1201 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/mdb/Makefile.kmdb.files Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/Makefile.kmdb.files Fri May 11 22:38:13 2012 -0400 @@ -23,6 +23,11 @@ # Use is subject to license terms. # +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# Copyright (c) 2012 Joyent, Inc. All rights reserved. +# + KMDBSRCS += \ ffs.c \ kaif_start.c \ @@ -75,6 +80,7 @@ mdb_string.c \ mdb_strio.c \ kmdb_stubs.c \ + mdb_tab.c \ mdb_target.c \ kmdb_terminfo.c \ mdb_termio.c \
--- a/usr/src/cmd/mdb/Makefile.mdb Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/Makefile.mdb Fri May 11 22:38:13 2012 -0400 @@ -19,11 +19,16 @@ # CDDL HEADER END # # -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# +# Copyright 2011 Nexenta Systems, Inc. All rights reserved. +# Copyright (c) 2012 by Delphix. All rights reserved. +# Copyright (c) 2012 Joyent, Inc. All rights reserved. +# + .KEEP_STATE: .SUFFIXES: @@ -76,6 +81,7 @@ mdb_stdlib.c \ mdb_string.c \ mdb_strio.c \ + mdb_tab.c \ mdb_target.c \ mdb_tdb.c \ mdb_termio.c \
--- a/usr/src/cmd/mdb/common/mdb/mdb.c Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb.c Fri May 11 22:38:13 2012 -0400 @@ -24,6 +24,11 @@ */ /* + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. + */ + +/* * Modular Debugger (MDB) * * Refer to the white paper "A Modular Debugger for Solaris" for information @@ -1132,6 +1137,16 @@ return (status); } +void +mdb_call_tab(mdb_idcmd_t *idcp, mdb_tab_cookie_t *mcp, uint_t flags, + uintmax_t argc, mdb_arg_t *argv) +{ + if (idcp->idc_tabp == NULL) + return; + + idcp->idc_tabp(mcp, flags, argc, argv); +} + /* * Call an internal dcmd directly: this code is used by module API functions * that need to execute dcmds, and by mdb_call() above.
--- a/usr/src/cmd/mdb/common/mdb/mdb.h Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb.h Fri May 11 22:38:13 2012 -0400 @@ -23,6 +23,11 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. + */ + #ifndef _MDB_H #define _MDB_H @@ -38,6 +43,7 @@ #include <mdb/mdb_modapi.h> #include <mdb/mdb_list.h> #include <mdb/mdb_vcb.h> +#include <mdb/mdb_tab.h> #ifdef _KMDB #include <kmdb/kmdb_wr.h> #endif @@ -206,6 +212,8 @@ extern int mdb_call_idcmd(mdb_idcmd_t *, uintmax_t, uintmax_t, uint_t, mdb_argvec_t *, mdb_addrvec_t *, mdb_vcb_t *); +extern void mdb_call_tab(mdb_idcmd_t *, mdb_tab_cookie_t *, uint_t, uintmax_t, + mdb_arg_t *); extern int mdb_call(uintmax_t, uintmax_t, uint_t); extern int mdb_run(void);
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Fri May 11 22:38:13 2012 -0400 @@ -24,6 +24,11 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. + */ + #include <sys/elf.h> #include <sys/elf_SPARC.h> @@ -61,6 +66,7 @@ #include <mdb/mdb_whatis.h> #include <mdb/mdb_whatis_impl.h> #include <mdb/mdb_macalias.h> +#include <mdb/mdb_tab.h> #ifdef _KMDB #include <kmdb/kmdb_kdi.h> #endif @@ -2129,6 +2135,24 @@ return (DCMD_OK); } +static int +cmd_walk_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + if (argc > 1) + return (1); + + if (argc == 1) { + ASSERT(argv[0].a_type == MDB_TYPE_STRING); + return (mdb_tab_complete_walker(mcp, argv[0].a_un.a_str)); + } + + if (argc == 0 && flags & DCMD_TAB_SPACE) + return (mdb_tab_complete_walker(mcp, NULL)); + + return (1); +} + static ssize_t mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg) { @@ -2924,7 +2948,8 @@ head_help }, { "help", "[cmd]", "list commands/command help", cmd_help }, { "list", "?type member [variable]", - "walk list using member as link pointer", cmd_list }, + "walk list using member as link pointer", cmd_list, NULL, + mdb_tab_complete_mt }, { "map", "?expr", "print dot after evaluating expression", cmd_map }, { "mappings", "?[name]", "print address space mappings", cmd_mappings }, { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]", @@ -2935,14 +2960,16 @@ { "obey", NULL, NULL, cmd_obey }, { "objects", "[-v]", "print load objects information", cmd_objects }, { "offsetof", "type member", "print the offset of a given struct " - "or union member", cmd_offsetof }, + "or union member", cmd_offsetof, NULL, mdb_tab_complete_mt }, { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]", - "print the contents of a data structure", cmd_print, print_help }, + "print the contents of a data structure", cmd_print, print_help, + cmd_print_tab }, { "regs", NULL, "print general purpose registers", cmd_notsup }, { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]", "get/set debugger properties", cmd_set }, { "showrev", "[-pv]", "print version information", cmd_showrev }, - { "sizeof", "type", "print the size of a type", cmd_sizeof }, + { "sizeof", "type", "print the size of a type", cmd_sizeof, NULL, + cmd_sizeof_tab }, { "stack", "?[cnt]", "print stack backtrace", cmd_notsup }, { "stackregs", "?", "print stack backtrace and registers", cmd_notsup }, @@ -2954,7 +2981,8 @@ { "version", NULL, "print debugger version string", cmd_version }, { "vtop", ":[-a as]", "print physical mapping of virtual address", cmd_vtop }, - { "walk", "?name [variable]", "walk data structure", cmd_walk }, + { "walk", "?name [variable]", "walk data structure", cmd_walk, NULL, + cmd_walk_tab }, { "walkers", NULL, "list available walkers", cmd_walkers }, { "whatis", ":[-aikqv]", "given an address, return information", cmd_whatis, whatis_help },
--- a/usr/src/cmd/mdb/common/mdb/mdb_modapi.h Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_modapi.h Fri May 11 22:38:13 2012 -0400 @@ -21,6 +21,8 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. */ #ifndef _MDB_MODAPI_H @@ -69,7 +71,7 @@ #define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif -#define MDB_API_VERSION 3 /* Current API version number */ +#define MDB_API_VERSION 4 /* Current API version number */ /* * Debugger command function flags: @@ -83,6 +85,11 @@ #define DCMD_HDRSPEC(fl) (((fl) & DCMD_LOOPFIRST) || !((fl) & DCMD_LOOP)) /* + * Debugger tab command function flags + */ +#define DCMD_TAB_SPACE 0x01 /* Tab cb invoked with trailing space */ + +/* * Debugger command function return values: */ #define DCMD_OK 0 /* Dcmd completed successfully */ @@ -111,7 +118,10 @@ } a_un; } mdb_arg_t; +typedef struct mdb_tab_cookie mdb_tab_cookie_t; typedef int mdb_dcmd_f(uintptr_t, uint_t, int, const mdb_arg_t *); +typedef int mdb_dcmd_tab_f(mdb_tab_cookie_t *, uint_t, int, + const mdb_arg_t *); typedef struct mdb_dcmd { const char *dc_name; /* Command name */ @@ -119,6 +129,7 @@ const char *dc_descr; /* Description */ mdb_dcmd_f *dc_funcp; /* Command function */ void (*dc_help)(void); /* Command help function (or NULL) */ + mdb_dcmd_tab_f *dc_tabp; /* Tab completion function */ } mdb_dcmd_t; #define WALK_ERR -1 /* Walk fatal error (terminate walk) */ @@ -302,6 +313,31 @@ extern void *mdb_callback_add(int, mdb_callback_f, void *); extern void mdb_callback_remove(void *); +#define MDB_TABC_ALL_TYPES 0x1 /* Include array types in type output */ +#define MDB_TABC_MEMBERS 0x2 /* Tab comp. types with members */ +#define MDB_TABC_NOPOINT 0x4 /* Tab comp. everything but pointers */ +#define MDB_TABC_NOARRAY 0x8 /* Don't include array data in output */ + +/* + * Module's interaction path + */ +extern void mdb_tab_insert(mdb_tab_cookie_t *, const char *); +extern void mdb_tab_setmbase(mdb_tab_cookie_t *, const char *); + +/* + * Tab completion utility functions for modules. + */ +extern int mdb_tab_complete_type(mdb_tab_cookie_t *, const char *, uint_t); +extern int mdb_tab_complete_member(mdb_tab_cookie_t *, const char *, + const char *); +extern int mdb_tab_typename(int *, const mdb_arg_t **, char *buf, size_t len); + +/* + * Tab completion functions for common signatures. + */ +extern int mdb_tab_complete_mt(mdb_tab_cookie_t *, uint_t, int, + const mdb_arg_t *); + extern size_t strlcat(char *, const char *, size_t); extern char *strcat(char *, const char *); extern char *strcpy(char *, const char *);
--- a/usr/src/cmd/mdb/common/mdb/mdb_module.c Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_module.c Fri May 11 22:38:13 2012 -0400 @@ -21,6 +21,8 @@ /* * 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. */ #include <sys/param.h> @@ -43,6 +45,20 @@ #include <mdb/mdb.h> /* + * The format of an mdb dcmd changed between MDB_API_VERSION 3 and 4, with an + * addition of a new field to the public interface. To maintain backwards + * compatibility with older versions, we know to keep around the old version of + * the structure so we can correctly read the set of dcmds passed in. + */ +typedef struct mdb_dcmd_v3 { + const char *dco_name; /* Command name */ + const char *dco_usage; /* Usage message (optional) */ + const char *dco_descr; /* Description */ + mdb_dcmd_f *dco_funcp; /* Command function */ + void (*dco_help)(void); /* Command help function (or NULL) */ +} mdb_dcmd_v3_t; + +/* * For builtin modules, we set mod_init to this function, which just * returns a constant modinfo struct with no dcmds and walkers. */ @@ -92,6 +108,9 @@ const mdb_dcmd_t *dcp; const mdb_walker_t *wp; + const mdb_dcmd_v3_t *dcop; + mdb_dcmd_t *dctp = NULL; + mdb_module_t *mod; mod = mdb_zalloc(sizeof (mdb_module_t), UM_SLEEP); @@ -164,6 +183,7 @@ */ switch (info->mi_dvers) { case MDB_API_VERSION: + case 3: case 2: case 1: /* @@ -186,6 +206,35 @@ } /* + * In MDB_API_VERSION 4, the size of the mdb_dcmd_t struct changed. If + * our module is from an earlier version, we need to walk it in the old + * structure and convert it to the new one. + * + * Note that we purposefully don't predicate on whether or not we have + * the empty list case and duplicate it anyways. That case is rare and + * it makes our logic simpler when we need to unload the module. + */ + if (info->mi_dvers < 4) { + int ii = 0; + for (dcop = (mdb_dcmd_v3_t *)&mod->mod_info->mi_dcmds[0]; + dcop->dco_name != NULL; dcop++) + ii++; + /* Don't forget null terminated one at the end */ + dctp = mdb_zalloc(sizeof (mdb_dcmd_t) * (ii + 1), UM_SLEEP); + ii = 0; + for (dcop = (mdb_dcmd_v3_t *)&mod->mod_info->mi_dcmds[0]; + dcop->dco_name != NULL; dcop++, ii++) { + dctp[ii].dc_name = dcop->dco_name; + dctp[ii].dc_usage = dcop->dco_usage; + dctp[ii].dc_descr = dcop->dco_descr; + dctp[ii].dc_funcp = dcop->dco_funcp; + dctp[ii].dc_help = dcop->dco_help; + dctp[ii].dc_tabp = NULL; + } + mod->mod_info->mi_dcmds = dctp; + } + + /* * Before we actually go ahead with the load, we need to check * each dcmd and walk structure for any invalid values: */ @@ -300,6 +349,7 @@ { mdb_var_t *v = mdb_nv_lookup(&mdb.m_modules, name); mdb_module_t *mod; + const mdb_dcmd_t *dcp; if (v == NULL) return (set_errno(EMDB_NOMOD)); @@ -358,6 +408,18 @@ mdb_nv_destroy(&mod->mod_dcmds); strfree((char *)mod->mod_name); + + if (mod->mod_info->mi_dvers < 4) { + int ii = 0; + + for (dcp = &mod->mod_info->mi_dcmds[0]; dcp->dc_name != NULL; + dcp++) + ii++; + + mdb_free((void *)mod->mod_info->mi_dcmds, + sizeof (mdb_dcmd_t) * (ii + 1)); + } + mdb_free(mod->mod_info, sizeof (mdb_modinfo_t)); mdb_free(mod, sizeof (mdb_module_t)); @@ -384,6 +446,7 @@ idcp->idc_descr = dcp->dc_descr; idcp->idc_help = dcp->dc_help; idcp->idc_funcp = dcp->dc_funcp; + idcp->idc_tabp = dcp->dc_tabp; idcp->idc_modp = mod; v = mdb_nv_insert(&mod->mod_dcmds, dcp->dc_name, NULL,
--- a/usr/src/cmd/mdb/common/mdb/mdb_module.h Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_module.h Fri May 11 22:38:13 2012 -0400 @@ -24,11 +24,14 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. + */ + #ifndef _MDB_MODULE_H #define _MDB_MODULE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <mdb/mdb_argvec.h> #include <mdb/mdb_nv.h> #include <mdb/mdb_modapi.h> @@ -67,6 +70,7 @@ const char *idc_descr; /* Description */ mdb_dcmd_f *idc_funcp; /* Command function */ void (*idc_help)(void); /* Help function */ + mdb_dcmd_tab_f *idc_tabp; /* Tab completion pointer */ mdb_module_t *idc_modp; /* Backpointer to module */ mdb_var_t *idc_var; /* Backpointer to global variable */ } mdb_idcmd_t;
--- a/usr/src/cmd/mdb/common/mdb/mdb_module_load.c Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_module_load.c Fri May 11 22:38:13 2012 -0400 @@ -21,6 +21,8 @@ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. */ #include <sys/param.h> @@ -201,6 +203,7 @@ mdb_iob_setflags(mdb.m_out, oflag); } +/*ARGSUSED*/ int mdb_module_unload(const char *name, int mode) {
--- a/usr/src/cmd/mdb/common/mdb/mdb_print.c Thu May 03 05:27:43 2012 -0500 +++ b/usr/src/cmd/mdb/common/mdb/mdb_print.c Fri May 11 22:38:13 2012 -0400 @@ -23,6 +23,11 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Joyent, Inc. All rights reserved. + */ + #include <mdb/mdb_modapi.h> #include <mdb/mdb_target.h> #include <mdb/mdb_argvec.h> @@ -34,6 +39,7 @@ #include <mdb/mdb_ctf.h> #include <mdb/mdb_ctf_impl.h> #include <mdb/mdb.h> +#include <mdb/mdb_tab.h> #include <sys/isa_defs.h> #include <sys/param.h> @@ -209,6 +215,28 @@ return (DCMD_OK); } +int +cmd_sizeof_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + char tn[MDB_SYM_NAMLEN]; + int ret; + + if (argc == 0 && !(flags & DCMD_TAB_SPACE)) + return (0); + + if (argc == 0 && (flags & DCMD_TAB_SPACE)) + return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT)); + + if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0) + return (ret); + + if (argc == 1) + return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT)); + + return (0); +} + /*ARGSUSED*/ int cmd_offsetof(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) @@ -1882,7 +1910,8 @@ return (-1); } - (void) mdb_snprintf(member, end - start + 1, start); + (void) mdb_snprintf(member, end - start + 1, "%s", + start); index = mdb_strtoull(member); @@ -1959,7 +1988,7 @@ for (end = start + 1; isalnum(*end) || *end == '_'; end++) continue; - (void) mdb_snprintf(member, end - start + 1, start); + (void) mdb_snprintf(member, end - start + 1, "%s", start); if (mdb_ctf_member_info(rid, member, &off, &id) != 0) { mdb_warn("failed to find member %s of %s", member, @@ -1981,6 +2010,170 @@ return (0); } +int +cmd_print_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + char tn[MDB_SYM_NAMLEN]; + char member[64]; + int i, dummy, delim, kind; + int ret = 0; + mdb_ctf_id_t id, rid; + mdb_ctf_arinfo_t ar; + char *start, *end; + ulong_t dul; + + /* + * This getopts is only here to make the tab completion work better when + * including options in the ::print arguments. None of the values should + * be used. This should only be updated with additional arguments, if + * they are added to cmd_print. + */ + i = mdb_getopts(argc, argv, + 'a', MDB_OPT_SETBITS, PA_SHOWADDR, &dummy, + 'C', MDB_OPT_SETBITS, TRUE, &dummy, + 'c', MDB_OPT_UINTPTR, &dummy, + 'd', MDB_OPT_SETBITS, PA_INTDEC, &dummy, + 'h', MDB_OPT_SETBITS, PA_SHOWHOLES, &dummy, + 'i', MDB_OPT_SETBITS, TRUE, &dummy, + 'L', MDB_OPT_SETBITS, TRUE, &dummy, + 'l', MDB_OPT_UINTPTR, &dummy, + 'n', MDB_OPT_SETBITS, PA_NOSYMBOLIC, &dummy, + 'p', MDB_OPT_SETBITS, TRUE, &dummy, + 's', MDB_OPT_UINTPTR, &dummy, + 'T', MDB_OPT_SETBITS, PA_SHOWTYPE | PA_SHOWBASETYPE, &dummy, + 't', MDB_OPT_SETBITS, PA_SHOWTYPE, &dummy, + 'x', MDB_OPT_SETBITS, PA_INTHEX, &dummy, + NULL); + + argc -= i; + argv += i; + + if (argc == 0 && !(flags & DCMD_TAB_SPACE)) + return (0); + + if (argc == 0 && (flags & DCMD_TAB_SPACE)) + return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_NOPOINT | + MDB_TABC_NOARRAY)); + + if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0) + return (ret); + + if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1)) + return (mdb_tab_complete_type(mcp, tn, MDB_TABC_NOPOINT | + MDB_TABC_NOARRAY)); + + if (argc == 1 && (flags & DCMD_TAB_SPACE)) + return (mdb_tab_complete_member(mcp, tn, NULL)); + + /* + * This is the reason that tab completion was created. We're going to go + * along and walk the delimiters until we find something a member that + * we don't recognize, at which point we'll try and tab complete it. + * Note that ::print takes multiple args, so this is going to operate on + * whatever the last arg that we have is. + */ + if (mdb_ctf_lookup_by_name(tn, &id) != 0) + return (1); + + (void) mdb_ctf_type_resolve(id, &rid); + start = (char *)argv[argc-1].a_un.a_str; + delim = parse_delimiter(&start); + + /* + * If we hit the case where we actually have no delimiters, than we need + * to make sure that we properly set up the fields the loops would. + */ + if (delim == MEMBER_DELIM_DONE) + (void) mdb_snprintf(member, sizeof (member), "%s", start); +