[RFAv4 1/3] default-args: allow to define default command/alias arguments
Christian Biesinger via gdb-patches
gdb-patches@sourceware.org
Mon Feb 10 01:21:00 GMT 2020
Hi Philippe,
I have some style comments below.
On Sat, Feb 8, 2020 at 9:10 AM Philippe Waroquiers
<philippe.waroquiers@skynet.be> wrote:
>
> Currently, a user can define an alias, but cannot have default
> arguments for this alias.
>
> This patch provides the following:
>
> * A new command 'set default-args' that can define default args
> to prepend to the command or alias arguments before executing it.
> Note that default args can be used for an alias and can nicely
> combine nested "with" (see below the changes for the alias command).
>
> (gdb) help set default-args
> Set or clear default args automatically prepended to a command or alias.
> Usage: set default-args COMMAND [DEFAULT-ARGS...]
> Set or clear the default arguments automatically prepended
> to the arguments the user provides when COMMAND is run.
> Note that COMMAND can be an alias. Commands and their aliases
> do not share their default arguments, so you can specify different
> default arguments for a command and for each of its aliases.
> Without the [= DEFAULT-ARGS...], clears COMMAND default arguments.
>
> Note that 'set default-args' command has a completer to help typing
> COMMAND and its default-args.
>
> * A new command 'show default-args'.
>
> (gdb) help show default-args
> Show the default args of a command, or of all commands.
> Usage: show default-args [COMMAND]
> Show the default args of COMMAND. Without COMMAND, show the default args
> of all commands.
>
> * The 'alias' command is modified so as to directly accept default-args.
>
> (gdb) help alias
> Define a new command that is an alias of an existing command.
> Usage: alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]
> ALIAS is the name of the alias command to create.
> COMMAND is the command being aliased to.
>
> Options:
> -a
> Specify that ALIAS is an abbreviation of COMMAND.
> Abbreviations are not shown in command lists displayed by the 'help' command.
> You can optionally provide DEFAULT-ARGS to define at the same time
> ALIAS and its default args. This is the equivalent of:
> alias ALIAS = COMMAND
> set default-args ALIAS DEFAULT-ARGS...
>
> Examples:
> Make "spe" an alias of "set print elements":
> alias spe set print elements
> Make "elms" an alias of "elements" in the "set print" command:
> alias -a set print elms set print elements
> Make "btf" an alias of "backtrace -full -past-entry -past-main" :
> alias btf = backtrace -full -past-entry -past-main
> Make "wLapPeu" an alias of 2 nested "with":
> alias wLapPeu = with language pascal -- with print elements unlimited --
>
> * 'alias' command now has a completer that helps to complete:
> - ALIAS (if the user defines an alias after a prefix),
> - the aliased COMMAND
> - the possible options for the aliased COMMAND.
>
> * A new setting 'set enable-default-args'. This can be used if the
> user wants to temporarily disable the usage of default args.
> 'show enable-default-args' shows the value of 'enable-default-args'.
> The main intended usage of this setting is to use it in the "with"
> command: as set default-args can add arguments to standard GDB commands,
> it is useful (e.g. in user defined commands) to be able to go back
> to the 'standard' behaviour of a command.
>
> gdb/ChangeLog
> YYYY-MM-DD Philippe Waroquiers <philippe.waroquiers@skynet.be>
>
> * cli/cli-cmds.c (default_args_cmd_completer)
> (lookup_cmd_for_default_args, set_default_args_command)
> (show_default_args, show_default_args_command_1)
> (show_default_args_command, alias_command_completer)
> (make_alias_options_def_group): New functions.
> (alias_opts, alias_option_defs): New struct and array.
> (alias_usage_error): Update usage.
> (alias_command): Handles optional DEFAULT-ARGS... arguments.
> Use option framework.
> (_initialize_cli_cmds): Install 'set|show default-args' commands.
> Update alias command help.
> (show_user, valid_command_p):
> Add NULL for new default_args lookup_cmd argument.
> * cli/cli-decode.c (help_cmd): Show default args if command has
> some.
> (lookup_cmd_1, lookup_cmd): New argument default_args.
> (add_alias_cmd):
> Add NULL for new default_args lookup_cmd argument.
> (print_help_for_command): Show default args.
> * cli/cli-decode.h (struct cmd_list_element): New member default_args.
> xfree default_args in destructor.
> * cli/cli-script.c (process_next_line, do_define_command):
> Add NULL for new default_args lookup_cmd argument.
> * command.h: Declare new default_args argument in lookup_cmd
> and lookup_cmd_1.
> * completer.c (complete_line_internal_1):
> Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
> * guile/scm-cmd.c (gdbscm_parse_command_name): Likewise.
> * guile/scm-param.c (add_setshow_generic, pascm_parameter_defined_p):
> Likewise.
> * infcmd.c (_initialize_infcmd): Likewise.
> * python/py-auto-load.c (gdbpy_initialize_auto_load): Likewise.
> * python/py-cmd.c (gdbpy_parse_command_name): Likewise.
> * python/py-param.c (add_setshow_generic): Likewise.
> * remote.c (_initialize_remote): Likewise.
> * top.c (enable_default_args_var): New flag.
> (execute_command): Prepend default_args if command has some.
> (set_verbose):
> Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
> (init_main): Install 'set|show enable-default-args.
> * tracepoint.c (validate_actionline, encode_actions_1):
> Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
> ---
> gdb/cli/cli-cmds.c | 325 ++++++++++++++++++++++++++++++++++----
> gdb/cli/cli-decode.c | 89 +++++++++--
> gdb/cli/cli-decode.h | 6 +
> gdb/cli/cli-script.c | 12 +-
> gdb/command.h | 2 +
> gdb/completer.c | 2 +-
> gdb/guile/scm-cmd.c | 2 +-
> gdb/guile/scm-param.c | 6 +-
> gdb/infcmd.c | 6 +-
> gdb/python/py-auto-load.c | 4 +-
> gdb/python/py-cmd.c | 2 +-
> gdb/python/py-param.c | 4 +-
> gdb/remote.c | 4 +-
> gdb/top.c | 40 ++++-
> gdb/tracepoint.c | 6 +-
> 15 files changed, 439 insertions(+), 71 deletions(-)
>
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index 6f324410e1..d8197aa740 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -50,6 +50,7 @@
> #include "cli/cli-cmds.h"
> #include "cli/cli-style.h"
> #include "cli/cli-utils.h"
> +#include "cli/cli-style.h"
>
> #include "extension.h"
> #include "gdbsupport/pathstuff.h"
> @@ -230,6 +231,7 @@ with_command_1 (const char *set_cmd_prefix,
> nested_cmd = repeat_previous ();
>
> cmd_list_element *set_cmd = lookup_cmd (&args, setlist, set_cmd_prefix,
> + nullptr,
> /*allow_unknown=*/ 0,
> /*ignore_help_classes=*/ 1);
> gdb_assert (set_cmd != nullptr);
> @@ -324,6 +326,146 @@ with_command_completer (struct cmd_list_element *ignore,
> with_command_completer_1 ("set ", tracker, text);
> }
>
> +/* Completer for the "set|show default-args" commands. */
> +
> +static void
> +default_args_cmd_completer (struct cmd_list_element *ignore,
> + completion_tracker &tracker,
> + const char *text, const char *word)
> +{
> + tracker.set_use_custom_word_point (true);
> +
> + complete_nested_command_line (tracker, text);
> +}
> +
> +/* Look up the contents of TEXT as a command usable with default args.
> + Throws an error if no such command is found.
> + Return the found command and advances TEXT past the found command.
> + If the found command is a postfix command, set *PREFIX_CMD to its prefix command. */
> +
> +static struct cmd_list_element *
> +lookup_cmd_for_default_args (const char **text,
> + struct cmd_list_element **prefix_cmd)
> +{
> + const char *orig_text = *text;
> + struct cmd_list_element *lcmd, *alias, *cmd;
I think in new functions it would be better to move declarations to
where they are first used.
> +
> + if (*text == nullptr || skip_spaces (*text) == nullptr)
> + error (_("COMMAND missing."));
> +
> + /* We first use lookup_cmd to verify TEXT unambiguously identifies
> + a command. */
> + lcmd = lookup_cmd (text, cmdlist, "", NULL,
> + /*allow_unknown=*/ 0,
> + /*ignore_help_classes=*/ 1);
> +
> + /* Note that we accept default args for prefix commands,
> + as a prefix command can also be a valid usable
> + command accepting some arguments.
> + For example, "thread apply" applies a command to a
> + list of thread ids, and is also the prefix command for
> + thread apply all. */
> +
> + /* We have an unambiguous command for which default args
> + can be specified. What remains after having fond LCMD
> + is either spaces, or the default args character. */
> +
> + /* We then use lookup_cmd_composition to detect if the user
> + has specified an alias, and find the possible prefix_cmd
> + of cmd. */
> + lookup_cmd_composition
> + (std::string (orig_text, *text - orig_text).c_str (),
> + &alias, prefix_cmd, &cmd);
> + gdb_assert (cmd != nullptr);
> + gdb_assert (cmd == lcmd);
> + if (alias != nullptr)
> + cmd = alias;
> +
> + return cmd;
> +}
> +
> +/* Implementation of the "set default-args" command. */
> +
> +static void
> +set_default_args_command (const char *arg, int from_tty)
> +{
> + struct cmd_list_element *prefix_cmd;
> + struct cmd_list_element *cmd = lookup_cmd_for_default_args (&arg, &prefix_cmd);
> +
> + const char *default_args = skip_spaces (arg);
> +
> + if (*default_args == '\0')
> + default_args = nullptr;
> +
> + if (cmd->default_args)
> + xfree ((char *) cmd->default_args);
> + if (default_args == nullptr)
> + cmd->default_args = nullptr;
> + else
> + cmd->default_args = xstrdup (default_args);
> +}
> +
> +/* Print a message showing C's name and its default args or <no default args>
> + if C has no default args.
> + If SILENT_FOR_NO_DEFAULT_ARGS, does nothing if C has no default args. */
> +
> +static void
> +show_default_args (struct cmd_list_element *c,
> + const char *prefix,
> + bool silent_for_no_default_args)
> +{
> + if (c->default_args != nullptr || !silent_for_no_default_args)
> + {
> + fputs_filtered ("default-args ", gdb_stdout);
> + fprintf_styled (gdb_stdout, title_style.style (),
> + "%s%s",
> + prefix == nullptr ? "" : prefix, c->name);
> + fprintf_filtered (gdb_stdout, " = %s\n",
> + c->default_args == nullptr
> + ? "<no default args>" : c->default_args);
> + }
> +}
> +
> +/* Recursively traverse COMMANDLIST and prints a message showing
> + the default-args of the commands that have non-null default args.
> + PREFIX is the prefix that led to COMMANDLIST. */
> +
> +static void
> +show_default_args_command_1 (struct cmd_list_element *commandlist,
> + const char *prefix)
> +{
> + /* Walk through the commands. */
> + for (cmd_list_element *c = commandlist; c; c = c->next)
> + {
> + show_default_args (c, prefix, true);
> + /* If C has subcommands, recursively search if its subcommands
> + have default args.
> + Do not recurse for abbreviations to avoid duplicates
> + in the output. */
> + if (c->prefixlist != NULL && !c->abbrev_flag)
> + show_default_args_command_1 (*c->prefixlist, c->prefixname);
> + }
> +}
> +
> +/* Implementation of the "show default-args" command. */
> +
> +static void
> +show_default_args_command (const char *arg, int from_tty)
> +{
> + if (skip_spaces (arg) != nullptr)
> + {
> + struct cmd_list_element *prefix_cmd;
> + struct cmd_list_element *c = lookup_cmd_for_default_args (&arg,
> + &prefix_cmd);
> +
> + show_default_args (c,
> + prefix_cmd == nullptr ? "" : prefix_cmd->prefixname,
> + false);
> + }
> + else
> + show_default_args_command_1 (cmdlist, "");
> +}
> +
>
> /* Provide documentation on command or list given by COMMAND. FROM_TTY
> is ignored. */
> @@ -1550,7 +1692,7 @@ show_user (const char *args, int from_tty)
> {
> const char *comname = args;
>
> - c = lookup_cmd (&comname, cmdlist, "", 0, 1);
> + c = lookup_cmd (&comname, cmdlist, "", NULL, 0, 1);
> if (!cli_user_command_p (c))
> error (_("Not a user command."));
> show_user_1 (c, "", args, gdb_stdout);
> @@ -1582,6 +1724,71 @@ apropos_command (const char *arg, int from_tty)
> apropos_cmd (gdb_stdout, cmdlist, verbose, pattern, "");
> }
>
> +/* The options for the "alias" command. */
> +
> +struct alias_opts
> +{
> + /* For "-a". */
> + bool abbrev_flag = 0;
> +};
> +
> +static const gdb::option::option_def alias_option_defs[] = {
> +
> + gdb::option::flag_option_def<alias_opts> {
> + "a",
> + [] (alias_opts *opts) { return &opts->abbrev_flag; },
> + N_("Specify that ALIAS is an abbreviation of COMMAND.\n\
> +Abbreviations are not shown in command lists displayed by the 'help' command."),
> + },
> +
> +};
> +
> +/* Create an option_def_group for the "alias" options, with
> + A_OPTS as context. */
> +
> +static inline gdb::option::option_def_group
> +make_alias_options_def_group (alias_opts *a_opts)
> +{
> + return {{alias_option_defs}, a_opts};
> +}
> +
> +/* Completer for the "alias_command". */
> +
> +static void
> +alias_command_completer (struct cmd_list_element *ignore,
> + completion_tracker &tracker,
> + const char *text, const char *word)
> +{
> + const auto grp = make_alias_options_def_group (nullptr);
> +
> + tracker.set_use_custom_word_point (true);
> +
> + if (gdb::option::complete_options
> + (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp))
> + return;
> +
> + const char *delim = strstr (text, "=");
strchr?
> +
> + /* If we're past the "=" delimiter, complete the
> + "alias ALIAS = COMMAND [DEFAULT-ARGS...]" as if the user is
> + typing COMMAND DEFAULT-ARGS... */
> + if (delim != text
> + && delim != nullptr
> + && isspace (delim[-1])
> + && (isspace (delim[1]) || delim[1] == '\0'))
> + {
> + std::string new_text = std::string (delim + 1);
> +
> + tracker.advance_custom_word_point_by (delim + 1 - text);
> + complete_nested_command_line (tracker, new_text.c_str ());
> + return;
> + }
> +
> + /* We're not yet past the "=" delimiter. Complete a command, as
> + the user might type an alias following a prefix command. */
> + complete_nested_command_line (tracker, text);
> +}
> +
> /* Subroutine of alias_command to simplify it.
> Return the first N elements of ARGV flattened back to a string
> with a space separating each element.
> @@ -1616,7 +1823,7 @@ valid_command_p (const char *command)
> {
> struct cmd_list_element *c;
>
> - c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
> + c = lookup_cmd_1 (& command, cmdlist, NULL, NULL, 1);
>
> if (c == NULL || c == (struct cmd_list_element *) -1)
> return false;
> @@ -1634,7 +1841,7 @@ valid_command_p (const char *command)
> static void
> alias_usage_error (void)
> {
> - error (_("Usage: alias [-a] [--] ALIAS = COMMAND"));
> + error (_("Usage: alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]"));
> }
>
> /* Make an alias of an existing command. */
> @@ -1642,8 +1849,13 @@ alias_usage_error (void)
> static void
> alias_command (const char *args, int from_tty)
> {
> + alias_opts a_opts;
> +
> + auto grp = make_alias_options_def_group (&a_opts);
> + gdb::option::process_options
> + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp);
> +
> int i, alias_argc, command_argc;
> - int abbrev_flag = 0;
> const char *equals;
> const char *alias, *command;
>
> @@ -1654,24 +1866,18 @@ alias_command (const char *args, int from_tty)
> std::string args2 (args, equals - args);
>
> gdb_argv built_alias_argv (args2.c_str ());
> - gdb_argv command_argv (equals + 1);
> +
> + const char *default_args = equals + 1;
> + struct cmd_list_element *c_command_prefix;
> +
> + lookup_cmd_for_default_args (&default_args, &c_command_prefix);
> + std::string command_argv_str (equals + 1,
> + default_args == nullptr
> + ? strlen (equals + 1)
> + : default_args - equals - 1);
> + gdb_argv command_argv (command_argv_str.c_str ());
>
> char **alias_argv = built_alias_argv.get ();
> - while (alias_argv[0] != NULL)
> - {
> - if (strcmp (alias_argv[0], "-a") == 0)
> - {
> - ++alias_argv;
> - abbrev_flag = 1;
> - }
> - else if (strcmp (alias_argv[0], "--") == 0)
> - {
> - ++alias_argv;
> - break;
> - }
> - else
> - break;
> - }
>
> if (alias_argv[0] == NULL || command_argv[0] == NULL
> || *alias_argv[0] == '\0' || *command_argv[0] == '\0')
> @@ -1706,6 +1912,8 @@ alias_command (const char *args, int from_tty)
> if (valid_command_p (alias))
> error (_("Alias already exists: %s"), alias);
>
> + struct cmd_list_element *alias_cmd;
> +
> /* If ALIAS is one word, it is an alias for the entire COMMAND.
> Example: alias spe = set print elements
>
> @@ -1718,8 +1926,8 @@ alias_command (const char *args, int from_tty)
> if (alias_argc == 1)
> {
> /* add_cmd requires *we* allocate space for name, hence the xstrdup. */
> - add_com_alias (xstrdup (alias_argv[0]), command, class_alias,
> - abbrev_flag);
> + alias_cmd = add_com_alias (xstrdup (alias_argv[0]), command, class_alias,
> + a_opts.abbrev_flag);
> }
> else
> {
> @@ -1739,19 +1947,30 @@ alias_command (const char *args, int from_tty)
> alias_prefix = alias_prefix_string.c_str ();
> command_prefix = command_prefix_string.c_str ();
>
> - c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
> + c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, NULL, 1);
> /* We've already tried to look up COMMAND. */
> gdb_assert (c_command != NULL
> && c_command != (struct cmd_list_element *) -1);
> gdb_assert (c_command->prefixlist != NULL);
> - c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
> + c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, NULL, 1);
> if (c_alias != c_command)
> error (_("ALIAS and COMMAND prefixes do not match."));
>
> /* add_cmd requires *we* allocate space for name, hence the xstrdup. */
> - add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
> - command_argv[command_argc - 1],
> - class_alias, abbrev_flag, c_command->prefixlist);
> + alias_cmd = add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
> + command_argv[command_argc - 1],
> + class_alias, a_opts.abbrev_flag,
> + c_command->prefixlist);
> + }
> +
> + gdb_assert (alias_cmd);
> + gdb_assert (alias_cmd->default_args == nullptr);
> + if (default_args != nullptr)
> + {
> + default_args = skip_spaces (default_args);
> +
> + if (*default_args != '\0')
> + alias_cmd->default_args = xstrdup (default_args);
> }
> }
>
> @@ -1940,7 +2159,7 @@ setting_cmd (const char *fnname, struct cmd_list_element *showlist,
> 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);
> + cmd_list_element *cmd = lookup_cmd (&a0, showlist, "", NULL, -1, 0);
>
> if (cmd == nullptr || cmd_type (cmd) != show_cmd)
> error (_("First argument of %s must be a "
> @@ -2299,6 +2518,26 @@ You can supply a command number to start with, or a `+' to start after\n\
> the previous command number shown."),
> &showlist);
>
> + c = add_cmd ("default-args", class_support, set_default_args_command, _("\
> +Set or clear default args automatically prepended to a command or alias.\n\
> +Usage: set default-args COMMAND [DEFAULT-ARGS...]\n\
> +Set or clear the default arguments automatically prepended\n\
> +to the arguments the user provides when COMMAND is run.\n\
> +Note that COMMAND can be an alias. Commands and their aliases\n\
> +do not share their default arguments, so you can specify different\n\
> +default arguments for a command and for each of its aliases.\n\
> +Without the [= DEFAULT-ARGS...], clears COMMAND default arguments."),
> + &setlist);
> + set_cmd_completer_handle_brkchars (c, default_args_cmd_completer);
> +
> + c = add_cmd ("default-args", class_support, show_default_args_command, _("\
> +Show the default args of a command, or of all commands.\n\
> +Usage: show default-args [COMMAND]\n\
> +Show the default args of COMMAND. Without COMMAND, show the default args\n\
> +of all commands."),
> + &showlist);
> + set_cmd_completer_handle_brkchars (c, default_args_cmd_completer);
> +
> add_cmd ("version", no_set_class, show_version,
> _("Show what version of GDB this is."), &showlist);
>
> @@ -2450,19 +2689,37 @@ When 'on', each command is displayed as it is executed."),
> NULL,
> &setlist, &showlist);
>
> - c = add_com ("alias", class_support, alias_command, _("\
> + const auto alias_opts = make_alias_options_def_group (nullptr);
> +
> + static std::string alias_help
> + = gdb::option::build_help (_("\
> Define a new command that is an alias of an existing command.\n\
> -Usage: alias [-a] [--] ALIAS = COMMAND\n\
> +Usage: alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]\n\
> ALIAS is the name of the alias command to create.\n\
> COMMAND is the command being aliased to.\n\
> -If \"-a\" is specified, the command is an abbreviation,\n\
> -and will not appear in help command list output.\n\
> +\n\
> +Options:\n\
> +%OPTIONS%\n\
> +You can optionally provide DEFAULT-ARGS to define at the same time\n\
> +ALIAS and its default args. This is the equivalent of:\n\
> + alias ALIAS = COMMAND\n\
> + set default-args ALIAS DEFAULT-ARGS...\n\
> \n\
> Examples:\n\
> Make \"spe\" an alias of \"set print elements\":\n\
> - alias spe = set print elements\n\
> + alias spe set print elements\n\
> Make \"elms\" an alias of \"elements\" in the \"set print\" command:\n\
> - alias -a set print elms = set print elements"));
> + alias -a set print elms set print elements\n\
> +Make \"btf\" an alias of \"backtrace -full -past-entry -past-main\" :\n\
> + alias btf = backtrace -full -past-entry -past-main\n\
> +Make \"wLapPeu\" an alias of 2 nested \"with\":\n\
> + alias wLapPeu = with language pascal -- with print elements unlimited --"),
> + alias_opts);
> +
> + c = add_com ("alias", class_support, alias_command,
> + alias_help.c_str ());
> +
> + set_cmd_completer_handle_brkchars (c, alias_command_completer);
>
> const char *source_help_text = xstrprintf (_("\
> Read commands from a file named FILE.\n\
> diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
> index 7aecd9897e..8cfff843d2 100644
> --- a/gdb/cli/cli-decode.c
> +++ b/gdb/cli/cli-decode.c
> @@ -343,7 +343,7 @@ add_alias_cmd (const char *name, const char *oldname,
> struct cmd_list_element *old;
>
> tmp = oldname;
> - old = lookup_cmd (&tmp, *list, "", 1, 1);
> + old = lookup_cmd (&tmp, *list, "", NULL, 1, 1);
>
> return add_alias_cmd (name, old, theclass, abbrev_flag, list);
> }
> @@ -1045,6 +1045,7 @@ void
> help_cmd (const char *command, struct ui_file *stream)
> {
> struct cmd_list_element *c;
> + const char *initial_command = command;
>
> if (!command)
> {
> @@ -1058,7 +1059,7 @@ help_cmd (const char *command, struct ui_file *stream)
> return;
> }
>
> - c = lookup_cmd (&command, cmdlist, "", 0, 0);
> + c = lookup_cmd (&command, cmdlist, "", NULL, 0, 0);
>
> if (c == 0)
> return;
> @@ -1078,6 +1079,41 @@ help_cmd (const char *command, struct ui_file *stream)
> fputs_filtered (c->doc, stream);
> fputs_filtered ("\n", stream);
>
> + if (c->func != nullptr)
> + {
> + /* Print the default args of the command if it has some.
> + Use lookup_cmd_composition to find if help was requested for
> + an alias. In this case, rather print the alias default_args. */
> +
> + struct cmd_list_element *alias, *prefix_cmd, *cmd;
> + const char *name, *default_args;
> +
> + lookup_cmd_composition (initial_command,
> + &alias, &prefix_cmd, &cmd);
> + gdb_assert (cmd != nullptr);
> + gdb_assert (cmd == c);
> +
> + if (alias == nullptr)
> + {
> + name = c->name;
> + default_args = c->default_args;
> + }
> + else
> + {
> + name = alias->name;
> + default_args = alias->default_args;
> + }
> + if (default_args != nullptr)
> + {
> + fputs_filtered ("default-args ", stream);
> + fprintf_styled (stream, title_style.style (),
> + "%s%s",
> + prefix_cmd == nullptr ? "" : prefix_cmd->prefixname,
> + name);
> + fprintf_filtered (stream, " = %s\n", default_args);
> + }
> + }
> +
> if (c->prefixlist == 0 && c->func != NULL)
> return;
> fprintf_filtered (stream, "\n");
> @@ -1271,6 +1307,13 @@ print_help_for_command (struct cmd_list_element *c, const char *prefix,
> fputs_filtered (" -- ", stream);
> print_doc_line (stream, c->doc, false);
> fputs_filtered ("\n", stream);
> + if (c->default_args != nullptr)
> + {
> + fputs_filtered (" default-args ", stream);
> + fprintf_styled (stream, title_style.style (),
> + "%s%s", prefix, c->name);
> + fprintf_filtered (stream, " = %s\n", c->default_args);
> + }
>
> if (recurse
> && c->prefixlist != 0
> @@ -1422,8 +1465,12 @@ valid_user_defined_cmd_name_p (const char *name)
> the list in which there are ambiguous choices (and *TEXT will be set to
> the ambiguous text string).
>
> + if DEFAULT_ARGS is not null and the found command has default args defined,
> + then *DEFAULT_ARGS points at these default args.
> +
> If the located command was an abbreviation, this routine returns the base
> - command of the abbreviation.
> + command of the abbreviation. Note that *DEFAULT_ARGS will point at the
> + default args defined for the alias.
>
> It does no error reporting whatsoever; control will always return
> to the superior routine.
> @@ -1450,11 +1497,13 @@ valid_user_defined_cmd_name_p (const char *name)
>
> struct cmd_list_element *
> lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> - struct cmd_list_element **result_list, int ignore_help_classes)
> + struct cmd_list_element **result_list, const char **default_args,
> + int ignore_help_classes)
> {
> char *command;
> int len, nfound;
> struct cmd_list_element *found, *c;
> + bool found_alias = false;
> const char *line = *text;
>
> while (**text == ' ' || **text == '\t')
> @@ -1490,6 +1539,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> /* Will be modified in calling routine
> if we know what the prefix command is. */
> *result_list = 0;
> + if (default_args != NULL)
> + *default_args = nullptr;
NULL -> nullptr, for consistency between these two lines?
> return CMD_LIST_AMBIGUOUS; /* Ambiguous. */
> }
>
> @@ -1505,22 +1556,30 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> are warning about the alias, we may also warn about the command
> itself and we will adjust the appropriate DEPRECATED_WARN_USER
> flags. */
> -
> +
> if (found->deprecated_warn_user)
> deprecated_cmd_warning (line);
> +
> + /* Return the default_args of the alias, not the default_args
> + of the command it is pointing to. */
> + if (default_args != NULL)
> + *default_args = found->default_args;
> found = found->cmd_pointer;
> + found_alias = true;
> }
> /* If we found a prefix command, keep looking. */
>
> if (found->prefixlist)
> {
> c = lookup_cmd_1 (text, *found->prefixlist, result_list,
> - ignore_help_classes);
> + default_args, ignore_help_classes);
> if (!c)
> {
> /* Didn't find anything; this is as far as we got. */
> if (result_list != NULL)
> *result_list = clist;
> + if (!found_alias && default_args != NULL)
> + *default_args = found->default_args;
> return found;
> }
> else if (c == CMD_LIST_AMBIGUOUS)
> @@ -1535,6 +1594,9 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> at the top of this function to clarify what is
> supposed to be going on. */
> *result_list = found;
> + /* For ambiguous commands, do not return any default_args args. */
> + if (default_args != nullptr)
> + *default_args = nullptr;
> return c;
> }
> else
> @@ -1547,6 +1609,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> {
> if (result_list != NULL)
> *result_list = clist;
> + if (!found_alias && default_args != NULL)
> + *default_args = found->default_args;
> return found;
> }
> }
> @@ -1566,8 +1630,14 @@ undef_cmd_error (const char *cmdtype, const char *q)
>
> /* Look up the contents of *LINE as a command in the command list LIST.
> LIST is a chain of struct cmd_list_element's.
> - If it is found, return the struct cmd_list_element for that command
> - and update *LINE to point after the command name, at the first argument.
> + If it is found, return the struct cmd_list_element for that command,
> + update *LINE to point after the command name, at the first argument
> + and update *DEFAULT_ARGS (if DEFAULT_ARGS is not null) to point at
> + the default args to prepend to the user provided args when running
> + the command.
> + Note that if the found cmd_list_element is found via an alias,
> + the default args of the alias are returned.
> +
> If not found, call error if ALLOW_UNKNOWN is zero
> otherwise (or if error returns) return zero.
> Call error if specified command is ambiguous,
> @@ -1581,6 +1651,7 @@ undef_cmd_error (const char *cmdtype, const char *q)
> struct cmd_list_element *
> lookup_cmd (const char **line, struct cmd_list_element *list,
> const char *cmdtype,
> + const char **default_args,
> int allow_unknown, int ignore_help_classes)
> {
> struct cmd_list_element *last_list = 0;
> @@ -1592,7 +1663,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
> if (!*line)
> error (_("Lack of needed %scommand"), cmdtype);
>
> - c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
> + c = lookup_cmd_1 (line, list, &last_list, default_args, ignore_help_classes);
>
> if (!c)
> {
> diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
> index 4f7c7701e4..92bff3b38c 100644
> --- a/gdb/cli/cli-decode.h
> +++ b/gdb/cli/cli-decode.h
> @@ -72,6 +72,8 @@ struct cmd_list_element
> xfree ((char *) doc);
> if (name_allocated)
> xfree ((char *) name);
> + if (default_args)
> + xfree ((char *) default_args);
> }
>
> DISABLE_COPY_AND_ASSIGN (cmd_list_element);
> @@ -183,6 +185,10 @@ struct cmd_list_element
> /* Hook for another command to be executed after this command. */
> struct cmd_list_element *hook_post = nullptr;
>
> + /* Default arguments to automatically prepend to the user
> + provided arguments when running this command or alias. */
> + const char *default_args = nullptr;
Have you considered making this an std::string or unique_xmalloc_ptr
to simplify the memory management/?
> +
> /* Nonzero identifies a prefix command. For them, the address
> of the variable containing the list of subcommands. */
> struct cmd_list_element **prefixlist = nullptr;
> diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
> index c9d2378906..e912613785 100644
> --- a/gdb/cli/cli-script.c
> +++ b/gdb/cli/cli-script.c
> @@ -974,7 +974,7 @@ process_next_line (const char *p, struct command_line **command,
> /* Resolve command abbreviations (e.g. 'ws' for 'while-stepping'). */
> const char *cmd_name = p;
> struct cmd_list_element *cmd
> - = lookup_cmd_1 (&cmd_name, cmdlist, NULL, 1);
> + = lookup_cmd_1 (&cmd_name, cmdlist, NULL, NULL, 1);
> cmd_name = skip_spaces (cmd_name);
> bool inline_cmd = *cmd_name != '\0';
>
> @@ -1331,7 +1331,7 @@ validate_comname (const char **comname)
> std::string prefix (*comname, last_word - 1);
> const char *tem = prefix.c_str ();
>
> - c = lookup_cmd (&tem, cmdlist, "", 0, 1);
> + c = lookup_cmd (&tem, cmdlist, "", NULL, 0, 1);
> if (c->prefixlist == NULL)
> error (_("\"%s\" is not a prefix command."), prefix.c_str ());
>
> @@ -1387,7 +1387,7 @@ do_define_command (const char *comname, int from_tty,
>
> /* Look it up, and verify that we got an exact match. */
> tem = comname;
> - c = lookup_cmd (&tem, *list, "", -1, 1);
> + c = lookup_cmd (&tem, *list, "", NULL, -1, 1);
> if (c && strcmp (comname, c->name) != 0)
> c = 0;
>
> @@ -1432,7 +1432,7 @@ do_define_command (const char *comname, int from_tty,
> {
> /* Look up cmd it hooks, and verify that we got an exact match. */
> tem = comname + hook_name_size;
> - hookc = lookup_cmd (&tem, *list, "", -1, 0);
> + hookc = lookup_cmd (&tem, *list, "", NULL, -1, 0);
> if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
> hookc = 0;
> if (!hookc && commands == nullptr)
> @@ -1518,7 +1518,7 @@ document_command (const char *comname, int from_tty)
> list = validate_comname (&comname);
>
> tem = comname;
> - c = lookup_cmd (&tem, *list, "", 0, 1);
> + c = lookup_cmd (&tem, *list, "", NULL, 0, 1);
>
> if (c->theclass != class_user)
> error (_("Command \"%s\" is built-in."), comfull);
> @@ -1567,7 +1567,7 @@ define_prefix_command (const char *comname, int from_tty)
>
> /* Look it up, and verify that we got an exact match. */
> tem = comname;
> - c = lookup_cmd (&tem, *list, "", -1, 1);
> + c = lookup_cmd (&tem, *list, "", NULL, -1, 1);
> if (c != nullptr && strcmp (comname, c->name) != 0)
> c = nullptr;
>
> diff --git a/gdb/command.h b/gdb/command.h
> index 7f436c72c9..cb28dd94cb 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -252,11 +252,13 @@ extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
> extern struct cmd_list_element *lookup_cmd (const char **,
> struct cmd_list_element *,
> const char *,
> + const char **,
> int, int);
>
> extern struct cmd_list_element *lookup_cmd_1 (const char **,
> struct cmd_list_element *,
> struct cmd_list_element **,
> + const char **,
> int);
>
> extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
> diff --git a/gdb/completer.c b/gdb/completer.c
> index 619fb8a028..5e9b13aa90 100644
> --- a/gdb/completer.c
> +++ b/gdb/completer.c
> @@ -1324,7 +1324,7 @@ complete_line_internal_1 (completion_tracker &tracker,
> }
> else
> {
> - c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
> + c = lookup_cmd_1 (&p, cmdlist, &result_list, NULL, ignore_help_classes);
> }
>
> /* Move p up to the next interesting thing. */
> diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c
> index ec1adffa25..8fd2772df4 100644
> --- a/gdb/guile/scm-cmd.c
> +++ b/gdb/guile/scm-cmd.c
> @@ -512,7 +512,7 @@ gdbscm_parse_command_name (const char *name,
> prefix_text[i + 1] = '\0';
>
> prefix_text2 = prefix_text;
> - elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
> + elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
> if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
> {
> msg = xstrprintf (_("could not find command prefix '%s'"), prefix_text);
> diff --git a/gdb/guile/scm-param.c b/gdb/guile/scm-param.c
> index b72766523a..62e2108740 100644
> --- a/gdb/guile/scm-param.c
> +++ b/gdb/guile/scm-param.c
> @@ -466,13 +466,13 @@ add_setshow_generic (enum var_types param_type, enum command_class cmd_class,
> /* Lookup created parameter, and register Scheme object against the
> parameter context. Perform this task against both lists. */
> tmp_name = cmd_name;
> - param = lookup_cmd (&tmp_name, *show_list, "", 0, 1);
> + param = lookup_cmd (&tmp_name, *show_list, "", NULL, 0, 1);
> gdb_assert (param != NULL);
> set_cmd_context (param, self);
> *set_cmd = param;
>
> tmp_name = cmd_name;
> - param = lookup_cmd (&tmp_name, *set_list, "", 0, 1);
> + param = lookup_cmd (&tmp_name, *set_list, "", NULL, 0, 1);
> gdb_assert (param != NULL);
> set_cmd_context (param, self);
> *show_cmd = param;
> @@ -969,7 +969,7 @@ pascm_parameter_defined_p (const char *name, struct cmd_list_element *list)
> {
> struct cmd_list_element *c;
>
> - c = lookup_cmd_1 (&name, list, NULL, 1);
> + c = lookup_cmd_1 (&name, list, NULL, NULL, 1);
>
> /* If the name is ambiguous that's ok, it's a new parameter still. */
> return c != NULL && c != CMD_LIST_AMBIGUOUS;
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 62890bde2a..fd754ea7f9 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -3191,7 +3191,7 @@ is restored."),
> show_inferior_tty_command,
> &setlist, &showlist);
> cmd_name = "inferior-tty";
> - c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
> + c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
> gdb_assert (c != NULL);
> add_alias_cmd ("tty", c, class_alias, 0, &cmdlist);
>
> @@ -3204,7 +3204,7 @@ Follow this command with any number of args, to be passed to the program."),
> set_args_command,
> show_args_command,
> &setlist, &showlist);
> - c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
> + c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
> gdb_assert (c != NULL);
> set_cmd_completer (c, filename_completer);
>
> @@ -3223,7 +3223,7 @@ working directory."),
> set_cwd_command,
> show_cwd_command,
> &setlist, &showlist);
> - c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
> + c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
> gdb_assert (c != NULL);
> set_cmd_completer (c, filename_completer);
>
> diff --git a/gdb/python/py-auto-load.c b/gdb/python/py-auto-load.c
> index 2084fc43ff..56db946463 100644
> --- a/gdb/python/py-auto-load.c
> +++ b/gdb/python/py-auto-load.c
> @@ -84,12 +84,12 @@ Show the debugger's behaviour regarding auto-loaded Python scripts, "
> NULL, NULL, show_auto_load_python_scripts,
> &setlist, &showlist);
> cmd_name = "auto-load-scripts";
> - cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1);
> + cmd = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
> deprecate_cmd (cmd, "set auto-load python-scripts");
>
> /* It is needed because lookup_cmd updates the CMD_NAME pointer. */
> cmd_name = "auto-load-scripts";
> - cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1);
> + cmd = lookup_cmd (&cmd_name, showlist, "", NULL, -1, 1);
> deprecate_cmd (cmd, "show auto-load python-scripts");
>
> add_cmd ("python-scripts", class_info, info_auto_load_python_scripts,
> diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
> index b822c14004..b8e2c365ee 100644
> --- a/gdb/python/py-cmd.c
> +++ b/gdb/python/py-cmd.c
> @@ -390,7 +390,7 @@ gdbpy_parse_command_name (const char *name,
> std::string prefix_text (name, i + 1);
>
> prefix_text2 = prefix_text.c_str ();
> - elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
> + elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
> if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
> {
> PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
> diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c
> index 7b183cfa55..fb39187b18 100644
> --- a/gdb/python/py-param.c
> +++ b/gdb/python/py-param.c
> @@ -569,12 +569,12 @@ add_setshow_generic (int parmclass, enum command_class cmdclass,
> /* Lookup created parameter, and register Python object against the
> parameter context. Perform this task against both lists. */
> tmp_name = cmd_name;
> - param = lookup_cmd (&tmp_name, *show_list, "", 0, 1);
> + param = lookup_cmd (&tmp_name, *show_list, "", NULL, 0, 1);
> if (param)
> set_cmd_context (param, self);
>
> tmp_name = cmd_name;
> - param = lookup_cmd (&tmp_name, *set_list, "", 0, 1);
> + param = lookup_cmd (&tmp_name, *set_list, "", NULL, 0, 1);
> if (param)
> set_cmd_context (param, self);
> }
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 34a8a08f56..3396a80b87 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -14373,10 +14373,10 @@ If set, a break, instead of a cntrl-c, is sent to the remote target."),
> set_remotebreak, show_remotebreak,
> &setlist, &showlist);
> cmd_name = "remotebreak";
> - cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1);
> + cmd = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
> deprecate_cmd (cmd, "set remote interrupt-sequence");
> cmd_name = "remotebreak"; /* needed because lookup_cmd updates the pointer */
> - cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1);
> + cmd = lookup_cmd (&cmd_name, showlist, "", NULL, -1, 1);
> deprecate_cmd (cmd, "show remote interrupt-sequence");
>
> add_setshow_enum_cmd ("interrupt-sequence", class_support,
> diff --git a/gdb/top.c b/gdb/top.c
> index f702af9acd..2042f3d473 100644
> --- a/gdb/top.c
> +++ b/gdb/top.c
> @@ -549,6 +549,11 @@ set_repeat_arguments (const char *args)
> repeat_arguments = args;
> }
>
> +/* Flag for whether we want to use the configured default args.
> + Default is yes. */
> +
> +static bool enable_default_args_var = true;
> +
> /* Execute the line P as a command, in the current user context.
> Pass FROM_TTY as second argument to the defining function. */
>
> @@ -577,6 +582,8 @@ execute_command (const char *p, int from_tty)
> {
> const char *cmd = p;
> const char *arg;
> + const char *default_args;
> + std::string default_args_and_arg;
> int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
>
> line = p;
> @@ -584,15 +591,27 @@ execute_command (const char *p, int from_tty)
> /* If trace-commands is set then this will print this command. */
> print_command_trace ("%s", p);
>
> - c = lookup_cmd (&cmd, cmdlist, "", 0, 1);
> + c = lookup_cmd (&cmd, cmdlist, "", &default_args, 0, 1);
> p = cmd;
>
> scoped_restore save_repeat_args
> = make_scoped_restore (&repeat_arguments, nullptr);
> const char *args_pointer = p;
>
> - /* Pass null arg rather than an empty one. */
> - arg = *p ? p : 0;
> + if (default_args != nullptr && enable_default_args_var)
> + {
> + if (*p)
> + default_args_and_arg = std::string (default_args)
> + + ' ' + std::string (p);
> + else
> + default_args_and_arg = std::string (default_args);
> + arg = default_args_and_arg.c_str ();
> + }
> + else
> + {
> + /* Pass null arg rather than an empty one. */
> + arg = *p ? p : 0;
> + }
>
> /* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy
> while the is_complete_command(cfunc) test is just plain
> @@ -1935,7 +1954,7 @@ set_verbose (const char *args, int from_tty, struct cmd_list_element *c)
> const char *cmdname = "verbose";
> struct cmd_list_element *showcmd;
>
> - showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
> + showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, NULL, 1);
> gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
>
> if (c->doc && c->doc_allocated)
> @@ -2171,6 +2190,19 @@ EMACS-like or VI-like commands like control-P or ESC."),
> show_editing,
> &setlist, &showlist);
>
> + add_setshow_boolean_cmd ("enable-default-args", class_support,
> + &enable_default_args_var, _("\
> +Set whether GDB prepends default args when running a command.\n\
> +The default args for a command are configured using\n\
> +\"set default-args COMMAND = DEFAULT-ARGS..."), _("\
> +Show whether GDB prepends default args when running a command."), _("\
> +Use \"on\" to enable the usage of the configured default args,\n\
> +and \"off\" to disable it.\n\
> +Without an argument, default args usage is enabled."),
> + NULL,
> + NULL,
> + &setlist, &showlist);
> +
> add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\
> Set saving of the history record on exit."), _("\
> Show saving of the history record on exit."), _("\
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index aa6bea4a8f..26df3e0f61 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -651,7 +651,7 @@ validate_actionline (const char *line, struct breakpoint *b)
> if (*p == '#') /* comment line */
> return;
>
> - c = lookup_cmd (&p, cmdlist, "", -1, 1);
> + c = lookup_cmd (&p, cmdlist, "", NULL, -1, 1);
> if (c == 0)
> error (_("`%s' is not a tracepoint action, or is ambiguous."), p);
>
> @@ -1303,7 +1303,7 @@ encode_actions_1 (struct command_line *action,
> action_exp = action->line;
> action_exp = skip_spaces (action_exp);
>
> - cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
> + cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
> if (cmd == 0)
> error (_("Bad action list item: %s"), action_exp);
>
> @@ -2673,7 +2673,7 @@ trace_dump_actions (struct command_line *action,
> if (*action_exp == '#') /* comment line */
> continue;
>
> - cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
> + cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
> if (cmd == 0)
> error (_("Bad action list item: %s"), action_exp);
>
> --
> 2.20.1
>
More information about the Gdb-patches
mailing list