diff options
-rw-r--r-- | gdb/ChangeLog | 27 | ||||
-rw-r--r-- | gdb/NEWS | 15 | ||||
-rw-r--r-- | gdb/cli/cli-cmds.c | 134 | ||||
-rw-r--r-- | gdb/cli/cli-cmds.h | 15 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.c | 74 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.h | 5 | ||||
-rw-r--r-- | gdb/command.h | 19 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 100 | ||||
-rw-r--r-- | gdb/maint.c | 28 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/with.c | 41 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/with.exp | 289 | ||||
-rw-r--r-- | gdb/top.c | 7 |
14 files changed, 717 insertions, 50 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4f74038..adc56b4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,32 @@ 2019-07-03 Pedro Alves <palves@redhat.com> + * NEWS (New commands): Mention "with" and "maint with". + * cli/cli-cmds.c (with_command_1, with_command_completer_1) + (with_command, with_command_completer): New. + (pipe_command): Adjust to new repeat_previous + interface. + (_initialize_cli_cmds): Install the "with" command and its "w" + alias. + * cli/cli-cmds.h (with_command_1, with_command_completer_1): New + declarations. + * cli/cli-setshow.c (parse_cli_var_uinteger) + (parse_cli_var_zuinteger_unlimited, do_set_command): Handle empty + argument strings for all var_types. + (get_setshow_command_value_string): New, factored out from ... + (do_show_command): ... this. + * cli/cli-setshow.h: Include <string>. + (get_setshow_command_value_string): Declare. + * command.h (repeat_previous): Now returns const char *. Adjust + comment. + * maint.c: Include "cli/cli-cmds.h". + (maintenance_with_cmd, maintenance_with_cmd_completer): New. + (_initialize_maint_cmds): Register the "maintenance with" command. + * top.c (repeat_previous): Move bits from pipe_command here: + Return the saved command line, if any; error out if there's no + command to relaunch. + +2019-07-03 Pedro Alves <palves@redhat.com> + * NEWS (New commands): Mention "maint set/show test-settings" instead of "maint test-settings". * maint-test-settings.c (maintenance_test_settings_list): Delete. @@ -46,6 +46,21 @@ pipe -d DELIM COMMAND DELIM SHELL_COMMAND With no COMMAND, repeat the last executed command and send its output to SHELL_COMMAND. +with SETTING [VALUE] [-- COMMAND] +w SETTING [VALUE] [-- COMMAND] + Temporarily set SETTING, run COMMAND, and restore SETTING. + Usage: with SETTING -- COMMAND + With no COMMAND, repeats the last executed command. + SETTING is any GDB setting you can change with the "set" + subcommands. For example, 'with language c -- print someobj' + temporarily switches to the C language in order to print someobj. + Settings can be combined: 'w lang c -- w print elements unlimited -- + usercmd' switches to the C language and runs usercmd with no limit + of array elements to print. + +maint with SETTING [VALUE] [-- COMMAND] + Like "with", but works with "maintenance set" settings. + set may-call-functions [on|off] show may-call-functions This controls whether GDB will attempt to call functions in diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 5124ab3..d1ecd62 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -211,6 +211,116 @@ show_command (const char *arg, int from_tty) cmd_show_list (showlist, from_tty, ""); } +/* See cli/cli-cmds.h. */ + +void +with_command_1 (const char *set_cmd_prefix, + cmd_list_element *setlist, const char *args, int from_tty) +{ + const char *delim = strstr (args, "--"); + const char *nested_cmd = nullptr; + + if (delim == args) + error (_("Missing setting before '--' delimiter")); + + if (delim == nullptr || *skip_spaces (&delim[2]) == '\0') + nested_cmd = repeat_previous (); + + cmd_list_element *set_cmd = lookup_cmd (&args, setlist, set_cmd_prefix, + /*allow_unknown=*/ 0, + /*ignore_help_classes=*/ 1); + gdb_assert (set_cmd != nullptr); + + if (set_cmd->var == nullptr) + error (_("Cannot use this setting with the \"with\" command")); + + std::string temp_value + = (delim == nullptr ? args : std::string (args, delim - args)); + + if (nested_cmd == nullptr) + nested_cmd = skip_spaces (delim + 2); + + std::string org_value = get_setshow_command_value_string (set_cmd); + + /* Tweak the setting to the new temporary value. */ + do_set_command (temp_value.c_str (), from_tty, set_cmd); + + try + { + scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); + + /* Execute the nested command. */ + execute_command (nested_cmd, from_tty); + } + catch (const gdb_exception &ex) + { + /* Restore the setting and rethrow. If restoring the setting + throws, swallow the new exception and warn. There's nothing + else we can reasonably do. */ + try + { + do_set_command (org_value.c_str (), from_tty, set_cmd); + } + catch (const gdb_exception &ex2) + { + warning (_("Couldn't restore setting: %s"), ex2.what ()); + } + + throw; + } + + /* Restore the setting. */ + do_set_command (org_value.c_str (), from_tty, set_cmd); +} + +/* See cli/cli-cmds.h. */ + +void +with_command_completer_1 (const char *set_cmd_prefix, + completion_tracker &tracker, + const char *text) +{ + tracker.set_use_custom_word_point (true); + + const char *delim = strstr (text, "--"); + + /* If we're still not past the "--" delimiter, complete the "with" + command as if it was a "set" command. */ + if (delim == text + || delim == nullptr + || !isspace (delim[-1]) + || !(isspace (delim[2]) || delim[2] == '\0')) + { + std::string new_text = std::string (set_cmd_prefix) + text; + tracker.advance_custom_word_point_by (-(int) strlen (set_cmd_prefix)); + complete_nested_command_line (tracker, new_text.c_str ()); + return; + } + + /* We're past the "--" delimiter. Complete on the sub command. */ + const char *nested_cmd = skip_spaces (delim + 2); + tracker.advance_custom_word_point_by (nested_cmd - text); + complete_nested_command_line (tracker, nested_cmd); +} + +/* The "with" command. */ + +static void +with_command (const char *args, int from_tty) +{ + with_command_1 ("set ", setlist, args, from_tty); +} + +/* "with" command completer. */ + +static void +with_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char * /*word*/) +{ + with_command_completer_1 ("set ", tracker, text); +} + /* Provide documentation on command or list given by COMMAND. FROM_TTY is ignored. */ @@ -878,12 +988,7 @@ pipe_command (const char *arg, int from_tty) arg += delim.length (); /* Skip the delimiter. */ if (gdb_cmd.empty ()) - { - repeat_previous (); - gdb_cmd = skip_spaces (get_saved_command_line ()); - if (gdb_cmd.empty ()) - error (_("No previous command to relaunch")); - } + gdb_cmd = repeat_previous (); const char *shell_command = skip_spaces (arg); if (*shell_command == '\0') @@ -1850,6 +1955,23 @@ Generic command for showing things about the debugger."), /* Another way to get at the same thing. */ add_info ("set", show_command, _("Show all GDB settings.")); + c = add_com ("with", class_vars, with_command, _("\ +Temporarily set SETTING to VALUE, run COMMAND, and restore SETTING.\n\ +Usage: with SETTING [VALUE] [-- COMMAND]\n\ +Usage: w SETTING [VALUE] [-- COMMAND]\n\ +With no COMMAND, repeats the last executed command.\n\ +\n\ +SETTING is any setting you can change with the \"set\" subcommands.\n\ +E.g.:\n\ + with language pascal -- print obj\n\ + with print elements unlimited -- print obj\n\ +\n\ +You can change multiple settings using nested with, and use\n\ +abbreviations for commands and/or values. E.g.:\n\ + w la p -- w p el u -- p obj")); + set_cmd_completer_handle_brkchars (c, with_command_completer); + add_com_alias ("w", "with", class_vars, 1); + add_cmd ("commands", no_set_class, show_commands, _("\ Show the history of commands you typed.\n\ You can supply a command number to start with, or a `+' to start after\n\ diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h index 63b8c40..94e210a 100644 --- a/gdb/cli/cli-cmds.h +++ b/gdb/cli/cli-cmds.h @@ -142,4 +142,19 @@ extern gdb::optional<open_script> extern int source_verbose; extern int trace_commands; +/* Common code for the "with" and "maintenance with" commands. + SET_CMD_PREFIX is the spelling of the corresponding "set" command + prefix: i.e., "set " or "maintenance set ". SETLIST is the command + element for the same "set" command prefix. */ +extern void with_command_1 (const char *set_cmd_prefix, + cmd_list_element *setlist, + const char *args, int from_tty); + +/* Common code for the completers of the "with" and "maintenance with" + commands. SET_CMD_PREFIX is the spelling of the corresponding + "set" command prefix: i.e., "set " or "maintenance set ". */ +extern void with_command_completer_1 (const char *set_cmd_prefix, + completion_tracker &tracker, + const char *text); + #endif /* CLI_CLI_CMDS_H */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index d588d04..6fb3244 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -190,7 +190,7 @@ parse_cli_var_uinteger (var_types var_type, const char **arg, { LONGEST val; - if (*arg == nullptr) + if (*arg == nullptr || **arg == '\0') { if (var_type == var_uinteger) error_no_arg (_("integer to set it to, or \"unlimited\".")); @@ -225,7 +225,7 @@ parse_cli_var_zuinteger_unlimited (const char **arg, bool expression) { LONGEST val; - if (*arg == nullptr) + if (*arg == nullptr || **arg == '\0') error_no_arg (_("integer to set it to, or \"unlimited\".")); if (is_unlimited_literal (arg, expression)) @@ -308,6 +308,9 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) gdb_assert (c->type == set_cmd); + if (arg == NULL) + arg = ""; + switch (c->var_type) { case var_string: @@ -317,8 +320,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) char *q; int ch; - if (arg == NULL) - arg = ""; newobj = (char *) xmalloc (strlen (arg) + 2); p = arg; q = newobj; @@ -364,9 +365,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) } break; case var_string_noescape: - if (arg == NULL) - arg = ""; - if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) { xfree (*(char **) c->var); @@ -376,14 +374,14 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) } break; case var_filename: - if (arg == NULL) + if (*arg == '\0') error_no_arg (_("filename to set it to.")); /* FALLTHROUGH */ case var_optional_filename: { char *val = NULL; - if (arg != NULL) + if (*arg != '\0') { /* Clear trailing whitespace of filename. */ const char *ptr = arg + strlen (arg) - 1; @@ -455,7 +453,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) { LONGEST val; - if (arg == NULL) + if (*arg == '\0') { if (c->var_type == var_integer) error_no_arg (_("integer to set it to, or \"unlimited\".")); @@ -625,24 +623,13 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) } } -/* Do a "show" command. ARG is NULL if no argument, or the - text of the argument, and FROM_TTY is nonzero if this command is - being entered directly by the user (i.e. these are just like any - other command). C is the command list element for the command. */ +/* See cli/cli-setshow.h. */ -void -do_show_command (const char *arg, int from_tty, struct cmd_list_element *c) +std::string +get_setshow_command_value_string (cmd_list_element *c) { - struct ui_out *uiout = current_uiout; - - gdb_assert (c->type == show_cmd); - string_file stb; - /* Possibly call the pre hook. */ - if (c->pre_show_hook) - (c->pre_show_hook) (c); - switch (c->var_type) { case var_string: @@ -672,9 +659,7 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c) stb.puts ("auto"); break; default: - internal_error (__FILE__, __LINE__, - _("do_show_command: " - "invalid var_auto_boolean")); + gdb_assert_not_reached ("invalid var_auto_boolean"); break; } break; @@ -703,23 +688,42 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c) } break; default: - error (_("gdb internal error: bad var_type in do_show_command")); + gdb_assert_not_reached ("bad var_type"); } + return std::move (stb.string ()); +} + + +/* Do a "show" command. ARG is NULL if no argument, or the + text of the argument, and FROM_TTY is nonzero if this command is + being entered directly by the user (i.e. these are just like any + other command). C is the command list element for the command. */ + +void +do_show_command (const char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + + gdb_assert (c->type == show_cmd); + + /* Possibly call the pre hook. */ + if (c->pre_show_hook) + (c->pre_show_hook) (c); + + std::string val = get_setshow_command_value_string (c); - /* FIXME: cagney/2005-02-10: Need to split this in half: code to - convert the value into a string (esentially the above); and - code to print the value out. For the latter there should be - MI and CLI specific versions. */ + /* FIXME: cagney/2005-02-10: There should be MI and CLI specific + versions of code to print the value out. */ if (uiout->is_mi_like_p ()) - uiout->field_stream ("value", stb); + uiout->field_string ("value", val.c_str ()); else { if (c->show_value_func != NULL) - c->show_value_func (gdb_stdout, from_tty, c, stb.c_str ()); + c->show_value_func (gdb_stdout, from_tty, c, val.c_str ()); else - deprecated_show_value_hack (gdb_stdout, from_tty, c, stb.c_str ()); + deprecated_show_value_hack (gdb_stdout, from_tty, c, val.c_str ()); } c->func (c, NULL, from_tty); diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index c00a098..8bfe7e8 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -17,6 +17,8 @@ #ifndef CLI_CLI_SETSHOW_H #define CLI_CLI_SETSHOW_H +#include <string> + struct cmd_list_element; /* Parse ARG, an option to a boolean variable. @@ -55,6 +57,9 @@ extern void do_set_command (const char *arg, int from_tty, extern void do_show_command (const char *arg, int from_tty, struct cmd_list_element *c); +/* Get a string version of C's current value. */ +extern std::string get_setshow_command_value_string (cmd_list_element *c); + extern void cmd_show_list (struct cmd_list_element *list, int from_tty, const char *prefix); diff --git a/gdb/command.h b/gdb/command.h index 4d52f00..648950b 100644 --- a/gdb/command.h +++ b/gdb/command.h @@ -461,14 +461,17 @@ extern void error_no_arg (const char *) ATTRIBUTE_NORETURN; extern void dont_repeat (); -/* Commands call repeat_previous if they want to repeat the previous command. - Such commands that repeat the previous command must indicate - to not repeat themselves, to avoid recursive repeat. - repeat_previous will mark the current command as not repeating, - and will ensure get_saved_command_line returns the previous command, - so that the currently executing command can repeat it. */ - -extern void repeat_previous (); +/* Commands call repeat_previous if they want to repeat the previous + command. Such commands that repeat the previous command must + indicate to not repeat themselves, to avoid recursive repeat. + repeat_previous marks the current command as not repeating, and + ensures get_saved_command_line returns the previous command, so + that the currently executing command can repeat it. If there's no + previous command, throws an error. Otherwise, returns the result + of get_saved_command_line, which now points at the command to + repeat. */ + +extern const char *repeat_previous (); /* Prevent dont_repeat from working, and return a cleanup that restores the previous state. */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 1ebaae3..1025916 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,4 +1,12 @@ 2019-07-03 Pedro Alves <palves@redhat.com> + Philippe Waroquiers <philippe.waroquiers@skynet.be> + + * gdb.texinfo (Command Settings): New node documenting the general + concept of settings, how to change them, and the new "with" + command. + (Maintenance Commands): Document "maint with". + +2019-07-03 Pedro Alves <palves@redhat.com> * gdb.texinfo (Maintenance Commands): Document "maint set/show test-settings" instead of "maint test-settings set/show". diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ca43166..299c4a1 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1561,6 +1561,7 @@ show you the alternatives available, if there is more than one possibility). @menu * Command Syntax:: How to give commands to @value{GDBN} +* Command Settings:: How to change default behavior of commands * Completion:: Command completion * Command Options:: Command options * Help:: How to ask @value{GDBN} for help @@ -1617,6 +1618,98 @@ commands. This command accepts the current line, like @key{RET}, and then fetches the next line relative to the current line from the history for editing. + +@node Command Settings +@section Command Settings +@cindex default behavior of commands, changing +@cindex default settings, changing + +Many commands change their behavior according to command-specific +variables or settings. These settings can be changed with the +@code{set} subcommands. For example, the @code{print} command +(@pxref{Data, ,Examining Data}) prints arrays differently depending on +settings changeable with the commands @code{set print elements +NUMBER-OF-ELEMENTS} and @code{set print array-indexes}, among others. + +You can change these settings to your preference in the gdbinit files +loaded at @value{GDBN} startup. @xref{Startup}. + +The settings can also be changed interactively during the debugging +session. For example, to change the limit of array elements to print, +you can do the following: +@smallexample +(@value{GDBN}) set print elements 10 +(@value{GDBN}) print some_array +$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@} +@end smallexample + +The above @code{set print elements 10} command changes the number of +elements to print from the default of 200 to 10. If you only intend +this limit of 10 to be used for printing @code{some_array}, then you +must restore the limit back to 200, with @code{set print elements +200}. + +Some commands allow overriding settings with command options. For +example, the @code{print} command supports a number of options that +allow overriding relevant global print settings as set by @code{set +print} subcommands. @xref{print options}. The example above could be +rewritten as: +@smallexample +(@value{GDBN}) print -elements 10 -- some_array +$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@} +@end smallexample + +Alternatively, you can use the @code{with} command to change a setting +temporarily, for the duration of a command invocation. + +@table @code +@kindex with command +@kindex w @r{(@code{with})} +@cindex settings +@cindex temporarily change settings +@item with @var{setting} [@var{value}] [-- @var{command}] +@itemx w @var{setting} [@var{value}] [-- @var{command}] +Temporarily set @var{setting} to @var{value} for the duration of +@var{command}. + +@var{setting} is any setting you can change with the @code{set} +subcommands. @var{value} is the value to assign to @code{setting} +while running @code{command}. + +If no @var{command} is provided, the last command executed is +repeated. + +If a @var{command} is provided, it must be preceded by a double dash +(@code{--}) separator. This is required because some settings accept +free-form arguments, such as expressions or filenames. + +For example, the command +@smallexample +(@value{GDBN}) with print array on -- print some_array +@end smallexample +@noindent +is equivalent to the following 3 commands: +@smallexample +(@value{GDBN}) set print array on +(@value{GDBN}) print some_array +(@value{GDBN}) set print array off +@end smallexample + +The @code{with} command is particularly useful when you want to +override a setting while running user-defined commands, or commands +defined in Python or Guile. @xref{Extending GDB,, Extending GDB}. + +@smallexample +(@value{GDBN}) with print pretty on -- my_complex_command +@end smallexample + +To change several settings for the same command, you can nest +@code{with} commands. For example, @code{with language ada -- with +print elements 10} temporarily changes the language to Ada and sets a +limit of 10 elements to print for arrays and strings. + +@end table + @node Completion @section Command Completion @@ -37634,6 +37727,13 @@ support in the command options framework. These are representative commands for each @var{kind} of setting type @value{GDBN} supports. They are used by the testsuite for exercising the settings infrastructure. + +@kindex maint with +@item maint with @var{setting} [@var{value}] [-- @var{command}] +Like the @code{with} command, but works with @code{maintenance set} +variables. This is used by the testsuite to exercise the @code{with} +command's infrastructure. + @end table The following command is useful for non-interactive invocations of diff --git a/gdb/maint.c b/gdb/maint.c index aaabb35..cecde84 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -43,6 +43,7 @@ #include "cli/cli-decode.h" #include "cli/cli-utils.h" #include "cli/cli-setshow.h" +#include "cli/cli-cmds.h" static void maintenance_do_deprecate (const char *, int); @@ -634,6 +635,24 @@ maintenance_show_cmd (const char *args, int from_tty) cmd_show_list (maintenance_show_cmdlist, from_tty, ""); } +/* "maintenance with" command. */ + +static void +maintenance_with_cmd (const char *args, int from_tty) +{ + with_command_1 ("maintenance set ", maintenance_set_cmdlist, args, from_tty); +} + +/* "maintenance with" command completer. */ + +static void +maintenance_with_cmd_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char * /*word*/) +{ + with_command_completer_1 ("maintenance set ", tracker, text); +} + /* Profiling support. */ static int maintenance_profile_p; @@ -1023,6 +1042,15 @@ Configure variables internal to GDB that aid in GDB's maintenance"), 0/*allow-unknown*/, &maintenancelist); + cmd = add_cmd ("with", class_maintenance, maintenance_with_cmd, _("\ +Like \"with\", but works with \"maintenance set\" variables.\n\ +Usage: maintenance with SETTING [VALUE] [-- COMMAND]\n\ +With no COMMAND, repeats the last executed command.\n\ +SETTING is any setting you can change with the \"maintenance set\"\n\ +subcommands."), + &maintenancelist); + set_cmd_completer_handle_brkchars (cmd, maintenance_with_cmd_completer); + #ifndef _WIN32 add_cmd ("dump-me", class_maintenance, maintenance_dump_me, _("\ Get fatal error; make debugger dump its core.\n\ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index a954e6d..9b988dc 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-07-03 Pedro Alves <palves@redhat.com> + * gdb.base/with.c: New file. + * gdb.base/with.exp: New file. + +2019-07-03 Pedro Alves <palves@redhat.com> + * gdb.base/settings.exp: Replace all references to "maint test-settings set" with references to "maint set test-settings", and all references to "maint test-settings show" with references diff --git a/gdb/testsuite/gdb.base/with.c b/gdb/testsuite/gdb.base/with.c new file mode 100644 index 0000000..c642662 --- /dev/null +++ b/gdb/testsuite/gdb.base/with.c @@ -0,0 +1,41 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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/>. */ + +int xxx1 = 123; + +struct S +{ + int a; + int b; + int c; +}; + +struct S g_s = {1, 2, 3}; + +static void +inc () +{ + g_s.a++;; +} + +int +main () +{ + inc (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp new file mode 100644 index 0000000..9ea7685 --- /dev/null +++ b/gdb/testsuite/gdb.base/with.exp @@ -0,0 +1,289 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2019 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/>. + +# Test the "with" command. + +load_lib completion-support.exp + +standard_testfile .c + +if {[build_executable "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +clean_restart $binfile + +# Test "maint with". VALUES is a list of values. A nested "with" is +# performed with each combination of pair of values from this list. +# This exercises setting a value, and restoring it too. This is +# particularly important for the "special" values like "unlimited", +# which for example for var_uinteger maps to 0 at the user-visible +# level, but maps to -1 internally. + +proc test_with {setting values} { + foreach val1 $values { + foreach val2 $values { + gdb_test \ + "maint with test-settings $setting $val1 -- maint with test-settings $setting $val2 -- p 1" \ + " = 1" + } + } +} + +# Test "maint with" in the error case. SETTING is the "maint set +# test-setting" setting to exercise. TMP_VAL is the value to set the +# setting to. EXPECTED_RE is the expected GDB output, which should be +# an error of some kind. Also checks that the setting's original +# value is preserved across the error. + +proc test_with_error {setting tmp_val expected_re} { + global gdb_prompt + + with_test_prefix "$setting, $tmp_val" { + set test "save org value" + set org_val "" + gdb_test_multiple "maint show test-settings $setting" $test { + -re "(.*)\r\n$gdb_prompt $" { + set org_val $expect_out(1,string) + pass $test + } + } + + gdb_test \ + "maint with test-settings $setting $tmp_val -- p 1" \ + $expected_re + + gdb_test "maint show test-settings $setting" "^$org_val" \ + "value hasn't changed across error" + } +} + +# Test "with" framework basics, using the internal "maint with +# test-settings" subcommands. +with_test_prefix "maint" { + test_with "auto-boolean" {"on" "off" "auto"} + test_with "boolean" {"" "on" "off" "0" "1" "enable" "disable"} + test_with "integer" {"0" "1" "-1" "unlimited"} + test_with "uinteger" {"0" "1" "unlimited"} + test_with "zinteger" {"0" "1" "-1"} + test_with "zuinteger" {"0" "1"} + test_with "zuinteger-unlimited" {"-1" "unlimited" "0" "1"} + test_with "string" {"" "foo" "\"hello world\""} + test_with "string-noescape" {"" "foo" "\"hello world\""} + test_with "filename" {"/foo" "bar/x/y"} + test_with "optional-filename" {"" "/foo" "bar/x/y"} + test_with "enum" {"xxx" "yyy"} + + # Check the most important error conditions. E.g., empty, + # negative or "unlimited" values for settings that don't accept + # those. Exhaustive error coverage of the set/with value parsing + # is left to "set" testing, in gdb.base/settings.exp. + test_with_error "auto-boolean" "" \ + "\"on\", \"off\" or \"auto\" expected\\." + test_with_error "auto-boolean" "xxx" \ + "\"on\", \"off\" or \"auto\" expected\\." + test_with_error "boolean" "2" "\"on\" or \"off\" expected\\." + test_with_error "uinteger" "-1" "integer -1 out of range" + test_with_error "uinteger" "" \ + "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\." + test_with_error "zuinteger" "-1" "integer -1 out of range" + test_with_error "zuinteger" "" \ + "Argument required \\(integer to set it to\\.\\)\\." + test_with_error "zuinteger-unlimited" "-2" \ + "only -1 is allowed to set as unlimited" + test_with_error "zuinteger-unlimited" "" \ + "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\." + test_with_error "filename" "" \ + "Argument required \\(filename to set it to\\.\\)\\." + test_with_error "enum" "" \ + "Requires an argument\\. Valid arguments are xxx, yyy, zzz\\." +} + +# Basic/core tests using user-visible commands. +with_test_prefix "basics" { + gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" + gdb_test "with print pretty -- print g_s" \ + [multi_line \ + " = {" \ + " a = 1," \ + " b = 2," \ + " c = 3" \ + "}"] + + # A boolean setting. + gdb_test "with non-stop on -- show non-stop" \ + "Controlling the inferior in non-stop mode is on\\." + gdb_test "show non-stop" \ + "Controlling the inferior in non-stop mode is off\\." + + # Language. + gdb_test "with language pascal -- show language" \ + "The current source language is \"pascal\"\\." + + gdb_test "show language" \ + "The current source language is \"auto; currently c\"\\." + + gdb_test "with language ada -- print g_s" \ + " = \\(a => 1, b => 2, c => 3\\)" + + # Nested "with"s. + gdb_test "with language ada -- with language c -- print g_s" \ + " = {a = 1, b = 2, c = 3}" + + # "w" alias. + gdb_test "w language pascal -- show language" \ + "The current source language is \"pascal\"\\." \ + "w alias works" + + # An early prototype of the "with" command got this wrong. + gdb_test \ + "w print repeats unlimited -- w print repeats 1 -- p \"1223334444\"" \ + " = \"1\", '2' <repeats 2 times>, '3' <repeats 3 times>, '4' <repeats 4 times>" +} + +# Check a user-defined command. +with_test_prefix "user-defined" { + # A user defined command. + set test "define usercmd" + gdb_test_multiple "define usercmd" $test { + -re "End with" { + gdb_test \ + [multi_line_input \ + {print g_s} \ + {end}] \ + "" \ + $test + } + } + gdb_test "with language ada -- usercmd" \ + " = \\(a => 1, b => 2, c => 3\\)" +} + +# Check repeating. +with_test_prefix "repeat" { + clean_restart $binfile + + # "with" with no command reinvokes the previous command. + gdb_test "with language ada" \ + "No previous command to relaunch" \ + "reinvoke with no previous command to relaunch" + + gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" + + gdb_test "with language ada" \ + " = \\(a => 1, b => 2, c => 3\\)" \ + "reinvoke with language" + + # Same, but with "--". + gdb_test "with language fortran --" \ + " = \\( a = 1, b = 2, c = 3 \\)" \ + "reinvoke with language and --" + + # Repeating repeats the original "print g_s", not the last "with" + # command. + set test "repeat command line" + send_gdb "\n" + gdb_test_multiple "" $test { + -re " = {a = 1, b = 2, c = 3}\r\n$gdb_prompt $" { + pass $test + } + } +} + +# Basic run control. +with_test_prefix "run control" { + clean_restart $binfile + + if ![runto_main] { + fail "cannot run to main" + return + } + + # Check "with" with a synchronous execution command. + gdb_test "with disassemble-next-line on -- next" \ + "return 0;.*=>.*" +} + +# Check errors. +with_test_prefix "errors" { + # Try both an unknown root setting and an unknown prefixed + # setting. The errors come from different locations in the + # sources. + gdb_test "with xxxx yyyy" \ + "Undefined set command: \"xxxx\". Try \"help set\"\\." + gdb_test "with print xxxx yyyy" \ + "Undefined set print command: \"xxxx yyyy\". Try \"help set print\"\\." + # Try one error case for "maint with", to make sure the right + # "maintenance with" prefix is shown. + gdb_test "maint with xxxx yyyy" \ + "Undefined maintenance set command: \"xxxx\". Try \"help maintenance set\"\\." + + # Try ambiguous settings. + gdb_test "with w" \ + "Ambiguous set command \"w\": watchdog, width, write\\." + gdb_test "with print m" \ + "Ambiguous set print command \"m\": max-depth, max-symbolic-offset\\." + + gdb_test "with variable xxx=1" \ + "Cannot use this setting with the \"with\" command" + + gdb_test "with print elements -- p 1" \ + "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\." + + gdb_test "with -- p 1" \ + "Missing setting before '--' delimiter" + + # Check that the setting is restored even if the command throws. + gdb_test "with print elements 1 -- unknowncommand" \ + "Undefined command: \"unknowncommand\"\\. Try \"help\"\\." + gdb_test "show print elements" \ + "Limit on string chars or array elements to print is 200\\." +} + +# Check completion. +with_test_prefix "completion" { + test_gdb_complete_unique \ + "with pri" \ + "with print" + + test_gdb_complete_unique \ + "with print ele" \ + "with print elements" + + test_gdb_complete_unique \ + "with print elements u" \ + "with print elements unlimited" + + test_gdb_complete_none \ + "with print elements unlimited " + + test_gdb_completion_offers_commands "with print elements unlimited -- " + + # Check that the completer nests into the nested command line's + # completer. + test_gdb_complete_unique \ + "with print elements unlimited -- with print ele" \ + "with print elements unlimited -- with print elements" + + # Check completion of "maint with". "maint with" and "with"'s + # completers share 99% of the code. All we need to care about + # here is that the completion word point is computed correctly, so + # any simple completion is sufficient. + test_gdb_complete_unique \ + "maint with test-set" \ + "maint with test-settings" +} @@ -730,7 +730,7 @@ dont_repeat (void) /* See command.h */ -void +const char * repeat_previous () { /* Do not repeat this command, as this command is a repeating command. */ @@ -740,6 +740,11 @@ repeat_previous () so swap it with previous_saved_command_line. */ std::swap (previous_saved_command_line, saved_command_line); std::swap (previous_repeat_arguments, repeat_arguments); + + const char *prev = skip_spaces (get_saved_command_line ()); + if (*prev == '\0') + error (_("No previous command to relaunch")); + return prev; } /* See command.h. */ |