aboutsummaryrefslogtreecommitdiff
path: root/gdb/python/py-value.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/python/py-value.c')
-rw-r--r--gdb/python/py-value.c116
1 files changed, 69 insertions, 47 deletions
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index c843c2c..255a308 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -70,41 +70,64 @@ struct value_object {
work around a linker bug on MacOS. */
static value_object *values_in_python = NULL;
+/* Clear out an old GDB value stored within SELF, and reset the fields to
+ nullptr. This should be called when a gdb.Value is deallocated, and
+ also if a gdb.Value is reinitialized with a new value. */
+
+static void
+valpy_clear_value (value_object *self)
+{
+ /* Indicate we are no longer interested in the value object. */
+ value_decref (self->value);
+ self->value = nullptr;
+
+ Py_CLEAR (self->address);
+ Py_CLEAR (self->type);
+ Py_CLEAR (self->dynamic_type);
+}
+
/* Called by the Python interpreter when deallocating a value object. */
static void
valpy_dealloc (PyObject *obj)
{
value_object *self = (value_object *) obj;
- /* Remove SELF from the global list. */
- if (self->prev)
- self->prev->next = self->next;
- else
+ /* If SELF failed to initialize correctly then it may not have a value
+ contained within it. */
+ if (self->value != nullptr)
{
- gdb_assert (values_in_python == self);
- values_in_python = self->next;
- }
- if (self->next)
- self->next->prev = self->prev;
-
- value_decref (self->value);
+ /* Remove SELF from the global list of values. */
+ if (self->prev != nullptr)
+ self->prev->next = self->next;
+ else
+ {
+ gdb_assert (values_in_python == self);
+ values_in_python = self->next;
+ }
+ if (self->next != nullptr)
+ self->next->prev = self->prev;
- Py_XDECREF (self->address);
- Py_XDECREF (self->type);
- Py_XDECREF (self->dynamic_type);
+ /* Release the value object and any cached Python objects. */
+ valpy_clear_value (self);
+ }
Py_TYPE (self)->tp_free (self);
}
-/* Helper to push a Value object on the global list. */
+/* Helper to push a gdb.Value object on to the global list of values. If
+ VALUE_OBJ is already on the lit then this does nothing. */
+
static void
note_value (value_object *value_obj)
{
- value_obj->next = values_in_python;
- if (value_obj->next)
- value_obj->next->prev = value_obj;
- value_obj->prev = NULL;
- values_in_python = value_obj;
+ if (value_obj->next == nullptr)
+ {
+ gdb_assert (value_obj->prev == nullptr);
+ value_obj->next = values_in_python;
+ if (value_obj->next != nullptr)
+ value_obj->next->prev = value_obj;
+ values_in_python = value_obj;
+ }
}
/* Convert a python object OBJ with type TYPE to a gdb value. The
@@ -142,60 +165,55 @@ convert_buffer_and_type_to_value (PyObject *obj, struct type *type)
return value_from_contents (type, (const gdb_byte *) py_buf.buf);
}
-/* Called when a new gdb.Value object needs to be allocated. Returns NULL on
- error, with a python exception set. */
-static PyObject *
-valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+/* Implement gdb.Value.__init__. */
+
+static int
+valpy_init (PyObject *self, PyObject *args, PyObject *kwds)
{
static const char *keywords[] = { "val", "type", NULL };
PyObject *val_obj = nullptr;
PyObject *type_obj = nullptr;
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "O|O", keywords,
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kwds, "O|O", keywords,
&val_obj, &type_obj))
- return nullptr;
+ return -1;
struct type *type = nullptr;
-
- if (type_obj != nullptr)
+ if (type_obj != nullptr && type_obj != Py_None)
{
type = type_object_to_type (type_obj);
if (type == nullptr)
{
PyErr_SetString (PyExc_TypeError,
_("type argument must be a gdb.Type."));
- return nullptr;
+ return -1;
}
}
- value_object *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;
- }
-
struct value *value;
-
if (type == nullptr)
value = convert_value_from_python (val_obj);
else
value = convert_buffer_and_type_to_value (val_obj, type);
-
if (value == nullptr)
{
- subtype->tp_free (value_obj);
- return NULL;
+ gdb_assert (PyErr_Occurred ());
+ return -1;
}
+ /* There might be a previous value here. */
+ value_object *value_obj = (value_object *) self;
+ if (value_obj->value != nullptr)
+ valpy_clear_value (value_obj);
+
+ /* Store the value into this Python object. */
value_obj->value = release_value (value).release ();
- value_obj->address = NULL;
- value_obj->type = NULL;
- value_obj->dynamic_type = NULL;
+
+ /* Ensure that this gdb.Value is in the set of all gdb.Value objects. If
+ we are already in the set then this is call does nothing. */
note_value (value_obj);
- return (PyObject *) value_obj;
+ return 0;
}
/* Iterate over all the Value objects, calling preserve_one_value on
@@ -1784,6 +1802,8 @@ value_to_value_object (struct value *val)
if (val_obj != NULL)
{
val_obj->value = release_value (val).release ();
+ val_obj->next = nullptr;
+ val_obj->prev = nullptr;
val_obj->address = NULL;
val_obj->type = NULL;
val_obj->dynamic_type = NULL;
@@ -1805,6 +1825,8 @@ value_to_value_object_no_release (struct value *val)
{
value_incref (val);
val_obj->value = val;
+ val_obj->next = nullptr;
+ val_obj->prev = nullptr;
val_obj->address = NULL;
val_obj->type = NULL;
val_obj->dynamic_type = NULL;
@@ -2232,7 +2254,7 @@ PyTypeObject value_object_type = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
- 0, /* tp_init */
+ valpy_init, /* tp_init */
0, /* tp_alloc */
- valpy_new /* tp_new */
+ PyType_GenericNew, /* tp_new */
};