* [PATCH 1/5] Save breakpoints so they are automatically pending
2023-01-29 16:21 [PATCH 0/5] Additions to "save" command Tom Tromey
@ 2023-01-29 16:21 ` Tom Tromey
2023-01-31 15:14 ` Alexandra Petlanova Hajkova
2023-01-29 16:21 ` [PATCH 2/5] Move show_user_1 to cli-cmds.c Tom Tromey
` (3 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2023-01-29 16:21 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
PR breakpoints/18183 points out that breakpoints saved with the "save
breakpoints" command can be slightly inconvenient, depending on "set
breakpoint pending".
This patch makes use of the new "with" command to save breakpoints
such that they will automatically be made pending, if necessary, when
being restored.
Unfortunately, reloading a breakpoint saved this way will also print:
No symbol table is loaded. Use the "file" command.
This seems strange to me, and also a bit useless, but changing
create_breakpoint not to call exception_print in the AUTO_BOOLEAN_TRUE
case caused other regressions, so I've left it as-is for the time
being.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18183
---
gdb/breakpoint.c | 1 +
gdb/testsuite/gdb.base/catch-signal.exp | 10 +++++-----
gdb/testsuite/gdb.base/save-bp.exp | 20 ++++++++++++++++++++
gdb/testsuite/gdb.base/ui-redirect.exp | 7 ++++---
4 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 00cc2ab401c..bd11d26fca4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -14170,6 +14170,7 @@ save_breakpoints (const char *filename, int from_tty,
if (filter && !filter (tp))
continue;
+ fp.puts ("with breakpoint pending on -- ");
tp->print_recreate (&fp);
/* Note, we can't rely on tp->number for anything, as we can't
diff --git a/gdb/testsuite/gdb.base/catch-signal.exp b/gdb/testsuite/gdb.base/catch-signal.exp
index 774eb8ee856..2e3160c2a33 100644
--- a/gdb/testsuite/gdb.base/catch-signal.exp
+++ b/gdb/testsuite/gdb.base/catch-signal.exp
@@ -128,10 +128,10 @@ foreach {arg desc} {"" "standard signals" \
set data [split $file_data "\n"]
close $fd
- if {$arg == ""} {
- set pattern "catch signal"
- } else {
- set pattern "catch signal $arg"
+ set prefix "with breakpoint pending on -- "
+ set pattern "${prefix}catch signal"
+ if {$arg != ""} {
+ append pattern " $arg"
}
gdb_assert {[expr [llength $data] == 3]} \
"Number of lines of save breakpoints for '$arg'"
@@ -139,7 +139,7 @@ foreach {arg desc} {"" "standard signals" \
gdb_assert {[string match $pattern [lindex $data 0]]} \
"1st line of save breakpoints for '$arg'"
# Check the second line.
- gdb_assert {[string match "break main" [lindex $data 1]]} \
+ gdb_assert {[string match "${prefix}break main" [lindex $data 1]]} \
"2nd line of save breakpoints for '$arg'"
# Check the trailing newline.
gdb_assert {[string match "" [lindex $data 2]]} \
diff --git a/gdb/testsuite/gdb.base/save-bp.exp b/gdb/testsuite/gdb.base/save-bp.exp
index a39712c7f5c..daa7509ae8e 100644
--- a/gdb/testsuite/gdb.base/save-bp.exp
+++ b/gdb/testsuite/gdb.base/save-bp.exp
@@ -89,3 +89,23 @@ gdb_test_sequence "info break" "info break" [list \
"\[\r\n\]+\[ \t\]+printf" \
"\[\r\n\]+$disabled_row_start main at \[^\r\n\]*$srcfile:$loc_bp8" \
]
+
+clean_restart
+gdb_test "source $bps" "" "source bps without symbol file"
+
+set pending "\[0-9\]+ +breakpoint +keep +y +<PENDING> +"
+set disabled_pending "\[0-9\]+ +breakpoint +keep +n +<PENDING> +"
+set dprintf_pending "\[0-9\]+ +dprintf +keep +y +<PENDING> +"
+gdb_test_sequence "info break" "info break without symbol file" \
+ [list \
+ "\[\r\n\]+Num +Type +Disp +Enb +Address +What" \
+ "\[\r\n\]+$pending break_me" \
+ "\[\r\n\]+$pending $srcfile:$loc_bp2" \
+ "\[\r\n\]+$pending $srcfile:$loc_bp3 +thread 1" \
+ "\[\r\n\]+$pending $srcfile:$loc_bp4" \
+ "\[\r\n\]+\[ \t\]+stop only if i == 1( \\((host|target) evals\\))?" \
+ "\[\r\n\]+$pending $srcfile:$loc_bp5" \
+ "\[\r\n\]+\[ \t\]+silent" \
+ "\[\r\n\]+$dprintf_pending $srcfile:$loc_bp5," \
+ "\[\r\n\]+$disabled_pending $srcfile:$loc_bp8" \
+ ]
diff --git a/gdb/testsuite/gdb.base/ui-redirect.exp b/gdb/testsuite/gdb.base/ui-redirect.exp
index c0ba4f11809..a95e4fa6e90 100644
--- a/gdb/testsuite/gdb.base/ui-redirect.exp
+++ b/gdb/testsuite/gdb.base/ui-redirect.exp
@@ -42,13 +42,14 @@ gdb_test_no_output "end"
gdb_breakpoint "foo"
gdb_breakpoint "bar"
+set prefix "with breakpoint pending on -- "
set cmds [multi_line_input \
- "break -qualified main" \
+ "${prefix}break -qualified main" \
" commands" \
" print 1" \
" end" \
- "break foo" \
- "break bar"]
+ "${prefix}break foo" \
+ "${prefix}break bar"]
set cmds "$cmds\n"
set outdir [standard_output_file {}]
set cmds_file "$outdir/cmds.txt"
--
2.39.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/5] Save breakpoints so they are automatically pending
2023-01-29 16:21 ` [PATCH 1/5] Save breakpoints so they are automatically pending Tom Tromey
@ 2023-01-31 15:14 ` Alexandra Petlanova Hajkova
0 siblings, 0 replies; 14+ messages in thread
From: Alexandra Petlanova Hajkova @ 2023-01-31 15:14 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1330 bytes --]
On Sun, Jan 29, 2023 at 5:21 PM Tom Tromey <tom@tromey.com> wrote:
> PR breakpoints/18183 points out that breakpoints saved with the "save
> breakpoints" command can be slightly inconvenient, depending on "set
> breakpoint pending".
>
> This patch makes use of the new "with" command to save breakpoints
> such that they will automatically be made pending, if necessary, when
> being restored.
>
> Unfortunately, reloading a breakpoint saved this way will also print:
>
> No symbol table is loaded. Use the "file" command.
>
> This seems strange to me, and also a bit useless, but changing
> create_breakpoint not to call exception_print in the AUTO_BOOLEAN_TRUE
> case caused other regressions, so I've left it as-is for the time
> being.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18183
>
> I've tried this out and I think it's very convenient and makes gdb more
user friendly.
Before this patch:
gdb]$ ./gdb -ex 'b write' /bin/ls
save breakpoints tbb
The pending breakpoint was not reloaded:
gdb]$ ./gdb /bin/ls
(gdb) source tbb
Function "write" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered
N; input not from terminal]
(gdb)
and after applying the patch pending breakpoint is there:
(gdb) source tbb
Function "write" not defined.
Breakpoint 1 (write) pending.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/5] Move show_user_1 to cli-cmds.c
2023-01-29 16:21 [PATCH 0/5] Additions to "save" command Tom Tromey
2023-01-29 16:21 ` [PATCH 1/5] Save breakpoints so they are automatically pending Tom Tromey
@ 2023-01-29 16:21 ` Tom Tromey
2023-01-29 16:21 ` [PATCH 3/5] Add "save user" command Tom Tromey
` (2 subsequent siblings)
4 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2023-01-29 16:21 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
show_user_1 is only called from cli-cmds.c, so move it there and make
it static.
---
gdb/cli/cli-cmds.c | 35 +++++++++++++++++++++++++++++++++++
gdb/cli/cli-script.c | 35 -----------------------------------
gdb/cli/cli-script.h | 5 -----
3 files changed, 35 insertions(+), 40 deletions(-)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 6c0d780face..61f890a7dae 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1643,6 +1643,41 @@ make_command (const char *arg, int from_tty)
}
}
+/* Print the definition of user command C to STREAM. Or, if C is a
+ prefix command, show the definitions of all user commands under C
+ (recursively). PREFIX and NAME combined are the name of the
+ current command. */
+static void
+show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
+ struct ui_file *stream)
+{
+ if (cli_user_command_p (c))
+ {
+ struct command_line *cmdlines = c->user_commands.get ();
+
+ gdb_printf (stream, "User %scommand \"",
+ c->is_prefix () ? "prefix" : "");
+ fprintf_styled (stream, title_style.style (), "%s%s",
+ prefix, name);
+ gdb_printf (stream, "\":\n");
+ if (cmdlines)
+ {
+ print_command_lines (current_uiout, cmdlines, 1);
+ gdb_puts ("\n", stream);
+ }
+ }
+
+ if (c->is_prefix ())
+ {
+ const std::string prefixname = c->prefixname ();
+
+ for (c = *c->subcommands; c != NULL; c = c->next)
+ if (c->theclass == class_user || c->is_prefix ())
+ show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout);
+ }
+
+}
+
static void
show_user (const char *args, int from_tty)
{
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 92005ba8c38..0bd5803dc31 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -1651,41 +1651,6 @@ script_from_file (FILE *stream, const char *file)
}
}
-/* Print the definition of user command C to STREAM. Or, if C is a
- prefix command, show the definitions of all user commands under C
- (recursively). PREFIX and NAME combined are the name of the
- current command. */
-void
-show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
- struct ui_file *stream)
-{
- if (cli_user_command_p (c))
- {
- struct command_line *cmdlines = c->user_commands.get ();
-
- gdb_printf (stream, "User %scommand \"",
- c->is_prefix () ? "prefix" : "");
- fprintf_styled (stream, title_style.style (), "%s%s",
- prefix, name);
- gdb_printf (stream, "\":\n");
- if (cmdlines)
- {
- print_command_lines (current_uiout, cmdlines, 1);
- gdb_puts ("\n", stream);
- }
- }
-
- if (c->is_prefix ())
- {
- const std::string prefixname = c->prefixname ();
-
- for (c = *c->subcommands; c != NULL; c = c->next)
- if (c->theclass == class_user || c->is_prefix ())
- show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout);
- }
-
-}
-
void _initialize_cli_script ();
void
_initialize_cli_script ()
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index da7307bbf8d..67ef0bb672e 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -130,11 +130,6 @@ extern counted_command_line read_command_lines_1
extern void script_from_file (FILE *stream, const char *file);
-extern void show_user_1 (struct cmd_list_element *c,
- const char *prefix,
- const char *name,
- struct ui_file *stream);
-
/* Execute the commands in CMDLINES. */
extern void execute_control_commands (struct command_line *cmdlines,
--
2.39.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3/5] Add "save user" command
2023-01-29 16:21 [PATCH 0/5] Additions to "save" command Tom Tromey
2023-01-29 16:21 ` [PATCH 1/5] Save breakpoints so they are automatically pending Tom Tromey
2023-01-29 16:21 ` [PATCH 2/5] Move show_user_1 to cli-cmds.c Tom Tromey
@ 2023-01-29 16:21 ` Tom Tromey
2023-01-29 16:57 ` Eli Zaretskii
2023-01-30 14:53 ` Pedro Alves
2023-01-29 16:21 ` [PATCH 4/5] Add "save skip" command Tom Tromey
2023-01-29 16:21 ` [PATCH 5/5] Add "save history" command Tom Tromey
4 siblings, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2023-01-29 16:21 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
PR cli/19395 points out that it would sometimes be convenient to save
one's user-defined commands to a file. This patch implements this
feature.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19395
---
gdb/NEWS | 3 ++
gdb/cli/cli-cmds.c | 72 +++++++++++++++++++++++++++++++++++++--------
gdb/doc/gdb.texinfo | 6 ++++
3 files changed, 68 insertions(+), 13 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 2bc1672632a..3b7d768732c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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 user FILENAME
+ Save all user-defined commands to the given file.
+
* MI changes
** mi now reports 'no-history' as a stop reason when hitting the end of the
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 61f890a7dae..3f488d1a544 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -51,6 +51,7 @@
#include "cli/cli-style.h"
#include "cli/cli-utils.h"
#include "cli/cli-style.h"
+#include "cli-out.h"
#include "extension.h"
#include "gdbsupport/pathstuff.h"
@@ -1646,24 +1647,41 @@ make_command (const char *arg, int from_tty)
/* Print the definition of user command C to STREAM. Or, if C is a
prefix command, show the definitions of all user commands under C
(recursively). PREFIX and NAME combined are the name of the
- current command. */
+ current command. DEF is true if the output should be written as a
+ source-able script. */
static void
show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
- struct ui_file *stream)
+ struct ui_file *stream, struct ui_out *uiout, bool def)
{
if (cli_user_command_p (c))
{
struct command_line *cmdlines = c->user_commands.get ();
- gdb_printf (stream, "User %scommand \"",
- c->is_prefix () ? "prefix" : "");
- fprintf_styled (stream, title_style.style (), "%s%s",
- prefix, name);
- gdb_printf (stream, "\":\n");
+ if (def)
+ gdb_printf (stream, "define%s %s%s\n",
+ c->is_prefix () ? "-prefix" : "",
+ prefix, name);
+ else
+ {
+ gdb_printf (stream, "User %scommand \"",
+ c->is_prefix () ? "prefix" : "");
+ fprintf_styled (stream, title_style.style (), "%s%s",
+ prefix, name);
+ gdb_printf (stream, "\":\n");
+ }
if (cmdlines)
{
- print_command_lines (current_uiout, cmdlines, 1);
- gdb_puts ("\n", stream);
+ print_command_lines (uiout, cmdlines, 1);
+ if (!def)
+ gdb_puts ("\n", stream);
+ }
+ if (def)
+ {
+ gdb_puts ("end\n", stream);
+
+ if (!c->is_prefix () && !streq (c->doc, "User-defined."))
+ gdb_printf (stream, "document %s%s\n%s\nend\n",
+ prefix, name, c->doc);
}
}
@@ -1673,9 +1691,8 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
for (c = *c->subcommands; c != NULL; c = c->next)
if (c->theclass == class_user || c->is_prefix ())
- show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout);
+ show_user_1 (c, prefixname.c_str (), c->name, stream, uiout, def);
}
-
}
static void
@@ -1690,18 +1707,40 @@ show_user (const char *args, int from_tty)
c = lookup_cmd (&comname, cmdlist, "", NULL, 0, 1);
if (!cli_user_command_p (c))
error (_("Not a user command."));
- show_user_1 (c, "", args, gdb_stdout);
+ show_user_1 (c, "", args, gdb_stdout, current_uiout, false);
}
else
{
for (c = cmdlist; c; c = c->next)
{
if (cli_user_command_p (c) || c->is_prefix ())
- show_user_1 (c, "", c->name, gdb_stdout);
+ show_user_1 (c, "", c->name, gdb_stdout, current_uiout, false);
}
}
}
+/* The "save user" command. */
+
+static void
+save_user_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));
+
+ cli_ui_out uiout (&fp);
+ for (struct cmd_list_element *c = cmdlist; c != nullptr; c = c->next)
+ {
+ if (cli_user_command_p (c) || c->is_prefix ())
+ show_user_1 (c, "", c->name, &fp, &uiout, true);
+ }
+}
+
/* Return true if COMMAND or any of its sub-commands is a user defined command.
This is a helper function for show_user_completer. */
@@ -2762,6 +2801,13 @@ Usage: apropos [-v] REGEXP\n\
Flag -v indicates to produce a verbose output, showing full documentation\n\
of the matching commands."));
+ c = add_cmd ("user", no_class, save_user_command, _("\
+Save current user-defined commands as a script.\n\
+Usage: save user FILE\n\
+Use the 'source' command in another debug session to restore them."),
+ &save_cmdlist);
+ set_cmd_completer (c, filename_completer);
+
add_setshow_uinteger_cmd ("max-user-call-depth", no_class,
&max_user_call_depth, _("\
Set the max call depth for non-python/scheme user-defined commands."), _("\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b5fad2cb16e..37db4785fd2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -28230,6 +28230,12 @@ The value of @code{max-user-call-depth} controls how many recursion
levels are allowed in user-defined commands before @value{GDBN} suspects an
infinite recursion and aborts the command.
This does not apply to user-defined python commands.
+
+@kindex save user
+@item save user @var{filename}
+Save all user-defined commands to the file @var{filename}. This
+command writes out the user-defined commands as a script that can be
+re-read into @value{GDBN} using the @code{source} command.
@end table
In addition to the above commands, user-defined commands frequently
--
2.39.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/5] Add "save user" command
2023-01-29 16:21 ` [PATCH 3/5] Add "save user" command Tom Tromey
@ 2023-01-29 16:57 ` Eli Zaretskii
2023-01-30 14:53 ` Pedro Alves
1 sibling, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2023-01-29 16:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sun, 29 Jan 2023 09:21:03 -0700
>
> PR cli/19395 points out that it would sometimes be convenient to save
> one's user-defined commands to a file. This patch implements this
> feature.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19395
> ---
> gdb/NEWS | 3 ++
> gdb/cli/cli-cmds.c | 72 +++++++++++++++++++++++++++++++++++++--------
> gdb/doc/gdb.texinfo | 6 ++++
> 3 files changed, 68 insertions(+), 13 deletions(-)
OK for the documentation parts, thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/5] Add "save user" command
2023-01-29 16:21 ` [PATCH 3/5] Add "save user" command Tom Tromey
2023-01-29 16:57 ` Eli Zaretskii
@ 2023-01-30 14:53 ` Pedro Alves
2023-01-30 23:35 ` Tom Tromey
1 sibling, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2023-01-30 14:53 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 2023-01-29 4:21 p.m., Tom Tromey wrote:
> PR cli/19395 points out that it would sometimes be convenient to save
> one's user-defined commands to a file. This patch implements this
> feature.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19395
Could we have a testcase for this?
Pedro Alves
> ---
> gdb/NEWS | 3 ++
> gdb/cli/cli-cmds.c | 72 +++++++++++++++++++++++++++++++++++++--------
> gdb/doc/gdb.texinfo | 6 ++++
> 3 files changed, 68 insertions(+), 13 deletions(-)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 2bc1672632a..3b7d768732c 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -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 user FILENAME
> + Save all user-defined commands to the given file.
> +
> * MI changes
>
> ** mi now reports 'no-history' as a stop reason when hitting the end of the
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index 61f890a7dae..3f488d1a544 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -51,6 +51,7 @@
> #include "cli/cli-style.h"
> #include "cli/cli-utils.h"
> #include "cli/cli-style.h"
> +#include "cli-out.h"
>
> #include "extension.h"
> #include "gdbsupport/pathstuff.h"
> @@ -1646,24 +1647,41 @@ make_command (const char *arg, int from_tty)
> /* Print the definition of user command C to STREAM. Or, if C is a
> prefix command, show the definitions of all user commands under C
> (recursively). PREFIX and NAME combined are the name of the
> - current command. */
> + current command. DEF is true if the output should be written as a
> + source-able script. */
> static void
> show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
> - struct ui_file *stream)
> + struct ui_file *stream, struct ui_out *uiout, bool def)
> {
> if (cli_user_command_p (c))
> {
> struct command_line *cmdlines = c->user_commands.get ();
>
> - gdb_printf (stream, "User %scommand \"",
> - c->is_prefix () ? "prefix" : "");
> - fprintf_styled (stream, title_style.style (), "%s%s",
> - prefix, name);
> - gdb_printf (stream, "\":\n");
> + if (def)
> + gdb_printf (stream, "define%s %s%s\n",
> + c->is_prefix () ? "-prefix" : "",
> + prefix, name);
> + else
> + {
> + gdb_printf (stream, "User %scommand \"",
> + c->is_prefix () ? "prefix" : "");
> + fprintf_styled (stream, title_style.style (), "%s%s",
> + prefix, name);
> + gdb_printf (stream, "\":\n");
> + }
> if (cmdlines)
> {
> - print_command_lines (current_uiout, cmdlines, 1);
> - gdb_puts ("\n", stream);
> + print_command_lines (uiout, cmdlines, 1);
> + if (!def)
> + gdb_puts ("\n", stream);
> + }
> + if (def)
> + {
> + gdb_puts ("end\n", stream);
> +
> + if (!c->is_prefix () && !streq (c->doc, "User-defined."))
> + gdb_printf (stream, "document %s%s\n%s\nend\n",
> + prefix, name, c->doc);
> }
> }
>
> @@ -1673,9 +1691,8 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
>
> for (c = *c->subcommands; c != NULL; c = c->next)
> if (c->theclass == class_user || c->is_prefix ())
> - show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout);
> + show_user_1 (c, prefixname.c_str (), c->name, stream, uiout, def);
> }
> -
> }
>
> static void
> @@ -1690,18 +1707,40 @@ show_user (const char *args, int from_tty)
> c = lookup_cmd (&comname, cmdlist, "", NULL, 0, 1);
> if (!cli_user_command_p (c))
> error (_("Not a user command."));
> - show_user_1 (c, "", args, gdb_stdout);
> + show_user_1 (c, "", args, gdb_stdout, current_uiout, false);
> }
> else
> {
> for (c = cmdlist; c; c = c->next)
> {
> if (cli_user_command_p (c) || c->is_prefix ())
> - show_user_1 (c, "", c->name, gdb_stdout);
> + show_user_1 (c, "", c->name, gdb_stdout, current_uiout, false);
> }
> }
> }
>
> +/* The "save user" command. */
> +
> +static void
> +save_user_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));
> +
> + cli_ui_out uiout (&fp);
> + for (struct cmd_list_element *c = cmdlist; c != nullptr; c = c->next)
> + {
> + if (cli_user_command_p (c) || c->is_prefix ())
> + show_user_1 (c, "", c->name, &fp, &uiout, true);
> + }
> +}
> +
> /* Return true if COMMAND or any of its sub-commands is a user defined command.
> This is a helper function for show_user_completer. */
>
> @@ -2762,6 +2801,13 @@ Usage: apropos [-v] REGEXP\n\
> Flag -v indicates to produce a verbose output, showing full documentation\n\
> of the matching commands."));
>
> + c = add_cmd ("user", no_class, save_user_command, _("\
> +Save current user-defined commands as a script.\n\
> +Usage: save user FILE\n\
> +Use the 'source' command in another debug session to restore them."),
> + &save_cmdlist);
> + set_cmd_completer (c, filename_completer);
> +
> add_setshow_uinteger_cmd ("max-user-call-depth", no_class,
> &max_user_call_depth, _("\
> Set the max call depth for non-python/scheme user-defined commands."), _("\
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index b5fad2cb16e..37db4785fd2 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -28230,6 +28230,12 @@ The value of @code{max-user-call-depth} controls how many recursion
> levels are allowed in user-defined commands before @value{GDBN} suspects an
> infinite recursion and aborts the command.
> This does not apply to user-defined python commands.
> +
> +@kindex save user
> +@item save user @var{filename}
> +Save all user-defined commands to the file @var{filename}. This
> +command writes out the user-defined commands as a script that can be
> +re-read into @value{GDBN} using the @code{source} command.
> @end table
>
> In addition to the above commands, user-defined commands frequently
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/5] Add "save skip" command
2023-01-29 16:21 [PATCH 0/5] Additions to "save" command Tom Tromey
` (2 preceding siblings ...)
2023-01-29 16:21 ` [PATCH 3/5] Add "save user" command Tom Tromey
@ 2023-01-29 16:21 ` Tom Tromey
2023-01-29 16:54 ` Eli Zaretskii
2023-01-29 16:21 ` [PATCH 5/5] Add "save history" command Tom Tromey
4 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2023-01-29 16:21 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
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(+)
diff --git a/gdb/NEWS b/gdb/NEWS
index 3b7d768732c..a5b6f8df2ff 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 37db4785fd2..31f73c33894 100644
--- 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.
+
@end table
@node Signals
diff --git a/gdb/skip.c b/gdb/skip.c
index f3b1bec9e4c..5f98df803f9 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -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);
}
diff --git a/gdb/testsuite/gdb.base/skip.exp b/gdb/testsuite/gdb.base/skip.exp
index 41c811b9769..4b4e890ea21 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+<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"
--
2.39.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/5] Add "save skip" command
2023-01-29 16:21 ` [PATCH 4/5] Add "save skip" command Tom Tromey
@ 2023-01-29 16:54 ` Eli Zaretskii
0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2023-01-29 16:54 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> 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"?
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 5/5] Add "save history" command
2023-01-29 16:21 [PATCH 0/5] Additions to "save" command Tom Tromey
` (3 preceding siblings ...)
2023-01-29 16:21 ` [PATCH 4/5] Add "save skip" command Tom Tromey
@ 2023-01-29 16:21 ` Tom Tromey
2023-01-29 16:56 ` Eli Zaretskii
2023-01-30 14:50 ` Pedro Alves
4 siblings, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2023-01-29 16:21 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
PR cli/23664 points out that it would sometimes be convenient to
immediately save the current history to a file. This patch implements
this feature.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23664
---
gdb/NEWS | 3 +++
gdb/doc/gdb.texinfo | 8 ++++++
gdb/testsuite/gdb.base/save-history.exp | 36 +++++++++++++++++++++++++
gdb/top.c | 18 +++++++++++++
4 files changed, 65 insertions(+)
create mode 100644 gdb/testsuite/gdb.base/save-history.exp
diff --git a/gdb/NEWS b/gdb/NEWS
index a5b6f8df2ff..0003dfc9bcb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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 history FILENAME
+ Save the command history to the given file.
+
save skip FILENAME
Save all current "skip"s to the given file.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 31f73c33894..5ba8fbc5d16 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -26588,6 +26588,14 @@ removal of duplicate history entries is disabled.
Only history entries added during the current session are considered for
removal. This option is set to 0 by default.
+@kindex save history
+@item save history @var{filename}
+Occasionally you may want to save your history to a file. This
+command will do just that, saving the commands in your current session
+to the named file. Note that you should normally edit the saved
+history before using @code{source} to reload it, as the @code{save
+history} command itself will be at the end of the file.
+
@end table
History expansion assigns special meaning to the character @kbd{!}.
diff --git a/gdb/testsuite/gdb.base/save-history.exp b/gdb/testsuite/gdb.base/save-history.exp
new file mode 100644
index 00000000000..bb7a56b2a72
--- /dev/null
+++ b/gdb/testsuite/gdb.base/save-history.exp
@@ -0,0 +1,36 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test the "save history" command.
+
+require {!is_remote host}
+
+gdb_start
+
+# Get something in history.
+gdb_test "print 23" " = 23"
+
+set filename [standard_output_file histfile]
+gdb_test_no_output "save history $filename" \
+ "save history"
+
+set expected "set height 0\n"
+append expected "set width 0\n"
+append expected "print 23\n"
+append expected "save history $filename\n"
+
+cmp_file_string $filename $expected "check history contents"
diff --git a/gdb/top.c b/gdb/top.c
index 205eb360ba3..f0c285e5989 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1325,6 +1325,18 @@ gdb_safe_append_history (void)
}
}
+/* Implementation of 'save history' command. */
+
+static void
+save_history_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));
+ write_history (expanded_filename.get ());
+}
+
/* Read one line from the command input stream `instream'.
CMD_LINE_BUFFER is a buffer that the function may use to store the result, if
@@ -2277,6 +2289,12 @@ Without an argument, saving is enabled."),
show_write_history_p,
&sethistlist, &showhistlist);
+ c = add_cmd ("history", no_class, save_history_command, _("\
+Save current history as a script.\n\
+Usage: save history FILE"),
+ &save_cmdlist);
+ set_cmd_completer (c, filename_completer);
+
add_setshow_zuinteger_unlimited_cmd ("size", no_class,
&history_size_setshow_var, _("\
Set the size of the command history."), _("\
--
2.39.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/5] Add "save history" command
2023-01-29 16:21 ` [PATCH 5/5] Add "save history" command Tom Tromey
@ 2023-01-29 16:56 ` Eli Zaretskii
2023-01-30 14:50 ` Pedro Alves
1 sibling, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2023-01-29 16:56 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sun, 29 Jan 2023 09:21:05 -0700
>
> PR cli/23664 points out that it would sometimes be convenient to
> immediately save the current history to a file. This patch implements
> this feature.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23664
> ---
> gdb/NEWS | 3 +++
> gdb/doc/gdb.texinfo | 8 ++++++
> gdb/testsuite/gdb.base/save-history.exp | 36 +++++++++++++++++++++++++
> gdb/top.c | 18 +++++++++++++
> 4 files changed, 65 insertions(+)
> create mode 100644 gdb/testsuite/gdb.base/save-history.exp
The documentation parts are okay, thanks.
> +Occasionally you may want to save your history to a file. This
> +command will do just that, saving the commands in your current session
> +to the named file. Note that you should normally edit the saved
> +history before using @code{source} to reload it, as the @code{save
> +history} command itself will be at the end of the file.
What is the rationale for saving the "save history" command as well?
Are there any circumstances when the user might want that?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/5] Add "save history" command
2023-01-29 16:21 ` [PATCH 5/5] Add "save history" command Tom Tromey
2023-01-29 16:56 ` Eli Zaretskii
@ 2023-01-30 14:50 ` Pedro Alves
2023-01-30 15:12 ` Pedro Alves
1 sibling, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2023-01-30 14:50 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 2023-01-29 4:21 p.m., Tom Tromey wrote:
>
> +@kindex save history
> +@item save history @var{filename}
> +Occasionally you may want to save your history to a file. This
> +command will do just that, saving the commands in your current session
> +to the named file. Note that you should normally edit the saved
> +history before using @code{source} to reload it, as the @code{save
> +history} command itself will be at the end of the file.
We could also suggest using "server save history" here. Something like,
"Alternatively, you can use the server prefix to blah, blah. @xref."
Prefixing a comment with "server" makes it so that it won't be added to
the history:
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Server-Prefix.html
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/5] Add "save history" command
2023-01-30 14:50 ` Pedro Alves
@ 2023-01-30 15:12 ` Pedro Alves
0 siblings, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2023-01-30 15:12 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 2023-01-30 2:50 p.m., Pedro Alves wrote:
> On 2023-01-29 4:21 p.m., Tom Tromey wrote:
>>
>> +@kindex save history
>> +@item save history @var{filename}
>> +Occasionally you may want to save your history to a file. This
>> +command will do just that, saving the commands in your current session
>> +to the named file. Note that you should normally edit the saved
>> +history before using @code{source} to reload it, as the @code{save
>> +history} command itself will be at the end of the file.
>
> We could also suggest using "server save history" here. Something like,
> "Alternatively, you can use the server prefix to blah, blah. @xref."
>
> Prefixing a comment with "server" makes it so that it won't be added to
> the history:
>
> https://sourceware.org/gdb/current/onlinedocs/gdb.html/Server-Prefix.html
>
An alternative idea would be to make use of the fact that history entries are
already numbered, and to let the user say which history entry range to save.
E.g., we have:
(gdb) help show commands
Show the history of commands you typed.
You can supply a command number to start with, or a `+' to start after
the previous command number shown.
and, e.g., I see currently:
(gdb) show commands
1016 q
1017 q
1018 p 1
1019 p 2
1020 p 3
1021 show commands
1022 p 4
1023 p 5
1024 apropos history
1025 show commands
so we could support something like:
(gdb) save history $filename 1020 1025 # save from 1020 to 1025
(gdb) save history $filename 1020 # save from 1020 to $end
(gdb) save history $filename -5 # save from 1020 ($last - 5) to end
(gdb) save history $filename -5 -1 # save from 1020 ($last - 5) to 1024 ($last - 1)
or whatever other syntax makes sense and achieves a similar effect.
Being able to save just the last N entries seems like a useful feature.
^ permalink raw reply [flat|nested] 14+ messages in thread