From: Tom Tromey Date: Tue, 24 Jan 2023 00:04:55 +0000 (-0700) Subject: Add "save skip" command X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=26c04da2e64c99f3ecefdf3a3354ec718b40071f;p=thirdparty%2Fbinutils-gdb.git Add "save skip" command 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 Reviewed-By: Eli Zaretskii Reviewed-By: Keith Seitz --- diff --git a/gdb/NEWS b/gdb/NEWS index e9a8022bdfa..888d1a468b3 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -81,6 +81,9 @@ unset local-environment environment. The local environment is used by "shell", "pipe", and other commands that launch a subprocess other than an inferior. +save skip FILENAME + Save all current "skip"s to the given file. + save user FILENAME Save all user-defined commands to the given file. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 5d90785be4a..92e73664281 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -7070,6 +7070,12 @@ skips. Disable the specified skip(s). If @var{range} is not specified, disable all skips. +@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. + @kindex set debug skip @item set debug skip @r{[}on|off@r{]} Set whether to print the debug output about skipping files and functions. diff --git a/gdb/skip.c b/gdb/skip.c index f4156d93d40..ea8e9a210af 100644 --- a/gdb/skip.c +++ b/gdb/skip.c @@ -38,6 +38,8 @@ #include #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. */ @@ -72,6 +74,9 @@ public: void enable () { m_enabled = true; }; void disable () { m_enabled = false; }; + /* 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 {}; @@ -159,6 +164,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) { @@ -656,6 +709,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 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); +} + INIT_GDB_FILE (step_skip) { static struct cmd_list_element *skiplist = NULL; @@ -734,4 +805,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, deprecated_filename_completer); } diff --git a/gdb/testsuite/gdb.base/skip.exp b/gdb/testsuite/gdb.base/skip.exp index 4541e61ec00..ea9eaf9c0e5 100644 --- a/gdb/testsuite/gdb.base/skip.exp +++ b/gdb/testsuite/gdb.base/skip.exp @@ -206,6 +206,9 @@ with_test_prefix "admin" { "4\\s+y\\s+n\\s+\\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" \ @@ -336,3 +339,13 @@ with_test_prefix "skip delete completion" { test_gdb_complete_none "skip delete a1" 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+\\s+n\\s+main" \ + "2\\s+y\\s+n\\s+$srcfile1\\s+n\\s+" \ + "3\\s+y\\s+n\\s+\\s+n\\s+baz"] \ + "info skip after re-reading"