[PATCH 1/2][PR gdb/20239] Make evaluation and type-printing of all NonZero-optimized enums work
Manish Goregaokar
manish@mozilla.com
Tue Jun 21 09:40:00 GMT 2016
Moved over from https://sourceware.org/bugzilla/show_bug.cgi?id=20239.
Regarding the xstrdup, this is done because strsep edits the string
itself.
Built and tested on OS X El Capitan. Methods tests fail, but they are
a preexisting failure due to Rust's debuginfo changing.
gdb/ChangeLog:
2016-06-21 Manish Goregaokar <manish@mozilla.com>
PR gdb/20239
* rust-lang.c (rust_get_disr_info): Correctly interpret
NonZero-optimized enums of arbitrary depth.
(rust_print_type): Correctly print NonZero-optimized
enums.
---
gdb/rust-lang.c | 72 +++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 55 insertions(+), 17 deletions(-)
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 5df99ce..baabf76 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -120,42 +120,69 @@ rust_get_disr_info (struct type *type, const
gdb_byte *valaddr,
if (strncmp (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX,
strlen (RUST_ENUM_PREFIX)) == 0)
{
- char *tail;
+ char *name, *tail, *token;
unsigned long fieldno;
struct type *member_type;
LONGEST value;
+ char *type_name;
+
ret.is_encoded = 1;
if (TYPE_NFIELDS (type) != 1)
error (_("Only expected one field in %s type"), RUST_ENUM_PREFIX);
- fieldno = strtoul (TYPE_FIELD_NAME (type, 0) + strlen (RUST_ENUM_PREFIX),
- &tail, 10);
- if (*tail != '$')
+ /* Optimized enums have only one field */
+ member_type = TYPE_FIELD_TYPE (type, 0);
+
+ name = xstrdup (TYPE_FIELD_NAME (type, 0));
+ cleanup = make_cleanup (xfree, name);
+ tail = name + strlen (RUST_ENUM_PREFIX);
+
+ /* The location of the value that doubles as a discriminant is
+ stored in the name of the field, as
+ RUST$ENCODED$ENUM$<fieldno>$<fieldno>$...$<variantname>
+ where the fieldnos are the indices of the fields that should be
+ traversed in order to find the field (which may be several
fields deep)
+ and the variantname is the name of the variant of the case when the
+ field is zero */
+ while ((token = strsep (&tail, "$")) != NULL)
+ {
+ if (sscanf (token, "%lu", &fieldno) != 1)
+ {
+ /* We have reached the enum name, which cannot start with
a digit */
+ break;
+ }
+ if (fieldno >= TYPE_NFIELDS (member_type))
+ error (_("%s refers to field after end of member type"),
+ RUST_ENUM_PREFIX);
+
+ embedded_offset += TYPE_FIELD_BITPOS (member_type, fieldno) / 8;
+ member_type = TYPE_FIELD_TYPE (member_type, fieldno);
+ type_name = TYPE_NAME (member_type);
+ };
+
+ if (token >= name + strlen (TYPE_FIELD_NAME (type, 0)))
error (_("Invalid form for %s"), RUST_ENUM_PREFIX);
+ value = unpack_long (member_type,
+ valaddr + embedded_offset);
+
- member_type = TYPE_FIELD_TYPE (type, 0);
- if (fieldno >= TYPE_NFIELDS (member_type))
- error (_("%s refers to field after end of member type"),
- RUST_ENUM_PREFIX);
- embedded_offset += TYPE_FIELD_BITPOS (member_type, fieldno) / 8;
- value = unpack_long (TYPE_FIELD_TYPE (member_type, fieldno),
- valaddr + embedded_offset);
if (value == 0)
{
ret.field_no = RUST_ENCODED_ENUM_HIDDEN;
- ret.name = concat (TYPE_NAME (type), "::", tail + 1, (char *) NULL);
+ ret.name = concat (TYPE_NAME (type), "::", token, (char *) NULL);
}
else
{
ret.field_no = RUST_ENCODED_ENUM_REAL;
ret.name = concat (TYPE_NAME (type), "::",
- rust_last_path_segment (TYPE_NAME (member_type)),
+ rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE
(type, 0))),
(char *) NULL);
}
+ do_cleanups (cleanup);
return ret;
}
@@ -841,6 +868,7 @@ rust_print_type (struct type *type, const char *varstring,
{
/* ADT enums */
int i, len = 0;
+ int skip_to = 1; /* Skip the discriminant field */
fputs_filtered ("enum ", stream);
if (TYPE_TAG_NAME (type) != NULL)
@@ -849,7 +877,17 @@ rust_print_type (struct type *type, const char *varstring,
fputs_filtered (" ", stream);
len = strlen (TYPE_TAG_NAME (type));
}
- fputs_filtered ("{\n", stream);
+ fputs_filtered ("{\n", stream);
+
+ if (strncmp (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX,
+ strlen (RUST_ENUM_PREFIX)) == 0) {
+ char *zero_field = strrchr (TYPE_FIELD_NAME (type, 0), '$');
+ if (zero_field != NULL && strlen (zero_field) > 1) {
+ fprintfi_filtered (level+2, stream, "%s,\n", zero_field+1);
+ /* there is no explicit discriminant field, skip nothing */
+ skip_to = 0;
+ }
+ }
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
@@ -859,14 +897,14 @@ rust_print_type (struct type *type, const char *varstring,
fprintfi_filtered (level + 2, stream, "%s", name);
- if (TYPE_NFIELDS (variant_type) > 1)
+ if (TYPE_NFIELDS (variant_type) > skip_to)
{
- int first = 1;
+ int first = 1;
int is_tuple = rust_tuple_variant_type_p (variant_type);
int j;
fputs_filtered (is_tuple ? "(" : "{", stream);
- for (j = 1; j < TYPE_NFIELDS (variant_type); j++)
+ for (j = skip_to; j < TYPE_NFIELDS (variant_type); j++)
{
if (first)
first = 0;
--
2.8.3
More information about the Gdb-patches
mailing list