[RFC,v2,05/21] gdb/python: add function () method to gdb.Type object

Message ID 20241121124714.419946-6-jan.vrany@labware.com
State New
Headers
Series Add Python "JIT" API |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-arm warning Skipped upon request
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 warning Skipped upon request

Commit Message

Jan Vraný Nov. 21, 2024, 12:46 p.m. UTC
  This commit adds a new method to Python type objects that returns
possibly new function type returning that type. Parameter types can
be specified too.

This will be useful later to create types for function symbols created
using Python extension code.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                             |  3 ++
 gdb/doc/python.texi                  |  8 +++++
 gdb/python/py-type.c                 | 54 ++++++++++++++++++++++++++++
 gdb/testsuite/gdb.python/py-type.exp | 20 +++++++++++
 4 files changed, 85 insertions(+)
  

Comments

Eli Zaretskii Nov. 21, 2024, 1:34 p.m. UTC | #1
> From: Jan Vrany <jan.vrany@labware.com>
> CC: Jan Vrany <jan.vrany@labware.com>,
> 	Eli Zaretskii <eliz@gnu.org>
> Date: Thu, 21 Nov 2024 12:46:58 +0000
> 
> This commit adds a new method to Python type objects that returns
> possibly new function type returning that type. Parameter types can
> be specified too.
> 
> This will be useful later to create types for function symbols created
> using Python extension code.
> 
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
> ---
>  gdb/NEWS                             |  3 ++
>  gdb/doc/python.texi                  |  8 +++++
>  gdb/python/py-type.c                 | 54 ++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.python/py-type.exp | 20 +++++++++++
>  4 files changed, 85 insertions(+)

The documentation parts are okay, but...

> +@defun Type.function (@r{[}param_type...@r{]})
> +Return a new @code{gdb.Type} object which represents a type of function
> +returning this type.  @code{param_type...} arguments specify parameter

...please use @dots{} instead of literal "..." in both cases here,
when you push.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
  
Jan Vraný Nov. 21, 2024, 2:06 p.m. UTC | #2
On Thu, 2024-11-21 at 15:34 +0200, Eli Zaretskii wrote:
> > From: Jan Vrany <jan.vrany@labware.com>
> > CC: Jan Vrany <jan.vrany@labware.com>,
> > 	Eli Zaretskii <eliz@gnu.org>
> > Date: Thu, 21 Nov 2024 12:46:58 +0000
> > 
> > This commit adds a new method to Python type objects that returns
> > possibly new function type returning that type. Parameter types can
> > be specified too.
> > 
> > This will be useful later to create types for function symbols
> > created
> > using Python extension code.
> > 
> > Reviewed-By: Eli Zaretskii <eliz@gnu.org>
> > ---
> >  gdb/NEWS                             |  3 ++
> >  gdb/doc/python.texi                  |  8 +++++
> >  gdb/python/py-type.c                 | 54
> > ++++++++++++++++++++++++++++
> >  gdb/testsuite/gdb.python/py-type.exp | 20 +++++++++++
> >  4 files changed, 85 insertions(+)
> 
> The documentation parts are okay, but...
> 
> > +@defun Type.function (@r{[}param_type...@r{]})
> > +Return a new @code{gdb.Type} object which represents a type of
> > function
> > +returning this type.  @code{param_type...} arguments specify
> > parameter
> 
> ...please use @dots{} instead of literal "..." in both cases here,
> when you push.
> 

Thanks! I have fixed this in my local working version
and it will part of next version. Same for the extra "to"
in the other commit (
https://sourceware.org/pipermail/gdb-patches/2024-November/213479.html
)

Jan

> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 765d14a1ae4..3d208744103 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -91,6 +91,9 @@ 
   ** Added gdb.Architecture.void_type. Returns a gdb.Type representing "void"
      type for that architecture.
 
+  ** Added gdb.Type.function.  Returns a new gdb.Type representing a function
+     returning that type.  Parameter types can be specified too.
+
 * Debugger Adapter Protocol changes
 
   ** The "scopes" request will now return a scope holding global
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index dac5115a5f8..272b51d32c5 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -1574,6 +1574,14 @@  Return a new @code{gdb.Type} object which represents a pointer to this
 type.
 @end defun
 
