aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/doc/python.texi3
-rw-r--r--gdb/python/py-value.c116
-rw-r--r--gdb/testsuite/gdb.python/py-value.exp59
3 files changed, 126 insertions, 52 deletions
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 4a66c11..568aabc 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -827,6 +827,9 @@ This second form of the @code{gdb.Value} constructor returns a
from the Python buffer object specified by @var{val}. The number of
bytes in the Python buffer object must be greater than or equal to the
size of @var{type}.
+
+If @var{type} is @code{None} then this version of @code{__init__}
+behaves as though @var{type} was not passed at all.
@end defun
@defun Value.cast (type)
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 */
};
diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp
index f4b7c23..297b128 100644
--- a/gdb/testsuite/gdb.python/py-value.exp
+++ b/gdb/testsuite/gdb.python/py-value.exp
@@ -51,6 +51,7 @@ proc test_value_creation {} {
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 (3,None)" "create integer value, with None type" 1
if { $gdb_py_is_py3k == 0 } {
gdb_py_test_silent_cmd "python i = gdb.Value (5L)" "create long value" 1
}
@@ -77,6 +78,18 @@ proc test_value_creation {} {
gdb_test "python print ('result = %s' % i.address)" "= None" "test address attribute in non-addressable value"
}
+# Check that we can call gdb.Value.__init__ to change a value.
+proc test_value_reinit {} {
+ gdb_py_test_silent_cmd "python v = gdb.Value (3)" \
+ "create initial integer value" 1
+ gdb_test "python print(v)" "3" \
+ "check initial value contents"
+ gdb_py_test_silent_cmd "python v.__init__(5)" \
+ "call gdb.Value.__init__ manually" 1
+ gdb_test "python print(v)" "5" \
+ "check new value contents"
+}
+
proc test_value_numeric_ops {} {
global gdb_prompt
global gdb_py_is_py3k
@@ -531,10 +544,14 @@ proc test_float_conversion {} {
gdb_test "python print(float(gdb.Value(0)))" "0\\.0"
}
-proc test_value_from_buffer {} {
- global gdb_prompt
- global gdb_py_is_py3k
-
+# Setup some Python variables:
+# tp : a gdb.Type for 'int',
+# size_a : the size of array 'a' from the inferior,
+# size_a0 : the size of array element 'a[0] from the inferior,
+# addr : the address of 'a[0]' from the inferior,
+# b : a buffer containing the full contents of array 'a' from the
+# inferior.
+proc prepare_type_and_buffer {} {
gdb_py_test_silent_cmd "python tp=gdb.lookup_type('int')" "look up int type" 0
gdb_py_test_silent_cmd "python size_a=gdb.parse_and_eval('sizeof(a)')" \
"find size of a" 0
@@ -543,7 +560,14 @@ proc test_value_from_buffer {} {
gdb_py_test_silent_cmd "python addr=gdb.parse_and_eval('&a')" \
"find address of a" 0
gdb_py_test_silent_cmd "python b=gdb.selected_inferior().read_memory(addr,size_a)" \
- "read buffer from memory" 1
+ "read buffer from memory" 0
+}
+
+proc test_value_from_buffer {} {
+ global gdb_prompt
+ global gdb_py_is_py3k
+
+ prepare_type_and_buffer
gdb_test "python v=gdb.Value(b,tp); print(v)" "1" \
"construct value from buffer"
gdb_test "python v=gdb.Value(b\[size_a0:\],tp); print(v)" "2" \
@@ -600,6 +624,29 @@ proc test_add_to_history {} {
"TypeError: Could not convert Python object: .*"
}
+# Check we can create sub-classes of gdb.Value.
+proc test_value_sub_classes {} {
+ prepare_type_and_buffer
+
+ gdb_test_multiline "Create sub-class of gdb.Value" \
+ "python" "" \
+ "class MyValue(gdb.Value):" "" \
+ " def __init__(self,val,type=None):" "" \
+ " gdb.Value.__init__(self,val,type)" "" \
+ " print(\"In MyValue.__init__\")" "" \
+ "end"
+
+ gdb_test "python obj = MyValue (123)" "In MyValue.__init__" \
+ "create instance of MyValue"
+ gdb_test "python print(obj)" "123" \
+ "check printing of MyValue"
+
+ gdb_test "python obj = MyValue(b\[size_a0:\],tp)" "In MyValue.__init__" \
+ "convert 2nd elem of buffer to a MyValue"
+ gdb_test "python print(obj)" "2" \
+ "check printing of MyValue when initiaized with a type"
+}
+
# Build C version of executable. C++ is built later.
if { [build_inferior "${binfile}" "c"] < 0 } {
return -1
@@ -612,6 +659,7 @@ clean_restart ${binfile}
if { [skip_python_tests] } { continue }
test_value_creation
+test_value_reinit
test_value_numeric_ops
test_value_boolean
test_value_compare
@@ -629,6 +677,7 @@ if ![runto_main] then {
test_value_in_inferior
test_value_from_buffer
+test_value_sub_classes
test_inferior_function_call
test_value_after_death