# This testcase is part of GDB, the GNU debugger. # Copyright 2019-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 . # Test the set/show commands framework. The test uses the # "maintenance test-settings set/show xxx" subcommands to exercise # TAB-completion and setting processing. load_lib completion-support.exp standard_testfile .c if {[build_executable "failed to prepare" $testfile $srcfile debug]} { return -1 } clean_restart if { ![readline_is_used] } { untested "no tab completion support without readline" return -1 } # Test the show command SHOW_CMD. EXPECTED_RE is the expected output. # Also verifies that $_gdb_maint_setting_str produces an equivalent output, # matching it with EXPECTED_RE. EXPECTED_RE double quotes are escaped # unless EXPECTED_RE_ESCAPED is true, indicating the quotes in EXPECTED_RE # are already escaped. # The value for the setting corresponding to SHOW_CMD is then reset # to RESET_VALUE, then set again to the value given by $_gdb_maint_setting_str # and $_gdb_maint_setting. The default value of RESET_VALUE (0) should work for # most settings. Note that we do not check that RESET_VALUE differs from # the expected value, as we assume different values will be verified. # The setting value must still be the one in force before calling show_setting. # In other words, this verifies that # maint set test-settings $_gdb_maint_setting_str() # maint set test-settings $_gdb_maint_setting() # do not change the setting value. # This procedure makes it easier to make the test # name/message unique, since we test the "show" commands many times. # EXPECTED_RE is made part of the test name. proc show_setting {show_cmd expected_re {expected_re_escaped 0} {reset_value 0}} { global gdb_prompt with_test_prefix "$show_cmd $expected_re" { gdb_test "$show_cmd" $expected_re "show" # Remove the first two words (such as "maint show") to have the # setting name to use for $_gdb_maint_setting_str. regsub "\[^ \]+ +\[^ \]+ +\(.*\)" $show_cmd "\\1" maint_setting if {$expected_re_escaped} { set escaped_expected_re $expected_re } else { regsub -all "\"" $expected_re "\\\\\\\"" escaped_expected_re } set test "print \$_gdb_maint_setting_str" set setting_str_value "xxxYYYxxx" gdb_test_multiple "print \$_gdb_maint_setting_str(\"$maint_setting\")" $test { -re " = \"\($escaped_expected_re\)\".*$gdb_prompt $" { set setting_str_value $expect_out(1,string) regsub -all "\\\\" $expect_out(1,string) "" setting_str_value pass $test } } # Change the setting value to RESET_VALUE, set it back to setting_str_value # and check we still have the original value. gdb_test_no_output "maintenance set $maint_setting $reset_value" "str reset $reset_value" gdb_test_no_output "maintenance set $maint_setting $setting_str_value" "str set again" gdb_test "$show_cmd" $expected_re "str show after reset+set again" # Same test, but with value captured from $_gdb_maint_setting. set test "print \$_gdb_maint_setting" set setting_value "xxxYYYxxx" gdb_test_multiple "print \$_gdb_maint_setting(\"$maint_setting\")" $test { -re " = \"\(.*\)\".*$gdb_prompt $" { set setting_value $expect_out(1,string) regsub -all "\\\\" $expect_out(1,string) "" setting_value pass $test } -re " = \(.*\)\r\n$gdb_prompt $" { set setting_value $expect_out(1,string) pass $test } } gdb_test_no_output "maintenance set $maint_setting $reset_value" "reset $reset_value" gdb_test_no_output "maintenance set $maint_setting $setting_value" "set again" gdb_test "$show_cmd" $expected_re "show after reset+set again" } } # Verifies that $_gdb_setting (SETTING) gives a value whose ptype matches EXPECTED. proc check_type {setting expected} { with_test_prefix "check_type $setting $expected" { gdb_test "print \$_gdb_maint_setting(\"$setting\")" gdb_test "ptype $" "$expected" # Currently, GDB ptype always tells it is type int. # ptype should better report an error such as: # "No type information for GDB functions" # Test 'type int', so as to make it fail if ptype is changed. gdb_test "ptype \$_gdb_maint_setting(\"$setting\")" \ "type = int" } } # var_Xinteger tests. VARIANT determines which command/variant to # exercise. proc test-integer {variant} { set set_cmd "maint set test-settings $variant" set show_cmd "maint show test-settings $variant" # A bogus value. gdb_test "$set_cmd bogus" \ "No symbol table is loaded\\. Use the \"file\" command\\." # Seemingly-valid but not quite valid value. gdb_test "$set_cmd 1a" \ "Invalid number \"1a\"\\." # Valid value followed by garbage. gdb_test "$set_cmd 1 1" \ "A syntax error in expression, near `1'\\." # Valid value followed by garbage. gdb_test "$set_cmd 1 x" \ "A syntax error in expression, near `x'\\." if {$variant == "zuinteger-unlimited"} { # -1 means unlimited. Other negative values are rejected. -1 # -is tested further below, along the "unlimited" tests. gdb_test "$set_cmd -2" "integer -2 out of range" check_type "test-settings $variant" "type = int" } elseif {$variant == "uinteger" || $variant == "zuinteger"} { # Negative values are not accepted. gdb_test "$set_cmd -1" "integer -1 out of range" gdb_test "$set_cmd -2" "integer -2 out of range" check_type "test-settings $variant" "type = unsigned int" } else { # Negative values are not accepted. gdb_test_no_output "$set_cmd -1" show_setting "$show_cmd" "-1" gdb_test_no_output "$set_cmd -2" show_setting "$show_cmd" "-2" check_type "test-settings $variant" "type = int" } # Regular integer is accepted. gdb_test_no_output "$set_cmd 999" show_setting "$show_cmd" "999" if {$variant == "zinteger" || $variant == "zuinteger"} { # 0 means 0. gdb_test_no_output "$set_cmd 0" show_setting "$show_cmd" "0" } else { # Either 0 or -1 mean unlimited. Test both the number and # "unlimited". For the latter, test both full name and # abbreviations. if {$variant == "zuinteger-unlimited"} { gdb_test_no_output "$set_cmd -1" } else { gdb_test_no_output "$set_cmd 0" } show_setting "$show_cmd" "unlimited" foreach_with_prefix value { "u" "un" "unl" "unli" "unlim" "unlimi" "unlimit" "unlimite" "unlimited" } { # Alternate between integer and unlimited, to make sure the # setting really took effect. gdb_test_no_output "$set_cmd 1" show_setting "$show_cmd" "1" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "unlimited" } } if {$variant == "zuinteger"} { test_gdb_complete_multiple "maint set test-settings " "zuinteger" "" { "zuinteger" "zuinteger-unlimited" } } else { test_gdb_complete_unique \ "$set_cmd" \ "$set_cmd" } if {$variant == "zinteger" || $variant == "zuinteger"} { test_gdb_complete_none \ "$set_cmd " } else { test_gdb_complete_multiple "$set_cmd " "" "" { "NUMBER" "unlimited" } test_gdb_complete_none \ "$set_cmd 1" test_gdb_complete_unique \ "$set_cmd u" \ "$set_cmd unlimited" } # Check junk after "unlimited". gdb_test "$set_cmd unlimitedu" "No symbol table is loaded.*" if {$variant == "zinteger" || $variant == "zuinteger"} { gdb_test "$set_cmd unlimited u" "No symbol table is loaded.*" gdb_test "$set_cmd unlimited 1" "No symbol table is loaded.*" gdb_test "$set_cmd unlimited -1" "No symbol table is loaded.*" } else { gdb_test "$set_cmd unlimited u" "Junk after \"unlimited\": u" gdb_test "$set_cmd unlimited 1" "Junk after \"unlimited\": 1" gdb_test "$set_cmd unlimited -1" "Junk after \"unlimited\": -1" } test_gdb_complete_none "$set_cmd unlimited " test_gdb_complete_none "$set_cmd unlimitedu" test_gdb_complete_none "$set_cmd unlimited u" test_gdb_complete_none "$set_cmd unlimited 1" test_gdb_complete_none "$set_cmd x" test_gdb_complete_none "$set_cmd x " test_gdb_complete_none "$set_cmd -1" test_gdb_complete_none "$set_cmd -1 " test_gdb_complete_none "$set_cmd 1 " # Check show command completion. if {$variant == "zuinteger"} { test_gdb_complete_multiple "maintenance show test-settings " "zuinteger" "" { "zuinteger" "zuinteger-unlimited" } } else { test_gdb_complete_unique \ "$show_cmd" \ "$show_cmd" } test_gdb_complete_none "$show_cmd " } # boolean tests. proc_with_prefix test-boolean {} { # Use these variables to make sure we don't call the wrong command # by mistake. set set_cmd "maint set test-settings boolean" set show_cmd "maint show test-settings boolean" # A bogus value. gdb_test "$set_cmd bogus" \ "\"on\" or \"off\" expected\\." # Seemingly-valid but not quite valid value. gdb_test "$set_cmd on1" \ "\"on\" or \"off\" expected\\." # Valid value followed by garbage. gdb_test "$set_cmd on 1" \ "\"on\" or \"off\" expected\\." # Unlike auto-bool settings, "-1" is not accepted. gdb_test "$set_cmd -1" \ "\"on\" or \"off\" expected\\." # Nor "auto". gdb_test "$set_cmd auto" \ "\"on\" or \"off\" expected\\." # "o" is ambiguous. gdb_test "$set_cmd o" \ "\"on\" or \"off\" expected\\." # Various valid values. Test both full value names and # abbreviations. # Note that unlike with auto-bool, empty value implies "on". foreach_with_prefix value { "" "on" "1" "y" "ye" "yes" "e" "en" "ena" "enab" "enabl" "enable" } { gdb_test_no_output "$set_cmd off" show_setting "$show_cmd" "off" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "on" } check_type "test-settings boolean" "type = int" foreach_with_prefix value { "of" "off" "0" "n" "no" "d" "di" "dis" "disa" "disab" "disabl" "disable" } { gdb_test_no_output "$set_cmd on" show_setting "$show_cmd" "on" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "off" } test_gdb_complete_multiple "$set_cmd " "" "o" { "off" "on" } test_gdb_complete_unique \ "$set_cmd of" \ "$set_cmd off" test_gdb_complete_none "$set_cmd x" # Check that the show command doesn't complete anything. test_gdb_complete_unique \ "$show_cmd" \ "$show_cmd" test_gdb_complete_none "$show_cmd " } # auto-boolean tests. proc_with_prefix test-auto-boolean {} { # Use these variables to make sure we don't call the wrong command # by mistake. set set_cmd "maint set test-settings auto-boolean" set show_cmd "maint show test-settings auto-boolean" # A bogus value. gdb_test "$set_cmd bogus" \ "\"on\", \"off\" or \"auto\" expected\\." # Seemingly-valid but not quite valid value. gdb_test "$set_cmd on1" \ "\"on\", \"off\" or \"auto\" expected\\." # Valid value followed by garbage. gdb_test "$set_cmd on 1" \ "\"on\", \"off\" or \"auto\" expected\\." # "o" is ambiguous. gdb_test "$set_cmd o" \ "\"on\", \"off\" or \"auto\" expected\\." # Various valid values. Test both full value names and # abbreviations. foreach_with_prefix value { "on" "1" "y" "ye" "yes" "e" "en" "ena" "enab" "enabl" "enable" } { gdb_test_no_output "$set_cmd off" show_setting "$show_cmd" "off" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "on" } foreach_with_prefix value { "of" "off" "0" "n" "no" "d" "di" "dis" "disa" "disab" "disabl" "disable" } { gdb_test_no_output "$set_cmd on" show_setting "$show_cmd" "on" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "off" } foreach_with_prefix value { "a" "au" "aut" "auto" "-1" } { gdb_test_no_output "$set_cmd on" show_setting "$show_cmd" "on" gdb_test_no_output "$set_cmd $value" show_setting "$show_cmd" "auto" } check_type "test-settings auto-boolean" "type = int" # "-" is not accepted as abbreviation of "-1". gdb_test "$set_cmd -" \ "\"on\", \"off\" or \"auto\" expected\\." test_gdb_complete_multiple "$set_cmd " "" "" { "auto" "off" "on" } test_gdb_complete_unique \ "$set_cmd of" \ "$set_cmd off" test_gdb_complete_none "$set_cmd x" # Check that the show command doesn't complete anything. test_gdb_complete_unique \ "$show_cmd" \ "$show_cmd" test_gdb_complete_none "$show_cmd " } # Enum option tests. proc_with_prefix test-enum {} { # Use these variables to make sure we don't call the wrong command # by mistake. set set_cmd "maint set test-settings enum" set show_cmd "maint show test-settings enum" # Missing value. gdb_test "$set_cmd" \ "Requires an argument\\. Valid arguments are xxx, yyy, zzz\\." # A bogus value. gdb_test "$set_cmd bogus" \ "Undefined item: \"bogus\"." # Seemingly-valid but not quite valid value. gdb_test "$set_cmd xxx1" \ "Undefined item: \"xxx1\"." # Valid value followed by garbage. gdb_test "$set_cmd xxx 1" \ "Junk after item \"xxx\": 1" # Valid value followed by garbage, with extra spaces. gdb_test "$set_cmd xxx 1" \ "Junk after item \"xxx\": 1" # Abbreviated value followed by garbage. gdb_test "$set_cmd xx 1" \ "Junk after item \"xx\": 1" # Various valid values. Test both full value names and # abbreviations. gdb_test_no_output "$set_cmd x" show_setting "$show_cmd" "xxx" 0 "zzz" gdb_test_no_output "$set_cmd yy" show_setting "$show_cmd" "yyy" 0 "zzz" gdb_test_no_output "$set_cmd zzz" show_setting "$show_cmd" "zzz" 0 "yyy" check_type "test-settings enum" "type = char \\\[4\\\]" test_gdb_complete_multiple "$set_cmd " "" "" { "xxx" "yyy" "zzz" } test_gdb_complete_unique \ "$set_cmd x" \ "$set_cmd xxx" test_gdb_complete_none "$set_cmd a" # Check that the show command doesn't complete anything. test_gdb_complete_unique \ "$show_cmd" \ "$show_cmd" test_gdb_complete_none "$show_cmd " } # string settings tests. proc test-string {variant} { global gdb_prompt global srcfile binfile # Load symbols for the completion test below. clean_restart $binfile # Use these variables to make sure we don't call the wrong command # by mistake. set set_cmd "maint set test-settings $variant" set show_cmd "maint show test-settings $variant" # Checks that gdb doesn't crash if we haven't set the string yet. if {$variant != "filename"} { # This odd expected output here is because we expect GDB to # emit a single blank line as a result of this command. gdb_test -nonl "$show_cmd" "^\r\n" "$show_cmd: show default" } else { gdb_test "$show_cmd" "/foo/bar" "$show_cmd: show default" } # A string value. gdb_test_no_output "$set_cmd hello world" show_setting "$show_cmd" "hello world" check_type "test-settings $variant" "type = char \\\[\[1-9\]\[0-9\]*\\\]" # A quoted string value. if {$variant == "string"} { gdb_test_no_output "$set_cmd \"hello world\"" show_setting "$show_cmd" "\\\\\"hello world\\\\\"" 1 } else { gdb_test_no_output "$set_cmd \"hello world\"" show_setting "$show_cmd" "\"hello world\"" } # Test clearing the string. with_test_prefix "clear string" { if {$variant == "filename"} { gdb_test "$set_cmd" \ "Argument required \\(filename to set it to\\.\\)\\." # Check the value didn't change. show_setting "$show_cmd" "\"hello world\"" } else { gdb_test_no_output "$set_cmd" # This odd expected output here is because we expect GDB to # emit a single blank line as a result of this command. gdb_test -nonl "$show_cmd" "^\r\n" "$show_cmd: empty second time" } } # Test completion. if {$variant == "string" || $variant == "string-noescape" } { # Make sure GDB doesn't try to complete on symbols, which # doesn't make any sense. test_gdb_complete_none "$set_cmd " } else { # Complete on filename. # See comments in gdb.base/completion.exp. # We `cd' to ${srcdir}, and then do the completion relative to # the current directory. # ${srcdir} may be a relative path. We want to make sure we # end up in the right directory - so make sure we know where # it is. with_cwd $::srcdir { set fullsrcdir [pwd] } gdb_test "cd ${fullsrcdir}" \ "Working directory [string_to_regexp ${fullsrcdir}].*" \ "cd to \${srcdir}" set unique_file ../testsuite/gdb.base/comp-dir/subdir/dummy test_gdb_complete_unique \ "$set_cmd ${unique_file}" \ "$set_cmd ${unique_file}.txt" test_gdb_complete_none "$set_cmd ${unique_file}.abc" } # Check show command completion. if {$variant == "string"} { test_gdb_complete_multiple "maint show test-settings " "string" "" { "string" "string-noescape" } } else { test_gdb_complete_unique \ "$show_cmd" \ "$show_cmd" } test_gdb_complete_none "$show_cmd " } # Check that $_gdb_setting & co report the correct error strings. proc test-setting-error {} { gdb_test {print $_gdb_setting("xxx")} \ "First argument of \\\$_gdb_setting must be a valid setting of the 'show' command\\." gdb_test {print $_gdb_setting_str("xxx")} \ "First argument of \\\$_gdb_setting_str must be a valid setting of the 'show' command\\." gdb_test {print $_gdb_maint_setting("xxx")} \ "First argument of \\\$_gdb_maint_setting must be a valid setting of the 'maintenance show' command\\." gdb_test {print $_gdb_maint_setting_str("xxx")} \ "First argument of \\\$_gdb_maint_setting_str must be a valid setting of the 'maintenance show' command\\." } foreach variant { uinteger integer zinteger zuinteger zuinteger-unlimited } { with_test_prefix "test-integer $variant" { test-integer $variant } } test-boolean test-auto-boolean test-enum foreach variant { string string-noescape optional-filename filename } { with_test_prefix "test-string $variant" { test-string $variant } } test-setting-error