3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * CDDL HEADER START
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * The contents of this file are subject to the terms of the
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Common Development and Distribution License (the "License").
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * You may not use this file except in compliance with the License.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * See the License for the specific language governing permissions
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * and limitations under the License.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * When distributing Covered Code, include this CDDL HEADER in each
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * If applicable, add the following below this CDDL HEADER, with the
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * fields enclosed by brackets "[]" replaced with your own identifying
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * information: Portions Copyright [yyyy] [name of copyright owner]
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * CDDL HEADER END
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * Copyright (c) 2013 by Delphix. All rights reserved.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Copyright (c) 2012 Joyent, Inc. All rights reserved.
065c692a88e4dcdd0c6eadc2476c046d6ee9dd1cJosef 'Jeff' Sipek * Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This file contains all of the interfaces for mdb's tab completion engine.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Currently some interfaces are private to mdb and its internal implementation,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * those are in mdb_tab.h. Other pieces are public interfaces. Those are in
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Memory allocations in tab completion context have to be done very carefully.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * We need to think of ourselves as the same as any other command that is being
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * executed by the user, which means we must use UM_GC to handle being
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * interrupted.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * There may be another way to do this, but this works well enough.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * find_command_start --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Given a buffer find the start of the last command.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurstatic char *
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur char *next = strstr(offset + strlen(COMMAND_SEPARATOR),
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * get_dcmd --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Given a buffer containing a command and its argument return
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * the name of the command and the offset in the buffer where
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * the command arguments start.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Note: This will modify the buffer.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurtab_get_dcmd(char *buf, char **args, uint_t *flags)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * count_args --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Given a buffer containing dmcd arguments return the total number
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * of arguments.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * While parsing arguments we need to keep track of whether or not the last
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * arguments ends with a trailing space.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * copy_args --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Given a buffer containing dcmd arguments and an array of mdb_arg_t's
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * initialize the string value of each mdb_arg_t.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Note: This will modify the buffer.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurtab_copy_args(char *input, int argc, mdb_arg_t *argv)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (-1);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * parse-buf --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Parse the given buffer and return the specified dcmd, the number
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * of arguments, and array of mdb_arg_t containing the argument
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Note: this will modify the specified buffer. Caller is responisble
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * for freeing argvp.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurtab_parse_buf(char *buf, char **dcmdp, int *argcp, mdb_arg_t **argvp,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (-1);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (-1);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (-1);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * tab_command --
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This function is executed anytime a tab is entered. It checks
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * the current buffer to determine if there is a valid dmcd,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * if that dcmd has a tab completion handler it will invoke it.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This function returns the string (if any) that should be added to the
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * existing buffer to complete it.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_command(mdb_tab_cookie_t *mcp, const char *buf)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Parsing the command and arguments will modify the buffer
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * (replacing spaces with \0), so make a copy of the specified
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * buffer first.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur data = mdb_alloc(strlen(buf) + 1, UM_SLEEP | UM_GC);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Get the specified dcmd and arguments from the buffer.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur ret = tab_parse_buf(data, &dcmd, &argc, &argv, &flags);
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * Match against global symbols if the input is not a dcmd
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Check to see if the buffer contains a valid dcmd
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * When argc is zero it indicates that we are trying to tab complete
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * a dcmd or a global symbol. Note, that if there isn't the start of
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * a dcmd, i.e. ::, then we will have already bailed in the call to
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * tab_parse_buf.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Invoke the command specific tab completion handler or the built in
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * dcmd one if there is no dcmd.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mdb_idcmd_t *idcp = mdb_nv_get_cookie(mdb_nv_get_cookie(v));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * The way that mdb is implemented, even commands like $C will show up
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * here. As such, we don't want to match anything that doesn't start
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * with an alpha or number. While nothing currently appears (via a
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * cursory search with mdb -k) to start with a capital letter or a
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * number, we'll support them anyways.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_dcmd(mdb_tab_cookie_t *mcp, const char *dcmd)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mdb_nv_sort_iter(&mdb.m_dcmds, tab_complete_dcmd, mcp,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mdb_iwalker_t *iwp = mdb_nv_get_cookie(mdb_nv_get_cookie(v));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_walker(mdb_tab_cookie_t *mcp, const char *walker)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mdb_nv_sort_iter(&mdb.m_walkers, tab_complete_walker, mcp,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mcp = mdb_zalloc(sizeof (mdb_tab_cookie_t), UM_SLEEP | UM_GC);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) mdb_nv_create(&mcp->mtc_nv, UM_SLEEP | UM_GC);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * Determine whether the specified name is a valid tab completion for
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * the given command. If the name is a valid tab completion then
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * it will be saved in the mdb_tab_cookie_t.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_insert(mdb_tab_cookie_t *mcp, const char *name)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * If we have a match set, then we want to verify that we actually match
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur strncmp(name, mcp->mtc_base, strlen(mcp->mtc_base)) != 0)
065c692a88e4dcdd0c6eadc2476c046d6ee9dd1cJosef 'Jeff' Sipek (void) mdb_nv_insert(&mcp->mtc_nv, name, NULL, 0, MDB_NV_RDONLY);
065c692a88e4dcdd0c6eadc2476c046d6ee9dd1cJosef 'Jeff' Sipek (void) strlcpy(mcp->mtc_match, name, MDB_SYM_NAMLEN);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur mdb_nv_sort_iter(&mcp->mtc_nv, tab_print_cb, NULL, UM_SLEEP | UM_GC);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_setmbase(mdb_tab_cookie_t *mcp, const char *base)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) strlcpy(mcp->mtc_base, base, MDB_SYM_NAMLEN);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This function is currently a no-op due to the fact that we have to GC because
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * we're in command context.
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattssontab_complete_global(void *arg, const GElf_Sym *sym, const char *name,
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson * This function tab completes against all loaded global symbols.
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattssonmdb_tab_complete_global(mdb_tab_cookie_t *mcp, const char *name)
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
22ce014825a14b6ce90123db2834a13e343d6cafMatthew Ahrens MDB_TGT_SYMTAB, MDB_TGT_BIND_ANY | MDB_TGT_TYPE_OBJECT |
72a1114bccf02392ab254b9615412236f3b63256Henrik Mattsson MDB_TGT_TYPE_FUNC, tab_complete_global, mcp);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This function takes a ctf id and determines whether or not the associated
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * type should be considered as a potential match for the given tab
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * completion command. We verify that the type itself is valid
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * for completion given the current context of the command, resolve
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * its actual name, and then pass it off to mdb_tab_insert to determine
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * if it's an actual match.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * CTF data includes types that mdb commands don't understand. Before
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * we resolve the actual type prune any entry that is a type we
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * don't care about.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT &&
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_module(void *data, const mdb_map_t *mp, const char *name)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) mdb_ctf_type_iter(name, tab_complete_type, data);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_type(mdb_tab_cookie_t *mcp, const char *name, uint_t flags)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) mdb_tgt_object_iter(t, mdb_tab_complete_module, mcp);
0a47c91c895e274dd0990009919e30e984364a8bRobert Mustacchi (void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, tab_complete_type,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurtab_complete_member(const char *name, mdb_ctf_id_t id, ulong_t off, void *arg)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_member_by_id(mdb_tab_cookie_t *mcp, mdb_ctf_id_t id,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur const char *member)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) mdb_ctf_member_iter(id, tab_complete_member, mcp);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_member(mdb_tab_cookie_t *mcp, const char *type,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur const char *member)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (-1);
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (mdb_tab_complete_member_by_id(mcp, id, member));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_complete_mt(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (mdb_tab_complete_type(mcp, NULL, MDB_TABC_MEMBERS));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur if ((ret = mdb_tab_typename(&argc, &argv, tn, sizeof (tn))) < 0)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur if (argc == 1 && (!(flags & DCMD_TAB_SPACE) || ret == 1))
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (mdb_tab_complete_type(mcp, tn, MDB_TABC_MEMBERS));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur return (mdb_tab_complete_member(mcp, tn, argv[1].a_un.a_str));
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * This is similar to mdb_print.c's args_to_typename, but it has subtle
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * differences surrounding how the strings of one element are handled that have
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * 'struct', 'enum', or 'union' in them and instead works with them for tab
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur * completion purposes.
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdurmdb_tab_typename(int *argcp, const mdb_arg_t **argvp, char *buf, size_t len)
3b6e0a598869dfc84461624e8699bf51738f68b3Matt Amdur (void) mdb_snprintf(buf, len, "%s", argv[0].a_un.a_str);