[RFAv4 0/3] Allow the user to define default args for commands and aliases

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFAv4 0/3] Allow the user to define default args for commands and aliases

Philippe Waroquiers
Allow the user to define default args for commands and aliases.

This patch series implements, tests and documents the following commands:

  set default-args COMMAND [DEFAULT-ARGS...]
  show default-args [COMMAND]
  set enable-default-args [on|off]
  show enable-default-args


It also changes the alias command to be:
  alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]


Using the above default-args commands and arguments, you can
define default arguments for commands or define powerful aliases.

For example:

  alias bt_ALL = backtrace -entry-values both -frame-arg all -past-main -past-entry -full

defines the alias bt_ALL that will give as much information as possible
in a backtrace.

Default args can usefully be combined with the 'with' command, such as:

Make "wLapPeu" an alias of 2 nested "with":
  alias wLapPeu = with language pascal -- with print elements unlimited --

or have an alias pp10 to pretty print an expression with a maximum of
10 elements:

  alias pp10 = with print pretty -- with print elem 10 -- print

This patch series also adds a completer for 'alias'.


This is the version 4 of the patch series.

Compared to the 3rd version:
  'leading args' has been replaced by 'default args'.

Compared to the second version, it handles the preliminary comments
of Pedro (and is rebased to the last master).

For what concerns changing 'alias -a' to 'alias -abbreviation":
This can for sure be done (and be backward compatible).  This can however
be done as a separate patch (I still also need to do a similar change
for the 'qcs' flags).

The second version changes were:
  * Removed the = separator between COMMAND and DEFAULT-ARGS
  * Converted alias command to use the option framework.
  * Show the default args of aliases in 'help aliases'.

Note 1: a preliminary version of this idea (using a command called
'add-args') was discussed in
https://sourceware.org/ml/gdb-patches/2019-06/msg00395.html
where Tom suggested to make it more GDB like, using 'set' command.

Note 2: Following another comment of Tom, there is no '=' character
to separate COMMAND from its default args.
If ever this would be ambiguous in some cases, we could introduce
an optional '=' character to separate COMMAND from its DEFAULT-ARGS.
Similarly, the alias command has no separator between COMMAND
and its DEFAULT-ARGS.



Reply | Threaded
Open this post in threaded view
|

[RFAv4 1/3] default-args: allow to define default command/alias arguments

Philippe Waroquiers
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  <[hidden email]>

        * 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;
