From 096d8adf6e9e1ab9a01174e94fd898b448d78341 Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Sun, 28 Apr 2019 14:38:18 +0200 Subject: [PATCH 1/3] Implement convenience functions to examine GDB settings. The new convenience functions $_gdb_setting and $_gdb_setting_str provide access to the GDB settings in user-defined commands. Similarly, $_gdb_maint_setting and $_gdb_maint_setting_str provide access to the GDB maintenance settings. The patch was developed following a comment of Eli about the 'set may-call-functions'. Eli said that user-defined functions should have a way to change their behavior according to this setting. Rather than have a specialized $_may_call_functions, this patch implements a general way to access any GDB setting. Compared to doing such access via Python 'gdb.parameter' and/or 'gdb.execute("set somesetting tosomevalue"): * The 'with' command is much better than the above python usage: if the user types C-c or an error happens between the set pagination off and the python "set pagination on", the above python does not restore the original setting. * Effectively, with the "gdb.parameter" python one liner, it is possible to do simple 'if' conditions, such as set and restore pagination. But mixing the "python if" within canned sequence of commands is cumbersome for non trivial combinations. E.g. if several commands have to be done for a certain condition accessed from python, I guess something like will be needed: python if __some_setting: gdb.execute("some command") python if __some_setting: gdb.execute("some other command") python if __some_setting: gdb.execute("some different command") (without speaking about nested "if-s"). With the convenience function: if $_gdb_setting("some_setting") some command some other command some different command end Integer settings (for example print elements) will also be more difficult to use. For example, a user defined function that scans and prints a linked list might want to use the value of "set print elements" to stop printing the linked list. Doing that by mixing python expression/if is likely doable, but seems not easy with the above one liners. So, in summary, the $_gdb_setting and $_gdb_setting_str avoids to have the heterogeneous mix of python and GDB commands in one single script (and of course, it works even if python is not configured, but that must be an unusual setup I guess). gdb/ChangeLog 2019-09-15 Philippe Waroquiers * cli/cli-cmds.c (setting_cmd, value_from_setting) (gdb_setting_internal_fn, gdb_maint_setting_internal_fn) (str_value_from_setting, gdb_setting_str_internal_fn) (gdb_maint_setting_str_internal_fn): New functions. (_initialize_cli_cmds): Define the new convenience functions. * gdb/cli/cli-setshow.h (get_setshow_command_value_string): Constify. * gdb/cli/cli-setshow.c (get_setshow_command_value_string): Constify. --- gdb/cli/cli-cmds.c | 232 ++++++++++++++++++++++++++++++++++++++++++ gdb/cli/cli-setshow.c | 2 +- gdb/cli/cli-setshow.h | 2 +- 3 files changed, 234 insertions(+), 2 deletions(-) diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index a39ea22604..ed699894f5 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -1912,6 +1912,200 @@ show_max_user_call_depth (struct ui_file *file, int from_tty, value); } +/* Returns the cmd_list_element in SHOWLIST corresponding to the first + argument of ARGV, which must contain one single value. + Throws an error if no value provided, or value not correct. + FNNAME is used in the error message. */ + +static cmd_list_element * +setting_cmd (const char *fnname, struct cmd_list_element *showlist, + int argc, struct value **argv) +{ + if (argc == 0) + error (_("You must provide an argument to %s"), fnname); + if (argc != 1) + error (_("You can only provide one argument to %s"), fnname); + + struct type *type0 = check_typedef (value_type (argv[0])); + + if (TYPE_CODE (type0) != TYPE_CODE_ARRAY + && TYPE_CODE (type0) != TYPE_CODE_STRING) + error (_("First argument of %s must be a string."), fnname); + + const char *a0 = (const char *) value_contents (argv[0]); + cmd_list_element *cmd = lookup_cmd (&a0, showlist, "", -1, 0); + + if (cmd == nullptr || cmd_type (cmd) != show_cmd) + error (_("First argument of %s must be a " + "valid setting of the 'show' command."), fnname); + + return cmd; +} + +/* Builds a value from the show CMD. */ + +static struct value * +value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch) +{ + switch (cmd->var_type) + { + case var_integer: + if (*(int *) cmd->var == INT_MAX) + return value_from_longest (builtin_type (gdbarch)->builtin_int, + 0); + else + return value_from_longest (builtin_type (gdbarch)->builtin_int, + *(int *) cmd->var); + case var_zinteger: + return value_from_longest (builtin_type (gdbarch)->builtin_int, + *(int *) cmd->var); + case var_boolean: + return value_from_longest (builtin_type (gdbarch)->builtin_int, + *(bool *) cmd->var ? 1 : 0); + case var_zuinteger_unlimited: + return value_from_longest (builtin_type (gdbarch)->builtin_int, + *(int *) cmd->var); + case var_auto_boolean: + { + int val; + + switch (*(enum auto_boolean*) cmd->var) + { + case AUTO_BOOLEAN_TRUE: + val = 1; + break; + case AUTO_BOOLEAN_FALSE: + val = 0; + break; + case AUTO_BOOLEAN_AUTO: + val = -1; + break; + default: + gdb_assert_not_reached ("invalid var_auto_boolean"); + } + return value_from_longest (builtin_type (gdbarch)->builtin_int, + val); + } + case var_uinteger: + if (*(unsigned int *) cmd->var == UINT_MAX) + return value_from_ulongest + (builtin_type (gdbarch)->builtin_unsigned_int, 0); + else + return value_from_ulongest + (builtin_type (gdbarch)->builtin_unsigned_int, + *(unsigned int *) cmd->var); + case var_zuinteger: + return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int, + *(unsigned int *) cmd->var); + case var_string: + case var_string_noescape: + case var_optional_filename: + case var_filename: + case var_enum: + if (*(char **) cmd->var) + return value_cstring (*(char **) cmd->var, strlen (*(char **) cmd->var), + builtin_type (gdbarch)->builtin_char); + else + return value_cstring ("", 1, + builtin_type (gdbarch)->builtin_char); + default: + gdb_assert_not_reached ("bad var_type"); + } +} + +/* Implementation of the convenience function $_gdb_setting. */ + +static struct value * +gdb_setting_internal_fn (struct gdbarch *gdbarch, + const struct language_defn *language, + void *cookie, int argc, struct value **argv) +{ + return value_from_setting (setting_cmd ("$_gdb_setting", showlist, + argc, argv), + gdbarch); +} + +/* Implementation of the convenience function $_gdb_maint_setting. */ + +static struct value * +gdb_maint_setting_internal_fn (struct gdbarch *gdbarch, + const struct language_defn *language, + void *cookie, int argc, struct value **argv) +{ + return value_from_setting (setting_cmd ("$_gdb_maint_setting", + maintenance_show_cmdlist, + argc, argv), + gdbarch); +} + +/* Builds a string value from the show CMD. */ + +static struct value * +str_value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch) +{ + switch (cmd->var_type) + { + case var_integer: + case var_zinteger: + case var_boolean: + case var_zuinteger_unlimited: + case var_auto_boolean: + case var_uinteger: + case var_zuinteger: + { + std::string cmd_val = get_setshow_command_value_string (cmd); + + return value_cstring (cmd_val.c_str (), cmd_val.size (), + builtin_type (gdbarch)->builtin_char); + } + + case var_string: + case var_string_noescape: + case var_optional_filename: + case var_filename: + case var_enum: + /* For these cases, we do not use get_setshow_command_value_string, + as this function handle some characters specially, e.g. by + escaping quotes. So, we directly use the cmd->var string value, + similarly to the value_from_setting code for these cases. */ + if (*(char **) cmd->var) + return value_cstring (*(char **) cmd->var, strlen (*(char **) cmd->var), + builtin_type (gdbarch)->builtin_char); + else + return value_cstring ("", 1, + builtin_type (gdbarch)->builtin_char); + + default: + gdb_assert_not_reached ("bad var_type"); + } +} + +/* Implementation of the convenience function $_gdb_setting_str. */ + +static struct value * +gdb_setting_str_internal_fn (struct gdbarch *gdbarch, + const struct language_defn *language, + void *cookie, int argc, struct value **argv) +{ + return str_value_from_setting (setting_cmd ("$_gdb_setting_str", + showlist, argc, argv), + gdbarch); +} + + +/* Implementation of the convenience function $_gdb_maint_setting_str. */ + +static struct value * +gdb_maint_setting_str_internal_fn (struct gdbarch *gdbarch, + const struct language_defn *language, + void *cookie, int argc, struct value **argv) +{ + return str_value_from_setting (setting_cmd ("$_gdb_maint_setting_str", + maintenance_show_cmdlist, + argc, argv), + gdbarch); +} + void _initialize_cli_cmds (void) { @@ -2053,6 +2247,44 @@ abbreviations for commands and/or values. E.g.:\n\ set_cmd_completer_handle_brkchars (c, with_command_completer); add_com_alias ("w", "with", class_vars, 1); + add_internal_function ("_gdb_setting_str", _("\ +$_gdb_setting_str - returns the value of a GDB setting as a string.\n\ +Usage: $_gdb_setting_str (setting)\n\ +\n\ +auto-boolean values are \"off\", \"on\", \"auto\".\n\ +boolean values are \"off\", \"on\".\n\ +The unlimited value for integer, uinteger, zuinteger-unlimited\n\ +settings is represented as \"unlimited\"."), + gdb_setting_str_internal_fn, NULL); + + add_internal_function ("_gdb_setting", _("\ +$_gdb_setting - returns the value of a GDB setting.\n\ +Usage: $_gdb_setting (setting)\n\ +auto-boolean values are \"off\", \"on\", \"auto\".\n\ +boolean values are \"off\", \"on\".\n\ +The unlimited value for integer, uinteger settings is 0.\n\ +The unlimited value for zuinteger-unlimited is -1."), + gdb_setting_internal_fn, NULL); + + add_internal_function ("_gdb_maint_setting_str", _("\ +$_gdb_maint_setting_str - returns the value of a GDB maintenance setting as a string.\n\ +Usage: $_gdb_maint_setting_str (setting)\n\ +\n\ +auto-boolean values are \"off\", \"on\", \"auto\".\n\ +boolean values are \"off\", \"on\".\n\ +The unlimited value for integer, uinteger, zuinteger-unlimited\n\ +settings is represented as \"unlimited\"."), + gdb_maint_setting_str_internal_fn, NULL); + + add_internal_function ("_gdb_maint_setting", _("\ +$_gdb_maint_setting - returns the value of a GDB maintenance setting.\n\ +Usage: $_gdb_maint_setting (setting)\n\ +auto-boolean values are \"off\", \"on\", \"auto\".\n\ +boolean values are \"off\", \"on\".\n\ +The unlimited value for integer, uinteger settings is 0.\n\ +The unlimited value for zuinteger-unlimited is -1."), + gdb_maint_setting_internal_fn, NULL); + 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-setshow.c b/gdb/cli/cli-setshow.c index d8391597ac..4cf2437e2a 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -627,7 +627,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) /* See cli/cli-setshow.h. */ std::string -get_setshow_command_value_string (cmd_list_element *c) +get_setshow_command_value_string (const cmd_list_element *c) { string_file stb; diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index 8bfe7e89f0..dbb3e9fdff 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -58,7 +58,7 @@ 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 std::string get_setshow_command_value_string (const cmd_list_element *c); extern void cmd_show_list (struct cmd_list_element *list, int from_tty, const char *prefix); -- 2.20.1 From 51d8c0e284280513828eb86f6f3ec00c3569309d Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Sun, 28 Apr 2019 14:40:50 +0200 Subject: [PATCH 2/3] Test the convenience functions $_gdb_setting and $_gdb_int_setting. gdb/testsuite/ChangeLog 2019-09-15 Philippe Waroquiers * gdb.base/setshow.exp: Test $_gdb_setting and $_gdb_setting_str. * gdb.base/settings.exp: Test all settings types using $_gdb_maint_setting and $_gdb_maint_setting_str in proc_show_setting, that now verifies that the value of "maint show" is the same as returned by the settings functions. Test the type of the maintenance settings. * gdb.base/default.exp: Update show_conv_list. --- gdb/testsuite/gdb.base/default.exp | 4 ++ gdb/testsuite/gdb.base/setshow.exp | 74 ++++++++++++++++++++++- gdb/testsuite/gdb.base/settings.exp | 94 ++++++++++++++++++++++++++--- 3 files changed, 162 insertions(+), 10 deletions(-) diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp index cf009cdc77..82ed4be17c 100644 --- a/gdb/testsuite/gdb.base/default.exp +++ b/gdb/testsuite/gdb.base/default.exp @@ -604,6 +604,10 @@ set show_conv_list \ {$_cimag = } \ {$_creal = } \ {$_isvoid = } \ + {$_gdb_maint_setting_str = } \ + {$_gdb_maint_setting = } \ + {$_gdb_setting_str = } \ + {$_gdb_setting = } \ {$_gdb_major = 9} \ {$_gdb_minor = 1} \ {$_shell_exitsignal = void} \ diff --git a/gdb/testsuite/gdb.base/setshow.exp b/gdb/testsuite/gdb.base/setshow.exp index d807d75a66..5316b48509 100644 --- a/gdb/testsuite/gdb.base/setshow.exp +++ b/gdb/testsuite/gdb.base/setshow.exp @@ -84,6 +84,9 @@ gdb_test "show annotate" "Annotation_level is 0..*" "show annotate (0)" #test annotation_level 0 gdb_test "info line 1" "Line 1 of .* is at address .* but contains no code.*" "annotation_level 0" +gdb_test "show args" "Argument list to give program being debugged when it is started is \"\"\." +gdb_test "p \$_gdb_setting_str(\"args\")" " = \"\"" + gdb_test_no_output "set args ~" gdb_test "show args" "Argument list to give program being debugged when it is started is \"~\"..*" \ "show args ~" @@ -91,6 +94,9 @@ gdb_test "show args" "Argument list to give program being debugged when it is st gdb_test_no_output "set args foo bar blup baz bubble" "set args" #test show args gdb_test "show args" "Argument list to give program being debugged when it is started is \"foo bar blup baz bubble\"..*" "show args" +gdb_test "p \$_gdb_setting(\"args\")" " = \"foo bar blup baz bubble\"" \ + "_gdb_setting args" + # Don't test if we can't pass args or if we're using a stub. if { !$use_gdb_stub && ![target_info exists noargs] } { @@ -100,32 +106,80 @@ if { !$use_gdb_stub && ![target_info exists noargs] } { gdb_test "run" "Starting program:.*foo bar blup baz bubble.*" "passing args" } #test set check range on -gdb_test "set check range on" ".*" "set check range on" +# Note: the below might produce a warning, so match anything. +gdb_test "set check range on" "" + +gdb_test "p \$_gdb_setting(\"check range\")" " = \"on\"" \ + "_gdb_setting check range on" #test show check range on gdb_test "show check range" "Range checking is \"on\"\..*" "show check range (on)" #test set check range off with trailing space gdb_test_no_output "set check range off " "set check range off" #test show check range off gdb_test "show check range" "Range checking is \"off\"\..*" "show check range (off)" +gdb_test "p \$_gdb_setting(\"check range\")" " = \"off\"" \ + "_gdb_setting check range off" #test set check range auto gdb_test_no_output "set check range auto" "set check range auto" #test show check range auto gdb_test "show check range" "Range checking is \"auto; currently .*" "show check range (auto)" +gdb_test "p \$_gdb_setting(\"check range\")" " = \"auto\"" \ + "_gdb_setting check range auto" # Test set check type on -gdb_test "set check type on" ".*" "set check type on" +gdb_test_no_output "set check type on" # Test show check type on gdb_test "show check type" "Strict type checking is on\..*" \ "show check type (on)" +gdb_test "p \$_gdb_setting_str(\"check type\")" " = \"on\"" \ + "_gdb_setting_str check type on" +gdb_test "p \$_gdb_setting(\"check type\")" " = 1" \ + "_gdb_setting check type on 1" # Test set check type off with trailing space gdb_test_no_output "set check type off " "set check type off" +gdb_test "p \$_gdb_setting_str(\"check type\")" " = \"off\"" \ + "_gdb_setting_str check type off" +gdb_test "p \$_gdb_setting(\"check type\")" " = 0" \ + "_gdb_setting check type off 0" # Test show check type off gdb_test "show check type" "Strict type checking is off\..*" \ "show check type (off)" +#test set breakpoint pending + +#test set breakpoint pending on +gdb_test_no_output "set breakpoint pending on" +gdb_test "p \$_gdb_setting_str(\"breakpoint pending\")" " = \"on\"" \ + "_gdb_setting_str breakpoint pending on" +gdb_test "p \$_gdb_setting(\"breakpoint pending\")" " = 1" \ + "_gdb_setting breakpoint pending 1" + +#test show breakpoint pending on +gdb_test "show breakpoint pending" " is on\..*" "show breakpoint pending on" + +#test show breakpoint pending off +gdb_test_no_output "set breakpoint pending off" +gdb_test "show breakpoint pending" " is off\..*" "show breakpoint pending off" +gdb_test "p \$_gdb_setting_str(\"breakpoint pending\")" " = \"off\"" \ + "_gdb_setting_str breakpoint pending off" +gdb_test "p \$_gdb_setting(\"breakpoint pending\")" " = 0" \ + "_gdb_setting breakpoint pending 0" + +#test set breakpoint pending auto +gdb_test_no_output "set breakpoint pending auto" + +#test show breakpoint pending auto +gdb_test "show breakpoint pending" " is auto.*" "show breakpoint pending auto" +gdb_test "p \$_gdb_setting_str(\"breakpoint pending\")" " = \"auto\"" \ + "_gdb_setting_str breakpoint pending auto" +gdb_test "p \$_gdb_setting(\"breakpoint pending\")" " = -1" \ + "_gdb_setting breakpoint pending -1" + + + #test set complaints 100 gdb_test_no_output "set complaints 100" "set complaints 100" #test show complaints 100 @@ -159,9 +213,17 @@ gdb_test "show environment FOOBARBAZ" "FOOBARBAZ = grbxgrbxgrbx.*" "show enviro gdb_test_no_output "set height 100" "set height 100" #test show height 100 gdb_test "show height" "Number of lines gdb thinks are in a page is 100..*" "show height" +gdb_test "p \$_gdb_setting_str(\"height\")" " = \"100\"" \ + "_gdb_setting_str height 100" +gdb_test "p \$_gdb_setting(\"height\")" " = 100" \ + "_gdb_setting height 100" # Back to infinite height to avoid pagers. While at it, check that # literal "unlimited" works just as well as 0. gdb_test_no_output "set height unlimited" +gdb_test "p \$_gdb_setting_str(\"height\")" " = \"unlimited\"" \ + "_gdb_setting_str height unlimited" +gdb_test "p \$_gdb_setting(\"height\")" " = 0" \ + "_gdb_setting height unlimited" #test set history expansion on gdb_test_no_output "set history expansion on" "set history expansion on" #test show history expansion on @@ -182,6 +244,12 @@ gdb_test_no_output "set history filename ~/foobar.baz" \ gdb_test "show history filename" \ "The filename in which to record the command history is \"[string_to_regexp $HOME]/foobar.baz\"..*" \ "show history filename (~/foobar.baz)" +gdb_test "p \$_gdb_setting(\"history filename\")" \ + " = \"[string_to_regexp $HOME]/foobar.baz\"..*" \ + "_gdb_setting history filename" +gdb_test "p \$_gdb_setting_str(\"history filename\")" \ + " = \"[string_to_regexp $HOME]/foobar.baz\"..*" \ + "_gdb_setting_str history filename" #get current working directory set PWD "" set test "show working directory" @@ -209,7 +277,7 @@ gdb_test_no_output "set history size 100" "set history size 100" #test show history size 100 gdb_test "show history size" "The size of the command history is 100..*" "show history size (100)" #test set language asm -gdb_test "set language asm" ".*" "set language asm" +gdb_test_no_output "set language asm" #test show language asm gdb_test "show language" "The current source language is \"asm\"..*" "show language (asm)" #test set language rust, with a trailing space diff --git a/gdb/testsuite/gdb.base/settings.exp b/gdb/testsuite/gdb.base/settings.exp index 53049d6b59..3cb6e63efe 100644 --- a/gdb/testsuite/gdb.base/settings.exp +++ b/gdb/testsuite/gdb.base/settings.exp @@ -35,11 +35,80 @@ if { ![readline_is_used] } { } # Test the show command SHOW_CMD. EXPECTED_RE is the expected output. -# This procedure exists in order to make it easier to make the test +# 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} { - gdb_test "$show_cmd" $expected_re "$show_cmd: $expected_re" +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" + } } # var_Xinteger tests. VARIANT determines which command/variant to @@ -68,16 +137,19 @@ proc test-integer {variant} { # -1 means unlimited. Other negative values are rejected. -1 # -is tested further below, along the "unlimited" tests. gdb_test "$set_cmd -2" "only -1 is allowed to set as unlimited" + 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. @@ -234,6 +306,8 @@ proc_with_prefix test-boolean {} { show_setting "$show_cmd" "on" } + check_type "test-settings boolean" "type = int" + foreach_with_prefix value { "of" "off" @@ -354,6 +428,8 @@ proc_with_prefix test-auto-boolean {} { 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\\." @@ -409,11 +485,13 @@ proc_with_prefix test-enum {} { # Various valid values. Test both full value names and # abbreviations. gdb_test_no_output "$set_cmd x" - show_setting "$show_cmd" "xxx" + show_setting "$show_cmd" "xxx" 0 "zzz" gdb_test_no_output "$set_cmd yy" - show_setting "$show_cmd" "yyy" + show_setting "$show_cmd" "yyy" 0 "zzz" gdb_test_no_output "$set_cmd zzz" - show_setting "$show_cmd" "zzz" + show_setting "$show_cmd" "zzz" 0 "yyy" + + check_type "test-settings enum" "type = char \\\[3\\\]" test_gdb_complete_multiple "$set_cmd " "" "" { "xxx" @@ -458,10 +536,12 @@ proc test-string {variant} { 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\\\\\"" + show_setting "$show_cmd" "\\\\\"hello world\\\\\"" 1 } else { gdb_test_no_output "$set_cmd \"hello world\"" show_setting "$show_cmd" "\"hello world\"" -- 2.20.1 From 7c6840123373fec635ce2fd00b9e2ec86a7d2fe9 Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Sun, 28 Apr 2019 14:44:44 +0200 Subject: [PATCH 3/3] NEWS and documentation for $_gdb_setting and $_gdb_int_setting. gdb/ChangeLog 2019-09-07 Philippe Waroquiers * NEWS: Mention $_gdb_setting, $_gdb_setting_str, $_gdb_maint_setting and $_gdb_maint_setting_str. gdb/doc/ChangeLog 2019-09-15 Philippe Waroquiers * gdb.texinfo (Convenience Funs): Document the new $_gdb_setting_str, $_gdb_maint_setting and $_gdb_maint_setting_str convenience functions. --- gdb/NEWS | 6 ++++ gdb/doc/gdb.texinfo | 80 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/gdb/NEWS b/gdb/NEWS index 25e67e43c8..a0d7ba9932 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -11,6 +11,12 @@ scripts that should work error-free with many different versions, such as in system-wide init files. +* New built-in convenience functions $_gdb_setting, $_gdb_setting_str, + $_gdb_maint_setting and $_gdb_maint_setting_str provide access to values + of the GDB settings and the GDB maintenance settings. They are handy + for changing the logic of user defined commands depending on the + current GDB settings. + * GDB now supports Thread Local Storage (TLS) variables on several FreeBSD architectures (amd64, i386, powerpc, riscv). Other architectures require kernel changes. TLS is not yet supported for diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 1208e4f615..cd1337ae85 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -11974,9 +11974,87 @@ $3 = void $4 = 1 @end smallexample +@item $_gdb_setting_str (@var{setting}) +@findex $_gdb_setting_str@r{, convenience function} +Return the value of the @value{GDBN} @var{setting} as a string. +@var{setting} is any setting that can be used in a @code{set} or +@code{show} command (@pxref{Controlling GDB}). + +@smallexample +(@value{GDBP}) show print frame-arguments +Printing of non-scalar frame arguments is "scalars". +(@value{GDBP}) p $_gdb_setting_str("print frame-arguments") +$1 = "scalars" +(@value{GDBP}) p $_gdb_setting_str("height") +$2 = "30" +(@value{GDBP}) +@end smallexample + +@item $_gdb_setting (@var{setting}) +@findex $_gdb_setting@r{, convenience function} +Return the value of the @value{GDBN} @var{setting}. +The type of the returned value depends on the setting. + +The value type for boolean and auto boolean settings is @code{int}. +The boolean values @code{off} and @code{on} are converted to +the integer values @code{0} and @code{1}. The value @code{auto} is +converted to the value @code{-1}. + +The value type for integer settings is either @code{unsigned int} +or @code{int}, depending on the setting. + +Some integer settings accept an @code{unlimited} value. +Depending on the setting, the @code{set} command also accepts +the value @code{0} or the value @code{@minus{}1} as a synonym for +@code{unlimited}. +For example, @code{set height unlimited} is equivalent to +@code{set height 0}. + +Some other settings that accept the @code{unlimited} value +use the value @code{0} to literally mean zero. +For example, @code{set history size 0} indicates to not +record any @value{GDBN} commands in the command history. +For such settings, @code{@minus{}1} is the synonym +for @code{unlimited}. + +See the documentation of the corresponding @code{set} command for +the numerical value equivalent to @code{unlimited}. + +The @code{$_gdb_setting} function converts the unlimited value +to a @code{0} or a @code{@minus{}1} value according to what the +@code{set} command uses. + +@smallexample +@group +(@value{GDBP}) p $_gdb_setting_str("height") +$1 = "30" +(@value{GDBP}) p $_gdb_setting("height") +$2 = 30 +(@value{GDBP}) set height unlimited +(@value{GDBP}) p $_gdb_setting_str("height") +$3 = "unlimited" +(@value{GDBP}) p $_gdb_setting("height") +$4 = 0 +@end group +@group +(@value{GDBP}) p $_gdb_setting_str("history size") +$5 = "unlimited" +(@value{GDBP}) p $_gdb_setting("history size") +$6 = -1 +(@value{GDBP}) p $_gdb_setting_str("disassemble-next-line") +$7 = "auto" +(@value{GDBP}) p $_gdb_setting("disassemble-next-line") +$8 = -1 +(@value{GDBP}) +@end group +@end smallexample + +Other setting types (enum, filename, optional filename, string, string noescape) +are returned as string values. + @end table -These functions require @value{GDBN} to be configured with +The following functions require @value{GDBN} to be configured with @code{Python} support. @table @code -- 2.20.1