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

Mike Frysinger
2012-08-02T03:54:08Z

The command line completion has spoiled me. Thus the lack of completion with
the "handle" command annoys me. Patch!

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
- improves the "signal" and "handle" help strings slightly

Signed-off-by: Mike Frysinger <vapier@gentoo.org>

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.
* 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 | 3 ++-
gdb/infrun.c | 35 +++++++++++++++++++++++++++++++++--
4 files changed, 94 insertions(+), 3 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;
+}
+
/* 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..9eaab06 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -3018,7 +3018,8 @@ all targets."));

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."));

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. */
+ 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));
+ }
+}
+
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\
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, _("\