diff options
author | Pedro Alves <palves@redhat.com> | 2019-07-03 13:34:20 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2019-07-03 13:35:45 +0100 |
commit | fdbc98707b0ab48fd8ca3ac37acefa120496baf6 (patch) | |
tree | 5894a73e3e58bcd087918752ce0e0790ec4c14bf /gdb/testsuite/gdb.base/with.exp | |
parent | c6ac893109fdc2c3fce2b7457adccdc10f235354 (diff) | |
download | gdb-fdbc98707b0ab48fd8ca3ac37acefa120496baf6.zip gdb-fdbc98707b0ab48fd8ca3ac37acefa120496baf6.tar.gz gdb-fdbc98707b0ab48fd8ca3ac37acefa120496baf6.tar.bz2 |
Introduce the "with" command
( See original discussion and prototype here:
https://sourceware.org/ml/gdb-patches/2019-05/msg00570.html )
(gdb) help with
Temporarily set SETTING to VALUE, run COMMAND, and restore SETTING.
Usage: with SETTING [VALUE] [-- COMMAND]
Usage: w SETTING [VALUE] [-- COMMAND]
With no COMMAND, repeats the last executed command.
SETTING is any setting you can change with the "set" subcommands.
E.g.:
with language pascal -- print obj
with print elements unlimited -- print obj
As can be seen above, the "with" command is just like "set", but
instead of setting the setting permanently, it sets the setting, runs
a command and then restores the setting.
(gdb) p g_s
$1 = {a = 1, b = 2, c = 3}
(gdb) with language ada -- print g_s
$2 = (a => 1, b => 2, c => 3)
Warning: the current language does not match this frame.
(gdb) show language
The current source language is "auto; currently c".
(gdb) with print elements 100 -- with print object on -- print 1
$3 = 1
You can shorten things a bit though, as long as unambiguous. So this:
(gdb) with print elements 100 -- with print object off -- print 1
is the same as:
(gdb) w p el 100 -- w p o 0 -- p 1
Note that the patch adds a "w" alias for "with", as "w" is not
currently taken:
(gdb) w
Ambiguous command "w": watch, wh, whatis, where, while, while-stepping, winheight, ws.
Let me know if you'd prefer to reserve "w" for one of the other
commands above. IMHO, this command will end up being used frequently
enough that it deserves the "w" shorthand.
A nice feature is that this is fully integrated with TAB-completion:
(gdb) with p[TAB]
pagination print prompt python
(gdb) with print [TAB]
address max-depth static-members
array max-symbolic-offset symbol
array-indexes null-stop symbol-filename
asm-demangle object symbol-loading
demangle pascal_static-members thread-events
elements pretty type
entry-values raw union
frame-arguments repeats vtbl
inferior-events sevenbit-strings
(gdb) with print [TAB]
(gdb) with print elements unlimited -- thread apply all -[TAB]
-ascending -c -q -s
(gdb) with print elements unlimited -- print -[TAB]
-address -max-depth -repeats -vtbl
-array -null-stop -static-members
-array-indexes -object -symbol
-elements -pretty -union
The main advantage of this new command compared to command options,
like the new "print -OPT", is that this command works with any
setting, and, it works nicely when you want to override a setting
while running a user-defined command, like:
(gdb) with print pretty -- usercmd
The disadvantage is that it isn't as compact or easy to type. I think
of command options and this command as complementary. I think that
even with this new command, it makes sense to continue developing the
command options in the direction of exposing most-oft-used settings as
command options.
Inspired by Philippe's "/" command proposal, if no command is
specified, then the last command is re-invoked, under the overridden
setting:
(gdb) p g_s
$1 = {a = 1, b = 2, c = 3}
(gdb) with language ada
$2 = (a => 1, b => 2, c => 3)
Warning: the current language does not match this frame.
Note: "with" requires "--" to separate the setting from the command.
It might be possible to do without that, but, I haven't tried it yet,
and I think that this can go in without it. We can always downgrade
to making "--" optional if we manage to make it work.
On to the patch itself, the implementation of the command is simpler
than one might expect. A few details:
- I factored out a bit from pipe_command into repeat_previous
directly, because otherwise I'd need to copy&paste the same code and
same error message in the with command.
- The parse_cli_var_uinteger / parse_cli_var_zuinteger_unlimited /
do_set_command changes are necessary since we can now pass an empty
string as argument.
- do_show_command was split in two, as a FIXME comment suggests, but
for a different reason: we need to get a string version of a "set"
command's value, and we already had code for that in
do_show_command. That code is now factored out to the new
get_setshow_command_value_string function.
- There's a new "maint with" command added too:
(gdb) help maint with
Like "with", but works with "maintenance set" variables.
Usage: maintenance with SETTING [VALUE] [-- COMMAND]
With no COMMAND, repeats the last executed command.
SETTING is any setting you can change with the "maintenance set"
subcommands.
"with" and "maint with" share 99% of the implementation.
This might be useful on its own, but it's also useful for testing,
since with this, we can use the "maint set/show test-settings"
settings for exercising the "with" machinery with all the command
type variants (all enum var_types). This is done in the new
gdb/base/with.exp testcase.
The documentation bits are originally based on Philippe's docs for the
"/" command, hence the attribution in the ChangeLog.
gdb/ChangeLog:
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.
gdb/doc/ChangeLog:
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".
gdb/testsuite/ChangeLog:
2019-07-03 Pedro Alves <palves@redhat.com>
* gdb.base/with.c: New file.
* gdb.base/with.exp: New file.
Diffstat (limited to 'gdb/testsuite/gdb.base/with.exp')
-rw-r--r-- | gdb/testsuite/gdb.base/with.exp | 289 |
1 files changed, 289 insertions, 0 deletions
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" +} |