diff options
author | Philippe Waroquiers <philippe.waroquiers@skynet.be> | 2019-04-28 14:38:18 +0200 |
---|---|---|
committer | Philippe Waroquiers <philippe.waroquiers@skynet.be> | 2019-10-31 23:31:43 +0100 |
commit | 9ad9b77d64920d3113a9e7ab9f022eb5a45cd49e (patch) | |
tree | 46aea16ddae3415219b847d785c4f3e1f63b3993 /gdb/cli | |
parent | e7e97a2ecd0e605d8128b3d055a8a5f7c2284b80 (diff) | |
download | gdb-9ad9b77d64920d3113a9e7ab9f022eb5a45cd49e.zip gdb-9ad9b77d64920d3113a9e7ab9f022eb5a45cd49e.tar.gz gdb-9ad9b77d64920d3113a9e7ab9f022eb5a45cd49e.tar.bz2 |
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-10-31 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* 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.
Diffstat (limited to 'gdb/cli')
-rw-r--r-- | gdb/cli/cli-cmds.c | 232 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.c | 2 | ||||
-rw-r--r-- | 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 a39ea22..4e58ddc 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\ +Some integer settings accept an unlimited value, returned\n\ +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\ +Some integer settings accept an unlimited value, returned\n\ +as 0 or -1 depending on the setting."), + 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\ +Some integer settings accept an unlimited value, returned\n\ +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\ +Some integer settings accept an unlimited value, returned\n\ +as 0 or -1 depending on the setting."), + 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 d839159..4cf2437 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 8bfe7e8..dbb3e9f 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); |