Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Simon Marchi via Gdb-patches <gdb-patches@sourceware.org>
To: Marco Barisione <mbarisione@undo.io>, gdb-patches@sourceware.org
Subject: Re: [PATCH v2 5/5] gdb: Add support for renaming commands
Date: Tue, 23 Mar 2021 14:45:21 -0400	[thread overview]
Message-ID: <c5832aaa-dc84-33e2-a2ae-509dfe8d9eec@polymtl.ca> (raw)
In-Reply-To: <20210125112649.56362-6-mbarisione@undo.io>



On 2021-01-25 6:26 a.m., Marco Barisione via Gdb-patches wrote:
> This patch adds:
> * A "rename" command.
> * A "-rename-existing-to" option for the "define" command.
> * A "rename_existing_to" optional argument to gdb.Command.__init__
>   which matches the behaviour of "define -rename-existing-to".
> 
> The goal of this is to allow users to build on top of existing commands
> without losing their original implementation.
> Something similar could be achieved through hooks but they are limited:
> * Hooks cannot prevent the command from being executed without printing
>   any error.
> * Hooks don't get passed the arguments passed to the command.
> * Post hooks can't know if the command failed.
> * Hooks cannot be defined in Python.

The command code really gives me headaches.  I read the code but I won't
pretend like I thoroughly check it.

Here are some minor things I noted while reading it.

> @@ -160,53 +166,191 @@ set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd,
>    cmd->completer_handle_brkchars = func;
>  }
>  
> -/* Like ADD_CMD, but the command function fields are not modified.  */
> +/* Update the prefix-related fields associated with command C, which must
> +   be part of the comand list *LIST, and, if not null, adds PREFIXLIST

comand -> command

> @@ -283,14 +435,19 @@ add_alias_cmd (const char *name, cmd_list_element *old,
>  {
>    if (old == 0)
>      {
> +      struct cmd_list_element **prefixlist;
> +      struct cmd_list_element *aliases;
>        struct cmd_list_element *prehook, *prehookee, *posthook, *posthookee;
> -      struct cmd_list_element *aliases = delete_cmd (name, list,
> -						     &prehook, &prehookee,
> -						     &posthook, &posthookee);
> -
> +      struct cmd_list_element *old_cmd
> +	= disconnect_cmd (name, list,
> +			  &prefixlist,
> +			  &aliases,
> +			  &prehook, &prehookee,
> +			  &posthook, &posthookee);
>        /* If this happens, it means a programmer error somewhere.  */
> -      gdb_assert (!aliases && !prehook && !prehookee
> -		  && !posthook && ! posthookee);
> +      gdb_assert (!old_cmd);

Compare pointers explicitly with nullptr:

  gdb_assert (old_cmd != nullptr);

> +      /* As OLD_CMD is null, NAME didn't exist, so the prefix list,
> +       * aliases and hooks are all null as well.  */

Remove the asterisk on the second line:

      /* As OLD_CMD is null, NAME didn't exist, so the prefix list,
         aliases and hooks are all null as well.  */

> diff --git a/gdb/command.h b/gdb/command.h
> index ca791cff809..b20737a6aee 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -175,24 +175,37 @@ extern bool valid_cmd_char_p (int c);
>     It should start with ? for a command that is an abbreviation
>     or with * for a command that most users don't need to know about.
>  
> +   If RENAME_EXISTING_TO is not null, then the existing command called
> +   NAME in *LIST will be renamed to RENAME_EXISTING_TO in
> +   *RENAME_EXISTING_TO_LIST.  If a command called RENAME_EXISTING_TO
> +   already exists in *RENAME_EXISTING_TO_LIST, it gets deleted first.
> +   Ownership of RENAME_EXISTING_TO is not taken by this function (i.e.
> +   the caller is responsible to free it if needed).
> +
>     If NAME already existed in *LIST, all its hooks and aliases are moved
>     to the new command.
>  
>     Return a pointer to the added command (not necessarily the head of
>     *LIST).  */
>  
> -extern struct cmd_list_element *add_cmd (const char *name,
> -					 enum command_class theclass,
> -					 cmd_const_cfunc_ftype *fun,
> -					 const char *doc,
> -					 struct cmd_list_element **list);
> +extern struct cmd_list_element *add_cmd
> +		(const char *name,
> +		 enum command_class theclass,
> +		 cmd_const_cfunc_ftype *fun,
> +		 const char *doc,
> +		 struct cmd_list_element **list,
> +		 const char *rename_existing_to=nullptr,
> +		 struct cmd_list_element **rename_existing_to_list=nullptr);

Spaces around `=`, apply everywhere where it's relevant.

When wrapping like this, where you need to start the parameter list on
another line, use a single indent (two spaces).  Like this:

