[PING] Re: [PATCH] Add support for creating new types from the Python API

Matheus Branco Borella via Gdb-patches
2023-06-27T03:53:31Z

Following the contribution checklist, so, pinging this.

On Tue, Jan 10, 2023 at 9:58 PM Matheus Branco Borella
<dark.ryu.550@gmail.com> wrote:
>
> This patch adds support for creating types from within the Python API. It does
> so by exposing the `init_*_type` family of functions, defined in `gdbtypes.h` to
> Python and having them return `gdb.Type` objects connected to the newly minted
> types.
>
> These functions are accessible in the root of the gdb module and all require
> a reference to a `gdb.Objfile`. Types created from this API are exclusively
> objfile-owned.
>
> This patch also adds an extra type - `gdb.FloatFormat` - to support creation of
> floating point types by letting users control the format from within Python. It
> is missing, however, a way to specify half formats and validation functions.
>
> It is important to note that types created using this interface are not
> automatically registered as a symbol, and so, types will become unreachable
> unless used to create a value that otherwise references it or saved in some way.
>
> The main drawback of using the `init_*_type` family over implementing type
> initialization by hand is that any type that's created gets immediately
> allocated on its owner objfile's obstack, regardless of what its real
> lifetime requirements are. The main implication of this is that types that
> become unreachable will leak their memory for the lifetime of the objfile.
>
> Keeping track of the initialization of the type by hand would require a
> deeper change to the existing type object infrastructure. A bit too ambitious
> for a first patch, I'd say.
>
> if it were to be done though, we would gain the ability to only keep in the
> obstack types that are known to be referenced in some other way - by allocating
> and copying the data to the obstack as other objects are created that reference
> it (eg. symbols).
> ---
> gdb/Makefile.in | 2 +
> gdb/python/py-float-format.c | 297 +++++++++++++++++++++++++++
> gdb/python/py-objfile.c | 12 ++
> gdb/python/py-type-init.c | 388 +++++++++++++++++++++++++++++++++++
> gdb/python/python-internal.h | 17 ++
> gdb/python/python.c | 44 +++-
> 6 files changed, 759 insertions(+), 1 deletion(-)
> create mode 100644 gdb/python/py-float-format.c
> create mode 100644 gdb/python/py-type-init.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index fb4d42c7baa..789f7dce224 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -432,6 +432,8 @@ SUBDIR_PYTHON_SRCS = \
> python/py-threadevent.c \
> python/py-tui.c \
> python/py-type.c \
> + python/py-type-init.c \
> + python/py-float-format.c \
> python/py-unwind.c \
> python/py-utils.c \
> python/py-value.c \
> diff --git a/gdb/python/py-float-format.c b/gdb/python/py-float-format.c
> new file mode 100644
> index 00000000000..e517e410899
> --- /dev/null
> +++ b/gdb/python/py-float-format.c
> @@ -0,0 +1,297 @@
> +/* Accessibility of float format controls from inside the Python API
> +
> + Copyright (C) 2008-2023 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 "python-internal.h"
> +#include "floatformat.h"
> +
> +/* Structure backing the float format Python interface. */
> +
> +struct float_format_object
> +{
> + PyObject_HEAD
> + struct floatformat format;
> +
> + struct floatformat *float_format ()
> + {
> + return &this->format;
> + }
> +};
> +
> +/* Initializes the float format type and registers it with the Python interpreter. */
> +
> +int
> +gdbpy_initialize_float_format (void)
> +{
> + if (PyType_Ready (&float_format_object_type) < 0)
> + return -1;
> +
> + if (gdb_pymodule_addobject (gdb_module, "FloatFormat",
> + (PyObject *) &float_format_object_type) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +#define INSTANCE_FIELD_GETTER(getter_name, field_name, field_type, field_conv) \
> + static PyObject * \
> + getter_name (PyObject *self, void *closure) \
> + { \
> + float_format_object *ff = (float_format_object*) self; \
> + field_type value = ff->float_format ()->field_name; \
> + return field_conv (value); \
> + }
> +
> +#define INSTANCE_FIELD_SETTER(getter_name, field_name, field_type, field_conv) \
> + static int \
> + getter_name (PyObject *self, PyObject* value, void *closure) \
> + { \
> + field_type native_value; \
> + if (!field_conv (value, &native_value)) \
> + return -1; \
> + float_format_object *ff = (float_format_object*) self; \
> + ff->float_format ()->field_name = native_value; \
> + return 0; \
> + }
> +
> +/* Converts from the intbit enum to a Python boolean. */
> +
> +static PyObject *
> +intbit_to_py (enum floatformat_intbit intbit)
> +{
> + gdb_assert (intbit == floatformat_intbit_yes || intbit == floatformat_intbit_no);
> + if (intbit == floatformat_intbit_no)
> + Py_RETURN_FALSE;
> + else
> + Py_RETURN_TRUE;
> +}
> +
> +/* Converts from a Python boolean to the intbit enum. */
> +
> +static bool
> +py_to_intbit (PyObject *object, enum floatformat_intbit *intbit)
> +{
> + if (!PyObject_IsInstance (object, (PyObject*) &PyBool_Type))
> + {
> + PyErr_SetString (PyExc_TypeError, "intbit must be True or False");
> + return false;
> + }
> +
> + *intbit = PyObject_IsTrue (object) ? floatformat_intbit_yes : floatformat_intbit_no;
> + return true;
> +}
> +
> +/* Converts from a Python integer to a unsigned integer. */
> +
> +static bool
> +py_to_unsigned_int (PyObject *object, unsigned int *val)
> +{
> + if (!PyObject_IsInstance (object, (PyObject*) &PyLong_Type))
> + {
> + PyErr_SetString (PyExc_TypeError, "value must be an integer");
> + return false;
> + }
> +
> + long native_val = PyLong_AsLong (object);
> + if (native_val > (long) UINT_MAX)
> + {
> + PyErr_SetString (PyExc_ValueError, "value is too large");
> + return false;
> + }
> + if (native_val < 0)
> + {
> + PyErr_SetString (PyExc_ValueError, "value must not be smaller than zero");
> + return false;
> + }
> +
> + *val = (unsigned int) native_val;
> + return true;
> +}
> +
> +/* Converts from a Python integer to a signed integer. */
> +
> +static bool
> +py_to_int(PyObject *object, int *val)
> +{
> + if(!PyObject_IsInstance(object, (PyObject*)&PyLong_Type))
> + {
> + PyErr_SetString(PyExc_TypeError, u8"value must be an integer");
> + return false;
> + }
> +
> + long native_val = PyLong_AsLong(object);
> + if(native_val > (long)INT_MAX)
> + {
> + PyErr_SetString(PyExc_ValueError, u8"value is too large");
> + return false;
> + }
> +
> + *val = (int)native_val;
> + return true;
> +}
> +
> +INSTANCE_FIELD_GETTER (ffpy_get_totalsize, totalsize, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_sign_start, sign_start, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_exp_start, exp_start, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_exp_len, exp_len, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_exp_bias, exp_bias, int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_exp_nan, exp_nan, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_man_start, man_start, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_man_len, man_len, unsigned int, PyLong_FromLong)
> +INSTANCE_FIELD_GETTER (ffpy_get_intbit, intbit, enum floatformat_intbit, intbit_to_py)
> +INSTANCE_FIELD_GETTER (ffpy_get_name, name, const char *, PyUnicode_FromString)
> +
> +INSTANCE_FIELD_SETTER (ffpy_set_totalsize, totalsize, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_sign_start, sign_start, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_exp_start, exp_start, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_exp_len, exp_len, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_exp_bias, exp_bias, int, py_to_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_exp_nan, exp_nan, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_man_start, man_start, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_man_len, man_len, unsigned int, py_to_unsigned_int)
> +INSTANCE_FIELD_SETTER (ffpy_set_intbit, intbit, enum floatformat_intbit, py_to_intbit)
> +
> +/* Makes sure float formats created from Python always test as valid. */
> +
> +static int
> +ffpy_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
> + const void *from ATTRIBUTE_UNUSED)
> +{
> + return 1;
> +}
> +
> +/* Initializes new float format objects. */
> +
> +static int
> +ffpy_init (PyObject *self,
> + PyObject *args ATTRIBUTE_UNUSED,
> + PyObject *kwds ATTRIBUTE_UNUSED)
> +{
> + auto ff = (float_format_object*) self;
> + ff->format = floatformat ();
> + ff->float_format ()->name = "";
> + ff->float_format ()->is_valid = ffpy_always_valid;
> + return 0;
> +}
> +
> +/* Retrieves a pointer to the underlying float format structure. */
> +
> +struct floatformat *
> +float_format_object_as_float_format (PyObject *self)
> +{
> + if (!PyObject_IsInstance (self, (PyObject*) &float_format_object_type))
> + return nullptr;
> + return ((float_format_object*) self)->float_format ();
> +}
> +
> +static gdb_PyGetSetDef float_format_object_getset[] =
> +{
> + { "totalsize", ffpy_get_totalsize, ffpy_set_totalsize,
> + "The total size of the floating point number, in bits.", nullptr },
> + { "sign_start", ffpy_get_sign_start, ffpy_set_sign_start,
> + "The bit offset of the sign bit.", nullptr },
> + { "exp_start", ffpy_get_exp_start, ffpy_set_exp_start,
> + "The bit offset of the start of the exponent.", nullptr },
> + { "exp_len", ffpy_get_exp_len, ffpy_set_exp_len,
> + "The size of the exponent, in bits.", nullptr },
> + { "exp_bias", ffpy_get_exp_bias, ffpy_set_exp_bias,
> + "Bias added to a \"true\" exponent to form the biased exponent.", nullptr },
> + { "exp_nan", ffpy_get_exp_nan, ffpy_set_exp_nan,
> + "Exponent value which indicates NaN.", nullptr },
> + { "man_start", ffpy_get_man_start, ffpy_set_man_start,
> + "The bit offset of the start of the mantissa.", nullptr },
> + { "man_len", ffpy_get_man_len, ffpy_set_man_len,
> + "The size of the mantissa, in bits.", nullptr },
> + { "intbit", ffpy_get_intbit, ffpy_set_intbit,
> + "Is the integer bit explicit or implicit?", nullptr },
> + { "name", ffpy_get_name, nullptr,
> + "Internal name for debugging.", nullptr },
> + { nullptr }
> +};
> +
> +static PyMethodDef float_format_object_methods[] =
> +{
> + { NULL }
> +};
> +
> +static PyNumberMethods float_format_object_as_number = {
> + nullptr, /* nb_add */
> + nullptr, /* nb_subtract */
> + nullptr, /* nb_multiply */
> + nullptr, /* nb_remainder */
> + nullptr, /* nb_divmod */
> + nullptr, /* nb_power */
> + nullptr, /* nb_negative */
> + nullptr, /* nb_positive */
> + nullptr, /* nb_absolute */
> + nullptr, /* nb_nonzero */
> + nullptr, /* nb_invert */
> + nullptr, /* nb_lshift */
> + nullptr, /* nb_rshift */
> + nullptr, /* nb_and */
> + nullptr, /* nb_xor */
> + nullptr, /* nb_or */
> + nullptr, /* nb_int */
> + nullptr, /* reserved */
> + nullptr, /* nb_float */
> +};
> +
> +PyTypeObject float_format_object_type =
> +{
> + PyVarObject_HEAD_INIT (NULL, 0)
> + "gdb.FloatFormat", /*tp_name*/
> + sizeof (float_format_object), /*tp_basicsize*/
> + 0, /*tp_itemsize*/
> + nullptr, /*tp_dealloc*/
> + 0, /*tp_print*/
> + nullptr, /*tp_getattr*/
> + nullptr, /*tp_setattr*/
> + nullptr, /*tp_compare*/
> + nullptr, /*tp_repr*/
> + &float_format_object_as_number, /*tp_as_number*/
> + nullptr, /*tp_as_sequence*/
> + nullptr, /*tp_as_mapping*/
> + nullptr, /*tp_hash */
> + nullptr, /*tp_call*/
> + nullptr, /*tp_str*/
> + nullptr, /*tp_getattro*/
> + nullptr, /*tp_setattro*/
> + nullptr, /*tp_as_buffer*/
> + Py_TPFLAGS_DEFAULT, /*tp_flags*/
> + "GDB float format object", /* tp_doc */
> + nullptr, /* tp_traverse */
> + nullptr, /* tp_clear */
> + nullptr, /* tp_richcompare */
> + 0, /* tp_weaklistoffset */
> + nullptr, /* tp_iter */
> + nullptr, /* tp_iternext */
> + float_format_object_methods, /* tp_methods */
> + nullptr, /* tp_members */
> + float_format_object_getset, /* tp_getset */
> + nullptr, /* tp_base */
> + nullptr, /* tp_dict */
> + nullptr, /* tp_descr_get */
> + nullptr, /* tp_descr_set */
> + 0, /* tp_dictoffset */
> + ffpy_init, /* tp_init */
> + nullptr, /* tp_alloc */
> + PyType_GenericNew, /* tp_new */
> +};
> +
> +
> diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
> index c278925531b..28a7c9a7873 100644
> --- a/gdb/python/py-objfile.c
> +++ b/gdb/python/py-objfile.c
> @@ -704,6 +704,18 @@ objfile_to_objfile_object (struct objfile *objfile)
> return gdbpy_ref<>::new_reference (result);
> }
>
> +struct objfile *
> +objfile_object_to_objfile (PyObject *self)
> +{
> + if (!PyObject_TypeCheck (self, &objfile_object_type))
> + return nullptr;
> +
> + auto objfile_object = (struct objfile_object*) self;
> + OBJFPY_REQUIRE_VALID (objfile_object);
> +
> + return objfile_object->objfile;
> +}
> +
> int
> gdbpy_initialize_objfile (void)
> {
> diff --git a/gdb/python/py-type-init.c b/gdb/python/py-type-init.c
> new file mode 100644
> index 00000000000..f3b6813c3ad
> --- /dev/null
> +++ b/gdb/python/py-type-init.c
> @@ -0,0 +1,388 @@
> +/* Functionality for creating new types accessible from python.
> +
> + Copyright (C) 2008-2023 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 "python-internal.h"
> +#include "gdbtypes.h"
> +#include "floatformat.h"
> +#include "objfiles.h"
> +#include "gdbsupport/gdb_obstack.h"
> +
> +
> +/* Copies a null-terminated string into an objfile's obstack. */
> +
> +static const char *
> +copy_string (struct objfile *objfile, const char *py_str)
> +{
> + unsigned int len = strlen (py_str);
> + return obstack_strndup (&objfile->per_bfd->storage_obstack,
> + py_str, len);
> +}
> +
> +/* Creates a new type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_type (PyObject *self, PyObject *args)
> +{
> + PyObject *objfile_object;
> + enum type_code code;
> + int bit_length;
> + const char *py_name;
> +
> + if(!PyArg_ParseTuple (args, "Oiis", &objfile_object, &code, &bit_length, &py_name))
> + return nullptr;
> +
> + struct objfile* objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_type (objfile, code, bit_length, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> +
> +/* Creates a new integer type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_integer_type (PyObject *self, PyObject *args)
> +{
> + PyObject *objfile_object;
> + int bit_size;
> + int unsigned_p;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "Oips", &objfile_object, &bit_size, &unsigned_p, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_integer_type (objfile, bit_size, unsigned_p, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object(type);
> +}
> +
> +/* Creates a new character type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_character_type (PyObject *self, PyObject *args)
> +{
> +
> + PyObject *objfile_object;
> + int bit_size;
> + int unsigned_p;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "Oips", &objfile_object, &bit_size, &unsigned_p, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_character_type (objfile, bit_size, unsigned_p, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> +
> +/* Creates a new boolean type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_boolean_type (PyObject *self, PyObject *args)
> +{
> +
> + PyObject *objfile_object;
> + int bit_size;
> + int unsigned_p;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "Oips", &objfile_object, &bit_size, &unsigned_p, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_boolean_type (objfile, bit_size, unsigned_p, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> +
> +/* Creates a new float type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_float_type (PyObject *self, PyObject *args)
> +{
> + PyObject *objfile_object, *float_format_object;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "OOs", &objfile_object, &float_format_object, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + struct floatformat *local_ff = float_format_object_as_float_format (float_format_object);
> + if (local_ff == nullptr)
> + return nullptr;
> +
> + /* Persist a copy of the format in the objfile's obstack. This guarantees that
> + * the format won't outlive the type being created from it and that changes
> + * made to the object used to create this type will not affect it after
> + * creation. */
> + auto ff = OBSTACK_CALLOC
> + (&objfile->objfile_obstack,
> + 1,
> + struct floatformat);
> + memcpy (ff, local_ff, sizeof (struct floatformat));
> +
> + /* We only support creating float types in the architecture's endianness, so
> + * make sure init_float_type sees the float format structure we need it to. */
> + enum bfd_endian endianness = gdbarch_byte_order (objfile->arch());
> + gdb_assert (endianness < BFD_ENDIAN_UNKNOWN);
> +
> + const struct floatformat *per_endian[2] = { nullptr, nullptr };
> + per_endian[endianness] = ff;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_float_type (objfile, -1, name, per_endian, endianness);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> +
> +/* Creates a new decimal float type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_decfloat_type (PyObject *self, PyObject *args)
> +{
> + PyObject *objfile_object;
> + int bit_length;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "Ois", &objfile_object, &bit_length, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_decfloat_type (objfile, bit_length, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> +
> +/* Returns whether a given type can be used to create a complex type. */
> +
> +PyObject *
> +gdbpy_can_create_complex_type (PyObject *self, PyObject *args)
> +{
> +
> + PyObject *type_object;
> +
> + if (!PyArg_ParseTuple (args, "O", &type_object))
> + return nullptr;
> +
> + struct type *type = type_object_to_type (type_object);
> + if (type == nullptr)
> + return nullptr;
> +
> + bool can_create_complex;
> + try
> + {
> + can_create_complex = can_create_complex_type (type);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + if (can_create_complex)
> + Py_RETURN_TRUE;
> + else
> + Py_RETURN_FALSE;
> +}
> +
> +/* Creates a new complex type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_complex_type (PyObject *self, PyObject *args)
> +{
> +
> + PyObject *type_object;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "Os", &type_object, &py_name))
> + return nullptr;
> +
> + struct type *type = type_object_to_type (type_object);
> + if (type == nullptr)
> + return nullptr;
> +
> + obstack *obstack;
> + if (type->is_objfile_owned ())
> + obstack = &type->objfile_owner ()->objfile_obstack;
> + else
> + obstack = gdbarch_obstack (type->arch_owner ());
> +
> + unsigned int len = strlen (py_name);
> + const char *name = obstack_strndup (obstack,
> + py_name,
> + len);
> + struct type *complex_type;
> + try
> + {
> + complex_type = init_complex_type (name, type);
> + gdb_assert (complex_type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (complex_type);
> +}
> +
> +/* Creates a new pointer type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_pointer_type (PyObject *self, PyObject *args)
> +{
> + PyObject *objfile_object, *type_object;
> + int bit_length;
> + const char *py_name;
> +
> + if (!PyArg_ParseTuple (args, "OOis", &objfile_object, &type_object, &bit_length, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + struct type *type = type_object_to_type (type_object);
> + if (type == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *pointer_type;
> + try
> + {
> + pointer_type = init_pointer_type (objfile, bit_length, name, type);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (pointer_type);
> +}
> +
> +/* Creates a new fixed point type and returns a new gdb.Type associated with it. */
> +
> +PyObject *
> +gdbpy_init_fixed_point_type (PyObject *self, PyObject *args)
> +{
> +
> + PyObject *objfile_object;
> + int bit_length;
> + int unsigned_p;
> + const char* py_name;
> +
> + if (!PyArg_ParseTuple (args, "Oips", &objfile_object, &bit_length, &unsigned_p, &py_name))
> + return nullptr;
> +
> + struct objfile *objfile = objfile_object_to_objfile (objfile_object);
> + if (objfile == nullptr)
> + return nullptr;
> +
> + const char *name = copy_string (objfile, py_name);
> + struct type *type;
> + try
> + {
> + type = init_fixed_point_type (objfile, bit_length, unsigned_p, name);
> + gdb_assert (type != nullptr);
> + }
> + catch (gdb_exception_error& ex)
> + {
> + GDB_PY_HANDLE_EXCEPTION (ex);
> + }
> +
> + return type_to_type_object (type);
> +}
> diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
> index 06357cc8c0b..3877f8a7ca9 100644
> --- a/gdb/python/python-internal.h
> +++ b/gdb/python/python-internal.h
> @@ -289,6 +289,8 @@ extern PyTypeObject frame_object_type
> CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("frame_object");
> extern PyTypeObject thread_object_type
> CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("thread_object");
> +extern PyTypeObject float_format_object_type
> + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("float_format");
>
> /* Ensure that breakpoint_object_type is initialized and return true. If
> breakpoint_object_type can't be initialized then set a suitable Python
> @@ -431,6 +433,17 @@ gdb::unique_xmalloc_ptr<char> gdbpy_parse_command_name
> PyObject *gdbpy_register_tui_window (PyObject *self, PyObject *args,
> PyObject *kw);
>
> +PyObject *gdbpy_init_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_integer_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_character_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_boolean_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_float_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_decfloat_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_can_create_complex_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_complex_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_pointer_type (PyObject *self, PyObject *args);
> +PyObject *gdbpy_init_fixed_point_type (PyObject *self, PyObject *args);
> +
> PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
> PyObject *symtab_to_symtab_object (struct symtab *symtab);
> PyObject *symbol_to_symbol_object (struct symbol *sym);
> @@ -481,6 +494,8 @@ struct symtab *symtab_object_to_symtab (PyObject *obj);
> struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj);
> frame_info_ptr frame_object_to_frame_info (PyObject *frame_obj);
> struct gdbarch *arch_object_to_gdbarch (PyObject *obj);
> +struct objfile *objfile_object_to_objfile (PyObject *self);
> +struct floatformat *float_format_object_as_float_format (PyObject *self);
>
> /* Convert Python object OBJ to a program_space pointer. OBJ must be a
> gdb.Progspace reference. Return nullptr if the gdb.Progspace is not
> @@ -559,6 +574,8 @@ int gdbpy_initialize_micommands (void)
> void gdbpy_finalize_micommands ();
> int gdbpy_initialize_disasm ()
> CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
> +int gdbpy_initialize_float_format ()
> + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
>
> PyMODINIT_FUNC gdbpy_events_mod_func ();
>
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 4aa24421dec..1ed29ff4dea 100644
> --- a/gdb/python/python.c
> +++ b/gdb/python/python.c
> @@ -2153,7 +2153,8 @@ do_start_initialization ()
> || gdbpy_initialize_membuf () < 0
> || gdbpy_initialize_connection () < 0
> || gdbpy_initialize_tui () < 0
> - || gdbpy_initialize_micommands () < 0)
> + || gdbpy_initialize_micommands () < 0
> + || gdbpy_initialize_float_format() < 0)
> return false;
>
> #define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
> @@ -2529,6 +2530,47 @@ Return current recording object." },
> "stop_recording () -> None.\n\
> Stop current recording." },
>
> + /* Type initialization functions. */
> + { "init_type", gdbpy_init_type, METH_VARARGS,
> + "init_type (objfile, type_code, bit_length, name) -> type\n\
> + Creates a new type with the given bit length and type code, owned\
> + by the given objfile." },
> + { "init_integer_type", gdbpy_init_integer_type, METH_VARARGS,
> + "init_integer_type (objfile, bit_length, unsigned, name) -> type\n\
> + Creates a new integer type with the given bit length and \
> + signedness, owned by the given objfile." },
> + { "init_character_type", gdbpy_init_character_type, METH_VARARGS,
> + "init_character_type (objfile, bit_length, unsigned, name) -> type\n\
> + Creates a new character type with the given bit length and \
> + signedness, owned by the given objfile." },
> + { "init_boolean_type", gdbpy_init_boolean_type, METH_VARARGS,
> + "init_boolean_type (objfile, bit_length, unsigned, name) -> type\n\
> + Creates a new boolean type with the given bit length and \
> + signedness, owned by the given objfile." },
> + { "init_float_type", gdbpy_init_float_type, METH_VARARGS,
> + "init_float_type (objfile, float_format, name) -> type\n\
> + Creates a new floating point type with the given bit length and \
> + format, owned by the given objfile." },
> + { "init_decfloat_type", gdbpy_init_decfloat_type, METH_VARARGS,
> + "init_decfloat_type (objfile, bit_length, name) -> type\n\
> + Creates a new decimal float type with the given bit length,\
> + owned by the given objfile." },
> + { "can_create_complex_type", gdbpy_can_create_complex_type, METH_VARARGS,
> + "can_create_complex_type (type) -> bool\n\
> + Returns whether a given type can form a new complex type." },
> + { "init_complex_type", gdbpy_init_complex_type, METH_VARARGS,
> + "init_complex_type (base_type, name) -> type\n\
> + Creates a new complex type whose components belong to the\
> + given type, owned by the given objfile." },
> + { "init_pointer_type", gdbpy_init_pointer_type, METH_VARARGS,
> + "init_pointer_type (objfile, target_type, bit_length, name) -> type\n\
> + Creates a new pointer type with the given bit length, pointing\
> + to the given target type, and owned by the given objfile." },
> + { "init_fixed_point_type", gdbpy_init_fixed_point_type, METH_VARARGS,
> + "init_fixed_point_type (objfile, bit_length, unsigned, name) -> type\n\
> + Creates a new fixed point type with the given bit length and\
> + signedness, owned by the given objfile." },
> +
> { "lookup_type", (PyCFunction) gdbpy_lookup_type,
> METH_VARARGS | METH_KEYWORDS,
> "lookup_type (name [, block]) -> type\n\
> --
> 2.37.3.windows.1
>