Add Python support for dynamic types
authorTom Tromey <tromey@adacore.com>
Fri, 24 Apr 2020 19:40:31 +0000 (13:40 -0600)
committerTom Tromey <tromey@adacore.com>
Fri, 24 Apr 2020 19:40:33 +0000 (13:40 -0600)
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-24  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-24  Tom Tromey  <tromey@adacore.com>

PR python/23662:
* python.texi (Types In Python): Document new features.

gdb/testsuite/ChangeLog
2020-04-24  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
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/python.texi
gdb/python/py-type.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/variant.exp
gdb/testsuite/gdb.rust/simple.exp

index 7cccdd0c3a181e4664e498e3ffea90eee56758ef..8911ff5dfdbabdd09b7301f59f63d60676b5be37 100644 (file)
@@ -1,3 +1,13 @@
+2020-04-24  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.
+
 2020-04-24  Tom Tromey  <tromey@adacore.com>
 
        * ada-typeprint.c (print_choices, print_variant_part)
index 6657f6fadcece17a1616f90ffb2dec79c95aa581..01e73c9e5eacf2d6773ea5048803276d636322a6 100644 (file)
--- 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.
index 0dc64768325c139380aa2f91a3c1de3c560c5d57..7073c17b2ea5df89bfc903ab676e418f142cde4e 100644 (file)
@@ -1,3 +1,8 @@
+2020-04-24  Tom Tromey  <tromey@adacore.com>
+
+       PR python/23662:
+       * python.texi (Types In Python): Document new features.
+
 2020-04-15  Artur Shepilko  <nomadbyte@gmail.com>
 
        * gdb.texinfo: Transform @var{[host]} to [@var{host}]; this
index 31e8995022917b686df5406d0369946c09b9c20b..cfa813128cec670a7dcabeefea7e32d7b9aba8b4 100644 (file)
@@ -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}.
 
 @item enumval
 This attribute is only available for @code{enum} fields, and its value
index 61720491c7ab7cbda20084b0f323290a22942797..db031e0fb6e3d8e7b99dd222fd4aaa32026c99de 100644 (file)
@@ -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,
index daeed54886d9091a4d0da39ee3b5a1e34eab8dde..862d8b09a65549cce2826bd9d4c333e3964b5952 100644 (file)
@@ -1,3 +1,9 @@
+2020-04-24  Tom Tromey  <tromey@adacore.com>
+
+       PR python/23662:
+       * gdb.ada/variant.exp: Add Python checks.
+       * gdb.rust/simple.exp: Add dynamic type checks.
+
 2020-04-24  Tom Tromey  <tromey@adacore.com>
 
        * gdb.ada/mi_var_array.exp: Try all -fgnat-encodings settings.
index 490956a2666fa19bd2b8f63751a9defbbd66c026..da51f7ba2e839378a95ac9415374016fd0c52092 100644 (file)
@@ -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"
+    }
 }
index 92b3666386bfdf5b1576e16ad24ab12cbd91862b..6daaf8415c53f48d43a94a02d203b95c8c4867dc 100644 (file)
@@ -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"