+
+  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, "=");
+
+  /* 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;
       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;
+
     /* 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

Reply | Threaded
Open this post in threaded view
|

[RFAv4 2/3] Add tests for new default-args related commands and arguments.

Philippe Waroquiers
In reply to this post by Philippe Waroquiers
Test the new default-args behaviour and completion.
Note that gdb.base/default-args.exp is somewhat copied from
with.exp (the test of the with command), while default-exp.c
is a plain copy of with.c.

gdb/testsuite/ChangeLog
YYYY-MM-DD  Philippe Waroquiers  <[hidden email]>

        * gdb.base/default-args.exp: New test.
        * gdb.base/default.c: New file.
        * gdb.base/alias.exp: Update expected error msg for alias foo=bar.
---
 gdb/testsuite/gdb.base/alias.exp        |   2 +-
 gdb/testsuite/gdb.base/default-args.c   |  41 +++++++
 gdb/testsuite/gdb.base/default-args.exp | 151 ++++++++++++++++++++++++
 3 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/default-args.c
 create mode 100644 gdb/testsuite/gdb.base/default-args.exp

diff --git a/gdb/testsuite/gdb.base/alias.exp b/gdb/testsuite/gdb.base/alias.exp
index be78d9e936..d98c3a38f1 100644
--- a/gdb/testsuite/gdb.base/alias.exp
+++ b/gdb/testsuite/gdb.base/alias.exp
@@ -56,7 +56,7 @@ test_abbrev_alias set6 "alias -a -- set6 = set" 46
 test_abbrev_alias -a "alias -a -- -a = set" 47
 
 gdb_test "alias set2=set" "already exists: set2"
-gdb_test "alias foo=bar" "Invalid command to alias to: bar"
+gdb_test "alias foo=bar" "Undefined command: \"bar\".  Try \"help\"."
 
 gdb_test_no_output "alias spe = set p elem"
 gdb_test_no_output "spe 50"
diff --git a/gdb/testsuite/gdb.base/default-args.c b/gdb/testsuite/gdb.base/default-args.c
new file mode 100644
index 0000000000..c6426625d4
--- /dev/null
+++ b/gdb/testsuite/gdb.base/default-args.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int xxx1 = 123;
+
+struct S
+{
+  int a;
+  int b;
+  int c;
+};
+
+struct S g_s = {1, 2, 3};
+
+static void
+inc ()
+{
+  g_s.a++;;
+}
+
+int
+main ()
+{
+  inc ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/default-args.exp b/gdb/testsuite/gdb.base/default-args.exp
new file mode 100644
index 0000000000..3b486a6c7a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/default-args.exp
@@ -0,0 +1,151 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the "default-args" related commands and arguments.
+
+load_lib completion-support.exp
+
+standard_testfile .c
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+    return -1
+}
+
+clean_restart $binfile
+
+# Basic/core tests using user-visible commands.
+with_test_prefix "basics" {
+    # Define an alias to pretty print something.
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" "simple print"
+    gdb_test_no_output "alias PP = print -pretty --" "alias PP"
+    gdb_test "show default-args PP" "default-args PP = -pretty --"
+    gdb_test "PP g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"]
+
+    # Define default-args for "inspect", should not impact "print".
+    gdb_test_no_output "set default-args inspect -pretty --" "inspect -pretty"
+    gdb_test "show default-args inspect" "default-args inspect = -pretty --"
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" "simple print not impacted"
+    gdb_test "inspect g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"]
+
+    # Set hex as default FMT for print.
+    gdb_test_no_output "set default-args print -- /x" "print hex"
+    gdb_test "inspect g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"] "inspect g_s still pretty"
+    gdb_test "print g_s" " = {a = 0x1, b = 0x2, c = 0x3}" "simple print hex"
+
+    # Test disabling default args.
+    gdb_test "show enable-default-args" \
+ "Whether GDB prepends default args when running a command is on\."
+    gdb_test_no_output "set enable-default-args off"
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" \
+ "simple print with enable-default-args off"
+    gdb_test_no_output "set enable-default-args on"
+    
+
+    # Define default-args for an alias of frame apply all
+    gdb_test_no_output "alias frame apply tout = frame apply all -past-entry -past-main" \
+ "alias frame apply tout"
+    gdb_test "show default-args frame apply tout" \
+ "default-args frame apply tout = -past-entry -past-main"
+
+    # Show all default args.
+    gdb_test "show default-args" \
+ [multi_line  \
+     "default-args PP = -pretty --" \
+     "default-args frame apply tout = -past-entry -past-main" \
+     "default-args inspect = -pretty --" \
+     "default-args print = -- /x"] "show default-args"
+
+    # Clear the default-args of "inspect".
+    gdb_test_no_output "set default-args inspect" "clear inspect default-args"
+    gdb_test "show default-args inspect" "default-args inspect = <no default args>"
+    gdb_test "inspect g_s" " = {a = 1, b = 2, c = 3}" "simple inspect"
+
+}
+
+# Check errors.
+with_test_prefix "errors" {
+    # Try an unknown root setting.
+    gdb_test "set default-args xxxx yyyy -someoption" \
+ "Undefined command: \"xxxx\".  Try \"help\"\\."
+
+    # Try ambiguous command.
+    gdb_test "set default-args a" \
+ "Ambiguous command \"a\":.*" "ambiguous a"
+    gdb_test "set default-args frame a" \
+ "Ambiguous frame command \"a\":.*" "ambiguous frame a"
+}
+
+
+# Check completion.
+with_test_prefix "completion" {
+    test_gdb_complete_unique \
+ "alias set pri" \
+ "alias set print"
+
+    test_gdb_complete_unique \
+ "alias set print items = set pri" \
+ "alias set print items = set print"
+
+    test_gdb_complete_unique \
+ "alias set print items = set print ele" \
+ "alias set print items = set print elements"
+
+   test_gdb_complete_unique \
+ "alias btfu = backt" \
+ "alias btfu = backtrace"
+
+   test_gdb_complete_unique \
+ "alias btfu = backtrace -fu" \
+ "alias btfu = backtrace -full"
+
+   test_gdb_complete_unique \
+ "alias btfu = backtrace -full -past-e" \
+ "alias btfu = backtrace -full -past-entry"
+
+    gdb_test_no_output "alias btfu = backtrace -full -past-entry" \
+ "alias btfu"
+
+    # Test completion of 'set default-args' (sharing most
+    # of the code that alias command uses to complete after
+    # the first =.
+    test_gdb_complete_unique \
+ "set default-args btf" \
+ "set default-args btfu"
+
+    test_gdb_complete_unique \
+ "set default-args btfu -frame-a" \
+ "set default-args btfu -frame-arguments"
+
+}
--
2.20.1

Reply | Threaded
Open this post in threaded view
|

[RFAv4 3/3] NEWS and documentation for default-args related concept and commands.

Philippe Waroquiers
In reply to this post by Philippe Waroquiers
gdb/ChangeLog
YYYY-MM-DD  Philippe Waroquiers  <[hidden email]>

        * NEWS: Mention new default-args commands.  Mention change
        to the alias command.

gdb/doc/ChangeLog
YYYY-MM-DD  Philippe Waroquiers  <[hidden email]>

        * gdb.texinfo (Command default args): New node documenting
        'set|show default-args' and 'set|show enable-default-args'.
        (Aliases): Document the new 'DEFAULT-ARGS...' option.
---
 gdb/NEWS            |  27 ++++++++++
 gdb/doc/gdb.texinfo | 126 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index d4e2e70f38..a59f9573fd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,33 @@ show exec-file-mismatch -- Show exec-file-mismatch handling (ask|warn|off).
   whether to load the process executable file; if 'warn', just display
   a warning; if 'off', don't attempt to detect a mismatch.
 
+set default-args COMMAND [DEFAULT-ARGS...]
+show default-args [COMMAND]
+set enable-default-args [on|off]
+show enable-default-args
+  GDB can now automatically prepend default args to a command or alias.
+  This allows to set default arguments or options for the GDB commands
+  or define easily more specialised aliases.
+  For example, 'set default-args backtrace -full -frame-arguments all'
+  ensures that backtrace will automatically use the options -full
+  -frame-arguments all, without having to retype them for each backtrace
+  command.
+
+* Changed commands
+
+alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]
+  The alias command can now directly define default-args
+  to prepend to arguments provided by the user on the command line.
+  For example, to have a backtrace with full details, you can define an
+  alias 'bt_ALL' as 'alias bt_ALL = backtrace -entry-values both -frame-arg
+  all -past-main -past-entry -full'.
+  Alias default arguments can also use a set of nested 'with' commands,
+  e.g. 'alias pp10 = with print pretty -- with print elem 10 -- print'
+  defines the alias pp10 that will pretty print a maximum of 10 elements
+  of the given expression (if the expression is an array).
+  See 'set default-args COMMAND [DEFAULT-ARGS...]' for more
+  information about default args concept.
+
 *** Changes in GDB 9
 
 * 'thread-exited' event is now available in the annotations interface.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a2866a2833..fb3c4926c4 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1577,6 +1577,7 @@ show you the alternatives available, if there is more than one possibility).
 * Command Settings::            How to change default behavior of commands
 * Completion::                  Command completion
 * Command Options::             Command options
+* Command default args::        Automatically prepend default arguments to commands and aliases
 * Help::                        How to ask @value{GDBN} for help
 @end menu
 
@@ -1997,6 +1998,116 @@ uppercase.
 (For more on using the @code{print} command, see @ref{Data, ,Examining
 Data}.)
 
+@node Command default args
+@section Automatically prepend default arguments to commands and aliases
+
+You can tell @value{GDBN} to always add some default options or
+arguments to a command.
+
+@cindex command options, automatically prepend
+@cindex command, default arguments
+
+@table @code
+@kindex set default-args
+@item set default-args @var{command} [@var{default-args@dots{}}]
+
+If you repetitively use the same arguments or options for a command,
+you can tell @value{GDBN} to automatically prepend these arguments
+or options to the arguments you type explicitely.
+
+For example, if you always want to have the command @code{thread apply all}
+working on the threads in ascending order and to continue in case it
+encounters an error, you can tell @value{GDBN} to automatically preprend
+the @code{-ascending} and @code{-c} options by using:
+
+@smallexample
+(@value{GDBP}) set default-args thread apply all -ascending -c
+@end smallexample
+
+Once you have set these default args, any time you type
+the @code{thread apply all} followed by @code{some arguments},
+@value{GDBN} will execute  @code{thread apply all -ascending -c some arguments}.
+
+As usual, unambiguous abbreviations can be used for @var{command}
+and @var{default-args}.
+
+Commands and their aliases do not share their default args.
+So, for example, you can configure the commands @code{bt}, @code{where},
+@code{backtrace} and @code{info stack} to output different levels
+of information and define a new alias @code{bt_ALL} showing all possible
+information using:
+@smallexample
+(@value{GDBP}) set default-args bt -entry-values no -frame-arguments none
+(@value{GDBP}) set default-args where -entry-values no -frame-argu scalars
+(@value{GDBP}) set default-args backtrace -entry-values no -frame-argu all
+(@value{GDBP}) set default-args info stack -entry-val both -fr all
+(@value{GDBP}) alias bt_ALL = backtrace
+(@value{GDBP}) set default-args bt_ALL -entry-values both -frame-arg all \
+-past-main -past-entry -full
+@end smallexample
+
+You can define an alias and specify its default args in one command using the shorter to type:
+@smallexample
+(@value{GDBP}) alias bt_ALL = backtrace -entry-values both -frame-arg all \
+-past-main -past-entry -full
+@end smallexample
+(For more on using the @code{alias} command, see @ref{Aliases}.)
+
+Default args are not limited to the arguments and options of @var{command},
+but can specify nested commands if @var{command} accepts such a nested command
+as argument.
+For example, the below defines @code{faalocalsoftype} that can be used to list
+the frames having locals of a certain type, together with the matching local
+vars:
+@smallexample
+(@value{GDBP}) alias faalocalsoftype = frame apply all info locals -q -t
+(@value{GDBP}) faalocalsoftype int
+#1  0x55554f5e in sleeper_or_burner (v=0xdf50) at sleepers.c:86
+i = 0
+ret = 21845
+@end smallexample
+
+This is also very useful to define an alias for a set of nested @code{with}
+commands to have a particular combination of temporary settings.  For example,
+the below defines the alias @code{pp10} that pretty prints an expression
+argument, with a maximum of 10 elements if the expression is a string or
+an array:
+@smallexample
+(@value{GDBP}) alias pp10 = with print pretty -- with print elem 10 -- print
+@end smallexample
+
+
+Use @code{set default-args @var{command}} (without giving @var{default-args})
+to clear the default args of @var{command}.
+
+@item show default-args [@var{command}]
+
+Use @code{show default-args @var{command}} to show the current values of
+the default args for @var{command}.  For example:
+@smallexample
+(@value{GDBP}) show default-args backtrace
+default-args backtrace = -entry-values no -frame-arguments all
+(@value{GDBP}) show default-args break
+default-args break = <no default args>
+@end smallexample
+
+To show all the commands and aliases that have some default args configured,
+use the command
+@code{show default-args} without giving a @var{command} argument.
+
+@item set enable-default-args @r{[}on|off@r{]}
+@itemx show enable-default-args
+By default, @value{GDBN} will use the configured default args.
+This can be disabled using @code{set enable-default-args off}.
+The default args of all commands are not cleared, but
+will not be used till you do @code{set enable-default-args on}.
+This can be useful in user defined commands to ensure only the specified
+set of options are used by a command launched by the user-defined command.
+You can also use this setting in the @code{with} command, to temporarily
+run a command without its possibly configured default args.
+
+@end table
+
 @node Help
 @section Getting Help
 @cindex online documentation
@@ -27481,7 +27592,7 @@ You can define a new alias with the @samp{alias} command.
 @table @code
 
 @kindex alias
-@item alias [-a] [--] @var{ALIAS} = @var{COMMAND}
+@item alias [-a] [--] @var{ALIAS} = @var{COMMAND} [DEFAULT-ARGS...]
 
 @end table
 
@@ -27499,6 +27610,19 @@ lists displayed by the @samp{help} command.
 The @samp{--} option specifies the end of options,
 and is useful when @var{ALIAS} begins with a dash.
 
+You can specify @var{default-args} for your alias.
+These @var{default-args} will be automatically added before the alias
+arguments typed explicitely on the command line.
+
+For example, the below defines an alias @code{btfullall} that shows all local
+variables and all frame arguments:
+@smallexample
+(@value{GDBP}) alias btfullall = backtrace -full -frame-arguments all
+@end smallexample
+
+For more information about @var{default-args}, see @ref{Command default args,
+,Automatically prepend default arguments to commands and aliases}
+
 Here is a simple example showing how to make an abbreviation
 of a command so that there is less to type.
 Suppose you were tired of typing @samp{disas}, the current
--
2.20.1

Reply | Threaded
Open this post in threaded view
|

Re: [RFAv4 3/3] NEWS and documentation for default-args related concept and commands.

Eli Zaretskii
> From: Philippe Waroquiers <[hidden email]>
> Cc: Philippe Waroquiers <[hidden email]>
> Date: Sat,  8 Feb 2020 15:09:13 +0100
>
> gdb/ChangeLog
> YYYY-MM-DD  Philippe Waroquiers  <[hidden email]>
>
> * NEWS: Mention new default-args commands.  Mention change
> to the alias command.
>
> gdb/doc/ChangeLog
> YYYY-MM-DD  Philippe Waroquiers  <[hidden email]>
>
> * gdb.texinfo (Command default args): New node documenting
> 'set|show default-args' and 'set|show enable-default-args'.
> (Aliases): Document the new 'DEFAULT-ARGS...' option.
> ---
>  gdb/NEWS            |  27 ++++++++++
>  gdb/doc/gdb.texinfo | 126 +++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 152 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index d4e2e70f38..a59f9573fd 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -23,6 +23,33 @@ show exec-file-mismatch -- Show exec-file-mismatch handling (ask|warn|off).
>    whether to load the process executable file; if 'warn', just display
>    a warning; if 'off', don't attempt to detect a mismatch.
>  
> +set default-args COMMAND [DEFAULT-ARGS...]
> +show default-args [COMMAND]
> +set enable-default-args [on|off]
> +show enable-default-args
> +  GDB can now automatically prepend default args to a command or alias.

Since we seem to be splitting hair now, at least in the documentation
parts: "prepending ... args to a command" doesn't sound right.  You
actually prepend the default arguments to the command's list of
arguments, right?

> +You can tell @value{GDBN} to always add some default options or
> +arguments to a command.

Same issue here.

> +If you repetitively use the same arguments or options for a command,
          ^^^^^^^^^^^^
"repeatedly" sounds better here.

> +@smallexample
> +(@value{GDBP}) alias bt_ALL = backtrace -entry-values both -frame-arg all \
> +-past-main -past-entry -full

Suggest to indent the second line of the example, to make it more
evident that it's a continuation of the previous line.

> +This is also very useful to define an alias for a set of nested @code{with}
> +commands to have a particular combination of temporary settings.  For example,
> +the below defines the alias @code{pp10} that pretty prints an expression
> +argument, with a maximum of 10 elements if the expression is a string or
> +an array:
> +@smallexample
> +(@value{GDBP}) alias pp10 = with print pretty -- with print elem 10 -- print
> +@end smallexample

I must admit I don't understand this particular feature.  What does
"with" signify here, and what is the significance of the "--" parts?
IOW, it would help if you deconstructed this example some more,
showing what each part of it does.

> +This can be disabled using @code{set enable-default-args off}.
> +The default args of all commands are not cleared, but

"not cleared by @code{set enable-default-args off}" makes this
sentence more clear, IMO.

And one more question that popped up while reading this: when I invoke
a command that has some default args defined for it, what is recorded
in command history? the full command with the default args, or just
what I typed?

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [RFAv4 1/3] default-args: allow to define default command/alias arguments

Sourceware - gdb-patches mailing list
In reply to this post by Philippe Waroquiers
Hi Philippe,

I have some style comments below.

On Sat, Feb 8, 2020 at 9:10 AM Philippe Waroquiers
<[hidden email]> 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  <[hidden email]>
>
>         * 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
>