Re: [patch v2] gdb: add completion handler for "handle"

Pedro Alves
2012-08-02T11:24:38Z

On 08/02/2012 04:58 AM, Mike Frysinger wrote:
> The command line completion has spoiled me. Thus the lack of completion with
> the "handle" command annoys me. Patch!

Nice!

> This does a few things:
> - adds a generic signal completer
> - adds a generic completer based on a specified array of strings
> - adds a completion handler for the "handle" command
> - adds a completion handler for the "signal" command
> - improves the "signal" and "handle" help strings slightly
>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
>
> v2
> - i'm dumb and realized that the "signal" command could easily use the
> new signal completer too
>
> 2012-08-01 Mike Frysinger <vapier@gentoo.org>
>
> * completer.c: Include gdb_signals.h.
> (signal_completer): Define.
> (string_array_completer): Define.
> * completer.h (signal_completer): Add prototype.
> (string_array_completer): Likewise.
> * infcmd.c (_initialize_infcmd): Add a reference to "handle"
> in the "string" documentation. Assign the command
> completer for "signal" to handle_completer.
> * infrun.c: Include completer.h.
> (handle_completer): Define.
> (_initialize_infrun): Declare a new local variable c. Store the
> result of add_com("handle") to it. Add simple usage to
> the start of the "handle" documentation. Assign the command
> completer for "handle" to handle_completer.
>
> gdb/completer.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/completer.h | 7 +++++++
> gdb/infcmd.c | 6 ++++--
> gdb/infrun.c | 35 +++++++++++++++++++++++++++++++++--
> 4 files changed, 96 insertions(+), 4 deletions(-)
>
> diff --git a/gdb/completer.c b/gdb/completer.c
> index b9f0699..1d81e36 100644
> --- a/gdb/completer.c
> +++ b/gdb/completer.c
> @@ -24,6 +24,7 @@
> #include "language.h"
> #include "gdb_assert.h"
> #include "exceptions.h"
> +#include "gdb_signals.h"
>
> #include "cli/cli-decode.h"
>
> @@ -797,6 +798,57 @@ command_completer (struct cmd_list_element *ignore,
> strlen (text), handle_help);
> }
>
> +/* Complete on signals. */
> +
> +VEC (char_ptr) *
> +signal_completer (struct cmd_list_element *ignore,
> + char *text, char *word)
> +{
> + int i;
> + VEC (char_ptr) *return_val = NULL;
> + size_t len = strlen (word);
> + enum gdb_signal signum;
> + const char *signame;
> +
> + for (signum = GDB_SIGNAL_FIRST; signum != GDB_SIGNAL_LAST; ++signum)
> + {
> + /* Can't handle this, so skip it. */
> + if (signum == GDB_SIGNAL_0)
> + continue;
> +
> + signame = gdb_signal_to_name (signum);
> +
> + /* Ignore the unknown signal case. */
> + if (!signame || strcmp (signame, "?") == 0)
> + continue;
> +
> + if (strncasecmp (signame, word, len) == 0)
> + VEC_safe_push (char_ptr, return_val, xstrdup (signame));
> + }
> +
> + return return_val;
> +}
> +
> +/* Complete based on an array of strings. */
> +
> +VEC (char_ptr) *
> +string_array_completer (struct cmd_list_element *ignore,
> + char *text, char *word, const char * const strings[],
> + size_t num_strings)
> +{
> + size_t i;
> + VEC (char_ptr) *return_val = NULL;
> + size_t len = strlen (word);
> +
> + for (i = 0; i < num_strings; ++i)
> + {
> + if (strncasecmp (strings[i], word, len) == 0)
> + VEC_safe_push (char_ptr, return_val, xstrdup (strings[i]));
> + }
> +
> + return return_val;
> +}
> +

See complete_on_enum.

