Re: [rfc] expose gdb values to python

Thiago Jung Bauermann
2008-09-29T16:16:21Z

El dom, 28-09-2008 a las 21:18 +0300, Eli Zaretskii escribiÃ³:
> Thanks for working on this, the new version is an improvement. Rather
> than responding with another set of comments, I decided to rephrase
> your text, interspersed with comments about noteworthy issues.

Thanks for your version! It is certainly better than mine. I adopted all
your changes.

Thanks as well for your tips. I'll try to follow them next time I write
a doc patch.

> > +The following method is provided:
>
> For pointer data types, @code{gdb.Value} provides a method for
> dereferencing the pointer to obtain the object it points to.
>
> (avoid passive tense again, and make it clear how this is connected to
> the rest of the section.)

In future patches, more methods will probably be added to gdb.Value, so
we may (or may not) return to the "list of methods" format. But I am
currently adopting your version.

> Btw, now that I've written this, I see that this begs a few questions
> about other kinds of data types: arrays, strings, and C/C++ unions,
> just for starters. Would it be useful to cover them as well? Or
> maybe they are already covered by one of the above, in which case the
> text should mention them as well.

Good observation. Unions work just like structs, so they are covered.
Arrays and strings are not implemented yet. I will cover them in a
future patch.

> Also, I don't see where we explain how to come by the gdb.Value object
> in the first place. For example, given a variable `foo', how do I
> create a gdb.Value object for it? Do I just use `foo'? i.e., is the
> example above (that says "foo.dereference ()" for `foo' that is a C
> pointer) valid? This is also something non-trivial that should be
> explained.

Good observation, again. :-)

This patch is not an end on itself, it is more of an infrastructure for
other python patches. The user won't want to directly produce a
gdb.Value for its own sake. He'll end up with one when trying to
accomplish other things.

For instance, if the user wants GDB to evaluate a C expression and get
the result, GDB will return a gdb.Value object. Or when implementing a
pretty-printer in Python, he'll be given a gdb.Value to examine and
pretty-print. Or if he is examining a stack frame and requests the value
of a register or a local variable, he'll be given a gdb.Value.

That's talking about features which are not in CVS yet. For now, the
only way to get a gdb.Value is using gdb.get_value_from_history. So,
with your example you could do:

(gdb) print foo
$3 = 2
(gdb) python foo = gdb.get_value_from_history (3)

I am attaching the latest version of this patch, which incorporates all
documentation and code review comments, and is adapted to yesterday's
CVS HEAD version. It applies cleanly, passes all included tests and
introduces no regression. Tested with x86_64-linux.

Daniel,

There are two differences from what you reviewed: I had to change
python-value.c to use only arch-independent builtin_type_*. And I had to
use value_binop instead of value_add and value_sub. This made gdb.Value
unable to do pointer math. I'll post a follow up patch explicitly adding
pointer math.

Is this ok?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

2008-09-28 Thiago Jung Bauermann <bauerman@br.ibm.com>

gdb/
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-value.o.
(SUBDIR_PYTHON_SRCS): Add python-value.c.
(python-value.o): New target.
* configure.ac (CONFIG_OBS): Add python-value.o.
(CONFIG_SRCS): Add python/python-value.c
* configure: Regenerate.
* python-internal.h (value_object_type): Add external declaration.
(gdbpy_get_value_from_history, value_to_value_object,
convert_value_from_python, gdbpy_initialize_values): Add function
prototype.
* python/python-value.c: New file.
* python/python.c (GdbMethods): Add gdbpy_get_value_from_history.
(_initialize_python): Call gdbpy_initialize_values.
* python/python.h (values_in_python): Add external declaration.
* value.c (value_prepend_to_list, value_remove_from_list): New
functions.
(preserve_values): Iterate over values_in_python list as well.
* value.h (value_prepend_to_list, value_remove_from_list): Add
function prototypes.

gdb/doc/
* gdb.texinfo. (Values From Inferior): New subsubsection.

gdb/testsuite/
* gdb.python/python-value.c: New file.
* gdb.python/python-value.exp: New file.

Index: gdb.git/gdb/Makefile.in
===================================================================
--- gdb.git.orig/gdb/Makefile.in 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/Makefile.in 2008-09-28 23:18:56.000000000 -0300
@@ -271,10 +271,12 @@ SUBDIR_TUI_CFLAGS= \
#
SUBDIR_PYTHON_OBS = \
python.o \
- python-utils.o
+ python-utils.o \
+ python-value.o
SUBDIR_PYTHON_SRCS = \
python/python.c \
- python/python-utils.c
+ python/python-utils.c \
+ python/python-value.c
SUBDIR_PYTHON_DEPS =
SUBDIR_PYTHON_LDFLAGS=
SUBDIR_PYTHON_CFLAGS=
@@ -1849,6 +1851,10 @@ python-utils.o: $(srcdir)/python/python-
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
$(POSTCOMPILE)

+python-value.o: $(srcdir)/python/python-value.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-value.c
+ $(POSTCOMPILE)
+
#
# Dependency tracking. Most of this is conditional on GNU Make being
# found by configure; if GNU Make is not found, we fall back to a
Index: gdb.git/gdb/configure
===================================================================
--- gdb.git.orig/gdb/configure 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/configure 2008-09-28 23:18:56.000000000 -0300
@@ -11704,10 +11704,10 @@ rm -f conftest.err conftest.$ac_objext c
echo "${ECHO_T}${PYTHON_CFLAGS}" >&6
fi
else
- # Even if Python support is not compiled in, we need to have this file
+ # Even if Python support is not compiled in, we need to have these files
# included in order to recognize the GDB command "python".
- CONFIG_OBS="$CONFIG_OBS python.o"
- CONFIG_SRCS="$CONFIG_SRCS python/python.c"
+ CONFIG_OBS="$CONFIG_OBS python.o python-value.o"
+ CONFIG_SRCS="$CONFIG_SRCS python/python.c python/python-value.c"
fi

Index: gdb.git/gdb/configure.ac
===================================================================
--- gdb.git.orig/gdb/configure.ac 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/configure.ac 2008-09-28 23:18:56.000000000 -0300
@@ -624,10 +624,10 @@ if test "${have_libpython}" = yes; then
AC_MSG_RESULT(${PYTHON_CFLAGS})
fi
else
- # Even if Python support is not compiled in, we need to have this file
+ # Even if Python support is not compiled in, we need to have these files
# included in order to recognize the GDB command "python".
- CONFIG_OBS="$CONFIG_OBS python.o"
- CONFIG_SRCS="$CONFIG_SRCS python/python.c"
+ CONFIG_OBS="$CONFIG_OBS python.o python-value.o"
+ CONFIG_SRCS="$CONFIG_SRCS python/python.c python/python-value.c"
fi
AC_SUBST(PYTHON_CFLAGS)

Index: gdb.git/gdb/doc/gdb.texinfo
===================================================================
--- gdb.git.orig/gdb/doc/gdb.texinfo 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/doc/gdb.texinfo 2008-09-28 23:19:46.000000000 -0300
@@ -17674,6 +17674,7 @@ situation, a Python @code{KeyboardInterr
@menu
* Basic Python:: Basic Python Functions.
* Exception Handling::
+* Values From Inferior::
@end menu

@node Basic Python
@@ -17752,6 +17753,64 @@ message as its value, and the Python cal
Python statement closest to where the @value{GDBN} error occured as the
traceback.

+@node Values From Inferior
+@subsubsection Values From Inferior
+@cindex values from inferior, with Python
+@cindex python, working with values from inferior
+
+@cindex @code{gdb.Value}
+@value{GDBN} provides values it obtains from the inferior program in
+an object of type @code{gdb.Value}. @value{GDBN} uses this object
+for its internal bookkeeping of the inferior's values, and for
+fetching values when necessary.
+
+Inferior values that are simple scalars can be used directly in
+Python expressions that are valid for the value's data type Here's
+an example for an integer or floating-point value @code{some_val}:
+
+@smallexample
+bar = some_val + 2
+@end smallexample
+
+@noindent
+As result of this, @code{bar} will also be a @code{gdb.Value} object
+whose values are of the same type as those of @code{some_val}.
+
+Inferior values that are structures or instances of some class can
+be accessed using the Python @dfn{dictionary syntax}. For example, if
+@code{some_val} is a @code{gdb.Value} instance holding a structure, you
+can access its @code{foo} element with:
+
+@smallexample
+bar = some_val['foo']
+@end smallexample
+
+Again, @code{bar} will also be a @code{gdb.Value} object.
+
+For pointer data types, @code{gdb.Value} provides a method for
+dereferencing the pointer to obtain the object it points to.
+
+@defmethod Value dereference
+This method returns a new @code{gdb.Value} object whose contents is
+the object pointed to by the pointer. For example, if @code{foo} is
+a C pointer to an @code{int}, declared in your C program as
+
+@smallexample
+int *foo;
+@end smallexample
+
+@noindent
+then you can use the corresponding @code{gdb.Value} to access what
+@code{foo} points to like this:
+
+@smallexample
+bar = foo.dereference ()
+@end smallexample
+
+The result @code{bar} will be a @code{gdb.Value} object holding the
+value pointed to by @code{foo}.
+@end defmethod
+
@node Interpreters
@chapter Command Interpreters
@cindex command interpreters
Index: gdb.git/gdb/python/python-internal.h
===================================================================
--- gdb.git.orig/gdb/python/python-internal.h 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/python/python-internal.h 2008-09-28 23:18:56.000000000 -0300
@@ -43,11 +43,18 @@ typedef Py_intptr_t Py_ssize_t;
#error "Unable to find usable Python.h"
#endif

-struct block;
-struct symbol;
-struct symtab_and_line;
+struct value;

extern PyObject *gdb_module;
+extern PyTypeObject value_object_type;
+
+PyObject *gdbpy_get_value_from_history (PyObject *self, PyObject *args);
+
+PyObject *value_to_value_object (struct value *v);
+
+struct value *convert_value_from_python (PyObject *obj);
+
+void gdbpy_initialize_values (void);

struct cleanup *make_cleanup_py_decref (PyObject *py);

Index: gdb.git/gdb/python/python-value.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb.git/gdb/python/python-value.c 2008-09-28 23:18:56.000000000 -0300
@@ -0,0 +1,684 @@
+/* Python interface to values.
+
+ Copyright (C) 2008 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 "charset.h"
+#include "value.h"
+#include "exceptions.h"
+#include "language.h"
+#include "dfp.h"
+
+/* List of all values which are currently exposed to Python. It is
+ maintained so that when an objfile is discarded, preserve_values
+ can copy the values' types if needed. This is declared
+ unconditionally to reduce the number of uses of HAVE_PYTHON in the
+ generic code. */
+struct value *values_in_python;
+
+#ifdef HAVE_PYTHON
+
+#include "python-internal.h"
+
+/* Python's integer type corresponds to native C's long type. */
+struct type *builtin_type_pyint;
+
+/* Python's float type corresponds to native C's double type (which is
+ assumed to use IEEE double format). */
+#define builtin_type_pyfloat builtin_type_ieee_double
+
+/* Python's long type corresponds to native C's long long type (which is
+ assumed to be int64_t). */
+#define builtin_type_pylong builtin_type_int64
+
+/* The current language may not have a boolean type, so always use an
+ integer as boolean type. Hopefully any language can deal with integers
+ as boolean values. */
+#define builtin_type_pybool builtin_type_int32
+
+typedef struct {
+ PyObject_HEAD
+ struct value *value;
+ int owned_by_gdb;
+} value_object;
+
+static void valpy_dealloc (PyObject *obj);
+static PyObject *valpy_new (PyTypeObject *subtype, PyObject *args,
+ PyObject *keywords);
+static Py_ssize_t valpy_length (PyObject *self);
+static PyObject *valpy_getitem (PyObject *self, PyObject *key);
+static int valpy_setitem (PyObject *self, PyObject *key, PyObject *value);
+static PyObject *valpy_str (PyObject *self);
+static PyObject *valpy_add (PyObject *self, PyObject *other);
+static PyObject *valpy_subtract (PyObject *self, PyObject *other);
+static PyObject *valpy_multiply (PyObject *self, PyObject *other);
+static PyObject *valpy_divide (PyObject *self, PyObject *other);
+static PyObject *valpy_remainder (PyObject *self, PyObject *other);
+static PyObject *valpy_power (PyObject *self, PyObject *other, PyObject *unused);
+static PyObject *valpy_negative (PyObject *self);
+static PyObject *valpy_positive (PyObject *self);
+static PyObject *valpy_absolute (PyObject *self);
+static int valpy_nonzero (PyObject *self);
+static PyObject *valpy_richcompare (PyObject *self, PyObject *other, int op);
+static PyObject *valpy_dereference (PyObject *self, PyObject *args);
+
+static PyMethodDef value_object_methods[] = {
+ { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." },
+ {NULL} /* Sentinel */
+};
+
+static PyNumberMethods value_object_as_number = {
+ valpy_add,
+ valpy_subtract,
+ valpy_multiply,
+ valpy_divide,
+ valpy_remainder,
+ NULL, /* nb_divmod */
+ valpy_power, /* nb_power */
+ valpy_negative, /* nb_negative */
+ valpy_positive, /* nb_positive */
+ valpy_absolute, /* nb_absolute */
+ valpy_nonzero /* nb_nonzero */
+};
+
+static PyMappingMethods value_object_as_mapping = {
+ valpy_length,
+ valpy_getitem,
+ valpy_setitem
+};
+
+PyTypeObject value_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Value", /*tp_name*/
+ sizeof (value_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ valpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ &value_object_as_number, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ &value_object_as_mapping, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ valpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ "GDB value object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ valpy_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ value_object_methods /* tp_methods */
+};
+
+
+/* Called by the Python interpreter when deallocating a value object. */
+static void
+valpy_dealloc (PyObject *obj)
+{
+ value_object *self = (value_object *) obj;
+
+ value_remove_from_list (&values_in_python, self->value);
+
+ if (!self->owned_by_gdb)
+ value_free (self->value);
+ self->ob_type->tp_free (self);
+}
+
+/* Called when a new gdb.Value object needs to be allocated. */
+static PyObject *
+valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords)
+{
+ struct value *value = NULL; /* Initialize to appease gcc warning. */
+ value_object *value_obj;
+ volatile struct gdb_exception except;
+
+ if (PyTuple_Size (args) != 1)
+ {
+ PyErr_SetString (PyExc_TypeError, _("Value object creation takes only "
+ "1 argument"));
+ return NULL;
+ }
+
+ value_obj = (value_object *) subtype->tp_alloc (subtype, 1);
+ if (value_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError, _("Could not allocate memory to "
+ "create Value object."));
+ return NULL;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ value = convert_value_from_python (PyTuple_GetItem (args, 0));
+ }
+ if (except.reason < 0)
+ {
+ subtype->tp_free (value_obj);
+ return PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_TypeError,
+ "%s", except.message);
+ }
+
+ value_obj->value = value;
+ release_value (value);
+ value_prepend_to_list (&values_in_python, value);
+
+ return (PyObject *) value_obj;
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it. */
+static PyObject *
+valpy_dereference (PyObject *self, PyObject *args)
+{
+ struct value *res_val = NULL; /* Initialize to appease gcc warning. */
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ res_val = value_ind (((value_object *) self)->value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return value_to_value_object (res_val);
+}
+
+static Py_ssize_t
+valpy_length (PyObject *self)
+{
+ /* We don't support getting the number of elements in a struct / class. */
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Invalid operation on gdb.Value.");
+ return -1;
+}
+
+/* Given string name of an element inside structure, return its value
+ object. */
+static PyObject *
+valpy_getitem (PyObject *self, PyObject *key)
+{
+ value_object *self_value = (value_object *) self;
+ char *field;
+ struct value *res_val = NULL; /* Initialize to appease gcc warning. */
+ struct cleanup *old;
+ volatile struct gdb_exception except;
+
+ field = python_string_to_target_string (key);
+ if (field == NULL)
+ return NULL;
+
+ old = make_cleanup (xfree, field);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ res_val = value_struct_elt (&self_value->value, NULL, field, 0, NULL);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ do_cleanups (old);
+
+ return value_to_value_object (res_val);
+}
+
+static int
+valpy_setitem (PyObject *self, PyObject *key, PyObject *value)
+{
+ PyErr_Format (PyExc_NotImplementedError,
+ _("Setting of struct elements is not currently supported."));
+ return -1;
+}
+
+/* Called by the Python interpreter to obtain string representation
+ of the object. */
+static PyObject *
+valpy_str (PyObject *self)
+{
+ char *s = NULL;
+ long dummy;
+ struct ui_file *stb;
+ struct cleanup *old_chain;
+ PyObject *result;
+ volatile struct gdb_exception except;
+
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ common_val_print (((value_object *) self)->value, stb, 0, 0, 0,
+ Val_pretty_default, current_language);
+ s = ui_file_xstrdup (stb, &dummy);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ do_cleanups (old_chain);
+
+ result = PyUnicode_Decode (s, strlen (s), host_charset (), NULL);
+ xfree (s);
+
+ return result;
+}
+
+enum valpy_opcode
+{
+ VALPY_ADD,
+ VALPY_SUB,
+ VALPY_MUL,
+ VALPY_DIV,
+ VALPY_REM,
+ VALPY_POW
+};
+
+/* Returns a value object which is the sum of this value with the given
+ integer argument. */
+static PyObject *
+valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
+{
+ long l;
+ double d;
+ struct value *res_val = NULL; /* Initialize to appease gcc warning. */
+ struct value *other_val;
+ value_object *self_value;
+ volatile struct gdb_exception except;
+
+ /* If the gdb.Value object is the second operand, then it will be passed
+ to us as the OTHER argument, and SELF will be an entirely different
+ kind of object, altogether. Swap them to avoid surprises. */
+ if (!PyObject_TypeCheck (self, &value_object_type))
+ {
+ PyObject *tmp;
+
+ tmp = self;
+ self = other;
+ other = tmp;
+ }
+
+ self_value = (value_object *) self;
+
+ if (PyObject_TypeCheck (other, &value_object_type))
+ other_val = ((value_object *) other)->value;
+ else if (PyInt_Check (other))
+ {
+ l = PyInt_AsLong (other);
+ if (PyErr_Occurred ())
+ return Py_NotImplemented;
+
+ other_val = value_from_longest (builtin_type_pyint, l);
+ }
+ else if (PyFloat_Check (other))
+ {
+ d = PyFloat_AsDouble (other);
+ if (PyErr_Occurred ())
+ return Py_NotImplemented;
+
+ other_val = value_from_double (builtin_type_pyfloat, d);
+ }
+ else
+ /* If the types cannot be added, Python documentation says to return
+ NotImplemented (http://docs.python.org/ref/numeric-types.html). */
+ return Py_NotImplemented;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch (opcode)
+ {
+ case VALPY_ADD:
+ res_val = value_binop (self_value->value, other_val, BINOP_ADD);
+ break;
+ case VALPY_SUB:
+ res_val = value_binop (self_value->value, other_val, BINOP_SUB);
+ break;
+ case VALPY_MUL:
+ res_val = value_binop (self_value->value, other_val, BINOP_MUL);
+ break;
+ case VALPY_DIV:
+ res_val = value_binop (self_value->value, other_val, BINOP_DIV);
+ break;
+ case VALPY_REM:
+ res_val = value_binop (self_value->value, other_val, BINOP_REM);
+ break;
+ case VALPY_POW:
+ res_val = value_binop (self_value->value, other_val, BINOP_EXP);
+ break;
+ }
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return value_to_value_object (res_val);
+}
+
+static PyObject *
+valpy_add (PyObject *self, PyObject *other)
+{
+ return valpy_binop (VALPY_ADD, self, other);
+}
+
+static PyObject *
+valpy_subtract (PyObject *self, PyObject *other)
+{
+ return valpy_binop (VALPY_SUB, self, other);
+}
+
+static PyObject *
+valpy_multiply (PyObject *self, PyObject *other)
+{
+ return valpy_binop (VALPY_MUL, self, other);
+}
+
+static PyObject *
+valpy_divide (PyObject *self, PyObject *other)
+{
+ return valpy_binop (VALPY_DIV, self, other);
+}
+
+static PyObject *
+valpy_remainder (PyObject *self, PyObject *other)
+{
+ return valpy_binop (VALPY_REM, self, other);
+}
+
+static PyObject *
+valpy_power (PyObject *self, PyObject *other, PyObject *unused)
+{
+ /* We don't support the ternary form of pow. I don't know how to express
+ that, so let's just throw NotImplementedError to at least do something
+ about it. */
+ if (unused != Py_None)
+ {
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Invalid operation on gdb.Value.");
+ return NULL;
+ }
+
+ return valpy_binop (VALPY_POW, self, other);
+}
+
+static PyObject *
+valpy_negative (PyObject *self)
+{
+ struct value *val = NULL;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ val = value_neg (((value_object *) self)->value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return value_to_value_object (val);
+}
+
+static PyObject *
+valpy_positive (PyObject *self)
+{
+ struct value *copy = value_copy (((value_object *) self)->value);
+
+ return value_to_value_object (copy);
+}
+
+static PyObject *
+valpy_absolute (PyObject *self)
+{
+ if (value_less (((value_object *) self)->value,
+ value_from_longest (builtin_type_int8, 0)))
+ return valpy_negative (self);
+ else
+ return valpy_positive (self);
+}
+
+/* Implements boolean evaluation of gdb.Value. */
+static int
+valpy_nonzero (PyObject *self)
+{
+ value_object *self_value = (value_object *) self;
+ struct type *type;
+
+ type = check_typedef (value_type (self_value->value));
+
+ if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR)
+ return !!value_as_long (self_value->value);
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return value_as_double (self_value->value) != 0;
+ else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+ return !decimal_is_zero (value_contents (self_value->value),
+ TYPE_LENGTH (type));
+ else
+ {
+ PyErr_SetString (PyExc_TypeError, _("Attempted truth testing on invalid "
+ "gdb.Value type."));
+ return 0;
+ }
+}
+
+/* Implements comparison operations for value objects. */
+static PyObject *
+valpy_richcompare (PyObject *self, PyObject *other, int op)
+{
+ int result = 0;
+ struct value *value_self, *value_other;
+ volatile struct gdb_exception except;
+
+ if (PyObject_TypeCheck (other, &value_object_type))
+ value_other = ((value_object *) other)->value;
+ else if (PyInt_Check (other))
+ {
+ LONGEST l;
+
+ l = PyInt_AsLong (other);
+ if (PyErr_Occurred ())
+ return NULL;
+
+ value_other = value_from_longest (builtin_type_pyint, l);
+ }
+ else if (PyFloat_Check (other))
+ {
+ DOUBLEST d;
+
+ d = PyFloat_AsDouble (other);
+ if (PyErr_Occurred ())
+ return NULL;
+
+ value_other = value_from_double (builtin_type_pyfloat, d);
+ }
+ else if (PyString_Check (other) || PyUnicode_Check (other))
+ {
+ char *str;
+
+ str = python_string_to_target_string (other);
+ value_other = value_from_string (str);
+ xfree (str);
+ }
+ else if (other == Py_None)
+ /* Comparing with None is special. From what I can tell, in Python
+ None is smaller than anything else. */
+ switch (op) {
+ case Py_LT:
+ case Py_LE:
+ case Py_EQ:
+ Py_RETURN_FALSE;
+ case Py_NE:
+ case Py_GT:
+ case Py_GE:
+ Py_RETURN_TRUE;
+ default:
+ /* Can't happen. */
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Invalid operation on gdb.Value.");
+ return NULL;
+ }
+ else
+ {
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Operation not supported on gdb.Value of this type.");
+ return NULL;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch (op) {
+ case Py_LT:
+ result = value_less (((value_object *) self)->value, value_other);
+ break;
+ case Py_LE:
+ result = value_less (((value_object *) self)->value, value_other)
+ || value_equal (((value_object *) self)->value, value_other);
+ break;
+ case Py_EQ:
+ result = value_equal (((value_object *) self)->value, value_other);
+ break;
+ case Py_NE:
+ result = !value_equal (((value_object *) self)->value, value_other);
+ break;
+ case Py_GT:
+ result = value_less (value_other, ((value_object *) self)->value);
+ break;
+ case Py_GE:
+ result = value_less (value_other, ((value_object *) self)->value)
+ || value_equal (((value_object *) self)->value, value_other);
+ break;
+ default:
+ /* Can't happen. */
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Invalid operation on gdb.Value.");
+ return NULL;
+ }
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (result == 1)
+ Py_RETURN_TRUE;
+
+ Py_RETURN_FALSE;
+}
+
+/* Returns an object for a value which is released from the all_values chain,
+ so its lifetime is not bound to the execution of a command. */
+PyObject *
+value_to_value_object (struct value *val)
+{
+ value_object *val_obj;
+
+ val_obj = PyObject_New (value_object, &value_object_type);
+ if (val_obj != NULL)
+ {
+ val_obj->value = val;
+ release_value (val);
+ value_prepend_to_list (&values_in_python, val);
+ }
+
+ return (PyObject *) val_obj;
+}
+
+/* Try to convert a Python value to a gdb value. If the value cannot
+ be converted, throw a gdb exception. */
+
+struct value *
+convert_value_from_python (PyObject *obj)
+{
+ struct value *value = NULL; /* -Wall */
+ PyObject *target_str, *unicode_str;
+ struct cleanup *old;
+
+ if (! obj)
+ error (_("Internal error while converting Python value."));
+
+ if (PyBool_Check (obj))
+ value = value_from_longest (builtin_type_pybool, obj == Py_True);
+ else if (PyInt_Check (obj))
+ value = value_from_longest (builtin_type_pyint, PyInt_AsLong (obj));
+ else if (PyLong_Check (obj))
+ {
+ LONGEST l = PyLong_AsLongLong (obj);
+ if (! PyErr_Occurred ())
+ value = value_from_longest (builtin_type_pylong, l);
+ }
+ else if (PyFloat_Check (obj))
+ {
+ double d = PyFloat_AsDouble (obj);
+ if (! PyErr_Occurred ())
+ value = value_from_double (builtin_type_pyfloat, d);
+ }
+ else if (PyString_Check (obj) || PyUnicode_Check (obj))
+ {
+ char *s;
+
+ s = python_string_to_target_string (obj);
+ if (s == NULL)
+ return NULL;
+
+ old = make_cleanup (xfree, s);
+ value = value_from_string (s);
+ do_cleanups (old);
+ }
+ else if (PyObject_TypeCheck (obj, &value_object_type))
+ value = ((value_object *) obj)->value;
+ else
+ error (_("Could not convert Python object: %s"),
+ PyString_AsString (PyObject_Str (obj)));
+
+ if (PyErr_Occurred ())
+ error (_("Error converting Python value."));
+
+ return value;
+}
+
+/* Returns value object in the ARGth position in GDB's history. */
+PyObject *
+gdbpy_get_value_from_history (PyObject *self, PyObject *args)
+{
+ int i;
+ struct value *res_val = NULL; /* Initialize to appease gcc warning. */
+ volatile struct gdb_exception except;
+
+ if (!PyArg_ParseTuple (args, "i", &i))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ res_val = access_value_history (i);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return value_to_value_object (res_val);
+}
+
+void
+gdbpy_initialize_values (void)
+{
+ builtin_type_pyint = init_type (TYPE_CODE_INT, sizeof (long), 0, "long",
+ (struct objfile *) NULL);
+
+ value_object_type.tp_new = valpy_new;
+ if (PyType_Ready (&value_object_type) < 0)
+ return;
+
+ Py_INCREF (&value_object_type);
+ PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type);
+
+ values_in_python = NULL;
+}
+
+#endif /* HAVE_PYTHON */
Index: gdb.git/gdb/python/python.c
===================================================================
--- gdb.git.orig/gdb/python/python.c 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/python/python.c 2008-09-28 23:18:56.000000000 -0300
@@ -52,6 +52,8 @@ static PyObject *gdbpy_flush (PyObject *

static PyMethodDef GdbMethods[] =
{
+ { "get_value_from_history", gdbpy_get_value_from_history, METH_VARARGS,
+ "Get a value from history" },
{ "execute", execute_gdb_command, METH_VARARGS,
"Execute a gdb command" },
{ "get_parameter", get_parameter, METH_VARARGS,
@@ -398,6 +400,8 @@ Enables or disables printing of Python s
PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name);
PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);

+ gdbpy_initialize_values ();
+
PyRun_SimpleString ("import gdb");

/* Create a couple objects which are used for Python's stdout and
Index: gdb.git/gdb/python/python.h
===================================================================
--- gdb.git.orig/gdb/python/python.h 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/python/python.h 2008-09-28 23:18:56.000000000 -0300
@@ -22,6 +22,8 @@

#include "value.h"

+extern struct value *values_in_python;
+
void eval_python_from_control_command (struct command_line *);

#endif /* GDB_PYTHON_H */
Index: gdb.git/gdb/testsuite/gdb.python/python-value.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb.git/gdb/testsuite/gdb.python/python-value.c 2008-09-28 23:18:56.000000000 -0300
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+struct s
+{
+ int a;
+ int b;
+};
+
+union u
+{
+ int a;
+ float b;
+};
+
+int
+main (int argc, char *argv[])
+{
+ struct s s;
+ union u u;
+
+ s.a = 3;
+ s.b = 5;
+ u.a = 7;
+
+ return 0; /* break to inspect struct and union */
+}
Index: gdb.git/gdb/testsuite/gdb.python/python-value.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb.git/gdb/testsuite/gdb.python/python-value.exp 2008-09-28 23:18:56.000000000 -0300
@@ -0,0 +1,236 @@
+# Copyright (C) 2008 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 values to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "python-value"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+# 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
+}
+
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+proc test_value_creation {} {
+ global gdb_prompt
+
+ gdb_py_test_silent_cmd "python i = gdb.Value (True)" "create boolean value" 1
+ gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create integer value" 1
+ gdb_py_test_silent_cmd "python i = gdb.Value (5L)" "create long value" 1
+ gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create double value" 1
+ gdb_py_test_silent_cmd "python a = gdb.Value ('string test')" "create 8-bit string value" 1
+ gdb_test "python print a" "\"string test\"" "print 8-bit string"
+ gdb_test "python print a.__class__" "<type 'gdb.Value'>" "verify type of 8-bit string"
+ gdb_py_test_silent_cmd "python a = gdb.Value (u'unicode test')" "create unicode value" 1
+ gdb_test "python print a" "\"unicode test\"" "print Unicode string"
+ gdb_test "python print a.__class__" "<type 'gdb.Value'>" "verify type of unicode string"
+}
+
+proc test_value_numeric_ops {} {
+ global gdb_prompt
+
+ gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create first integer value" 0
+ gdb_py_test_silent_cmd "python j = gdb.Value (2)" "create second integer value" 0
+ gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create first double value" 0
+ gdb_py_test_silent_cmd "python g = gdb.Value (2.5)" "create second double value" 0
+ gdb_test "python print 'result = ' + str(i+j)" " = 7" "add two integer values"
+ gdb_test "python print (i+j).__class__" "<type 'gdb.Value'>" "verify type of integer add result"
+
+ gdb_test "python print 'result = ' + str(f+g)" " = 3.75" "add two double values"
+ gdb_test "python print 'result = ' + str(i-j)" " = 3" "subtract two integer values"
+ gdb_test "python print 'result = ' + str(f-g)" " = -1.25" "subtract two double values"
+ gdb_test "python print 'result = ' + str(i*j)" " = 10" "multiply two integer values"
+ gdb_test "python print 'result = ' + str(f*g)" " = 3.125" "multiply two double values"
+ gdb_test "python print 'result = ' + str(i/j)" " = 2" "divide two integer values"
+ gdb_test "python print 'result = ' + str(f/g)" " = 0.5" "divide two double values"
+ gdb_test "python print 'result = ' + str(i%j)" " = 1" "take remainder of two integer values"
+ # Remainder of float is implemented in Python but not in GDB's value system.
+
+ gdb_test "python print 'result = ' + str(i**j)" " = 25" "integer value raised to the power of another integer value"
+ gdb_test "python print 'result = ' + str(g**j)" " = 6.25" "double value raised to the power of integer value"
+
+ gdb_test "python print 'result = ' + str(-i)" " = -5" "negated integer value"
+ gdb_test "python print 'result = ' + str(+i)" " = 5" "positive integer value"
+ gdb_test "python print 'result = ' + str(-f)" " = -1.25" "negated double value"
+ gdb_test "python print 'result = ' + str(+f)" " = 1.25" "positive double value"
+ gdb_test "python print 'result = ' + str(abs(j-i))" " = 3" "absolute of integer value"
+ gdb_test "python print 'result = ' + str(abs(f-g))" " = 1.25" "absolute of double value"
+
+ # Test gdb.Value mixed with Python types.
+
+ gdb_test "python print 'result = ' + str(i+1)" " = 6" "add integer value with python integer"
+ gdb_test "python print (i+1).__class__" "<type 'gdb.Value'>" "verify type of mixed integer add result"
+ gdb_test "python print 'result = ' + str(f+1.5)" " = 2.75" "add double value with python float"
+
+ gdb_test "python print 'result = ' + str(1+i)" " = 6" "add python integer with integer value"
+ gdb_test "python print 'result = ' + str(1.5+f)" " = 2.75" "add python float with double value"
+
+ # Test some invalid operations.
+
+ gdb_test_multiple "python print 'result = ' + str(i+'foo')" "catch error in python type conversion" {
+ -re "unsupported operand type.*$gdb_prompt $" {pass "catch error in python type conversion"}
+ -re "result = .*$gdb_prompt $" {fail "catch error in python type conversion"}
+ -re "$gdb_prompt $" {fail "catch error in python type conversion"}
+ }
+
+ gdb_test_multiple "python print 'result = ' + str(i+gdb.Value('foo'))" "catch throw of GDB error" {
+ -re "Traceback.*$gdb_prompt $" {pass "catch throw of GDB error"}
+ -re "result = .*$gdb_prompt $" {fail "catch throw of GDB error"}
+ -re "$gdb_prompt $" {fail "catch throw of GDB error"}
+ }
+}
+
+proc test_value_boolean {} {
+ # First, define a useful function to test booleans.
+ gdb_py_test_multiple "define function to test booleans" \
+ "python" "" \
+ "def test_bool (val):" "" \
+ " if val:" "" \
+ " print 'yay'" "" \
+ " else:" "" \
+ " print 'nay'" "" \
+ "end" ""
+
+ gdb_test "py test_bool (gdb.Value (True))" "yay" "check evaluation of true boolean value in expression"
+
+ gdb_test "py test_bool (gdb.Value (False))" "nay" "check evaluation of false boolean value in expression"
+
+ gdb_test "py test_bool (gdb.Value (5))" "yay" "check evaluation of true integer value in expression"
+
+ gdb_test "py test_bool (gdb.Value (0))" "nay" "check evaluation of false integer value in expression"
+
+ gdb_test "py test_bool (gdb.Value (5.2))" "yay" "check evaluation of true integer value in expression"
+
+ gdb_test "py test_bool (gdb.Value (0.0))" "nay" "check evaluation of false integer value in expression"
+}
+
+proc test_value_compare {} {
+ gdb_test "py print gdb.Value (1) < gdb.Value (1)" "False" "less than, equal"
+ gdb_test "py print gdb.Value (1) < gdb.Value (2)" "True" "less than, less"
+ gdb_test "py print gdb.Value (2) < gdb.Value (1)" "False" "less than, greater"
+ gdb_test "py print gdb.Value (2) < None" "False" "less than, None"
+
+ gdb_test "py print gdb.Value (1) <= gdb.Value (1)" "True" "less or equal, equal"
+ gdb_test "py print gdb.Value (1) <= gdb.Value (2)" "True" "less or equal, less"
+ gdb_test "py print gdb.Value (2) <= gdb.Value (1)" "False" "less or equal, greater"
+ gdb_test "py print gdb.Value (2) <= None" "False" "less or equal, None"
+
+ gdb_test "py print gdb.Value (1) == gdb.Value (1)" "True" "equality of gdb.Values"
+ gdb_test "py print gdb.Value (1) == gdb.Value (2)" "False" "inequality of gdb.Values"
+ gdb_test "py print gdb.Value (1) == 1.0" "True" "equality of gdb.Value with Python value"
+ gdb_test "py print gdb.Value (1) == 2" "False" "inequality of gdb.Value with Python value"
+ gdb_test "py print gdb.Value (1) == None" "False" "inequality of gdb.Value with None"
+
+ gdb_test "py print gdb.Value (1) != gdb.Value (1)" "False" "inequality, false"
+ gdb_test "py print gdb.Value (1) != gdb.Value (2)" "True" "inequality, true"
+ gdb_test "py print gdb.Value (1) != None" "True" "inequality, None"
+
+ gdb_test "py print gdb.Value (1) > gdb.Value (1)" "False" "greater than, equal"
+ gdb_test "py print gdb.Value (1) > gdb.Value (2)" "False" "greater than, less"
+ gdb_test "py print gdb.Value (2) > gdb.Value (1)" "True" "greater than, greater"
+ gdb_test "py print gdb.Value (2) > None" "True" "greater than, None"
+
+ gdb_test "py print gdb.Value (1) >= gdb.Value (1)" "True" "greater or equal, equal"
+ gdb_test "py print gdb.Value (1) >= gdb.Value (2)" "False" "greater or equal, less"
+ gdb_test "py print gdb.Value (2) >= gdb.Value (1)" "True" "greater or equal, greater"
+ gdb_test "py print gdb.Value (2) >= None" "True" "greater or equal, None"
+}
+
+proc test_value_in_inferior {} {
+ global gdb_prompt
+ global testfile
+
+ gdb_breakpoint [gdb_get_line_number "break to inspect struct and union"]
+ gdb_start_cmd
+
+ # Avoid race condition where a continue command in gdb_continue_to_breakpoint
+ # is issued too early.
+ gdb_test "" "$gdb_prompt"
+
+ gdb_continue_to_breakpoint "break to inspect struct and union"
+
+ # Just get inferior variable s in the value history, available to python.
+ gdb_test "print s" " = {a = 3, b = 5}" ""
+
+ gdb_py_test_silent_cmd "python s = gdb.get_value_from_history (0)" "get value from history" 1
+
+ gdb_test "python print 'result = ' + str(s\['a'\])" " = 3" "acess element inside struct using 8-bit string name"
+ gdb_test "python print 'result = ' + str(s\[u'a'\])" " = 3" "acess element inside struct using unicode name"
+
+ # Test dereferencing the argv pointer
+
+ # Just get inferior variable argv the value history, available to python.
+ gdb_test "print argv" " = \\(char \\*\\*\\) 0x.*" ""
+
+ gdb_py_test_silent_cmd "python argv = gdb.get_value_from_history (0)" "" 0
+ gdb_py_test_silent_cmd "python arg0 = argv.dereference ()" "dereference value" 1
+
+ # Check that the dereferenced value is sane
+ gdb_test "python print arg0" "0x.*$testfile\"" "verify dereferenced value"
+}
+
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+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 $" {}
+}
+
+test_value_creation
+test_value_numeric_ops
+test_value_boolean
+test_value_compare
+test_value_in_inferior
Index: gdb.git/gdb/value.c
===================================================================
--- gdb.git.orig/gdb/value.c 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/value.c 2008-09-28 23:18:56.000000000 -0300
@@ -37,6 +37,8 @@
#include "dfp.h"
#include "objfiles.h"

+#include "python/python.h"
+
/* Prototypes for exported functions. */

void _initialize_values (void);
@@ -130,8 +132,8 @@ struct value

/* Values are stored in a chain, so that they can be deleted easily
over calls to the inferior. Values assigned to internal
- variables or put into the value history are taken off this
- list. */
+ variables, put into the value history or exposed to Python are
+ taken off this list. */
struct value *next;

/* Register number if the value is from a register. */
@@ -257,6 +259,31 @@ allocate_repeat_value (struct type *type
type, range_type));
}

+/* Needed if another module needs to maintain its on list of values. */
+void
+value_prepend_to_list (struct value **head, struct value *val)
+{
+ val->next = *head;
+ *head = val;
+}
+
+/* Needed if another module needs to maintain its on list of values. */
+void
+value_remove_from_list (struct value **head, struct value *val)
+{
+ struct value *prev;
+
+ if (*head == val)
+ *head = (*head)->next;
+ else
+ for (prev = *head; prev->next; prev = prev->next)
+ if (prev->next == val)
+ {
+ prev->next = val->next;
+ break;
+ }
+}
+
/* Accessor methods. */

struct value *
@@ -916,6 +943,7 @@ preserve_values (struct objfile *objfile
htab_t copied_types;
struct value_history_chunk *cur;
struct internalvar *var;
+ struct value *val;
int i;

/* Create the hash table. We allocate on the objfile's obstack, since
@@ -930,6 +958,9 @@ preserve_values (struct objfile *objfile
for (var = internalvars; var; var = var->next)
preserve_one_value (var->value, objfile, copied_types);

+ for (val = values_in_python; val; val = val->next)
+ preserve_one_value (val, objfile, copied_types);
+
htab_delete (copied_types);
}

Index: gdb.git/gdb/value.h
===================================================================
--- gdb.git.orig/gdb/value.h 2008-09-28 23:17:19.000000000 -0300
+++ gdb.git/gdb/value.h 2008-09-28 23:18:56.000000000 -0300
@@ -40,9 +40,15 @@ struct language_defn;

struct value;

+/* Needed if another module needs to maintain its on list of values. */
+
+void value_prepend_to_list (struct value **head, struct value *val);
+void value_remove_from_list (struct value **head, struct value *val);
+
/* Values are stored in a chain, so that they can be deleted easily
- over calls to the inferior. Values assigned to internal variables
- or put into the value history are taken off this list. */
+ over calls to the inferior. Values assigned to internal variables,
+ put into the value history or exposed to Python are taken off this
+ list. */

struct value *value_next (struct value *);