+@defun Type.function (@r{[}param_type...@r{]})
+Return a new @code{gdb.Type} object which represents a type of function
+returning this type.  @code{param_type...} arguments specify parameter
+types.  Use @code{None} as last parameter type to create a vararg function
+type.  When invoked with single @code{None} argument or with no arguments at
+all it creates a vararg function taking zero or more parameters.
+@end defun
+
 @defun Type.strip_typedefs ()
 Return a new @code{gdb.Type} that represents the real type,
 after removing all layers of typedefs.
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 284960a3a87..348889dddd8 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -774,6 +774,57 @@  typy_unqualified (PyObject *self, PyObject *args)
   return type_to_type_object (type);
 }
 
+/* Return a function type. */
+static PyObject *
+typy_function (PyObject *self, PyObject *args)
+{
+  struct type *type = ((type_object *) self)->type;
+
+  gdb_assert (PySequence_Check (args));
+
+  std::vector<struct type *> param_types (PySequence_Length (args));
+
+  for (int i = 0; i < PySequence_Length (args); i++)
+    {
+      PyObject *param_type_obj = PySequence_GetItem (args, i);
+
+      if (param_type_obj == Py_None)
+	{
+	  param_types[i] = nullptr;
+	  if (i != (PySequence_Length (args) - 1))
+	    {
+	      PyErr_Format (PyExc_ValueError,
+			    _("Argument at index %d is None but None can "
+			      "only be the last type."), i);
+	      return nullptr;
+	    }
+	}
+      else
+	{
+	  param_types[i] = type_object_to_type (param_type_obj);
+	  if (!param_types[i])
+	    {
+	      PyErr_Format (PyExc_TypeError,
+			    _("Argument at index %d is not a gdb.Type "
+			      "object."), i);
+	      return nullptr;
+	    }
+	}
+    }
+
+  try
+    {
+      type = lookup_function_type_with_arguments (
+	       type, param_types.size (), param_types.data ());
+    }
+  catch (const gdb_exception &except)
+    {
+      return gdbpy_handle_gdb_exception (nullptr, except);
+    }
+
+  return type_to_type_object (type);
+}
+
 /* Return the size of the type represented by SELF, in bytes.  */
 static PyObject *
 typy_get_sizeof (PyObject *self, void *closure)
@@ -1641,6 +1692,9 @@  Return the type of a template argument." },
   { "unqualified", typy_unqualified, METH_NOARGS,
     "unqualified () -> Type\n\
 Return a variant of this type without const or volatile attributes." },
+  { "function", typy_function, METH_VARARGS,
+    "function () -> Type\n\
+Return a function type returning value of this type." },
   { "values", typy_values, METH_NOARGS,
     "values () -> list\n\
 Return a list holding all the fields of this type.\n\
diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp
index 7e469c93c35..783261e6f4a 100644
--- a/gdb/testsuite/gdb.python/py-type.exp
+++ b/gdb/testsuite/gdb.python/py-type.exp
@@ -365,6 +365,26 @@  if { [build_inferior "${binfile}" "c"] == 0 } {
   gdb_test "python print(gdb.lookup_type('int').optimized_out())" \
       "<optimized out>"
 
+  gdb_test_no_output "python int_t = gdb.lookup_type('int')"
+
+  gdb_test "python print(repr(int_t.function()))" \
+      "<gdb.Type code=TYPE_CODE_FUNC name=int \\(\\)>"
+
+  gdb_test "python print(repr(int_t.function(int_t, int_t, int_t)))" \
+      "<gdb.Type code=TYPE_CODE_FUNC name=int \\(int, int, int\\)>"
+
+  gdb_test "python print(repr(int_t.function(int_t, None)))" \
+      "<gdb.Type code=TYPE_CODE_FUNC name=int \\(int, ...\\)>"
+
+  gdb_test "python print(repr(int_t.function(None)))" \
+      "<gdb.Type code=TYPE_CODE_FUNC name=int \\(\\)>"
+
+  gdb_test "python print(repr(int_t.function(123)))" \
+      "TypeError.*:.*"
+
+   gdb_test "python print(repr(int_t.function(int_t, None, int_t)))" \
+      "ValueError.*:.*"
+
   set sint [get_sizeof int 0]
   gdb_test "python print(gdb.parse_and_eval('aligncheck').type.alignof)" \
       $sint