extern struct cmd_list_element *add_cmd
  (const char *name,
   enum command_class theclass,
   cmd_const_cfunc_ftype *fun,
   const char *doc,
   struct cmd_list_element **list,
   const char *rename_existing_to=nullptr,
   struct cmd_list_element **rename_existing_to_list=nullptr);

Optionally, you can also put multiple parameters on the same line to use
less lines.  Since we use C++, I like to get rid of `struct` or `enum`
keywords when possible, that's less verbose.

extern cmd_list_element *add_cmd
  (const char *name, command_class theclass, cmd_const_cfunc_ftype *fun,
   const char *doc, cmd_list_element **list,
   const char *rename_existing_to = nullptr,
   cmd_list_element **rename_existing_to_list = nullptr);


> diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
> index 35568594f58..22155f595c6 100644
> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -3657,7 +3657,7 @@ You can implement new @value{GDBN} CLI commands in Python.  A CLI
>  command is implemented using an instance of the @code{gdb.Command}
>  class, most commonly using a subclass.
>  
> -@defun Command.__init__ (name, @var{command_class} @r{[}, @var{completer_class} @r{[}, @var{prefix}@r{]]})
> +@defun Command.__init__ (name, @var{command_class} @r{[}, @var{completer_class} @r{[}, @var{prefix} @r{[}, @var{rename_existing_to}@r{]]]})

I think the way this renders to is misleading:

    Command.__init__ (name, command_class [, completer_class [, prefix [, rename_existing_to]]])

The brackets are nested, so it makes it sound like rename_existing_to
can only be used when prefix is given.  And they both can only be used
when completer_class is given.

And since command_class is now sometimes optional, it should be marked
as such.

    Command.__init__ (name[, command_class] [, completer_class] [, prefix] [, rename_existing_to])

> @@ -3931,6 +3945,24 @@ registration of the command with @value{GDBN}.  Depending on how the
>  Python code is read into @value{GDBN}, you may need to import the
>  @code{gdb} module explicitly.
>  
> +The following code snippet shows how a CLI command building on top of an
> +existing command can be implemented:
> +
> +@smallexample
> +class MyQuit (gdb.Command):
> +  """Print a message before executing the "quit" command."""
> +
> +  def __init__ (self):
> +    super (MyQuit, self).__init__ ("quit", gdb.COMMAND_RUNNING,
> +                                  rename_existing_to="original-quit")

Do you use COMMAND_RUNNING on purpose here, to show that it's possible
to change the class of a command?