> /* Get the list of chars that are considered as word breaks
> for the current command. */
>
> diff --git a/gdb/completer.h b/gdb/completer.h
> index 680bc2d..fa1b213 100644
> --- a/gdb/completer.h
> +++ b/gdb/completer.h
> @@ -41,6 +41,13 @@ extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
> extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
> char *, char *);
>
> +extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
> + char *, char *);
> +
> +extern VEC (char_ptr) *string_array_completer (struct cmd_list_element *,
> + char *, char *,
> + const char * const[], size_t);
> +
> extern char *get_gdb_completer_quote_characters (void);
>
> extern char *gdb_completion_word_break_characters (void);
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 635e577..b76ee96 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -3016,9 +3016,11 @@ Disconnect from a target.\n\
> The target will wait for another debugger to connect. Not available for\n\
> all targets."));
>
> - add_com ("signal", class_run, signal_command, _("\
> + c = add_com ("signal", class_run, signal_command, _("\
> Continue program giving it signal specified by the argument.\n\
> -An argument of \"0\" means continue program without giving it a signal."));
> +An argument of \"0\" means continue program without giving it a signal.\n\
> +Use the \"handle\" command to automate signal behavior."));
> + set_cmd_completer (c, signal_completer);
>
> add_com ("stepi", class_run, stepi_command, _("\
> Step one instruction exactly.\n\
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index efc4162..19fa6ac 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -57,6 +57,7 @@
> #include "skip.h"
> #include "probe.h"
> #include "objfiles.h"
> +#include "completer.h"
>
> /* Prototypes for local functions */
>
> @@ -6416,6 +6417,34 @@ Are you sure you want to change it? "),
> do_cleanups (old_chain);
> }
>
> +/* Complete the "handle" command. */
> +
> +static VEC (char_ptr) *
> +handle_completer (struct cmd_list_element *ignore,
> + char *text, char *word)
> +{
> + /* First word is a signal, while the rest are keywords. */

Actually, "handle" accepts more than one signal. E.g.,

(gdb) handle SIGCANCEL SIGABRT stop
Signal Stop Print Pass to program Description
SIGABRT Yes Yes Yes Aborted
SIGCANCEL Yes Yes Yes LWP internal signal

Can we make that work? Basically, for all but the first arg, you'd
accept the union of the signal names, and the possible actions.

> + if (text == word)
> + return signal_completer (ignore, text, word);
> + else
> + {
> + static const char * const keywords[] =
> + {
> + "all",
> + "stop",
> + "ignore",
> + "print",
> + "pass",
> + "nostop",
> + "noignore",
> + "noprint",
> + "nopass",
> + };
> + return string_array_completer (ignore, text, word, keywords,
> + ARRAY_SIZE (keywords));

You can use the existing complete_on_enum instead. (Just add a NULL terminator
to the string array.)

> + }
> +}
> +
> static void
> xdb_handle_command (char *args, int from_tty)
> {
> @@ -7059,14 +7088,15 @@ _initialize_infrun (void)
> {
> int i;
> int numsigs;
> + struct cmd_list_element *c;
>
> add_info ("signals", signals_info, _("\
> What debugger does when program gets various signals.\n\
> Specify a signal as argument to print info on that signal only."));
> add_info_alias ("handle", "signals", 0);
>
> - add_com ("handle", class_run, handle_command, _("\
> -Specify how to handle a signal.\n\
> + c = add_com ("handle", class_run, handle_command, _("\
> +Handle signals: handle SIGNAL [KEYWORDS]\n\
> Args are signals and actions to apply to those signals.\n\

The first line of the doc is special. It's what "apropos" shows.

before:
(gdb) apropos signals
handle -- Specify how to handle a signal
info handle -- What debugger does when program gets various signals
info signals -- What debugger does when program gets various signals

after:
(gdb) apropos signals
handle -- Handle signals: handle SIGNAL [KEYWORDS]
info handle -- What debugger does when program gets various signals
info signals -- What debugger does when program gets various signals

The old strings looked better here to me.

This and the "signal" docu change are a bit of a tangent wrt completion,
so split them out, please.

> Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\
> from 1-15 are allowed for compatibility with old versions of GDB.\n\
> @@ -7080,6 +7110,7 @@ Print means print a message if this signal happens.\n\
> Pass means let program see this signal; otherwise program doesn't know.\n\
> Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
> Pass and Stop may be combined."));
> + set_cmd_completer (c, handle_completer);
> if (xdb_commands)
> {
> add_com ("lz", class_info, signals_info, _("\
>

--
Pedro Alves