RE: [PATCH] Allow user-defined as a category for python gdb macros (resend)

Scott Goldman
2012-02-14T07:57:41Z

Hi Doug.

I appreciate the comments.

> At the very least, I think this requires a proper comment explaining
> why one needs to test c->user_commands.

done.

> Also, this patch feels like it's incomplete.
> If I can see "user" python "macros" [sic] then happens if I do "show
> user foo"? (a user may reasonably ask)
> And given that that won't work, we'll have to explain(document) why.

I added the relevant documentation specifying the behavior. I'm not sure how I would explain it other than "because Python doesn't provide a way to retrieve the code" and I wasn't sure if this was sufficiently useful information to be worth documenting, so i just stuck to clarifying that the commands were only relevant for user-defined non-python commands.

I would prefer to just get the `show user ...` functionality to work for python commands. The python `inspect` module sounds promising, but unfortunately seems to just throw an exception when I use it on a class. I'll fool around with it some more. Maybe I can make it work for certain limited cases.

> Plus one now needs to explain that "document" and
> "max-user-call-depth" don't apply to these commands

`document` actually seems to work fine, but yeah `max-user-call-depth` is not relevant for python commands. I updated the documentation to reflect that.

I'd be happy to further develop the change based on more feedback. My only real goal is to be able to have all the user-defined commands listed in one place.

-sjg

2012-02-13 Scott J. Goldman <scottjg@vmware.com>

* gdb.texinfo: put example python macro in COMMAND_USER category
rather than COMMAND_OBSCURE.
* gdb.texinfo: update documentation to clarify set/show max-user-call-depth and show user don't apply to
* python commands.

2012-02-13 Scott J. Goldman <scottjg@vmware.com>

* cli-cmds.c (show_user): print error when used on a python command.
* (init_cli_cmds): update documentation strings for show user and set/show max-user-call-depth
* to clarify that it does not apply to python commands.
* py-cmd.c (cmdpy_init): treat class_user as a valid class in error check
(gdbpy_initialize_commands): Add COMMAND_USER as a constant in
gdb python api.
* top.c (execute_command): only execute a user-defined command as a
legacy macro if c->user_commands is set.

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 983f017..49808b6 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1241,7 +1241,8 @@ show_user (char *args, int from_tty)
char *comname = args;

c = lookup_cmd (&comname, cmdlist, "", 0, 1);
- if (c->class != class_user)
+ /* c->user_commands would be NULL if it's a python command */
+ if (c->class != class_user || !c->user_commands)
error (_("Not a user command."));
show_user_1 (c, "", args, gdb_stdout);
}
@@ -1912,7 +1913,7 @@ Two arguments (separated by a comma) are taken as a range of memory to dump,\n\
Run the ``make'' program using the rest of the line as arguments."));
set_cmd_completer (c, filename_completer);
add_cmd ("user", no_class, show_user, _("\
-Show definitions of user defined commands.\n\
+Show definitions of non-python user defined commands.\n\
Argument is the name of the user defined command.\n\
With no argument, show definitions of all user defined commands."), &showlist);
add_com ("apropos", class_support, apropos_command,
@@ -1920,8 +1921,8 @@ With no argument, show definitions of all user defined commands."), &showlist);

add_setshow_integer_cmd ("max-user-call-depth", no_class,
&max_user_call_depth, _("\
-Set the max call depth for user-defined commands."), _("\
-Show the max call depth for user-defined commands."), NULL,
+Set the max call depth for non-python user-defined commands."), _("\
+Show the max call depth for non-python user-defined commands."), NULL,
NULL,
show_max_user_call_depth,
&setlist, &showlist);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9edc6ad..988d3d3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -21061,7 +21061,8 @@ List all user-defined commands, with the first line of the documentation
@itemx show user @var{commandname}
Display the @value{GDBN} commands used to define @var{commandname} (but
not its documentation). If no @var{commandname} is given, display the
-definitions for all user-defined commands.
+definitions for all user-defined commands. This does not work for user-defined
+python commands.

@cindex infinite recursion in user-defined commands
@kindex show max-user-call-depth
@@ -21070,7 +21071,8 @@ definitions for all user-defined commands.
@itemx set max-user-call-depth
The value of @code{max-user-call-depth} controls how many recursion
levels are allowed in user-defined commands before @value{GDBN} suspects an
-infinite recursion and aborts the command.
+infinite recursion and aborts the command. This does not apply to user-defined
+python commands.
@end table

In addition to the above commands, user-defined commands frequently
@@ -21871,7 +21873,7 @@ to handle this case. Example:
>class HelloWorld (gdb.Command):
> """Greet the whole world."""
> def __init__ (self):
-> super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+> super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_USER)
> def invoke (self, args, from_tty):
> argv = gdb.string_to_argv (args)
> if len (argv) != 0:
@@ -23311,7 +23313,7 @@ class HelloWorld (gdb.Command):
"""Greet the whole world."""

def __init__ (self):
- super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+ super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_USER)

def invoke (self, arg, from_tty):
print "Hello, World!"
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index aad1ab4..04476db 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -436,7 +436,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
&& cmdtype != class_files && cmdtype != class_support
&& cmdtype != class_info && cmdtype != class_breakpoint
&& cmdtype != class_trace && cmdtype != class_obscure
- && cmdtype != class_maintenance)
+ && cmdtype != class_maintenance && cmdtype != class_user)
{
PyErr_Format (PyExc_RuntimeError, _("Invalid command class argument."));
return -1;
@@ -578,7 +578,8 @@ gdbpy_initialize_commands (void)
|| PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
class_obscure) < 0
|| PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
- class_maintenance) < 0)
+ class_maintenance) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_USER", class_user) < 0)
return;

for (i = 0; i < N_COMPLETERS; ++i)
diff --git a/gdb/top.c b/gdb/top.c
index e41f56c..e73a772 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -470,7 +470,8 @@ execute_command (char *p, int from_tty)
if (c->flags & DEPRECATED_WARN_USER)
deprecated_cmd_warning (&line);

- if (c->class == class_user)
+ /* c->user_commands would be NULL in the case of a python command. */
+ if (c->class == class_user && c->user_commands)
execute_user_command (c, arg);
else if (c->type == set_cmd || c->type == show_cmd)
do_setshow_command (arg, from_tty, c);