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>
|
||||
|
||||
* c-lang.c (evaluate_subexp_c): Call check_typedef.
|
||||
|
|
|
@ -271,11 +271,13 @@ SUBDIR_TUI_CFLAGS= \
|
|||
SUBDIR_PYTHON_OBS = \
|
||||
python.o \
|
||||
python-cmd.o \
|
||||
python-function.o \
|
||||
python-utils.o \
|
||||
python-value.o
|
||||
SUBDIR_PYTHON_SRCS = \
|
||||
python/python.c \
|
||||
python/python-cmd.c \
|
||||
python/python-function.c \
|
||||
python/python-utils.c \
|
||||
python/python-value.c
|
||||
SUBDIR_PYTHON_DEPS =
|
||||
|
@ -1850,6 +1852,10 @@ python-cmd.o: $(srcdir)/python/python-cmd.c
|
|||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
|
||||
$(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
|
||||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
|
||||
$(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>
|
||||
|
||||
* 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
|
||||
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
|
||||
@section Registers
|
||||
|
||||
|
@ -18178,6 +18192,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
|||
* Exception Handling::
|
||||
* Values From Inferior::
|
||||
* Commands In Python:: Implementing new commands in Python.
|
||||
* Functions In Python:: Writing new convenience functions.
|
||||
@end menu
|
||||
|
||||
@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
|
||||
@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
|
||||
@chapter Command Interpreters
|
||||
@cindex command interpreters
|
||||
|
|
|
@ -40,9 +40,12 @@
|
|||
#include "regcache.h"
|
||||
#include "user-regs.h"
|
||||
#include "valprint.h"
|
||||
#include "python/python.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* This is defined in valops.c */
|
||||
extern int overload_resolution;
|
||||
|
||||
|
@ -1512,6 +1515,9 @@ evaluate_subexp_standard (struct type *expect_type,
|
|||
else
|
||||
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);
|
||||
/* 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_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
|
||||
|
|
|
@ -306,7 +306,7 @@ write_exp_elt_intern (struct internalvar *expelt)
|
|||
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,
|
||||
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
|
||||
actual length is recorded in expression elements at each end of the
|
||||
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_commands (void);
|
||||
void gdbpy_initialize_functions (void);
|
||||
|
||||
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
||||
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_commands ();
|
||||
gdbpy_initialize_functions ();
|
||||
|
||||
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>
|
||||
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
113
gdb/value.c
113
gdb/value.c
|
@ -37,6 +37,7 @@
|
|||
#include "dfp.h"
|
||||
#include "objfiles.h"
|
||||
#include "valprint.h"
|
||||
#include "cli/cli-decode.h"
|
||||
|
||||
#include "python/python.h"
|
||||
|
||||
|
@ -44,6 +45,23 @@
|
|||
|
||||
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
|
||||
{
|
||||
/* 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 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
|
||||
(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. */
|
||||
|
||||
struct internalvar *
|
||||
lookup_only_internalvar (char *name)
|
||||
lookup_only_internalvar (const char *name)
|
||||
{
|
||||
struct internalvar *var;
|
||||
|
||||
|
@ -894,7 +916,7 @@ lookup_only_internalvar (char *name)
|
|||
NAME should not normally include a dollar sign. */
|
||||
|
||||
struct internalvar *
|
||||
create_internalvar (char *name)
|
||||
create_internalvar (const char *name)
|
||||
{
|
||||
struct internalvar *var;
|
||||
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
|
||||
|
@ -902,6 +924,7 @@ create_internalvar (char *name)
|
|||
var->value = allocate_value (builtin_type_void);
|
||||
var->endian = gdbarch_byte_order (current_gdbarch);
|
||||
var->make_value = NULL;
|
||||
var->canonical = 0;
|
||||
release_value (var->value);
|
||||
var->next = internalvars;
|
||||
internalvars = var;
|
||||
|
@ -934,7 +957,7 @@ create_internalvar_type_lazy (char *name, internalvar_make_value fun)
|
|||
one is created, with a void value. */
|
||||
|
||||
struct internalvar *
|
||||
lookup_internalvar (char *name)
|
||||
lookup_internalvar (const char *name)
|
||||
{
|
||||
struct internalvar *var;
|
||||
|
||||
|
@ -1031,6 +1054,9 @@ set_internalvar (struct internalvar *var, struct value *val)
|
|||
{
|
||||
struct value *newval;
|
||||
|
||||
if (var->canonical)
|
||||
error (_("Cannot overwrite convenience function %s"), var->name);
|
||||
|
||||
newval = value_copy (val);
|
||||
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
|
||||
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
|
||||
called), because after the error free_all_values will get called before
|
||||
long. */
|
||||
|
@ -1059,6 +1085,76 @@ internalvar_name (struct internalvar *var)
|
|||
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
|
||||
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\
|
||||
exist or does not contain a value. The EXPRESSION is not evaluated if the\n\
|
||||
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;
|
||||
internalvar_make_value make_value;
|
||||
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,
|
||||
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 *
|
||||
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);
|
||||
|
||||
|
@ -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_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) */
|
||||
|
|
Loading…
Reference in a new issue