From fe07eca59d0544eb6c56c3559da9ceece23cae6e Mon Sep 17 00:00:00 2001 From: Kevin Buettner Date: Sat, 16 Feb 2019 17:46:33 -0700 Subject: [PATCH] Define gdb.Value(bufobj, type) constructor 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 | 5 +++ gdb/python/py-value.c | 72 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f311a24618b..5d845e9a214 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ 2019-02-26 Kevin Buettner + * 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. diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 20ef5822f8e..445be729467 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -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; -- 2.30.2