[PATCH 10/11] Add Python support for dynamic types

Christian Biesinger cbiesinger@google.com
Thu Apr 9 00:20:21 GMT 2020


On Wed, Apr 8, 2020 at 12:55 PM Tom Tromey <tromey@adacore.com> wrote:
>
> This changes the gdb Python API to add support for dynamic types.  In
> particular, this adds an attribute to gdb.Type, and updates some
> attributes to reflect dynamic sizes and field offsets.
>
> There's still no way to get the dynamic type from one of its concrete
> instances.  This could perhaps be added if needed.
>
> gdb/ChangeLog
> 2020-04-08  Tom Tromey  <tromey@adacore.com>
>
>         PR python/23662:
>         * python/py-type.c (convert_field): Handle
>         FIELD_LOC_KIND_DWARF_BLOCK.
>         (typy_get_sizeof): Handle TYPE_HAS_DYNAMIC_LENGTH.
>         (typy_get_dynamic): Nw function.
>         (type_object_getset): Add "dynamic".
>         * NEWS: Add entry.
>
> gdb/doc/ChangeLog
> 2020-04-08  Tom Tromey  <tromey@adacore.com>
>
>         PR python/23662:
>         * python.texi (Types In Python): Document new features.
>
> gdb/testsuite/ChangeLog
> 2020-04-08  Tom Tromey  <tromey@adacore.com>
>
>         PR python/23662:
>         * gdb.ada/variant.exp: Add Python checks.
>         * gdb.rust/simple.exp: Add dynamic type checks.
> ---
>  gdb/ChangeLog                     | 10 +++++++++
>  gdb/NEWS                          |  5 +++++
>  gdb/doc/ChangeLog                 |  5 +++++
>  gdb/doc/python.texi               | 14 +++++++++++--
>  gdb/python/py-type.c              | 35 +++++++++++++++++++++++++++++--
>  gdb/testsuite/ChangeLog           |  6 ++++++
>  gdb/testsuite/gdb.ada/variant.exp | 10 +++++++++
>  gdb/testsuite/gdb.rust/simple.exp | 10 +++++++++
>  8 files changed, 91 insertions(+), 4 deletions(-)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6657f6fadce..01e73c9e5ea 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -68,6 +68,11 @@ GNU/Linux/RISC-V (gdbserver) riscv*-*-linux*
>    ** gdb.register_window_type can be used to implement new TUI windows
>       in Python.
>
> +  ** Dynamic types can now be queried.  gdb.Type has a new attribute,
> +     "dynamic", and gdb.Type.sizeof can be None for a dynamic type.  A
> +     field of a dynamic type may have None for its "bitpos" attribute
> +     as well.
> +
>  *** Changes in GDB 9
>
>  * 'thread-exited' event is now available in the annotations interface.
> diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
> index 76cdf7f5419..bcc27f6a224 100644
> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -1068,6 +1068,12 @@ The type code for this type.  The type code will be one of the
>  @code{TYPE_CODE_} constants defined below.
>  @end defvar
>
> +@defvar Type.dynamic
> +A boolean indicating whether this type is dynamic.  In some
> +situations, such as Rust @code{enum} types or Ada variant records, the
> +concrete type of a value may vary depending on its contents.
> +@end defvar
> +
>  @defvar Type.name
>  The name of this type.  If this type has no name, then @code{None}
>  is returned.
> @@ -1076,7 +1082,9 @@ is returned.
>  @defvar Type.sizeof
>  The size of this type, in target @code{char} units.  Usually, a
>  target's @code{char} type will be an 8-bit byte.  However, on some
> -unusual platforms, this type may have a different size.
> +unusual platforms, this type may have a different size.  A dynamic
> +type may not have a fixed size; in this case, this attribute's value
> +will be @code{None}.
>  @end defvar
>
>  @defvar Type.tag
> @@ -1106,7 +1114,9 @@ Each field is a @code{gdb.Field} object, with some pre-defined attributes:
>  @item bitpos
>  This attribute is not available for @code{enum} or @code{static}
>  (as in C@t{++}) fields.  The value is the position, counting
> -in bits, from the start of the containing type.
> +in bits, from the start of the containing type.  Note that, in a
> +dynamic type, the position of a field may not be constant.  In this
> +case, the value will be @code{None}.

Just to make sure I understand, if I have a type like this (using
Haskell-like syntax, I hope this makes sense):

Type t =
  Int x |
  Float y |
  (String a, Float b)

This would be reflected in Python as the type having fields x, y, a
and b, all of which have a None position?

Is there a way to access these fields, and is there a way to see which
specific type a certain variable value is?

Christian

