From 1acda8039ba681e88416a7da6a6e3abdcae6b86b Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 24 Apr 2020 13:40:31 -0600 Subject: [PATCH] Add Python support for dynamic types 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 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 PR python/23662: * python.texi (Types In Python): Document new features. gdb/testsuite/ChangeLog 2020-04-24 Tom Tromey 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/ChangeLog b/gdb/ChangeLog index 7cccdd0c3a1..8911ff5dfdb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2020-04-24 Tom Tromey + + 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 * ada-typeprint.c (print_choices, print_variant_part) 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/ChangeLog b/gdb/doc/ChangeLog index 0dc64768325..7073c17b2ea 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2020-04-24 Tom Tromey + + PR python/23662: + * python.texi (Types In Python): Document new features. + 2020-04-15 Artur Shepilko * gdb.texinfo: Transform @var{[host]} to [@var{host}]; this diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 31e89950229..cfa813128ce 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}. @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 61720491c7a..db031e0fb6e 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/ChangeLog b/gdb/testsuite/ChangeLog index daeed54886d..862d8b09a65 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-04-24 Tom Tromey + + PR python/23662: + * gdb.ada/variant.exp: Add Python checks. + * gdb.rust/simple.exp: Add dynamic type checks. + 2020-04-24 Tom Tromey * gdb.ada/mi_var_array.exp: Try all -fgnat-encodings settings. 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 . 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.30.2