gdb/
2009-03-05 Tom Tromey <tromey@redhat.com> Add support for convenience functions in Python. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-function.o. (SUBDIR_PYTHON_SRCS): Add python-function.c. (python-function.o): New target. * eval.c: Include "python/python.h" and <ctype.h>. (evaluate_subexp_standard): Handle values of type TYPE_CODE_INTERNAL_FUNCTION. * gdbtypes.h (type_code): Add TYPE_CODE_INTERNAL_FUNCTION. * parse.c (write_exp_string): Remove duplicate word in comment. * python/python-function.c: New file. * python/python-internal.h (gdbpy_initialize_functions): Add prototype. * python/python.c (_initialize_python): Call gdbpy_initialize_functions. * valprint.c (value_check_printable): Handle values of type TYPE_CODE_INTERNAL_FUNCTION. * value.c: Include "cli/cli-decode.h". (internal_function): New struct. (functionlist, internal_fn_type): New static variables. (lookup_only_internalvar, lookup_internalvar): Add const qualifier to name argument. (create_internalvar): Likewise. Initialize new field. (set_internal_var): Fix typo in comment. Don't allow assignment to canonical variable. (value_create_internal_function, value_internal_function_name, call_internal_function, function_command, function_destroyer, add_internal_function): New functions. (_initialize_values): Create `function' placeholder command. Initialize internal_fn_type. * value.h (lookup_only_internalvar, create_internalvar, lookup_internalvar): Add const qualifier to name argument. (internal_function_fn, add_internal_function, call_internal_function, value_internal_function_name): Add prototypes. (struct internalvar) <canonical>: New field. gdb/doc/ 2008-03-05 Tom Tromey <tromey@redhat.com> * gdb.texinfo (Convenience Vars): Document convenience functions. (Functions In Python): New node. (Python API): Update. gdb/testsuite/ 2009-03-05 Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.python/python-function.exp: New file.
This commit is contained in:
parent
c6dd29cec2
commit
bc3b79fd1a
15 changed files with 523 additions and 9 deletions
|
@ -1,3 +1,40 @@
|
||||||
|
2009-03-20 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
|
Add support for convenience functions in Python.
|
||||||
|
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-function.o.
|
||||||
|
(SUBDIR_PYTHON_SRCS): Add python-function.c.
|
||||||
|
(python-function.o): New target.
|
||||||
|
* eval.c: Include "python/python.h" and <ctype.h>.
|
||||||
|
(evaluate_subexp_standard): Handle values of type
|
||||||
|
TYPE_CODE_INTERNAL_FUNCTION.
|
||||||
|
* gdbtypes.h (type_code): Add TYPE_CODE_INTERNAL_FUNCTION.
|
||||||
|
* parse.c (write_exp_string): Remove duplicate word in comment.
|
||||||
|
* python/python-function.c: New file.
|
||||||
|
* python/python-internal.h (gdbpy_initialize_functions): Add
|
||||||
|
prototype.
|
||||||
|
* python/python.c (_initialize_python): Call
|
||||||
|
gdbpy_initialize_functions.
|
||||||
|
* valprint.c (value_check_printable): Handle values of type
|
||||||
|
TYPE_CODE_INTERNAL_FUNCTION.
|
||||||
|
* value.c: Include "cli/cli-decode.h".
|
||||||
|
(internal_function): New struct.
|
||||||
|
(functionlist, internal_fn_type): New static variables.
|
||||||
|
(lookup_only_internalvar,
|
||||||
|
lookup_internalvar): Add const qualifier to name argument.
|
||||||
|
(create_internalvar): Likewise. Initialize new field.
|
||||||
|
(set_internal_var): Fix typo in comment. Don't allow assignment
|
||||||
|
to canonical variable.
|
||||||
|
(value_create_internal_function, value_internal_function_name,
|
||||||
|
call_internal_function, function_command, function_destroyer,
|
||||||
|
add_internal_function): New functions.
|
||||||
|
(_initialize_values): Create `function' placeholder command.
|
||||||
|
Initialize internal_fn_type.
|
||||||
|
* value.h (lookup_only_internalvar, create_internalvar,
|
||||||
|
lookup_internalvar): Add const qualifier to name argument.
|
||||||
|
(internal_function_fn, add_internal_function, call_internal_function,
|
||||||
|
value_internal_function_name): Add prototypes.
|
||||||
|
(struct internalvar) <canonical>: New field.
|
||||||
|
|
||||||
2009-03-20 Tom Tromey <tromey@redhat.com>
|
2009-03-20 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* c-lang.c (evaluate_subexp_c): Call check_typedef.
|
* c-lang.c (evaluate_subexp_c): Call check_typedef.
|
||||||
|
|
|
@ -271,11 +271,13 @@ SUBDIR_TUI_CFLAGS= \
|
||||||
SUBDIR_PYTHON_OBS = \
|
SUBDIR_PYTHON_OBS = \
|
||||||
python.o \
|
python.o \
|
||||||
python-cmd.o \
|
python-cmd.o \
|
||||||
|
python-function.o \
|
||||||
python-utils.o \
|
python-utils.o \
|
||||||
python-value.o
|
python-value.o
|
||||||
SUBDIR_PYTHON_SRCS = \
|
SUBDIR_PYTHON_SRCS = \
|
||||||
python/python.c \
|
python/python.c \
|
||||||
python/python-cmd.c \
|
python/python-cmd.c \
|
||||||
|
python/python-function.c \
|
||||||
python/python-utils.c \
|
python/python-utils.c \
|
||||||
python/python-value.c
|
python/python-value.c
|
||||||
SUBDIR_PYTHON_DEPS =
|
SUBDIR_PYTHON_DEPS =
|
||||||
|
@ -1850,6 +1852,10 @@ python-cmd.o: $(srcdir)/python/python-cmd.c
|
||||||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
|
||||||
$(POSTCOMPILE)
|
$(POSTCOMPILE)
|
||||||
|
|
||||||
|
python-function.o: $(srcdir)/python/python-function.c
|
||||||
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c
|
||||||
|
$(POSTCOMPILE)
|
||||||
|
|
||||||
python-utils.o: $(srcdir)/python/python-utils.c
|
python-utils.o: $(srcdir)/python/python-utils.c
|
||||||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
|
||||||
$(POSTCOMPILE)
|
$(POSTCOMPILE)
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2008-03-20 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Convenience Vars): Document convenience functions.
|
||||||
|
(Functions In Python): New node.
|
||||||
|
(Python API): Update.
|
||||||
|
|
||||||
2009-03-20 Tom Tromey <tromey@redhat.com>
|
2009-03-20 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* gdb.texinfo (Character Sets): Remove obsolete text. Document
|
* gdb.texinfo (Character Sets): Remove obsolete text. Document
|
||||||
|
|
|
@ -7436,6 +7436,20 @@ On HP-UX systems, if you refer to a function or variable name that
|
||||||
begins with a dollar sign, @value{GDBN} searches for a user or system
|
begins with a dollar sign, @value{GDBN} searches for a user or system
|
||||||
name first, before it searches for a convenience variable.
|
name first, before it searches for a convenience variable.
|
||||||
|
|
||||||
|
@cindex convenience functions
|
||||||
|
@value{GDBN} also supplies some @dfn{convenience functions}. These
|
||||||
|
have a syntax similar to convenience variables. A convenience
|
||||||
|
function can be used in an expression just like an ordinary function;
|
||||||
|
however, a convenience function is implemented internally to
|
||||||
|
@value{GDBN}.
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item help function
|
||||||
|
@kindex help function
|
||||||
|
@cindex show all convenience functions
|
||||||
|
Print a list of all convenience functions.
|
||||||
|
@end table
|
||||||
|
|
||||||
@node Registers
|
@node Registers
|
||||||
@section Registers
|
@section Registers
|
||||||
|
|
||||||
|
@ -18178,6 +18192,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
||||||
* Exception Handling::
|
* Exception Handling::
|
||||||
* Values From Inferior::
|
* Values From Inferior::
|
||||||
* Commands In Python:: Implementing new commands in Python.
|
* Commands In Python:: Implementing new commands in Python.
|
||||||
|
* Functions In Python:: Writing new convenience functions.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Basic Python
|
@node Basic Python
|
||||||
|
@ -18612,6 +18627,65 @@ registration of the command with @value{GDBN}. Depending on how the
|
||||||
Python code is read into @value{GDBN}, you may need to import the
|
Python code is read into @value{GDBN}, you may need to import the
|
||||||
@code{gdb} module explicitly.
|
@code{gdb} module explicitly.
|
||||||
|
|
||||||
|
@node Functions In Python
|
||||||
|
@subsubsection Writing new convenience functions
|
||||||
|
|
||||||
|
@cindex writing convenience functions
|
||||||
|
@cindex convenience functions in python
|
||||||
|
@cindex python convenience functions
|
||||||
|
@tindex gdb.Function
|
||||||
|
@tindex Function
|
||||||
|
You can implement new convenience functions (@pxref{Convenience Vars})
|
||||||
|
in Python. A convenience function is an instance of a subclass of the
|
||||||
|
class @code{gdb.Function}.
|
||||||
|
|
||||||
|
@defmethod Function __init__ name
|
||||||
|
The initializer for @code{Function} registers the new function with
|
||||||
|
@value{GDBN}. The argument @var{name} is the name of the function,
|
||||||
|
a string. The function will be visible to the user as a convenience
|
||||||
|
variable of type @code{internal function}, whose name is the same as
|
||||||
|
the given @var{name}.
|
||||||
|
|
||||||
|
The documentation for the new function is taken from the documentation
|
||||||
|
string for the new class.
|
||||||
|
@end defmethod
|
||||||
|
|
||||||
|
@defmethod Function invoke @var{*args}
|
||||||
|
When a convenience function is evaluated, its arguments are converted
|
||||||
|
to instances of @code{gdb.Value}, and then the function's
|
||||||
|
@code{invoke} method is called. Note that @value{GDBN} does not
|
||||||
|
predetermine the arity of convenience functions. Instead, all
|
||||||
|
available arguments are passed to @code{invoke}, following the
|
||||||
|
standard Python calling convention. In particular, a convenience
|
||||||
|
function can have default values for parameters without ill effect.
|
||||||
|
|
||||||
|
The return value of this method is used as its value in the enclosing
|
||||||
|
expression. If an ordinary Python value is returned, it is converted
|
||||||
|
to a @code{gdb.Value} following the usual rules.
|
||||||
|
@end defmethod
|
||||||
|
|
||||||
|
The following code snippet shows how a trivial convenience function can
|
||||||
|
be implemented in Python:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
class Greet (gdb.Function):
|
||||||
|
"""Return string to greet someone.
|
||||||
|
Takes a name as argument."""
|
||||||
|
|
||||||
|
def __init__ (self):
|
||||||
|
super (Greet, self).__init__ ("greet")
|
||||||
|
|
||||||
|
def invoke (self, name):
|
||||||
|
return "Hello, %s!" % name.string ()
|
||||||
|
|
||||||
|
Greet ()
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
The last line instantiates the class, and is necessary to trigger the
|
||||||
|
registration of the function 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
|
@node Interpreters
|
||||||
@chapter Command Interpreters
|
@chapter Command Interpreters
|
||||||
@cindex command interpreters
|
@cindex command interpreters
|
||||||
|
|
|
@ -40,9 +40,12 @@
|
||||||
#include "regcache.h"
|
#include "regcache.h"
|
||||||
#include "user-regs.h"
|
#include "user-regs.h"
|
||||||
#include "valprint.h"
|
#include "valprint.h"
|
||||||
|
#include "python/python.h"
|
||||||
|
|
||||||
#include "gdb_assert.h"
|
#include "gdb_assert.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/* This is defined in valops.c */
|
/* This is defined in valops.c */
|
||||||
extern int overload_resolution;
|
extern int overload_resolution;
|
||||||
|
|
||||||
|
@ -1512,6 +1515,9 @@ evaluate_subexp_standard (struct type *expect_type,
|
||||||
else
|
else
|
||||||
error (_("Expression of type other than \"Function returning ...\" used as function"));
|
error (_("Expression of type other than \"Function returning ...\" used as function"));
|
||||||
}
|
}
|
||||||
|
if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_INTERNAL_FUNCTION)
|
||||||
|
return call_internal_function (argvec[0], nargs, argvec + 1);
|
||||||
|
|
||||||
return call_function_by_hand (argvec[0], nargs, argvec + 1);
|
return call_function_by_hand (argvec[0], nargs, argvec + 1);
|
||||||
/* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */
|
/* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,10 @@ enum type_code
|
||||||
|
|
||||||
TYPE_CODE_NAMESPACE, /* C++ namespace. */
|
TYPE_CODE_NAMESPACE, /* C++ namespace. */
|
||||||
|
|
||||||
TYPE_CODE_DECFLOAT /* Decimal floating point. */
|
TYPE_CODE_DECFLOAT, /* Decimal floating point. */
|
||||||
|
|
||||||
|
/* Internal function type. */
|
||||||
|
TYPE_CODE_INTERNAL_FUNCTION
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
|
/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
|
||||||
|
|
|
@ -306,7 +306,7 @@ write_exp_elt_intern (struct internalvar *expelt)
|
||||||
strings with embedded null bytes, as is required for some languages.
|
strings with embedded null bytes, as is required for some languages.
|
||||||
|
|
||||||
Don't be fooled by the fact that the string is null byte terminated,
|
Don't be fooled by the fact that the string is null byte terminated,
|
||||||
this is strictly for the convenience of debugging gdb itself. Gdb
|
this is strictly for the convenience of debugging gdb itself.
|
||||||
Gdb does not depend up the string being null terminated, since the
|
Gdb does not depend up the string being null terminated, since the
|
||||||
actual length is recorded in expression elements at each end of the
|
actual length is recorded in expression elements at each end of the
|
||||||
string. The null byte is taken into consideration when computing how
|
string. The null byte is taken into consideration when computing how
|
||||||
|
|
180
gdb/python/python-function.c
Normal file
180
gdb/python/python-function.c
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/* Convenience functions 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"
|
||||||
|
#include "expression.h"
|
||||||
|
|
||||||
|
static PyTypeObject fnpy_object_type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
convert_values_to_python (int argc, struct value **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PyObject *result = PyTuple_New (argc);
|
||||||
|
for (i = 0; i < argc; ++i)
|
||||||
|
{
|
||||||
|
PyObject *elt = value_to_value_object (argv[i]);
|
||||||
|
if (! elt)
|
||||||
|
{
|
||||||
|
Py_DECREF (result);
|
||||||
|
error (_("Could not convert value to Python object."));
|
||||||
|
}
|
||||||
|
PyTuple_SetItem (result, i, elt);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call a Python function object's invoke method. */
|
||||||
|
|
||||||
|
static struct value *
|
||||||
|
fnpy_call (void *cookie, int argc, struct value **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct value *value = NULL;
|
||||||
|
PyObject *result, *callable, *args;
|
||||||
|
struct cleanup *cleanup;
|
||||||
|
PyGILState_STATE state;
|
||||||
|
|
||||||
|
state = PyGILState_Ensure ();
|
||||||
|
cleanup = make_cleanup_py_restore_gil (&state);
|
||||||
|
|
||||||
|
args = convert_values_to_python (argc, argv);
|
||||||
|
|
||||||
|
callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke");
|
||||||
|
if (! callable)
|
||||||
|
{
|
||||||
|
Py_DECREF (args);
|
||||||
|
error (_("No method named 'invoke' in object."));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = PyObject_Call (callable, args, NULL);
|
||||||
|
Py_DECREF (callable);
|
||||||
|
Py_DECREF (args);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
error (_("Error while executing Python code."));
|
||||||
|
}
|
||||||
|
|
||||||
|
value = convert_value_from_python (result);
|
||||||
|
if (value == NULL)
|
||||||
|
{
|
||||||
|
Py_DECREF (result);
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
error (_("Error while executing Python code."));
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF (result);
|
||||||
|
do_cleanups (cleanup);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializer for a Function object. It takes one argument, the name
|
||||||
|
of the function. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
fnpy_init (PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
char *name, *docstring = NULL;
|
||||||
|
if (! PyArg_ParseTuple (args, "s", &name))
|
||||||
|
return -1;
|
||||||
|
Py_INCREF (self);
|
||||||
|
|
||||||
|
if (PyObject_HasAttrString (self, "__doc__"))
|
||||||
|
{
|
||||||
|
PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__");
|
||||||
|
if (ds_obj && gdbpy_is_string (ds_obj))
|
||||||
|
/* Nothing ever frees this. */
|
||||||
|
docstring = python_string_to_host_string (ds_obj);
|
||||||
|
}
|
||||||
|
if (! docstring)
|
||||||
|
docstring = _("This function is not documented.");
|
||||||
|
|
||||||
|
add_internal_function (name, docstring, fnpy_call, self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize internal function support. */
|
||||||
|
|
||||||
|
void
|
||||||
|
gdbpy_initialize_functions (void)
|
||||||
|
{
|
||||||
|
if (PyType_Ready (&fnpy_object_type) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Py_INCREF (&fnpy_object_type);
|
||||||
|
PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static PyTypeObject fnpy_object_type =
|
||||||
|
{
|
||||||
|
PyObject_HEAD_INIT (NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"gdb.Function", /*tp_name*/
|
||||||
|
sizeof (PyObject), /*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 function object", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
0, /* 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 */
|
||||||
|
fnpy_init, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
PyType_GenericNew /* tp_new */
|
||||||
|
};
|
|
@ -71,6 +71,7 @@ struct value *convert_value_from_python (PyObject *obj);
|
||||||
|
|
||||||
void gdbpy_initialize_values (void);
|
void gdbpy_initialize_values (void);
|
||||||
void gdbpy_initialize_commands (void);
|
void gdbpy_initialize_commands (void);
|
||||||
|
void gdbpy_initialize_functions (void);
|
||||||
|
|
||||||
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
||||||
struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
|
struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
|
||||||
|
|
|
@ -413,6 +413,7 @@ Enables or disables printing of Python stack traces."),
|
||||||
|
|
||||||
gdbpy_initialize_values ();
|
gdbpy_initialize_values ();
|
||||||
gdbpy_initialize_commands ();
|
gdbpy_initialize_commands ();
|
||||||
|
gdbpy_initialize_functions ();
|
||||||
|
|
||||||
PyRun_SimpleString ("import gdb");
|
PyRun_SimpleString ("import gdb");
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2009-03-20 Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||||
|
|
||||||
|
* gdb.python/python-function.exp: New file.
|
||||||
|
|
||||||
2009-03-20 Tom Tromey <tromey@redhat.com>
|
2009-03-20 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* gdb.base/store.exp: Update for change to escape output.
|
* gdb.base/store.exp: Update for change to escape output.
|
||||||
|
|
65
gdb/testsuite/gdb.python/python-function.exp
Normal file
65
gdb/testsuite/gdb.python/python-function.exp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# Copyright (C) 2009 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/>.
|
||||||
|
|
||||||
|
# This file is part of the GDB testsuite. It tests the mechanism
|
||||||
|
# exposing convenience functions to Python.
|
||||||
|
|
||||||
|
if $tracelevel then {
|
||||||
|
strace $tracelevel
|
||||||
|
}
|
||||||
|
|
||||||
|
# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
|
||||||
|
# Run a test named NAME, consisting of multiple lines of input.
|
||||||
|
# After each input line INPUT, search for result line RESULT.
|
||||||
|
# Succeed if all results are seen; fail otherwise.
|
||||||
|
proc gdb_py_test_multiple {name args} {
|
||||||
|
global gdb_prompt
|
||||||
|
foreach {input result} $args {
|
||||||
|
if {[gdb_test_multiple $input "$name - $input" {
|
||||||
|
-re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
|
||||||
|
pass "$name - $input"
|
||||||
|
}
|
||||||
|
}]} {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start with a fresh gdb.
|
||||||
|
|
||||||
|
gdb_exit
|
||||||
|
gdb_start
|
||||||
|
gdb_reinitialize_dir $srcdir/$subdir
|
||||||
|
|
||||||
|
gdb_test_multiple "python print 'hello, world!'" "verify python support" {
|
||||||
|
-re "not supported.*$gdb_prompt $" {
|
||||||
|
unsupported "python support is disabled"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
-re "$gdb_prompt $" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_py_test_multiple "input convenience function" \
|
||||||
|
"python" "" \
|
||||||
|
"class test_func (gdb.Function):" "" \
|
||||||
|
" def __init__ (self):" "" \
|
||||||
|
" super (test_func, self).__init__ (\"test_func\")" "" \
|
||||||
|
" def invoke (self, arg):" "" \
|
||||||
|
" return \"test_func output, arg = %s\" % arg.string ()" "" \
|
||||||
|
"test_func ()" "" \
|
||||||
|
"end" ""
|
||||||
|
|
||||||
|
gdb_test "print \$test_func (\"ugh\")" "= \"test_func output, arg = ugh\"" "call function"
|
|
@ -287,6 +287,13 @@ value_check_printable (struct value *val, struct ui_file *stream)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TYPE_CODE (value_type (val)) == TYPE_CODE_INTERNAL_FUNCTION)
|
||||||
|
{
|
||||||
|
fprintf_filtered (stream, _("<internal function %s>"),
|
||||||
|
value_internal_function_name (val));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
113
gdb/value.c
113
gdb/value.c
|
@ -37,6 +37,7 @@
|
||||||
#include "dfp.h"
|
#include "dfp.h"
|
||||||
#include "objfiles.h"
|
#include "objfiles.h"
|
||||||
#include "valprint.h"
|
#include "valprint.h"
|
||||||
|
#include "cli/cli-decode.h"
|
||||||
|
|
||||||
#include "python/python.h"
|
#include "python/python.h"
|
||||||
|
|
||||||
|
@ -44,6 +45,23 @@
|
||||||
|
|
||||||
void _initialize_values (void);
|
void _initialize_values (void);
|
||||||
|
|
||||||
|
/* Definition of a user function. */
|
||||||
|
struct internal_function
|
||||||
|
{
|
||||||
|
/* The name of the function. It is a bit odd to have this in the
|
||||||
|
function itself -- the user might use a differently-named
|
||||||
|
convenience variable to hold the function. */
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* The handler. */
|
||||||
|
internal_function_fn handler;
|
||||||
|
|
||||||
|
/* User data for the handler. */
|
||||||
|
void *cookie;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cmd_list_element *functionlist;
|
||||||
|
|
||||||
struct value
|
struct value
|
||||||
{
|
{
|
||||||
/* Type of value; either not an lval, or one of the various
|
/* Type of value; either not an lval, or one of the various
|
||||||
|
@ -203,6 +221,10 @@ struct value_history_chunk
|
||||||
static struct value_history_chunk *value_history_chain;
|
static struct value_history_chunk *value_history_chain;
|
||||||
|
|
||||||
static int value_history_count; /* Abs number of last entry stored */
|
static int value_history_count; /* Abs number of last entry stored */
|
||||||
|
|
||||||
|
/* The type of internal functions. */
|
||||||
|
|
||||||
|
static struct type *internal_fn_type;
|
||||||
|
|
||||||
/* List of all value objects currently allocated
|
/* List of all value objects currently allocated
|
||||||
(except for those released by calls to release_value)
|
(except for those released by calls to release_value)
|
||||||
|
@ -878,7 +900,7 @@ init_if_undefined_command (char* args, int from_tty)
|
||||||
the return value is NULL. */
|
the return value is NULL. */
|
||||||
|
|
||||||
struct internalvar *
|
struct internalvar *
|
||||||
lookup_only_internalvar (char *name)
|
lookup_only_internalvar (const char *name)
|
||||||
{
|
{
|
||||||
struct internalvar *var;
|
struct internalvar *var;
|
||||||
|
|
||||||
|
@ -894,7 +916,7 @@ lookup_only_internalvar (char *name)
|
||||||
NAME should not normally include a dollar sign. */
|
NAME should not normally include a dollar sign. */
|
||||||
|
|
||||||
struct internalvar *
|
struct internalvar *
|
||||||
create_internalvar (char *name)
|
create_internalvar (const char *name)
|
||||||
{
|
{
|
||||||
struct internalvar *var;
|
struct internalvar *var;
|
||||||
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
|
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
|
||||||
|
@ -902,6 +924,7 @@ create_internalvar (char *name)
|
||||||
var->value = allocate_value (builtin_type_void);
|
var->value = allocate_value (builtin_type_void);
|
||||||
var->endian = gdbarch_byte_order (current_gdbarch);
|
var->endian = gdbarch_byte_order (current_gdbarch);
|
||||||
var->make_value = NULL;
|
var->make_value = NULL;
|
||||||
|
var->canonical = 0;
|
||||||
release_value (var->value);
|
release_value (var->value);
|
||||||
var->next = internalvars;
|
var->next = internalvars;
|
||||||
internalvars = var;
|
internalvars = var;
|
||||||
|
@ -934,7 +957,7 @@ create_internalvar_type_lazy (char *name, internalvar_make_value fun)
|
||||||
one is created, with a void value. */
|
one is created, with a void value. */
|
||||||
|
|
||||||
struct internalvar *
|
struct internalvar *
|
||||||
lookup_internalvar (char *name)
|
lookup_internalvar (const char *name)
|
||||||
{
|
{
|
||||||
struct internalvar *var;
|
struct internalvar *var;
|
||||||
|
|
||||||
|
@ -1031,6 +1054,9 @@ set_internalvar (struct internalvar *var, struct value *val)
|
||||||
{
|
{
|
||||||
struct value *newval;
|
struct value *newval;
|
||||||
|
|
||||||
|
if (var->canonical)
|
||||||
|
error (_("Cannot overwrite convenience function %s"), var->name);
|
||||||
|
|
||||||
newval = value_copy (val);
|
newval = value_copy (val);
|
||||||
newval->modifiable = 1;
|
newval->modifiable = 1;
|
||||||
|
|
||||||
|
@ -1042,7 +1068,7 @@ set_internalvar (struct internalvar *var, struct value *val)
|
||||||
|
|
||||||
/* Begin code which must not call error(). If var->value points to
|
/* Begin code which must not call error(). If var->value points to
|
||||||
something free'd, an error() obviously leaves a dangling pointer.
|
something free'd, an error() obviously leaves a dangling pointer.
|
||||||
But we also get a danling pointer if var->value points to
|
But we also get a dangling pointer if var->value points to
|
||||||
something in the value chain (i.e., before release_value is
|
something in the value chain (i.e., before release_value is
|
||||||
called), because after the error free_all_values will get called before
|
called), because after the error free_all_values will get called before
|
||||||
long. */
|
long. */
|
||||||
|
@ -1059,6 +1085,76 @@ internalvar_name (struct internalvar *var)
|
||||||
return var->name;
|
return var->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct value *
|
||||||
|
value_create_internal_function (const char *name,
|
||||||
|
internal_function_fn handler,
|
||||||
|
void *cookie)
|
||||||
|
{
|
||||||
|
struct value *result = allocate_value (internal_fn_type);
|
||||||
|
gdb_byte *addr = value_contents_writeable (result);
|
||||||
|
struct internal_function **fnp = (struct internal_function **) addr;
|
||||||
|
struct internal_function *ifn = XNEW (struct internal_function);
|
||||||
|
ifn->name = xstrdup (name);
|
||||||
|
ifn->handler = handler;
|
||||||
|
ifn->cookie = cookie;
|
||||||
|
*fnp = ifn;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
value_internal_function_name (struct value *val)
|
||||||
|
{
|
||||||
|
gdb_byte *addr = value_contents_writeable (val);
|
||||||
|
struct internal_function *ifn = * (struct internal_function **) addr;
|
||||||
|
return ifn->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct value *
|
||||||
|
call_internal_function (struct value *func, int argc, struct value **argv)
|
||||||
|
{
|
||||||
|
gdb_byte *addr = value_contents_writeable (func);
|
||||||
|
struct internal_function *ifn = * (struct internal_function **) addr;
|
||||||
|
return (*ifn->handler) (ifn->cookie, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The 'function' command. This does nothing -- it is just a
|
||||||
|
placeholder to let "help function NAME" work. This is also used as
|
||||||
|
the implementation of the sub-command that is created when
|
||||||
|
registering an internal function. */
|
||||||
|
static void
|
||||||
|
function_command (char *command, int from_tty)
|
||||||
|
{
|
||||||
|
/* Do nothing. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up if an internal function's command is destroyed. */
|
||||||
|
static void
|
||||||
|
function_destroyer (struct cmd_list_element *self, void *ignore)
|
||||||
|
{
|
||||||
|
xfree (self->name);
|
||||||
|
xfree (self->doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a new internal function. NAME is the name of the function; DOC
|
||||||
|
is a documentation string describing the function. HANDLER is
|
||||||
|
called when the function is invoked. COOKIE is an arbitrary
|
||||||
|
pointer which is passed to HANDLER and is intended for "user
|
||||||
|
data". */
|
||||||
|
void
|
||||||
|
add_internal_function (const char *name, const char *doc,
|
||||||
|
internal_function_fn handler, void *cookie)
|
||||||
|
{
|
||||||
|
struct cmd_list_element *cmd;
|
||||||
|
struct internalvar *var = lookup_internalvar (name);
|
||||||
|
struct value *fnval = value_create_internal_function (name, handler, cookie);
|
||||||
|
set_internalvar (var, fnval);
|
||||||
|
var->canonical = 1;
|
||||||
|
|
||||||
|
cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc,
|
||||||
|
&functionlist);
|
||||||
|
cmd->destroyer = function_destroyer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to
|
/* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to
|
||||||
prevent cycles / duplicates. */
|
prevent cycles / duplicates. */
|
||||||
|
|
||||||
|
@ -1944,4 +2040,13 @@ init-if-undefined VARIABLE = EXPRESSION\n\
|
||||||
Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\
|
Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\
|
||||||
exist or does not contain a value. The EXPRESSION is not evaluated if the\n\
|
exist or does not contain a value. The EXPRESSION is not evaluated if the\n\
|
||||||
VARIABLE is already initialized."));
|
VARIABLE is already initialized."));
|
||||||
|
|
||||||
|
add_prefix_cmd ("function", no_class, function_command, _("\
|
||||||
|
Placeholder command for showing help on convenience functions."),
|
||||||
|
&functionlist, "function ", 0, &cmdlist);
|
||||||
|
|
||||||
|
internal_fn_type = alloc_type (NULL);
|
||||||
|
TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION;
|
||||||
|
TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *);
|
||||||
|
TYPE_NAME (internal_fn_type) = "<internal function>";
|
||||||
}
|
}
|
||||||
|
|
25
gdb/value.h
25
gdb/value.h
|
@ -314,6 +314,9 @@ struct internalvar
|
||||||
struct value *value;
|
struct value *value;
|
||||||
internalvar_make_value make_value;
|
internalvar_make_value make_value;
|
||||||
int endian;
|
int endian;
|
||||||
|
/* True if this internalvar is the canonical name for a convenience
|
||||||
|
function. */
|
||||||
|
int canonical;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -535,14 +538,14 @@ extern void set_internalvar_component (struct internalvar *var,
|
||||||
int bitpos, int bitsize,
|
int bitpos, int bitsize,
|
||||||
struct value *newvalue);
|
struct value *newvalue);
|
||||||
|
|
||||||
extern struct internalvar *lookup_only_internalvar (char *name);
|
extern struct internalvar *lookup_only_internalvar (const char *name);
|
||||||
|
|
||||||
extern struct internalvar *create_internalvar (char *name);
|
extern struct internalvar *create_internalvar (const char *name);
|
||||||
|
|
||||||
extern struct internalvar *
|
extern struct internalvar *
|
||||||
create_internalvar_type_lazy (char *name, internalvar_make_value fun);
|
create_internalvar_type_lazy (char *name, internalvar_make_value fun);
|
||||||
|
|
||||||
extern struct internalvar *lookup_internalvar (char *name);
|
extern struct internalvar *lookup_internalvar (const char *name);
|
||||||
|
|
||||||
extern int value_equal (struct value *arg1, struct value *arg2);
|
extern int value_equal (struct value *arg1, struct value *arg2);
|
||||||
|
|
||||||
|
@ -661,4 +664,20 @@ extern struct value *value_allocate_space_in_inferior (int);
|
||||||
extern struct value *value_of_local (const char *name, int complain);
|
extern struct value *value_of_local (const char *name, int complain);
|
||||||
|
|
||||||
extern struct value * value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound);
|
extern struct value * value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound);
|
||||||
|
|
||||||
|
/* User function handler. */
|
||||||
|
|
||||||
|
typedef struct value *(*internal_function_fn) (void *cookie,
|
||||||
|
int argc,
|
||||||
|
struct value **argv);
|
||||||
|
|
||||||
|
void add_internal_function (const char *name, const char *doc,
|
||||||
|
internal_function_fn handler,
|
||||||
|
void *cookie);
|
||||||
|
|
||||||
|
struct value *call_internal_function (struct value *function,
|
||||||
|
int argc, struct value **argv);
|
||||||
|
|
||||||
|
char *value_internal_function_name (struct value *);
|
||||||
|
|
||||||
#endif /* !defined (VALUE_H) */
|
#endif /* !defined (VALUE_H) */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue