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
Cc: Matheus Branco Borella <dark.ryu.550@gmail.com>
Subject: [PATCH] Add support for creating new types from the Python API
Date: Tue, 10 Jan 2023 21:58:28 -0300	[thread overview]
Message-ID: <20230111005828.952-1-dark.ryu.550@gmail.com> (raw)
In-Reply-To: <88e10ffd-8e87-b2bf-e6b3-f4567fb50e17@simark.ca>

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-01-11  0:58 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   ` Matheus Branco Borella [this message]
2023-06-27  3:52     ` [PING] Re: [PATCH] Add support for creating new types from " Matheus Branco Borella
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=20230111005828.952-1-dark.ryu.550@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).