[4/5] Add "save skip" command
Commit Message
PR cli/17997 points out that it would sometimes be convenient to save
the current "skip"s to a file. This patch implements this feature.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17997
---
gdb/NEWS | 3 ++
gdb/doc/gdb.texinfo | 6 +++
gdb/skip.c | 78 +++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/skip.exp | 12 +++++
4 files changed, 99 insertions(+)
Comments
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sun, 29 Jan 2023 09:21:04 -0700
>
> PR cli/17997 points out that it would sometimes be convenient to save
> the current "skip"s to a file. This patch implements this feature.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17997
> ---
> gdb/NEWS | 3 ++
> gdb/doc/gdb.texinfo | 6 +++
> gdb/skip.c | 78 +++++++++++++++++++++++++++++++++
> gdb/testsuite/gdb.base/skip.exp | 12 +++++
> 4 files changed, 99 insertions(+)
Thanks, the documentation parts are okay, with one comment:
>
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -6707,6 +6707,12 @@ Set whether to print the debug output about skipping files and functions.
> @item show debug skip
> Show whether the debug output about skipping files and functions is printed.
>
> +@kindex save skip
> +@item save skip @var{filename}
> +Save all skips to the file @var{filename}. This command writes out
> +the skips as a script that can be re-read into @value{GDBN} using the
> +@code{source} command.
I wonder whether this new command should be described before "set/show
debug skip"?
@@ -17,6 +17,9 @@ maintenance print record-instruction [ N ]
prints how GDB would undo the N-th previous instruction, and if N is
positive, it prints how GDB will redo the N-th following instruction.
+save skip FILENAME
+ Save all current "skip"s to the given file.
+
save user FILENAME
Save all user-defined commands to the given file.
@@ -6707,6 +6707,12 @@ Set whether to print the debug output about skipping files and functions.
@item show debug skip
Show whether the debug output about skipping files and functions is printed.
+@kindex save skip
+@item save skip @var{filename}
+Save all skips to the file @var{filename}. This command writes out
+the skips as a script that can be re-read into @value{GDBN} using the
+@code{source} command.
+
@end table
@node Signals
@@ -38,6 +38,8 @@
#include <list>
#include "cli/cli-style.h"
#include "gdbsupport/buildargv.h"
+#include "safe-ctype.h"
+#include "readline/tilde.h"
/* True if we want to print debug printouts related to file/function
skipping. */
@@ -76,6 +78,9 @@ class skiplist_entry
skiplist_entry (const skiplist_entry &) = delete;
void operator= (const skiplist_entry &) = delete;
+ /* Print a gdb command that can be used to recreate this skip. */
+ void print_recreate (ui_file *stream) const;
+
private:
/* Key that grants access to the constructor. */
struct private_key {};
@@ -160,6 +165,54 @@ skiplist_entry::add_entry (bool file_is_glob, std::string &&file,
skiplist_entries.back ().m_number = ++highest_skiplist_entry_num;
}
+/* A helper function for print_recreate that prints a correctly-quoted
+ string to STREAM. */
+
+static void
+print_quoted (ui_file *stream, const std::string &str)
+{
+ gdb_putc ('"', stream);
+ for (char c : str)
+ {
+ if (ISSPACE (c) || c == '\\' || c == '\'' || c == '"')
+ gdb_putc ('\\', stream);
+ gdb_putc (c, stream);
+ }
+ gdb_putc ('"', stream);
+}
+
+void
+skiplist_entry::print_recreate (ui_file *stream) const
+{
+ if (!m_file_is_glob && !m_file.empty ()
+ && !m_function_is_regexp && m_function.empty ())
+ gdb_printf (stream, "skip file %s\n", m_file.c_str ());
+ else if (!m_file_is_glob && m_file.empty ()
+ && !m_function_is_regexp && !m_function.empty ())
+ gdb_printf (stream, "skip function %s\n", m_function.c_str ());
+ else
+ {
+ gdb_printf (stream, "skip ");
+ if (!m_file.empty ())
+ {
+ if (m_file_is_glob)
+ gdb_printf (stream, "-gfile ");
+ else
+ gdb_printf (stream, "-file ");
+ print_quoted (stream, m_file);
+ }
+ if (!m_function.empty ())
+ {
+ if (m_function_is_regexp)
+ gdb_printf (stream, "-rfunction ");
+ else
+ gdb_printf (stream, "-function ");
+ print_quoted (stream, m_function);
+ }
+ gdb_printf (stream, "\n");
+ }
+}
+
static void
skip_file_command (const char *arg, int from_tty)
{
@@ -657,6 +710,24 @@ complete_skip_number (cmd_list_element *cmd,
}
}
+/* Implementation of 'save skip' command. */
+
+static void
+save_skip_command (const char *filename, int from_tty)
+{
+ if (filename == nullptr || *filename == '\0')
+ error (_("Argument required (file name in which to save)"));
+
+ gdb::unique_xmalloc_ptr<char> expanded_filename (tilde_expand (filename));
+ stdio_file fp;
+ if (!fp.open (expanded_filename.get (), "w"))
+ error (_("Unable to open file '%s' for saving (%s)"),
+ expanded_filename.get (), safe_strerror (errno));
+
+ for (const auto &entry : skiplist_entries)
+ entry.print_recreate (&fp);
+}
+
void _initialize_step_skip ();
void
_initialize_step_skip ()
@@ -737,4 +808,11 @@ Show whether the debug output about skipping files and functions is printed."),
When non-zero, debug output about skipping files and functions is displayed."),
NULL, NULL,
&setdebuglist, &showdebuglist);
+
+ c = add_cmd ("skip", no_class, save_skip_command, _("\
+Save current skips as a script.\n\
+Usage: save skip FILE\n\
+Use the 'source' command in another debug session to restore them."),
+ &save_cmdlist);
+ set_cmd_completer (c, filename_completer);
}
@@ -206,6 +206,9 @@ with_test_prefix "admin" {
"4\\s+y\\s+n\\s+<none>\\s+n\\s+baz"] \
"info skip after enabling all"
+ gdb_test_no_output "save skip [standard_output_file skips]" \
+ "save skips to file"
+
gdb_test "skip disable 4 2-3"
gdb_test "info skip" \
[multi_line "Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function" \
@@ -337,3 +340,12 @@ with_test_prefix "skip delete completion" {
test_gdb_complete_none "skip delete 2-33"
}
+clean_restart
+gdb_test "source [standard_output_file skips]" "" \
+ "re-read saved skips"
+gdb_test "info skip" \
+ [multi_line "Num\\s+Enb\\s+Glob\\s+File\\s+RE\\s+Function" \
+ "1\\s+y\\s+n\\s+<none>\\s+n\\s+main" \
+ "2\\s+y\\s+n\\s+$srcfile1\\s+n\\s+<none>" \
+ "3\\s+y\\s+n\\s+<none>\\s+n\\s+baz"] \
+ "info skip after re-reading"