[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