public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Matheus Branco Borella <dark.ryu.550@gmail.com>
To: gdb-patches@sourceware.org
Subject: [PING] Re: [PATCH] Add support for creating new types from the Python API
Date: Tue, 27 Jun 2023 00:52:51 -0300	[thread overview]
Message-ID: <CAOJgb+VzuBbZmDk_cTs1KV+GsWtLh_pxVMwaaPRk3tCdHHvt6w@mail.gmail.com> (raw)
In-Reply-To: <20230111005828.952-1-dark.ryu.550@gmail.com>

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
>

  reply	other threads:[~2023-06-27  3:53 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-05 23:56 [PATCH 1/1] Add support for gdb.Type initialization from within " dark.ryu.550
2023-01-06 20:00 ` Simon Marchi
2023-01-11  0:58   ` [PATCH] Add support for creating new types from " Matheus Branco Borella
2023-06-27  3:52     ` Matheus Branco Borella [this message]
2023-05-26  3:30   ` Matheus Branco Borella
2023-08-07 14:53     ` Andrew Burgess
2023-08-08 21:00       ` [PATCH v2] " Matheus Branco Borella
2024-01-13  1:37         ` [PATCH v3] " Matheus Branco Borella
2024-01-13  7:21           ` Eli Zaretskii
2024-01-16  4:55             ` Matheus Branco Borella

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAOJgb+VzuBbZmDk_cTs1KV+GsWtLh_pxVMwaaPRk3tCdHHvt6w@mail.gmail.com \
    --to=dark.ryu.550@gmail.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).