Define gdb.Value(bufobj, type) constructor
authorKevin Buettner <kevinb@redhat.com>
Sun, 17 Feb 2019 00:46:33 +0000 (17:46 -0700)
committerKevin Buettner <kevinb@redhat.com>
Tue, 26 Feb 2019 17:23:23 +0000 (10:23 -0700)
Provided a buffer BUFOBJ and a type TYPE, construct a gdb.Value object
with type TYPE, where the value's contents are taken from BUFOBJ.

E.g...

(gdb) python import struct
(gdb) python unsigned_int_type=gdb.lookup_type('unsigned int')
(gdb) python b=struct.pack('=I',0xdeadbeef)
(gdb) python v=gdb.Value(b, unsigned_int_type) ; print("%#x" % v)
0xdeadbeef

This two argument form of the gdb.Value constructor may also be used
to obtain gdb values from selected portions of buffers read with
Inferior.read_memory().  The test case (which is in a separate patch)
demonstrates this use case.

gdb/ChangeLog:

* python/py-value.c (convert_buffer_and_type_to_value): New
function.
(valpy_new): Parse arguments via gdb_PyArg_ParseTupleAndKeywords.
Add support for handling an optional second argument.  Call
convert_buffer_and_type_to_value as appropriate.

gdb/ChangeLog
gdb/python/py-value.c

index f311a24618b0390754a156e82e2c79368ece367b..5d845e9a214b2c7d5b0531b61c7133b834e0da43 100644 (file)
@@ -1,5 +1,10 @@
 2019-02-26  Kevin Buettner  <kevinb@redhat.com>
 
+       * python/py-value.c (convert_buffer_and_type_to_value): New
+       function.
+       (valpy_new): Parse arguments via gdb_PyArg_ParseTupleAndKeywords.
+       Add support for handling an optional second argument.  Call
+       convert_buffer_and_type_to_value as appropriate.
        * python/python-internal.h (Py_buffer_deleter): New struct.
        (Py_buffer_up): New typedef.
 
index 20ef5822f8ee932866c88779f0ee6e8f685f7661..445be72946746c2ca781c56a18e6d2a0db46c47e 100644 (file)
@@ -107,22 +107,68 @@ note_value (value_object *value_obj)
   values_in_python = value_obj;
 }
 
+/* Convert a python object OBJ with type TYPE to a gdb value.  The
+   python object in question must conform to the python buffer
+   protocol.  On success, return the converted value, otherwise
+   nullptr.  */
+
+static struct value *
+convert_buffer_and_type_to_value (PyObject *obj, struct type *type)
+{
+  Py_buffer_up buffer_up;
+  Py_buffer py_buf;
+
+  if (PyObject_CheckBuffer (obj) 
+      && PyObject_GetBuffer (obj, &py_buf, PyBUF_SIMPLE) == 0)
+    {
+      /* Got a buffer, py_buf, out of obj.  Cause it to be released
+         when it goes out of scope.  */
+      buffer_up.reset (&py_buf);
+    }
+  else
+    {
+      PyErr_SetString (PyExc_TypeError,
+                      _("Object must support the python buffer protocol."));
+      return nullptr;
+    }
+
+  if (TYPE_LENGTH (type) > py_buf.len)
+    {
+      PyErr_SetString (PyExc_ValueError,
+                      _("Size of type is larger than that of buffer object."));
+      return nullptr;
+    }
+
+  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 *keywords)
+valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
 {
-  struct value *value = NULL;   /* Initialize to appease gcc warning.  */
-  value_object *value_obj;
+  static const char *keywords[] = { "val", "type", NULL };
+  PyObject *val_obj = nullptr;
+  PyObject *type_obj = nullptr;
+
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "O|O", keywords,
+                                       &val_obj, &type_obj))
+    return nullptr;
 
-  if (PyTuple_Size (args) != 1)
+  struct type *type = nullptr;
+
+  if (type_obj != nullptr)
     {
-      PyErr_SetString (PyExc_TypeError, _("Value object creation takes only "
-                                         "1 argument"));
-      return NULL;
+      type = type_object_to_type (type_obj);
+      if (type == nullptr)
+        {
+         PyErr_SetString (PyExc_TypeError,
+                          _("type argument must be a gdb.Type."));
+         return nullptr;
+       }
     }
 
-  value_obj = (value_object *) subtype->tp_alloc (subtype, 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 "
@@ -130,8 +176,14 @@ valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords)
       return NULL;
     }
 
-  value = convert_value_from_python (PyTuple_GetItem (args, 0));
-  if (value == 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;