From patchwork Sat Sep 7 11:38:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philippe Waroquiers X-Patchwork-Id: 34442 Received: (qmail 104735 invoked by alias); 7 Sep 2019 11:38:39 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 104663 invoked by uid 89); 7 Sep 2019 11:38:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy=cumbersome, Cc, C-c X-HELO: mailsec106.isp.belgacom.be Received: from mailsec106.isp.belgacom.be (HELO mailsec106.isp.belgacom.be) (195.238.20.102) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 07 Sep 2019 11:38:36 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=skynet.be; i=@skynet.be; q=dns/txt; s=securemail; t=1567856316; x=1599392316; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mDBV9ADxmm1s0927WlKalj6GhHcnk41WqPrXnP6ey6s=; b=h+Y+vo92NYxh9ntJRC9oqVHO+uv9lOzMtNPwlIjiB0fgTpGDvyCK9l0T +2sHxTUIISAc2cwZHY5tb9N03aIStg==; Received: from 255.38-242-81.adsl-dyn.isp.belgacom.be (HELO md.home) ([81.242.38.255]) by relay.skynet.be with ESMTP/TLS/DHE-RSA-AES128-GCM-SHA256; 07 Sep 2019 13:38:31 +0200 From: Philippe Waroquiers To: gdb-patches@sourceware.org Cc: Philippe Waroquiers Subject: [RFAv4 1/3] Implement convenience functions to examine GDB settings. Date: Sat, 7 Sep 2019 13:38:21 +0200 Message-Id: <20190907113823.17436-2-philippe.waroquiers@skynet.be> In-Reply-To: <20190907113823.17436-1-philippe.waroquiers@skynet.be> References: <20190907113823.17436-1-philippe.waroquiers@skynet.be> MIME-Version: 1.0 X-IsSubscribed: yes The new convenience functions $_gdb_setting and $_gdb_setting_str provide access to the GDB settings in user-defined commands. Simimilarly, $_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 restor 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 heterogenous 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-07 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 | 231 ++++++++++++++++++++++++++++++++++++++++++ gdb/cli/cli-setshow.c | 2 +- gdb/cli/cli-setshow.h | 2 +- 3 files changed, 233 insertions(+), 2 deletions(-) diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 4fc656775c..c49fd56554 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -1908,6 +1908,199 @@ 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); + + int len0 = TYPE_LENGTH (type0); + std::vector arg0 (len0); + + memcpy (arg0.data (), value_contents (argv[0]), len0); + + const char *a0 = arg0.data (); + 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: + 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"); + break; + } + 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 (nullptr, 0, + 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 (), strlen (cmd_val.c_str ()), + builtin_type (gdbarch)->builtin_char); + } + + 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 (nullptr, 0, + 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) { @@ -2049,6 +2242,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 40538832b5..9e3332bf51 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);