> @@ -450,40 +457,130 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
>        return -1;
>      }
>  
> -  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "si|iO",
> -					keywords, &name, &cmdtype,
> -					&completetype, &is_prefix_obj))
> +  /* The second argument (command_class) is marked as optional because
> +     it should not be specified if RENAME_EXISTING_TO is specified.
> +     Otherwise it's required.  */
> +  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!Os",
> +					keywords,
> +					&name,
> +					&PyInt_Type, &cmdtype_obj,
> +					&PyInt_Type, &completetype_obj,
> +					&is_prefix_obj,
> +					&rename_existing_to))
>      return -1;
>  
> -  if (cmdtype != no_class && cmdtype != class_run
> -      && cmdtype != class_vars && cmdtype != class_stack
> -      && cmdtype != class_files && cmdtype != class_support
> -      && cmdtype != class_info && cmdtype != class_breakpoint
> -      && cmdtype != class_trace && cmdtype != class_obscure
> -      && cmdtype != class_maintenance && cmdtype != class_user
> -      && cmdtype != class_tui)
> -    {
> -      PyErr_Format (PyExc_RuntimeError, _("Invalid command class argument."));
> -      return -1;
> -    }
> -
> -  if (completetype < -1 || completetype >= (int) N_COMPLETERS)
> -    {
> -      PyErr_Format (PyExc_RuntimeError,
> -		    _("Invalid completion type argument."));
> -      return -1;
> -    }
> -
>    cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist);
>    if (! cmd_name)
>      return -1;
>  
> +  /* Deal with rename_existing_to before other arguments as it affects how
> +     some of them are treated.  */
> +  if (rename_existing_to != NULL)
> +    {
> +      renamed_cmd = lookup_cmd_exact (cmd_name, *cmd_list);
> +      if (renamed_cmd == nullptr)
> +	{
> +	  PyErr_Format (PyExc_RuntimeError,
> +			_("Command \"%s\" does not exist, so it cannot "
> +			  "be renamed to \"%s\"."),
> +			name, rename_existing_to);
> +	  xfree (cmd_name);
> +	  return -1;
> +	}
> +
> +      rename_existing_to_cmd_name =
> +	gdbpy_parse_command_name (rename_existing_to,
> +				  &rename_existing_to_cmd_list,
> +				  &cmdlist);
> +      if (! rename_existing_to_cmd_name)

  if (rename_existing_to_cmd_name == nullptr)

If the surrounding code is incorrect, you can fix it up too, if you want
to keep it consistent.

> +	{
> +	  xfree (cmd_name);
> +	  return -1;

Instead of xfree'ing cmd_name by hand, I'll make a patch that makes
gdbpy_parse_command_name return a gdb::unique_xmalloc_ptr.  You'll have
to update this code, but it will just make it simpler.

Here it is, I would appreciate if you could give it a look:

  https://sourceware.org/pipermail/gdb-patches/2021-March/177162.html

Thanks,

Simon

  reply	other threads:[~2021-03-23 18:45 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-08 10:07 [PATCH 0/4] Add support for command renaming Marco Barisione via Gdb-patches
2021-01-08 10:07 ` [PATCH 1/4] gdb: add lookup_cmd_exact to simplify a common pattern Marco Barisione via Gdb-patches
2021-01-10  0:06   ` Lancelot SIX via Gdb-patches
2021-01-17 10:47     ` Marco Barisione via Gdb-patches
2021-01-17 19:02       ` Lancelot SIX via Gdb-patches
2021-01-25 11:33         ` Luis Machado via Gdb-patches
2021-01-08 10:07 ` [PATCH 2/4] gdb: prevent prefix commands from being hooks Marco Barisione via Gdb-patches
2021-01-08 10:07 ` [PATCH 3/4] gdb: update the docs for add_cmd and do_add_cmd to match reality Marco Barisione via Gdb-patches
2021-01-08 10:07 ` [PATCH 4/4] gdb: Add support for renaming commands Marco Barisione via Gdb-patches
2021-01-08 10:30   ` Eli Zaretskii via Gdb-patches
2021-01-25 11:26 ` [PATCH v2 0/5] Add support for command renaming Marco Barisione via Gdb-patches
2021-01-25 11:26   ` [PATCH v2 1/5] gdb: add lookup_cmd_exact to simplify a common pattern Marco Barisione via Gdb-patches
2021-03-08 18:58     ` Simon Marchi
2021-05-07 14:47       ` Marco Barisione via Gdb-patches
2021-01-25 11:26   ` [PATCH v2 2/5] gdb: prevent prefix commands from being hooks Marco Barisione via Gdb-patches
2021-03-08 21:32     ` Simon Marchi via Gdb-patches
2021-03-09  9:42       ` Marco Barisione via Gdb-patches
2021-03-16  3:17         ` Simon Marchi via Gdb-patches
2021-05-07 14:59           ` Marco Barisione via Gdb-patches
2021-05-07 19:30             ` Simon Marchi via Gdb-patches
2021-05-07 20:11               ` Marco Barisione via Gdb-patches
2021-05-14 20:38       ` [PATCH v3 " Marco Barisione via Gdb-patches
2021-01-25 11:26   ` [PATCH v2 3/5] gdb: update the docs for add_cmd and do_add_cmd to match reality Marco Barisione via Gdb-patches
2021-03-08 22:52     ` Simon Marchi via Gdb-patches
2021-03-08 23:10       ` Simon Marchi via Gdb-patches
2021-05-14 20:39       ` [PATCH v3 3/5] gdb: move declarations and docs for cli-decode.c to cli-decode.h Marco Barisione via Gdb-patches
2021-01-25 11:26   ` [PATCH v2 4/5] gdb: generate the prefix name for prefix commands on demand Marco Barisione via Gdb-patches
2021-03-08 23:25     ` Simon Marchi via Gdb-patches
2021-03-16 17:00       ` Simon Marchi via Gdb-patches
2021-05-12 11:10       ` Marco Barisione via Gdb-patches
2021-01-25 11:26   ` [PATCH v2 5/5] gdb: Add support for renaming commands Marco Barisione via Gdb-patches
2021-03-23 18:45     ` Simon Marchi via Gdb-patches [this message]
2021-05-14 20:41       ` [PATCH v3 5/5] gdb: add " Marco Barisione via Gdb-patches
2021-02-08 17:53   ` [PING] [PATCH v2 0/5] Add support for command renaming Marco Barisione via Gdb-patches
2021-02-15  8:27     ` [PING2] " Marco Barisione via Gdb-patches
2021-02-22  8:28       ` [PING 3] " Marco Barisione via Gdb-patches
2021-03-01  8:32         ` [PING 4] " Marco Barisione via Gdb-patches
2021-03-08  9:23           ` [PING 5] " Marco Barisione via Gdb-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c5832aaa-dc84-33e2-a2ae-509dfe8d9eec@polymtl.ca \
    --to=gdb-patches@sourceware.org \
    --cc=mbarisione@undo.io \
    --cc=simon.marchi@polymtl.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox