aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog35
-rw-r--r--gdb/Makefile.in6
-rw-r--r--gdb/NEWS2
-rw-r--r--gdb/cli/cli-decode.c8
-rw-r--r--gdb/cli/cli-decode.h10
-rw-r--r--gdb/command.h3
-rw-r--r--gdb/completer.c16
-rw-r--r--gdb/completer.h10
-rw-r--r--gdb/doc/ChangeLog5
-rw-r--r--gdb/doc/gdb.texinfo254
-rw-r--r--gdb/interps.c5
-rw-r--r--gdb/python/python-cmd.c585
-rw-r--r--gdb/python/python-internal.h3
-rw-r--r--gdb/python/python.c5
-rw-r--r--gdb/symtab.c10
-rw-r--r--gdb/symtab.h2
-rw-r--r--gdb/testsuite/ChangeLog4
17 files changed, 943 insertions, 20 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6038287..0f28a82 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,38 @@
+2009-02-06 Tom Tromey <tromey@redhat.com>
+
+ * Makefile.in (SUBDIR_PYTHON_OBS): Add python-cmd.o.
+ (SUBDIR_PYTHON_SRCS): Add python-cmd.c.
+ (python-cmd.o): New target.
+ * cli/cli-decode.c (set_cmd_completer): Add self parameter to
+ completer prototype.
+ (add_cmd): Initialize destroyer member of cmd_list_element. Use
+ make_symbol_completion_list_fn as completer.
+ (delete_cmd): Call destroyer if one is set.
+ * cli/cli-decode.h (cmd_list_element): Add cmd parameter to
+ completer member. Add destroyer member.
+ (set_cmd_completer): Add self parameter to
+ completer prototype.
+ * command.h (set_cmd_completer): Add cmd parameter to
+ completer prototype.
+ * completer.c (noop_completer, filename_completer,
+ location_completer, expression_completer, command_completer): Adapt
+ to new completer prototype.
+ (complete_line_internal): Pass new parameter to completer function.
+ * completer.h (noop_completer, filename_completer,
+ location_completer, expression_completer, command_completer): Adapt
+ prototypes to new completer prototype.
+ * interps.c (interpreter_completer): Adapt to new completer
+ prototype.
+ * python/python-cmd.c: New file.
+ * python/python-internal.h (gdbpy_initialize_commands): Add
+ prototype.
+ (gdbpy_doc_cst): Add forward declaration.
+ * python/python.c (gdbpy_doc_cst): Declare.
+ (_initialize_python): Call gdbpy_initialize_commands. Initialize
+ gdbpy_doc_cst.
+ * symtab.c (make_symbol_completion_list_fn): New function.
+ * symtab.h (make_symbol_completion_list_fn): Add prototype.
+
2009-02-06 Pedro Alves <pedro@codesourcery.com>
* target.c (target_get_osdata): Check for equal or higher than
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6a4f77d..7400702 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -270,10 +270,12 @@ SUBDIR_TUI_CFLAGS= \
#
SUBDIR_PYTHON_OBS = \
python.o \
+ python-cmd.o \
python-utils.o \
python-value.o
SUBDIR_PYTHON_SRCS = \
python/python.c \
+ python/python-cmd.c \
python/python-utils.c \
python/python-value.c
SUBDIR_PYTHON_DEPS =
@@ -1836,6 +1838,10 @@ python.o: $(srcdir)/python/python.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
$(POSTCOMPILE)
+python-cmd.o: $(srcdir)/python/python-cmd.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
+ $(POSTCOMPILE)
+
python-utils.o: $(srcdir)/python/python-utils.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index a85caeb..d1abf0c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -96,6 +96,8 @@ are treated as the standard definitions, regardless of context.
GDB now has support for scripting using Python. Whether this is
available is determined at configure time.
+ New GDB commands can now be written in Python.
+
* Ada tasking support
Ada tasks can now be inspected in GDB. The following commands have
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 556c027..8760ebf 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -132,7 +132,8 @@ cmd_type (struct cmd_list_element *cmd)
void
set_cmd_completer (struct cmd_list_element *cmd,
- char **(*completer) (char *text, char *word))
+ char **(*completer) (struct cmd_list_element *self,
+ char *text, char *word))
{
cmd->completer = completer; /* Ok. */
}
@@ -207,7 +208,8 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
c->prefixname = NULL;
c->allow_unknown = 0;
c->abbrev_flag = 0;
- set_cmd_completer (c, make_symbol_completion_list);
+ set_cmd_completer (c, make_symbol_completion_list_fn);
+ c->destroyer = NULL;
c->type = not_set_cmd;
c->var = NULL;
c->var_type = var_boolean;
@@ -688,6 +690,8 @@ delete_cmd (char *name, struct cmd_list_element **list,
{
if (strcmp (iter->name, name) == 0)
{
+ if (iter->destroyer)
+ iter->destroyer (iter, iter->context);
if (iter->hookee_pre)
iter->hookee_pre->hook_pre = 0;
*prehook = iter->hook_pre;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 56ea9bf..26ca2f7 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -167,7 +167,12 @@ struct cmd_list_element
returned relative to this position. For example, suppose TEXT is "foo"
and we want to complete to "foobar". If WORD is "oo", return
"oobar"; if WORD is "baz/foo", return "baz/foobar". */
- char **(*completer) (char *text, char *word);
+ char **(*completer) (struct cmd_list_element *cmd, char *text, char *word);
+
+ /* Destruction routine for this command. If non-NULL, this is
+ called when this command instance is destroyed. This may be
+ used to finalize the CONTEXT field, if needed. */
+ void (*destroyer) (struct cmd_list_element *self, void *context);
/* Type of "set" or "show" command (or SET_NOT_SET if not "set"
or "show"). */
@@ -242,7 +247,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
struct cmd_list_element * c));
extern void set_cmd_completer (struct cmd_list_element *cmd,
- char **(*completer) (char *text, char *word));
+ char **(*completer) (struct cmd_list_element *self,
+ char *text, char *word));
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
diff --git a/gdb/command.h b/gdb/command.h
index b3f7013..bed615c 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -138,7 +138,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
cmd_sfunc_ftype *sfunc);
extern void set_cmd_completer (struct cmd_list_element *cmd,
- char **(*completer) (char *text, char *word));
+ char **(*completer) (struct cmd_list_element *cmd,
+ char *text, char *word));
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
diff --git a/gdb/completer.c b/gdb/completer.c
index 298cdd0..43fcf7a 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -105,14 +105,14 @@ readline_line_completion_function (const char *text, int matches)
/* This can be used for functions which don't want to complete on symbols
but don't want to complete on anything else either. */
char **
-noop_completer (char *text, char *prefix)
+noop_completer (struct cmd_list_element *ignore, char *text, char *prefix)
{
return NULL;
}
/* Complete on filenames. */
char **
-filename_completer (char *text, char *word)
+filename_completer (struct cmd_list_element *ignore, char *text, char *word)
{
int subsequent_name;
char **return_val;
@@ -195,7 +195,7 @@ filename_completer (char *text, char *word)
This is intended to be used in commands that set breakpoints etc. */
char **
-location_completer (char *text, char *word)
+location_completer (struct cmd_list_element *ignore, char *text, char *word)
{
int n_syms = 0, n_files = 0;
char ** fn_list = NULL;
@@ -412,7 +412,7 @@ add_struct_fields (struct type *type, int *nextp, char **output,
names, but some language parsers also have support for completing
field names. */
char **
-expression_completer (char *text, char *word)
+expression_completer (struct cmd_list_element *ignore, char *text, char *word)
{
struct type *type;
char *fieldname, *p;
@@ -456,7 +456,7 @@ expression_completer (char *text, char *word)
;
/* Not ideal but it is what we used to do before... */
- return location_completer (p, word);
+ return location_completer (ignore, p, word);
}
/* Here are some useful test cases for completion. FIXME: These should
@@ -651,7 +651,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
p--)
;
}
- list = (*c->completer) (p, word);
+ list = (*c->completer) (c, p, word);
}
}
else
@@ -719,7 +719,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
p--)
;
}
- list = (*c->completer) (p, word);
+ list = (*c->completer) (c, p, word);
}
}
}
@@ -737,7 +737,7 @@ complete_line (const char *text, char *line_buffer, int point)
/* Complete on command names. Used by "help". */
char **
-command_completer (char *text, char *word)
+command_completer (struct cmd_list_element *ignore, char *text, char *word)
{
return complete_line_internal (word, text, strlen (text), 1);
}
diff --git a/gdb/completer.h b/gdb/completer.h
index da1c38119..6adbf1b 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -21,15 +21,15 @@ extern char **complete_line (const char *text, char *line_buffer, int point);
extern char *readline_line_completion_function (const char *text, int matches);
-extern char **noop_completer (char *, char *);
+extern char **noop_completer (struct cmd_list_element *, char *, char *);
-extern char **filename_completer (char *, char *);
+extern char **filename_completer (struct cmd_list_element *, char *, char *);
-extern char **expression_completer (char *, char *);
+extern char **expression_completer (struct cmd_list_element *, char *, char *);
-extern char **location_completer (char *, char *);
+extern char **location_completer (struct cmd_list_element *, char *, char *);
-extern char **command_completer (char *, char *);
+extern char **command_completer (struct cmd_list_element *, char *, char *);
extern char *get_gdb_completer_quote_characters (void);
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 0f5363c..98502db 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+2009-02-06 Tom Tromey <tromey@redhat.com>
+
+ * gdb.texinfo (Python API): Add entry for Commands In Python.
+ (Commands In Python): New node.
+
2009-02-05 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Values From Inferior): Document Value.string.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a2ed0b8..354b888 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18064,6 +18064,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Basic Python:: Basic Python Functions.
* Exception Handling::
* Values From Inferior::
+* Commands In Python:: Implementing new commands in Python.
@end menu
@node Basic Python
@@ -18246,6 +18247,259 @@ The optional @var{errors} argument is the same as the corresponding
argument to Python's @code{string.decode} method.
@end defmethod
+@node Commands In Python
+@subsubsection Commands In Python
+
+@cindex commands in python
+@cindex python commands
+@tindex Command
+@tindex gdb.Command
+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.
+
+@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]}
+The object initializer for @code{Command} registers the new command
+with @value{GDBN}. This initializer is normally invoked from the
+subclass' own @code{__init__} method.
+
+@var{name} is the name of the command. If @var{name} consists of
+multiple words, then the initial words are looked for as prefix
+commands. In this case, if one of the prefix commands does not exist,
+an exception is raised.
+
+There is no support for multi-line commands.
+
+@var{command-class} should be one of the @samp{COMMAND_} constants
+defined below. This argument tells @value{GDBN} how to categorize the
+new command in the help system.
+
+@var{completer-class} is an optional argument. If given, it should be
+one of the @samp{COMPLETE_} constants defined below. This argument
+tells @value{GDBN} how to perform completion for this command. If not
+given, @value{GDBN} will attempt to complete using the object's
+@code{complete} method (see below); if no such method is found, an
+error will occur when completion is attempted.
+
+@var{prefix} is an optional argument. If @code{True}, then the new
+command is a prefix command; sub-commands of this command may be
+registered.
+
+The help text for the new command is taken from the Python
+documentation string for the command's class, if there is one. If no
+documentation string is provided, the default value ``This command is
+not documented.'' is used.
+@end defmethod
+
+@defmethod Command dont_repeat
+By default, a @value{GDBN} command is repeated when the user enters a
+blank line at the command prompt. A command can suppress this
+behavior by invoking the @code{dont_repeat} method. This is similar
+to the user command @code{dont-repeat}, see @ref{Define, dont-repeat}.
+@end defmethod
+
+@defmethod Command invoke argument from_tty
+This method is called by @value{GDBN} when this command is invoked.
+
+@var{argument} is a string. It is the argument to the command, after
+leading and trailing whitespace has been stripped.
+
+@var{from_tty} is a boolean argument. When true, this means that the
+command was entered by the user at the terminal; when false it means
+that the command came from elsewhere.
+
+If this method throws an exception, it is turned into a @value{GDBN}
+@code{error} call. Otherwise, the return value is ignored.
+@end defmethod
+
+@defmethod Command complete text word
+This method is called by @value{GDBN} when the user attempts
+completion on this command. All forms of completion are handled by
+this method, that is, the @key{TAB} and @key{M-?} key bindings, and
+the @code{complete} command.
+
+The arguments @var{text} and @var{word} are both strings. @var{text}
+holds the complete command line up to the cursor's location.
+@var{word} holds the last word of the command line; this is computed
+using a word-breaking heuristic.
+
+The @code{complete} method can return several values:
+@itemize @bullet
+@item
+If the return value is a sequence, the contents of the sequence are
+used as the completions. It is up to @code{complete} to ensure that the
+contents actually do complete the word. A zero-length sequence is
+allowed, it means that there were no completions available. Only
+string elements of the sequence are used; other elements in the
+sequence are ignored.
+
+@item
+If the return value is one of the @samp{COMPLETE_} constants defined
+below, then the corresponding @value{GDBN}-internal completion
+function is invoked, and its result is used.
+
+@item
+All other results are treated as though there were no available
+completions.
+@end itemize
+@end defmethod
+
+
+When a new command is registered, it must be declared as a member of
+some general class of commands. This is used to classify top-level
+commands in the on-line help system; note that prefix commands are not
+listed under their own category but rather that of their top-level
+command. The available classifications are represented by constants
+defined in the @code{gdb} module:
+
+@table @code
+@findex COMMAND_NONE
+@findex gdb.COMMAND_NONE
+@item COMMAND_NONE
+The command does not belong to any particular class. A command in
+this category will not be displayed in any of the help categories.
+
+@findex COMMAND_RUNNING
+@findex gdb.COMMAND_RUNNING
+@item COMMAND_RUN
+The command is related to running the inferior. For example,
+@code{start}, @code{step}, and @code{continue} are in this category.
+Type @code{help running} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_DATA
+@findex gdb.COMMAND_DATA
+@item COMMAND_VARS
+The command is related to data or variables. For example,
+@code{call}, @code{find}, and @code{print} are in this category. Type
+@code{help data} at the @value{GDBN} prompt to see a list of commands
+in this category.
+
+@findex COMMAND_STACK
+@findex gdb.COMMAND_STACK
+@item COMMAND_STACK
+The command has to do with manipulation of the stack. For example,
+@code{backtrace}, @code{frame}, and @code{return} are in this
+category. Type @code{help stack} at the @value{GDBN} prompt to see a
+list of commands in this category.
+
+@findex COMMAND_FILES
+@findex gdb.COMMAND_FILES
+@item COMMAND_FILES
+This class is used for file-related commands. For example,
+@code{file}, @code{list} and @code{section} are in this category.
+Type @code{help files} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_SUPPORT
+@findex gdb.COMMAND_SUPPORT
+@item COMMAND_SUPPORT
+This should be used for ``support facilities'', generally meaning
+things that are useful to the user when interacting with @value{GDBN},
+but not related to the state of the inferior. For example,
+@code{help}, @code{make}, and @code{shell} are in this category. Type
+@code{help support} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_STATUS
+@findex gdb.COMMAND_STATUS
+@item COMMAND_INFO
+The command is an @samp{info}-related command, that is, related to the
+state of @value{GDBN} itself. For example, @code{info}, @code{macro},
+and @code{show} are in this category. Type @code{help status} at the
+@value{GDBN} prompt to see a list of commands in this category.
+
+@findex COMMAND_BREAKPOINTS
+@findex gdb.COMMAND_BREAKPOINTS
+@item COMMAND_BREAKPOINT
+The command has to do with breakpoints. For example, @code{break},
+@code{clear}, and @code{delete} are in this category. Type @code{help
+breakpoints} at the @value{GDBN} prompt to see a list of commands in
+this category.
+
+@findex COMMAND_TRACEPOINTS
+@findex gdb.COMMAND_TRACEPOINTS
+@item COMMAND_TRACE
+The command has to do with tracepoints. For example, @code{trace},
+@code{actions}, and @code{tfind} are in this category. Type
+@code{help tracepoints} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_OBSCURE
+@findex gdb.COMMAND_OBSCURE
+@item COMMAND_OBSCURE
+The command is only used in unusual circumstances, or is not of
+general interest to users. For example, @code{checkpoint},
+@code{fork}, and @code{stop} are in this category. Type @code{help
+obscure} at the @value{GDBN} prompt to see a list of commands in this
+category.
+
+@findex COMMAND_MAINTENANCE
+@findex gdb.COMMAND_MAINTENANCE
+@item COMMAND_MAINTENANCE
+The command is only useful to @value{GDBN} maintainers. The
+@code{maintenance} and @code{flushregs} commands are in this category.
+Type @code{help internals} at the @value{GDBN} prompt to see a list of
+commands in this category.
+@end table
+
+
+A new command can use a predefined completion function, either by
+specifying it via an argument at initialization, or by returning it
+from the @code{complete} method. These predefined completion
+constants are all defined in the @code{gdb} module:
+
+@table @code
+@findex COMPLETE_NONE
+@findex gdb.COMPLETE_NONE
+@item COMPLETE_NONE
+This constant means that no completion should be done.
+
+@findex COMPLETE_FILENAME
+@findex gdb.COMPLETE_FILENAME
+@item COMPLETE_FILENAME
+This constant means that filename completion should be performed.
+
+@findex COMPLETE_LOCATION
+@findex gdb.COMPLETE_LOCATION
+@item COMPLETE_LOCATION
+This constant means that location completion should be done.
+@xref{Specify Location}.
+
+@findex COMPLETE_COMMAND
+@findex gdb.COMPLETE_COMMAND
+@item COMPLETE_COMMAND
+This constant means that completion should examine @value{GDBN}
+command names.
+
+@findex COMPLETE_SYMBOL
+@findex gdb.COMPLETE_SYMBOL
+@item COMPLETE_SYMBOL
+This constant means that completion should be done using symbol names
+as the source.
+@end table
+
+The following code snippet shows how a trivial CLI command can be
+implemented in Python:
+
+@smallexample
+class HelloWorld (gdb.Command):
+ """Greet the whole world."""
+
+ def __init__ (self):
+ super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+
+ def invoke (self, arg, from_tty):
+ print "Hello, World!"
+
+HelloWorld ()
+@end smallexample
+
+The last line instantiates the class, and is necessary to trigger the
+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.
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
diff --git a/gdb/interps.c b/gdb/interps.c
index 6814a72..da05ee2 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -71,7 +71,8 @@ struct interp
/* Functions local to this file. */
static void initialize_interps (void);
-static char **interpreter_completer (char *text, char *word);
+static char **interpreter_completer (struct cmd_list_element *cmd,
+ char *text, char *word);
/* The magic initialization routine for this module. */
@@ -416,7 +417,7 @@ interpreter_exec_cmd (char *args, int from_tty)
/* List the possible interpreters which could complete the given text. */
static char **
-interpreter_completer (char *text, char *word)
+interpreter_completer (struct cmd_list_element *ignore, char *text, char *word)
{
int alloced = 0;
int textlen;
diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c
new file mode 100644
index 0000000..36cde34
--- /dev/null
+++ b/gdb/python/python-cmd.c
@@ -0,0 +1,585 @@
+/* gdb commands implemented in Python
+
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+#include "completer.h"
+
+/* Struct representing built-in completion types. */
+struct cmdpy_completer
+{
+ /* Python symbol name. */
+ char *name;
+ /* Completion function. */
+ char **(*completer) (struct cmd_list_element *, char *, char *);
+};
+
+static struct cmdpy_completer completers[] =
+{
+ { "COMPLETE_NONE", noop_completer },
+ { "COMPLETE_FILENAME", filename_completer },
+ { "COMPLETE_LOCATION", location_completer },
+ { "COMPLETE_COMMAND", command_completer },
+ { "COMPLETE_SYMBOL", make_symbol_completion_list_fn },
+};
+
+#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0]))
+
+/* A gdb command. For the time being only ordinary commands (not
+ set/show commands) are allowed. */
+struct cmdpy_object
+{
+ PyObject_HEAD
+
+ /* The corresponding gdb command object, or NULL if the command is
+ no longer installed. */
+ struct cmd_list_element *command;
+
+ /* A prefix command requires storage for a list of its sub-commands.
+ A pointer to this is passed to add_prefix_command, and to add_cmd
+ for sub-commands of that prefix. If this Command is not a prefix
+ command, then this field is unused. */
+ struct cmd_list_element *sub_list;
+};
+
+typedef struct cmdpy_object cmdpy_object;
+
+static PyTypeObject cmdpy_object_type;
+
+
+/* Constants used by this module. */
+static PyObject *invoke_cst;
+static PyObject *complete_cst;
+
+
+
+/* Python function which wraps dont_repeat. */
+static PyObject *
+cmdpy_dont_repeat (PyObject *self, PyObject *args)
+{
+ dont_repeat ();
+ Py_RETURN_NONE;
+}
+
+
+
+/* Called if the gdb cmd_list_element is destroyed. */
+static void
+cmdpy_destroyer (struct cmd_list_element *self, void *context)
+{
+ cmdpy_object *cmd;
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+
+ /* Release our hold on the command object. */
+ cmd = (cmdpy_object *) context;
+ cmd->command = NULL;
+ Py_DECREF (cmd);
+
+ /* We allocated the name, doc string, and perhaps the prefix
+ name. */
+ xfree (self->name);
+ xfree (self->doc);
+ xfree (self->prefixname);
+
+ PyGILState_Release (state);
+}
+
+/* Called by gdb to invoke the command. */
+static void
+cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
+{
+ cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+ PyObject *argobj, *ttyobj, *result;
+ struct cleanup *cleanup;
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+ cleanup = make_cleanup_py_restore_gil (&state);
+
+ if (! obj)
+ error (_("Invalid invocation of Python command object."));
+ if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst))
+ {
+ if (obj->command->prefixname)
+ {
+ /* A prefix command does not need an invoke method. */
+ do_cleanups (cleanup);
+ return;
+ }
+ error (_("Python command object missing 'invoke' method."));
+ }
+
+ if (! args)
+ args = "";
+ argobj = PyUnicode_Decode (args, strlen (args), host_charset (), NULL);
+ if (! argobj)
+ error (_("Could not convert arguments to Python string."));
+
+ ttyobj = from_tty ? Py_True : Py_False;
+ Py_INCREF (ttyobj);
+ result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj,
+ ttyobj, NULL);
+ Py_DECREF (argobj);
+ Py_DECREF (ttyobj);
+ if (! result)
+ {
+ PyObject *ptype, *pvalue, *ptraceback;
+ char *s, *str;
+
+ PyErr_Fetch (&ptype, &pvalue, &ptraceback);
+
+ if (pvalue && PyString_Check (pvalue))
+ {
+ /* Make a temporary copy of the string data. */
+ char *s = PyString_AsString (pvalue);
+ char *copy = alloca (strlen (s) + 1);
+ strcpy (copy, s);
+
+ PyErr_Restore (ptype, pvalue, ptraceback);
+ gdbpy_print_stack ();
+ error (_("Error occurred in Python command: %s"), copy);
+ }
+ else
+ {
+ PyErr_Restore (ptype, pvalue, ptraceback);
+ gdbpy_print_stack ();
+ error (_("Error occurred in Python command."));
+ }
+ }
+ Py_DECREF (result);
+ do_cleanups (cleanup);
+}
+
+/* Called by gdb for command completion. */
+static char **
+cmdpy_completer (struct cmd_list_element *command, char *text, char *word)
+{
+ cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+ PyObject *textobj, *wordobj, *resultobj = NULL;
+ char **result = NULL;
+ struct cleanup *cleanup;
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+ cleanup = make_cleanup_py_restore_gil (&state);
+
+ if (! obj)
+ error (_("Invalid invocation of Python command object."));
+ if (! PyObject_HasAttr ((PyObject *) obj, complete_cst))
+ {
+ /* If there is no complete method, don't error -- instead, just
+ say that there are no completions. */
+ goto done;
+ }
+
+ textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL);
+ if (! textobj)
+ error (_("Could not convert argument to Python string."));
+ wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL);
+ if (! wordobj)
+ error (_("Could not convert argument to Python string."));
+
+ resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst,
+ textobj, wordobj, NULL);
+ Py_DECREF (textobj);
+ Py_DECREF (wordobj);
+ if (! resultobj)
+ {
+ /* Just swallow errors here. */
+ PyErr_Clear ();
+ goto done;
+ }
+ make_cleanup_py_decref (resultobj);
+
+ result = NULL;
+ if (PySequence_Check (resultobj))
+ {
+ Py_ssize_t i, len = PySequence_Size (resultobj);
+ Py_ssize_t out;
+ if (len < 0)
+ goto done;
+
+ result = (char **) xmalloc ((len + 1) * sizeof (char *));
+ for (i = out = 0; i < len; ++i)
+ {
+ int l;
+ PyObject *elt = PySequence_GetItem (resultobj, i);
+ if (elt == NULL || ! gdbpy_is_string (elt))
+ {
+ /* Skip problem elements. */
+ PyErr_Clear ();
+ continue;
+ }
+ result[out] = python_string_to_host_string (elt);
+ ++out;
+ }
+ result[out] = NULL;
+ }
+ else if (PyInt_Check (resultobj))
+ {
+ /* User code may also return one of the completion constants,
+ thus requesting that sort of completion. */
+ long value = PyInt_AsLong (resultobj);
+ if (value >= 0 && value < (long) N_COMPLETERS)
+ result = completers[value].completer (command, text, word);
+ }
+
+ done:
+
+ do_cleanups (cleanup);
+
+ return result;
+}
+
+/* Helper for cmdpy_init which locates the command list to use and
+ pulls out the command name.
+
+ TEXT is the command name list. The final word in the list is the
+ name of the new command. All earlier words must be existing prefix
+ commands.
+
+ *BASE_LIST is set to the final prefix command's list of
+ *sub-commands.
+
+ This function returns the xmalloc()d name of the new command. On
+ error sets the Python error and returns NULL. */
+static char *
+parse_command_name (char *text, struct cmd_list_element ***base_list)
+{
+ struct cmd_list_element *elt;
+ int len = strlen (text);
+ int i, lastchar;
+ char *prefix_text;
+ char *result;
+
+ /* Skip trailing whitespace. */
+ for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+ ;
+ if (i < 0)
+ {
+ PyErr_SetString (PyExc_RuntimeError, _("no command name found"));
+ return NULL;
+ }
+ lastchar = i;
+
+ /* Find first character of the final word. */
+ for (; i > 0 && (isalnum (text[i - 1])
+ || text[i - 1] == '-'
+ || text[i - 1] == '_');
+ --i)
+ ;
+ result = xmalloc (lastchar - i + 2);
+ memcpy (result, &text[i], lastchar - i + 1);
+ result[lastchar - i + 1] = '\0';
+
+ /* Skip whitespace again. */
+ for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+ ;
+ if (i < 0)
+ {
+ *base_list = &cmdlist;
+ return result;
+ }
+
+ prefix_text = xmalloc (i + 2);
+ memcpy (prefix_text, text, i + 1);
+ prefix_text[i + 1] = '\0';
+
+ text = prefix_text;
+ elt = lookup_cmd_1 (&text, cmdlist, NULL, 1);
+ if (!elt || elt == (struct cmd_list_element *) -1)
+ {
+ PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"),
+ prefix_text);
+ xfree (prefix_text);
+ xfree (result);
+ return NULL;
+ }
+
+ if (elt->prefixlist)
+ {
+ xfree (prefix_text);
+ *base_list = elt->prefixlist;
+ return result;
+ }
+
+ PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"),
+ prefix_text);
+ xfree (prefix_text);
+ xfree (result);
+ return NULL;
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+ Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]).
+
+ NAME is the name of the command. It may consist of multiple words,
+ in which case the final word is the name of the new command, and
+ earlier words must be prefix commands.
+
+ CMDCLASS is the kind of command. It should be one of the COMMAND_*
+ constants defined in the gdb module.
+
+ COMPLETERCLASS is the kind of completer. If not given, the
+ "complete" method will be used. Otherwise, it should be one of the
+ COMPLETE_* constants defined in the gdb module.
+
+ If PREFIX is True, then this command is a prefix command.
+
+ The documentation for the command is taken from the doc string for
+ the python class.
+
+*/
+static int
+cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+ cmdpy_object *obj = (cmdpy_object *) self;
+ char *name;
+ int cmdtype;
+ int completetype = -1;
+ char *docstring = NULL;
+ volatile struct gdb_exception except;
+ struct cmd_list_element **cmd_list;
+ char *cmd_name, *pfx_name;
+ PyObject *is_prefix = NULL;
+ int cmp;
+
+ if (obj->command)
+ {
+ /* Note: this is apparently not documented in Python. We return
+ 0 for success, -1 for failure. */
+ PyErr_Format (PyExc_RuntimeError,
+ _("command object already initialized"));
+ return -1;
+ }
+
+ if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype,
+ &completetype, &is_prefix))
+ 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)
+ {
+ 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 = parse_command_name (name, &cmd_list);
+ if (! cmd_name)
+ return -1;
+
+ pfx_name = NULL;
+ if (is_prefix != NULL)
+ {
+ cmp = PyObject_IsTrue (is_prefix);
+ if (cmp == 1)
+ {
+ int i, out;
+
+ /* Make a normalized form of the command name. */
+ pfx_name = xmalloc (strlen (name) + 2);
+
+ i = 0;
+ out = 0;
+ while (name[i])
+ {
+ /* Skip whitespace. */
+ while (name[i] == ' ' || name[i] == '\t')
+ ++i;
+ /* Copy non-whitespace characters. */
+ while (name[i] && name[i] != ' ' && name[i] != '\t')
+ pfx_name[out++] = name[i++];
+ /* Add a single space after each word -- including the final
+ word. */
+ pfx_name[out++] = ' ';
+ }
+ pfx_name[out] = '\0';
+ }
+ else if (cmp < 0)
+ return -1;
+ }
+ if (PyObject_HasAttr (self, gdbpy_doc_cst))
+ {
+ PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst);
+ if (ds_obj && gdbpy_is_string (ds_obj))
+ docstring = python_string_to_host_string (ds_obj);
+ }
+ if (! docstring)
+ docstring = xstrdup (_("This command is not documented."));
+
+ Py_INCREF (self);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ struct cmd_list_element *cmd;
+
+ if (pfx_name)
+ {
+ int allow_unknown;
+
+ /* If we have our own "invoke" method, then allow unknown
+ sub-commands. */
+ allow_unknown = PyObject_HasAttr (self, invoke_cst);
+ cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype,
+ NULL, docstring, &obj->sub_list,
+ pfx_name, allow_unknown, cmd_list);
+ }
+ else
+ cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL,
+ docstring, cmd_list);
+
+ /* There appears to be no API to set this. */
+ cmd->func = cmdpy_function;
+ cmd->destroyer = cmdpy_destroyer;
+
+ obj->command = cmd;
+ set_cmd_context (cmd, self);
+ set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer
+ : completers[completetype].completer));
+ }
+ if (except.reason < 0)
+ {
+ xfree (cmd_name);
+ xfree (docstring);
+ xfree (pfx_name);
+ Py_DECREF (self);
+ PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+ "%s", except.message);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+/* Initialize the 'commands' code. */
+void
+gdbpy_initialize_commands (void)
+{
+ int i;
+
+ if (PyType_Ready (&cmdpy_object_type) < 0)
+ return;
+
+ /* Note: alias and user are special; pseudo appears to be unused,
+ and there is no reason to expose tui or xdb, I think. */
+ if (PyModule_AddIntConstant (gdb_module, "COMMAND_NONE", no_class) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_RUNNING", class_run) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_DATA", class_vars) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_STACK", class_stack) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_FILES", class_files) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_SUPPORT",
+ class_support) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_STATUS", class_info) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINTS",
+ class_breakpoint) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACEPOINTS",
+ class_trace) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
+ class_obscure) < 0
+ || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
+ class_maintenance) < 0)
+ return;
+
+ for (i = 0; i < N_COMPLETERS; ++i)
+ {
+ if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0)
+ return;
+ }
+
+ Py_INCREF (&cmdpy_object_type);
+ PyModule_AddObject (gdb_module, "Command",
+ (PyObject *) &cmdpy_object_type);
+
+ invoke_cst = PyString_FromString ("invoke");
+ complete_cst = PyString_FromString ("complete");
+}
+
+
+
+static PyMethodDef cmdpy_object_methods[] =
+{
+ { "dont_repeat", cmdpy_dont_repeat, METH_NOARGS,
+ "Prevent command repetition when user enters empty line." },
+
+ { 0 }
+};
+
+static PyTypeObject cmdpy_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Command", /*tp_name*/
+ sizeof (cmdpy_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "GDB command object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ cmdpy_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ cmdpy_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1457928..02dbfc4 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -70,6 +70,7 @@ PyObject *value_to_value_object (struct value *v);
struct value *convert_value_from_python (PyObject *obj);
void gdbpy_initialize_values (void);
+void gdbpy_initialize_commands (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
@@ -94,4 +95,6 @@ char *python_string_to_host_string (PyObject *obj);
PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
+extern PyObject *gdbpy_doc_cst;
+
#endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 96bb5f5..4f97416 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -46,6 +46,8 @@ static PyMethodDef GdbMethods[];
PyObject *gdb_module;
+PyObject *gdbpy_doc_cst;
+
/* Given a command_line, return a command string suitable for passing
to Python. Lines in the string are separated by newlines. The
return value is allocated using xmalloc and the caller is
@@ -407,9 +409,12 @@ Enables or disables printing of Python stack traces."),
PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
gdbpy_initialize_values ();
+ gdbpy_initialize_commands ();
PyRun_SimpleString ("import gdb");
+ gdbpy_doc_cst = PyString_FromString ("__doc__");
+
/* Create a couple objects which are used for Python's stdout and
stderr. */
PyRun_SimpleString ("\
diff --git a/gdb/symtab.c b/gdb/symtab.c
index b9befed..97d7950 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3890,6 +3890,16 @@ make_symbol_completion_list (char *text, char *word)
return current_language->la_make_symbol_completion_list (text, word);
}
+/* Like make_symbol_completion_list, but suitable for use as a
+ completion function. */
+
+char **
+make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+ char *text, char *word)
+{
+ return make_symbol_completion_list (text, word);
+}
+
/* Like make_symbol_completion_list, but returns a list of symbols
defined in a source file FILE. */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 2446d1e..8b086f3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1238,6 +1238,8 @@ extern void select_source_symtab (struct symtab *);
extern char **default_make_symbol_completion_list (char *, char *);
extern char **make_symbol_completion_list (char *, char *);
+extern char **make_symbol_completion_list_fn (struct cmd_list_element *,
+ char *, char *);
extern char **make_file_symbol_completion_list (char *, char *, char *);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index b77ea99..0b72438 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2009-02-06 Thiago Jung Bauermann <bauerman@br.ibm.com>
+
+ * gdb.python/python-cmd.exp: New file.
+
2009-02-06 Tristan Gingold <gingold@adacore.com>
* gdb.arch/i386-sse.c (main): Replace call to puts by an nop asm.