>
>  @item enumval
>  This attribute is only available for @code{enum} fields, and its value
> diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
> index b19cad098a4..acdd80fccc3 100644
> --- a/gdb/python/py-type.c
> +++ b/gdb/python/py-type.c
> @@ -189,8 +189,11 @@ convert_field (struct type *type, int field)
>         }
>        else
>         {
> -         arg.reset (gdb_py_long_from_longest (TYPE_FIELD_BITPOS (type,
> -                                                                 field)));
> +         if (TYPE_FIELD_LOC_KIND (type, field) == FIELD_LOC_KIND_DWARF_BLOCK)
> +           arg = gdbpy_ref<>::new_reference (Py_None);
> +         else
> +           arg.reset (gdb_py_long_from_longest (TYPE_FIELD_BITPOS (type,
> +                                                                   field)));
>           attrstring = "bitpos";
>         }
>
> @@ -710,9 +713,12 @@ typy_get_sizeof (PyObject *self, void *closure)
>  {
>    struct type *type = ((type_object *) self)->type;
>
> +  bool size_varies = false;
>    try
>      {
>        check_typedef (type);
> +
> +      size_varies = TYPE_HAS_DYNAMIC_LENGTH (type);
>      }
>    catch (const gdb_exception &except)
>      {
> @@ -720,6 +726,8 @@ typy_get_sizeof (PyObject *self, void *closure)
>
>    /* Ignore exceptions.  */
>
> +  if (size_varies)
> +    Py_RETURN_NONE;
>    return gdb_py_long_from_longest (TYPE_LENGTH (type));
>  }
>
> @@ -744,6 +752,27 @@ typy_get_alignof (PyObject *self, void *closure)
>    return gdb_py_object_from_ulongest (align).release ();
>  }
>
> +/* Return whether or not the type is dynamic.  */
> +static PyObject *
> +typy_get_dynamic (PyObject *self, void *closure)
> +{
> +  struct type *type = ((type_object *) self)->type;
> +
> +  bool result = false;
> +  try
> +    {
> +      result = is_dynamic_type (type);
> +    }
> +  catch (const gdb_exception &except)
> +    {
> +      /* Ignore exceptions.  */
> +    }
> +
> +  if (result)
> +    Py_RETURN_TRUE;
> +  Py_RETURN_FALSE;
> +}
> +
>  static struct type *
>  typy_lookup_typename (const char *type_name, const struct block *block)
>  {
> @@ -1436,6 +1465,8 @@ static gdb_PyGetSetDef type_object_getset[] =
>      "The alignment of this type, in bytes.", NULL },
>    { "code", typy_get_code, NULL,
>      "The code for this type.", NULL },
> +  { "dynamic", typy_get_dynamic, NULL,
> +    "Whether this type is dynamic.", NULL },
>    { "name", typy_get_name, NULL,
>      "The name for this type, or None.", NULL },
>    { "sizeof", typy_get_sizeof, NULL,
> diff --git a/gdb/testsuite/gdb.ada/variant.exp b/gdb/testsuite/gdb.ada/variant.exp
> index 490956a2666..da51f7ba2e8 100644
> --- a/gdb/testsuite/gdb.ada/variant.exp
> +++ b/gdb/testsuite/gdb.ada/variant.exp
> @@ -14,6 +14,7 @@
>  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
>
>  load_lib "ada.exp"
> +load_lib "gdb-python.exp"
>
>  standard_ada_testfile pkg
>
> @@ -43,4 +44,13 @@ foreach_with_prefix scenario {none all minimal} {
>         " = \\(one => 3, two => 0, str => \"zzz\", onevalue => 33, str2 => \"\"\\)"
>      gdb_test "print nav3" \
>         " = \\(one => 3, two => 7, str => \"zzz\", onevalue => 33, str2 => \"qqqqqqq\", twovalue => 88\\)"
> +
> +    # This is only supported for the DWARF encoding.
> +    if {$scenario == "minimal" && ![skip_python_tests]} {
> +       gdb_test_no_output \
> +           "python t = gdb.lookup_type('nested_and_variable')" \
> +           "fetch type for python"
> +       gdb_test "python print(t.dynamic)" "True"
> +       gdb_test "python print(t\['onevalue'\].bitpos)" "None"
> +    }
>  }
> diff --git a/gdb/testsuite/gdb.rust/simple.exp b/gdb/testsuite/gdb.rust/simple.exp
> index 92b3666386b..6daaf8415c5 100644
> --- a/gdb/testsuite/gdb.rust/simple.exp
> +++ b/gdb/testsuite/gdb.rust/simple.exp
> @@ -364,3 +364,13 @@ if {[skip_python_tests]} {
>  }
>
>  gdb_test "python print(gdb.lookup_type('simple::HiBob'))" "simple::HiBob"
> +
> +gdb_test_no_output "python e = gdb.parse_and_eval('e')" \
> +    "get value of e for python"
> +gdb_test "python print(len(e.type.fields()))" "2"
> +gdb_test "python print(e.type.fields()\[0\].artificial)" "True"
> +gdb_test "python print(e.type.fields()\[1\].name)" "Two"
> +
> +gdb_test "python print(e.type.dynamic)" "False"
> +gdb_test "python print(gdb.lookup_type('simple::MoreComplicated').dynamic)" \
> +    "True"
> --
> 2.21.1
>


More information about the Gdb-patches mailing list