This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFA 1/3] Initial support for variant parts
- From: Tom Tromey <tom at tromey dot com>
- To: gdb-patches at sourceware dot org
- Cc: Tom Tromey <tom at tromey dot com>
- Date: Tue, 20 Feb 2018 12:06:11 -0700
- Subject: [RFA 1/3] Initial support for variant parts
- Authentication-results: sourceware.org; auth=none
- References: <20180220190613.24148-1-tom@tromey.com>
This adds some initial support for variant parts to gdbtypes.h. A
variant part is represented as a union. The union has a flag
indicating that it has a discriminant, and information about the
discriminant is attached using the dynamic property system.
2018-02-19 Tom Tromey <tom@tromey.com>
* value.h (value_union_variant): Declare.
* valops.c (value_union_variant): New function.
* gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro.
(struct discriminant_info): New.
(enum dynamic_prop_node_kind) <DYN_PROP_DISCRIMINATED>: New
enumerator.
(struct main_type) <flag_discriminated_union>: New field.
---
gdb/ChangeLog | 10 ++++++++++
gdb/gdbtypes.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/valops.c | 41 +++++++++++++++++++++++++++++++++++++++++
gdb/value.h | 8 ++++++++
4 files changed, 110 insertions(+)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index eac1572280..28990a4ec6 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+2018-02-19 Tom Tromey <tom@tromey.com>
+
+ * value.h (value_union_variant): Declare.
+ * valops.c (value_union_variant): New function.
+ * gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro.
+ (struct discriminant_info): New.
+ (enum dynamic_prop_node_kind) <DYN_PROP_DISCRIMINATED>: New
+ enumerator.
+ (struct main_type) <flag_discriminated_union>: New field.
+
2018-02-20 Markus Metzger <markus.t.metzger@intel.com>
* gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add mkstemp.
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 613257c47d..62cd8b6f82 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -304,6 +304,14 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
#define TYPE_FLAG_ENUM(t) (TYPE_MAIN_TYPE (t)->flag_flag_enum)
+/* * True if this type is a discriminated union type. Only valid for
+ TYPE_CODE_UNION. A discriminated union stores a reference to the
+ discriminant field along with the discriminator values in a dynamic
+ property. */
+
+#define TYPE_FLAG_DISCRIMINATED_UNION(t) \
+ (TYPE_MAIN_TYPE (t)->flag_discriminated_union)
+
/* * Constant type. If this is set, the corresponding type has a
const modifier. */
@@ -373,6 +381,39 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
#define TYPE_ADDRESS_CLASS_ALL(t) (TYPE_INSTANCE_FLAGS(t) \
& TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL)
+/* * Information needed for a discriminated union. A discriminated
+ union is handled somewhat differently from an ordinary union.
+
+ One field is designated as the discriminant. Only one other field
+ is active at a time; which one depends on the value of the
+ discriminant and the data in this structure.
+
+ Additionally, it is possible to have a univariant discriminated
+ union. In this case, the union has just a single field, which is
+ assumed to be the only active variant -- in this case no
+ discriminant is provided. */
+
+struct discriminant_info
+{
+ /* * The index of the discriminant field. If -1, then this union
+ must have just a single field. */
+
+ int discriminant_index;
+
+ /* * The index of the default branch of the union. If -1, then
+ there is no default branch. */
+
+ int default_index;
+
+ /* * The discriminant values corresponding to each branch. This has
+ a number of entries equal to the number of fields in this union.
+ If discriminant_index is not -1, then that entry in this array is
+ not used. If default_index is not -1, then that entry in this
+ array is not used. */
+
+ ULONGEST discriminants[1];
+};
+
enum dynamic_prop_kind
{
PROP_UNDEFINED, /* Not defined. */
@@ -431,6 +472,9 @@ enum dynamic_prop_node_kind
/* A property providing an array's byte stride. */
DYN_PROP_BYTE_STRIDE,
+
+ /* A property holding information about a discriminated union. */
+ DYN_PROP_DISCRIMINATED,
};
/* * List for dynamic type attributes. */
@@ -650,6 +694,13 @@ struct main_type
unsigned int flag_flag_enum : 1;
+ /* * True if this type is a discriminated union type. Only valid
+ for TYPE_CODE_UNION. A discriminated union stores a reference to
+ the discriminant field along with the discriminator values in a
+ dynamic property. */
+
+ unsigned int flag_discriminated_union : 1;
+
/* * A discriminant telling us which field of the type_specific
union is being used for this type, if any. */
diff --git a/gdb/valops.c b/gdb/valops.c
index e038c04fd1..2d31762b8a 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -2257,6 +2257,47 @@ value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype,
return NULL;
}
+/* See value.h. */
+
+int
+value_union_variant (struct type *union_type, const gdb_byte *contents)
+{
+ gdb_assert (TYPE_CODE (union_type) == TYPE_CODE_UNION
+ && TYPE_FLAG_DISCRIMINATED_UNION (union_type));
+
+ struct dynamic_prop *discriminant_prop
+ = get_dyn_prop (DYN_PROP_DISCRIMINATED, union_type);
+ gdb_assert (discriminant_prop != nullptr);
+
+ struct discriminant_info *info
+ = (struct discriminant_info *) discriminant_prop->data.baton;
+ gdb_assert (info != nullptr);
+
+ /* If this is a univariant union, just return the sole field. */
+ if (TYPE_NFIELDS (union_type) == 1)
+ return 0;
+ /* This should only happen for univariants, which we already dealt
+ with. */
+ gdb_assert (info->discriminant_index != -1);
+
+ /* Compute the discriminant. */
+ ULONGEST discriminant = unpack_field_as_long (union_type, contents,
+ info->discriminant_index);
+
+ for (int i = 0; i < TYPE_NFIELDS (union_type); ++i)
+ {
+ if (i != info->default_index
+ && i != info->discriminant_index
+ && discriminant == info->discriminants[i])
+ return i;
+ }
+
+ if (info->default_index == -1)
+ error (_("Could not find variant corresponding to discriminant %s"),
+ pulongest (discriminant));
+ return info->default_index;
+}
+
/* Search through the methods of an object (and its bases) to find a
specified method. Return the pointer to the fn_field list FN_LIST of
overloaded instances defined in the source language. If available
diff --git a/gdb/value.h b/gdb/value.h
index e0ea22d4e5..4386be4135 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1169,4 +1169,12 @@ extern struct type *result_type_of_xmethod (struct value *method,
extern struct value *call_xmethod (struct value *method,
int argc, struct value **argv);
+/* Given a discriminated union type and some corresponding value
+ contents, this will return the field index of the currently active
+ variant. This will throw an exception if no active variant can be
+ found. */
+
+extern int value_union_variant (struct type *union_type,
+ const gdb_byte *contents);
+
#endif /* !defined (VALUE_H) */
--
2.13.6