This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/5, doc RFA]: Enhancements to "flags": main patch


Hi.

This is the main patch to add support for multibit and enum bitfields
to "flags" register specs.

In addition, it adds support for "ptype" for flags.

2016-02-29  Doug Evans  <dje@google.com>

	Extend flags to support multibit and enum bitfields.
	* c-typeprint.c (c_type_print_varspec_prefix): Handle TYPE_CODE_FLAGS.
	(c_type_print_varspec_suffix, c_type_print_base): Ditto.
	* gdbtypes.c (arch_flags_type): Don't assume all fields are one bit.
	(append_flags_type_field): New function.
	(append_flags_type_flag): Call it.
	* gdbtypes.h (append_flags_type_field): Declare.
	* target-descriptions.c (struct tdesc_type_flag): Delete.
	(enum tdesc_type_kind) <TDESC_TYPE_BOOL>: New enum value.
	(enum tdesc_type_kind) <TDESC_TYPE_ENUM>: Ditto.
	(struct tdesc_type) <u.f>: Delete.
	(tdesc_predefined_types): Add "bool".
	(tdesc_predefined_type): New function.
	(tdesc_gdb_type): Handle TDESC_TYPE_BOOL, TDESC_TYPE_ENUM.
	Update TDESC_TYPE_FLAGS support.
	(tdesc_free_type): Handle TDESC_TYPE_ENUM.  Update TDESC_TYPE_FLAGS.
	(tdesc_create_flags): Update.
	(tdesc_create_enum): New function.
	(tdesc_add_field): Initialize start,end to -1.
	(tdesc_add_typed_bitfield): New function.
	(tdesc_add_bitfield): Call it.
	(tdesc_add_flag): Allow TDESC_TYPE_STRUCT.  Update.
	(tdesc_add_enum_value): New function.
	(maint_print_c_tdesc_cmd): Fold TDESC_TYPE_FLAGS support into
	TDESC_TYPE_STRUCT.  Handle TDESC_TYPE_ENUM.
	* target-descriptions.h (tdesc_create_enum): Declare.
	(tdesc_add_typed_bitfield, tdesc_add_enum_value): Declare.
	* valprint.c (generic_val_print_enum_1): New function.
	(generic_val_print_enum): Call it.
	(val_print_type_code_flags): Make static.  Handle multibit bitfields
	and enum bitfields.
	* valprint.h (val_print_type_code_flags): Delete.
	* xml-tdesc.c (struct tdesc_parsing_data) <current_type_is_flags>:
	Delete.  All uses removed.
	(tdesc_start_enum): New function.
	(tdesc_start_field): Handle multibit and enum bitfields.
	(tdesc_start_enum_value): New function.
	(enum_value_attributes, enum_children, enum_attributes): New static
	globals.
	(feature_children): Add "enum".
	* features/gdb-target.dtd (enum, evalue): New elements.

	doc/
	* gdb.texinfo (Target Descriptions): New menu item "Enum Target Types".
	(Target Description Format): Mention enum types.  Update docs on
	flags types.
	(Predefined Target Types): Add "bool".
	(Enum Target Types): New node.

	testsuite/
	* gdb.xml/extra-regs.xml: Add enum, mixed_flags values.
	* gdb.xml/tdesc-regs.exp (load_description): New arg xml_file.
	All callers updated.  Add tests for enums, mixed flags register.

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 6b9e6b3..ed16fc3 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -371,6 +371,7 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
     case TYPE_CODE_ENUM:
+    case TYPE_CODE_FLAGS:
     case TYPE_CODE_INT:
     case TYPE_CODE_FLT:
     case TYPE_CODE_VOID:
@@ -748,6 +749,7 @@ c_type_print_varspec_suffix (struct type *type,
     case TYPE_CODE_UNDEF:
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
+    case TYPE_CODE_FLAGS:
     case TYPE_CODE_ENUM:
     case TYPE_CODE_INT:
     case TYPE_CODE_FLT:
@@ -1402,6 +1404,54 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	}
       break;

+    case TYPE_CODE_FLAGS:
+      {
+	struct type_print_options local_flags = *flags;
+
+	local_flags.local_typedefs = NULL;
+
+	c_type_print_modifier (type, stream, 0, 1);
+	fprintf_filtered (stream, "flag ");
+	print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
+	if (show > 0)
+	  {
+	    fputs_filtered (" ", stream);
+	    fprintf_filtered (stream, "{\n");
+	    if (TYPE_NFIELDS (type) == 0)
+	      {
+		if (TYPE_STUB (type))
+		  fprintfi_filtered (level + 4, stream,
+				     _("<incomplete type>\n"));
+		else
+		  fprintfi_filtered (level + 4, stream,
+				     _("<no data fields>\n"));
+	      }
+	    len = TYPE_NFIELDS (type);
+	    for (i = 0; i < len; i++)
+	      {
+		QUIT;
+		print_spaces_filtered (level + 4, stream);
+		/* We pass "show" here and not "show - 1" to get enum types
+		   printed.  There's no other way to see them.  */
+		c_print_type (TYPE_FIELD_TYPE (type, i),
+			      TYPE_FIELD_NAME (type, i),
+			      stream, show, level + 4,
+			      &local_flags);
+		fprintf_filtered (stream, " @%d",
+				  TYPE_FIELD_BITPOS (type, i));
+		if (TYPE_FIELD_BITSIZE (type, i) > 1)
+		  {
+		    fprintf_filtered (stream, "-%d",
+				      TYPE_FIELD_BITPOS (type, i)
+				      + TYPE_FIELD_BITSIZE (type, i) - 1);
+		  }
+		fprintf_filtered (stream, ";\n");
+	      }
+	    fprintfi_filtered (level, stream, "}");
+	  }
+      }
+      break;
+
     case TYPE_CODE_VOID:
       fprintf_filtered (stream, "void");
       break;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4ec0ec1..16261c6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40330,6 +40330,7 @@ target descriptions.  @xref{Expat}.
 * Target Description Format::       The contents of a target description.
 * Predefined Target Types::         Standard types available for target
                                     descriptions.
+* Enum Target Types::               How to define enum target types.
 * Standard Target Features::        Features @value{GDBN} knows about.
 @end menu

@@ -40530,7 +40531,8 @@ Any register's value is a collection of bits which @value{GDBN} must
 interpret.  The default interpretation is a two's complement integer,
 but other types can be requested by name in the register description.
 Some predefined types are provided by @value{GDBN} (@pxref{Predefined
-Target Types}), and the description can define additional composite types.
+Target Types}), and the description can define additional composite
+and enum types.

 Each type element must have an @samp{id} attribute, which gives
 a unique (within the containing @samp{<feature>}) name to the type.
@@ -40560,46 +40562,84 @@ each of which has a @var{name} and a @var{type}:
 @end smallexample

 @cindex <struct>
+@cindex <flags>
 If a register's value is composed from several separate values, define
-it with a structure type.  There are two forms of the @samp{<struct>}
-element; a @samp{<struct>} element must either contain only bitfields
-or contain no bitfields.  If the structure contains only bitfields,
-its total size in bytes must be specified, each bitfield must have an
-explicit start and end, and bitfields are automatically assigned an
-integer type.  The field's @var{start} should be less than or
-equal to its @var{end}, and zero represents the least significant bit.
+it with either a structure type or a flags type.
+A flags type may only contain bitfields.
+A structure type may either contain only bitfields or contain no bitfields.
+If the value contains only bitfields, its total size in bytes must be
+specified.
+
+Non-bitfield values have a @var{name} and @var{type}.

 @smallexample
-<struct id="@var{id}" size="@var{size}">
-  <field name="@var{name}" start="@var{start}" end="@var{end}"/>
+<struct id="@var{id}">
+  <field name="@var{name}" type="@var{type}"/>
   @dots{}
 </struct>
 @end smallexample

-If the structure contains no bitfields, then each field has an
-explicit type, and no implicit padding is added.
+Both @var{name} and @var{type} values are required.
+No implicit padding is added.
+
+Bitfield values have a @var{name}, @var{start}, @var{end} and @var{type}.

 @smallexample
-<struct id="@var{id}">
-  <field name="@var{name}" type="@var{type}"/>
+<struct id="@var{id}" size="@var{size}">
+ <field name="@var{name}" start="@var{start}" end="@var{end}" type="@var{type}"/>
   @dots{}
 </struct>
 @end smallexample

-@cindex <flags>
-If a register's value is a series of single-bit flags, define it with
-a flags type.  The @samp{<flags>} element has an explicit @var{size}
-and contains one or more @samp{<field>} elements.  Each field has a
-@var{name}, a @var{start}, and an @var{end}.  Only single-bit flags
-are supported.
-
 @smallexample
 <flags id="@var{id}" size="@var{size}">
-  <field name="@var{name}" start="@var{start}" end="@var{end}"/>
+ <field name="@var{name}" start="@var{start}" end="@var{end}" type="@var{type}"/>
   @dots{}
 </flags>
 @end smallexample

+The @var{name} value is required.
+Bitfield values may be named with the empty string, @samp{""},
+in which case the field is ``filler'' and its value is not printed.
+Not all bits need to be specified, so ``filler'' fields are optional.
+
+The @var{start} value is required, and @var{end} and @var{type}
+are optional.
+The field's @var{start} must be less than or equal to its @var{end},
+and zero represents the least significant bit.
+The default value of @var{end} is @var{start}, a single bit field.
+
+The default value of @var{type} depends on whether the
+@var{end} was specified.  If @var{end} is specified then the default
+value of @var{type} is an unsigned integer.  If @var{end} is unspecified
+then the default value of @var{type} is @code{bool}.
+
+Which to choose?  Structures or flags?
+
+Registers defined with @samp{flags} have these advantages over
+defining them with @samp{struct}:
+
+@itemize @bullet
+@item
+Arithmetic may be performed on them as if they were integers.
+@item
+They are printed in a more readable fashion.
+@end itemize
+
+Registers defined with @samp{struct} have one advantage over
+defining them with @samp{flags}:
+
+@itemize @bullet
+@item
+One can fetch individual fields like in @samp{C}.
+
+@smallexample
+(gdb) print $my_struct_reg.field3
+$1 = 42
+@end smallexample
+
+@end itemize
+
 @subsection Registers
 @cindex <reg>

@@ -40668,6 +40708,9 @@ types.  The currently supported types are:

 @table @code

+@item bool
+Boolean type, occupying a single bit.
+
 @item int8
 @itemx int16
 @itemx int32
@@ -40710,6 +40753,44 @@ The 10-byte extended precision format used by x87 registers.

 @end table

+@node Enum Target Types
+@section Enum Target Types
+@cindex target descriptions, enum types
+
+Enum target types are useful in @samp{struct} and @samp{flags}
+register descriptions. @xref{Target Description Format}.
+
+Enum types have a name, size and a list of name/value pairs.
+
+@smallexample
+<enum id="@var{id}" size="@var{size}">
+  <evalue name="@var{name}" value="@var{value}"/>
+  @dots{}
+</enum>
+@end smallexample
+
+Enums must be defined before they are used.
+
+@smallexample
+<enum id="levels_type" size="4">
+  <evalue name="low" value="0"/>
+  <evalue name="high" value="1"/>
+</enum>
+<flags id="flags_type" size="4">
+  <field name="X" start="0"/>
+  <field name="LEVEL" start="1" end="1" type="levels_type"/>
+</flags>
+<reg name="flags" bitsize="32" type="flags_type"/>
+@end smallexample
+
+Given that description, a value of 3 for the @samp{flags} register
+would be printed as:
+
+@smallexample
+(gdb) info register flags
+flags 0x3 [ X LEVEL=high ]
+@end smallexample
+
 @node Standard Target Features
 @section Standard Target Features
 @cindex target descriptions, standard features
diff --git a/gdb/features/gdb-target.dtd b/gdb/features/gdb-target.dtd
index 3fd61c2..a6f0b07 100644
--- a/gdb/features/gdb-target.dtd
+++ b/gdb/features/gdb-target.dtd
@@ -45,6 +45,11 @@
 	id		CDATA	#REQUIRED
 	size		CDATA	#REQUIRED>

+<!ELEMENT enum		(evalue+)>
+<!ATTLIST enum
+	id		CDATA	#REQUIRED
+	size		CDATA	#REQUIRED>
+
 <!ELEMENT struct	(field+)>
 <!ATTLIST struct
 	id		CDATA	#REQUIRED
@@ -61,5 +66,10 @@
 	start		CDATA	#IMPLIED
 	end		CDATA	#IMPLIED>

+<!ELEMENT evalue	EMPTY>
+<!ATTLIST evalue
+	name		CDATA	#REQUIRED
+	value		CDATA	#REQUIRED>
+
 <!ENTITY % xinclude SYSTEM "xinclude.dtd">
 %xinclude;
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index f129b0e..5db3ebc 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4706,38 +4706,55 @@ arch_complex_type (struct gdbarch *gdbarch,
 struct type *
 arch_flags_type (struct gdbarch *gdbarch, char *name, int length)
 {
-  int nfields = length * TARGET_CHAR_BIT;
+  int max_nfields = length * TARGET_CHAR_BIT;
   struct type *type;

   type = arch_type (gdbarch, TYPE_CODE_FLAGS, length, name);
   TYPE_UNSIGNED (type) = 1;
-  TYPE_NFIELDS (type) = nfields;
+  TYPE_NFIELDS (type) = 0;
+  /* Pre-allocate enough space assuming every field is one bit.  */
   TYPE_FIELDS (type)
-    = (struct field *) TYPE_ZALLOC (type, nfields * sizeof (struct field));
+ = (struct field *) TYPE_ZALLOC (type, max_nfields * sizeof (struct field));

   return type;
 }

 /* Add field to TYPE_CODE_FLAGS type TYPE to indicate the bit at
+   position BITPOS is called NAME.  Pass NAME as "" for fields that
+   should not be printed.  */
+
+void
+append_flags_type_field (struct type *type, int start_bitpos, int nr_bits,
+			 struct type *field_type, char *name)
+{
+  int type_bitsize = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
+  int field_nr = TYPE_NFIELDS (type);
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLAGS);
+  gdb_assert (TYPE_NFIELDS (type) + 1 <= type_bitsize);
+  gdb_assert (start_bitpos >= 0 && start_bitpos < type_bitsize);
+  gdb_assert (nr_bits >= 1 && nr_bits <= type_bitsize);
+  gdb_assert (name != NULL);
+
+  TYPE_FIELD_NAME (type, field_nr) = xstrdup (name);
+  TYPE_FIELD_TYPE (type, field_nr) = field_type;
+  SET_FIELD_BITPOS (TYPE_FIELD (type, field_nr), start_bitpos);
+  TYPE_FIELD_BITSIZE (type, field_nr) = nr_bits;
+  ++TYPE_NFIELDS (type);
+}
+
+/* Special version of append_flags_type_field to add a flag field.
+   Add field to TYPE_CODE_FLAGS type TYPE to indicate the bit at
    position BITPOS is called NAME.  */

 void
 append_flags_type_flag (struct type *type, int bitpos, char *name)
 {
-  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLAGS);
-  gdb_assert (bitpos < TYPE_NFIELDS (type));
-  gdb_assert (bitpos >= 0);
+  struct gdbarch *gdbarch = get_type_arch (type);

-  if (name)
-    {
-      TYPE_FIELD_NAME (type, bitpos) = xstrdup (name);
-      SET_FIELD_BITPOS (TYPE_FIELD (type, bitpos), bitpos);
-    }
-  else
-    {
-      /* Don't show this field to the user.  */
-      SET_FIELD_BITPOS (TYPE_FIELD (type, bitpos), -1);
-    }
+  append_flags_type_field (type, bitpos, 1,
+			   builtin_type (gdbarch)->builtin_bool,
+			   name);
 }

 /* Allocate a TYPE_CODE_STRUCT or TYPE_CODE_UNION type structure (as
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index e775a1d..1518a7a 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1704,9 +1704,12 @@ struct field *append_composite_type_field_raw (struct type *t, char *name,

 /* Helper functions to construct a bit flags type.  An initially empty
    type is created using arch_flag_type().  Flags are then added using
-   append_flag_type_flag().  */
+   append_flag_type_field() and append_flag_type_flag().  */
 extern struct type *arch_flags_type (struct gdbarch *gdbarch,
 				     char *name, int length);
+extern void append_flags_type_field (struct type *type,
+				     int start_bitpos, int nr_bits,
+				     struct type *field_type, char *name);
extern void append_flags_type_flag (struct type *type, int bitpos, char *name);

 extern void make_vector_type (struct type *array_type);
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index ac6e3a2..40f0478 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -90,20 +90,17 @@ typedef struct tdesc_type_field
 {
   char *name;
   struct tdesc_type *type;
+  /* For non-enum-values, either both are -1 (non-bitfield), or both are
+ not -1 (bitfield). For enum values, start is the value (which could be
+     -1), end is -1.  */
   int start, end;
 } tdesc_type_field;
 DEF_VEC_O(tdesc_type_field);

-typedef struct tdesc_type_flag
-{
-  char *name;
-  int start;
-} tdesc_type_flag;
-DEF_VEC_O(tdesc_type_flag);
-
 enum tdesc_type_kind
 {
   /* Predefined types.  */
+  TDESC_TYPE_BOOL,
   TDESC_TYPE_INT8,
   TDESC_TYPE_INT16,
   TDESC_TYPE_INT32,
@@ -125,7 +122,8 @@ enum tdesc_type_kind
   TDESC_TYPE_VECTOR,
   TDESC_TYPE_STRUCT,
   TDESC_TYPE_UNION,
-  TDESC_TYPE_FLAGS
+  TDESC_TYPE_FLAGS,
+  TDESC_TYPE_ENUM
 };

 typedef struct tdesc_type
@@ -146,19 +144,12 @@ typedef struct tdesc_type
       int count;
     } v;

-    /* Struct or union type.  */
+    /* Struct, union, flags, or enum type.  */
     struct
     {
       VEC(tdesc_type_field) *fields;
       int size;
     } u;
-
-    /* Flags type.  */
-    struct
-    {
-      VEC(tdesc_type_flag) *flags;
-      int size;
-    } f;
   } u;
 } *tdesc_type_p;
 DEF_VEC_P(tdesc_type_p);
@@ -527,6 +518,7 @@ tdesc_feature_name (const struct tdesc_feature *feature)
 /* Predefined types.  */
 static struct tdesc_type tdesc_predefined_types[] =
 {
+  { "bool", TDESC_TYPE_BOOL },
   { "int8", TDESC_TYPE_INT8 },
   { "int16", TDESC_TYPE_INT16 },
   { "int32", TDESC_TYPE_INT32 },
@@ -545,6 +537,21 @@ static struct tdesc_type tdesc_predefined_types[] =
   { "i387_ext", TDESC_TYPE_I387_EXT }
 };

+/* Lookup a predefined type.  */
+
+static struct tdesc_type *
+tdesc_predefined_type (enum tdesc_type_kind kind)
+{
+  int ix;
+  struct tdesc_type *type;
+
+  for (ix = 0; ix < ARRAY_SIZE (tdesc_predefined_types); ix++)
+    if (tdesc_predefined_types[ix].kind == kind)
+      return &tdesc_predefined_types[ix];
+
+  gdb_assert_not_reached ("bad predefined tdesc type");
+}
+
 /* Return the type associated with ID in the context of FEATURE, or
    NULL if none.  */

@@ -602,6 +609,9 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
   switch (tdesc_type->kind)
     {
     /* Predefined types.  */
+    case TDESC_TYPE_BOOL:
+      return builtin_type (gdbarch)->builtin_bool;
+
     case TDESC_TYPE_INT8:
       return builtin_type (gdbarch)->builtin_int8;

@@ -690,17 +700,18 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
 	     VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
 	     ix++)
 	  {
-	    if (f->type == NULL)
+	    if (f->start != -1 && f->end != -1)
 	      {
 		/* Bitfield.  */
 		struct field *fld;
 		struct type *field_type;
 		int bitsize, total_size;

-		/* This invariant should be preserved while creating
-		   types.  */
+		/* This invariant should be preserved while creating types.  */
 		gdb_assert (tdesc_type->u.u.size != 0);
-		if (tdesc_type->u.u.size > 4)
+		if (f->type != NULL)
+		  field_type = tdesc_gdb_type (gdbarch, f->type);
+		else if (tdesc_type->u.u.size > 4)
 		  field_type = builtin_type (gdbarch)->builtin_uint64;
 		else
 		  field_type = builtin_type (gdbarch)->builtin_uint32;
@@ -725,6 +736,7 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
 	      }
 	    else
 	      {
+		gdb_assert (f->start == -1 && f->end == -1);
 		field_type = tdesc_gdb_type (gdbarch, f->type);
 		append_composite_type_field (type, xstrdup (f->name),
 					     field_type);
@@ -763,19 +775,45 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)

     case TDESC_TYPE_FLAGS:
       {
-	struct tdesc_type_flag *f;
+	struct tdesc_type_field *f;
 	int ix;

 	type = arch_flags_type (gdbarch, tdesc_type->name,
-				tdesc_type->u.f.size);
+				tdesc_type->u.u.size);
+	for (ix = 0;
+	     VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
+	     ix++)
+	  {
+	    struct type *field_type;
+	    int bitsize = f->end - f->start + 1;
+
+	    gdb_assert (f->type != NULL);
+	    field_type = tdesc_gdb_type (gdbarch, f->type);
+	    append_flags_type_field (type, f->start, bitsize,
+				     field_type, f->name);
+	  }
+
+	return type;
+      }
+
+    case TDESC_TYPE_ENUM:
+      {
+	struct tdesc_type_field *f;
+	int ix;
+
+	type = arch_type (gdbarch, TYPE_CODE_ENUM,
+			  tdesc_type->u.u.size, tdesc_type->name);
+	TYPE_UNSIGNED (type) = 1;
 	for (ix = 0;
-	     VEC_iterate (tdesc_type_flag, tdesc_type->u.f.flags, ix, f);
+	     VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
 	     ix++)
-	  /* Note that contrary to the function name, this call will
-	     just set the properties of an already-allocated
-	     field.  */
-	  append_flags_type_flag (type, f->start,
-				  *f->name ? f->name : NULL);
+	  {
+	    struct field *fld
+	      = append_composite_type_field_raw (type, xstrdup (f->name),
+						 NULL);
+
+	    SET_FIELD_BITPOS (fld[0], f->start);
+	  }

 	return type;
       }
@@ -1266,6 +1304,11 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name,
   VEC_safe_push (tdesc_reg_p, feature->registers, reg);
 }

+/* Subroutine of tdesc_free_feature to simplify it.
+   Note: We do not want to free any referenced types here (e.g., types of
+   fields of a struct).  All types of a feature are recorded in
+   feature->types and are freed that way.  */
+
 static void
 tdesc_free_type (struct tdesc_type *type)
 {
@@ -1273,6 +1316,8 @@ tdesc_free_type (struct tdesc_type *type)
     {
     case TDESC_TYPE_STRUCT:
     case TDESC_TYPE_UNION:
+    case TDESC_TYPE_FLAGS:
+    case TDESC_TYPE_ENUM:
       {
 	struct tdesc_type_field *f;
 	int ix;
@@ -1286,20 +1331,6 @@ tdesc_free_type (struct tdesc_type *type)
       }
       break;

-    case TDESC_TYPE_FLAGS:
-      {
-	struct tdesc_type_flag *f;
-	int ix;
-
-	for (ix = 0;
-	     VEC_iterate (tdesc_type_flag, type->u.f.flags, ix, f);
-	     ix++)
-	  xfree (f->name);
-
-	VEC_free (tdesc_type_flag, type->u.f.flags);
-      }
-      break;
-
     default:
       break;
     }
@@ -1369,15 +1400,29 @@ tdesc_create_flags (struct tdesc_feature *feature, const char *name,

   type->name = xstrdup (name);
   type->kind = TDESC_TYPE_FLAGS;
-  type->u.f.size = size;
+  type->u.u.size = size;

   VEC_safe_push (tdesc_type_p, feature->types, type);
   return type;
 }

-/* Add a new field.  Return a temporary pointer to the field, which
-   is only valid until the next call to tdesc_add_field (the vector
-   might be reallocated).  */
+struct tdesc_type *
+tdesc_create_enum (struct tdesc_feature *feature, const char *name,
+		   int size)
+{
+  struct tdesc_type *type = XCNEW (struct tdesc_type);
+
+  gdb_assert (size > 0);
+
+  type->name = xstrdup (name);
+  type->kind = TDESC_TYPE_ENUM;
+  type->u.u.size = size;
+
+  VEC_safe_push (tdesc_type_p, feature->types, type);
+  return type;
+}
+
+/* Add a new field to TYPE.  */

 void
 tdesc_add_field (struct tdesc_type *type, const char *field_name,
@@ -1390,39 +1435,88 @@ tdesc_add_field (struct tdesc_type *type, const char *field_name,

   f.name = xstrdup (field_name);
   f.type = field_type;
+  /* Initialize these values so we know this is not a bit-field
+     when we print-c-tdesc.  */
+  f.start = -1;
+  f.end = -1;

   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }

-/* Add a new bitfield.  */
+/* Add a new typed bitfield to TYPE.  */

 void
-tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
-		    int start, int end)
+tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
+			  int start, int end, struct tdesc_type *field_type)
 {
   struct tdesc_type_field f = { 0 };

-  gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+  gdb_assert (type->kind == TDESC_TYPE_STRUCT
+	      || type->kind == TDESC_TYPE_FLAGS);
+  gdb_assert (start >= 0 && end >= start);

   f.name = xstrdup (field_name);
   f.start = start;
   f.end = end;
+  f.type = field_type;

   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }

+/* Add a new untyped bitfield to TYPE.
+   Untyped bitfields become either uint32 or uint64 depending on the size
+   of the underlying type.  */
+
+void
+tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
+		    int start, int end)
+{
+  struct tdesc_type *field_type;
+
+  gdb_assert (start >= 0 && end >= start);
+
+  if (type->u.u.size > 4)
+    field_type = tdesc_predefined_type (TDESC_TYPE_UINT64);
+  else
+    field_type = tdesc_predefined_type (TDESC_TYPE_UINT32);
+
+  tdesc_add_typed_bitfield (type, field_name, start, end, field_type);
+}
+
+/* A flag is just a typed(bool) single-bit bitfield.
+   This function is kept to minimize changes in generated files.  */
+
 void
 tdesc_add_flag (struct tdesc_type *type, int start,
 		const char *flag_name)
 {
-  struct tdesc_type_flag f = { 0 };
+  struct tdesc_type_field f = { 0 };

-  gdb_assert (type->kind == TDESC_TYPE_FLAGS);
+  gdb_assert (type->kind == TDESC_TYPE_FLAGS
+	      || type->kind == TDESC_TYPE_STRUCT);

   f.name = xstrdup (flag_name);
   f.start = start;
+  f.end = start;
+  f.type = tdesc_predefined_type (TDESC_TYPE_BOOL);

-  VEC_safe_push (tdesc_type_flag, type->u.f.flags, &f);
+  VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
+}
+
+void
+tdesc_add_enum_value (struct tdesc_type *type, int value,
+		      const char *name)
+{
+  struct tdesc_type_field f = { 0 };
+
+  gdb_assert (type->kind == TDESC_TYPE_ENUM);
+
+  f.name = xstrdup (name);
+  f.start = value;
+  f.end = -1;
+  f.type = tdesc_predefined_type (TDESC_TYPE_INT32);
+
+  VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }

 static void
@@ -1623,7 +1717,6 @@ maint_print_c_tdesc_cmd (char *args, int from_tty)
   struct tdesc_reg *reg;
   struct tdesc_type *type;
   struct tdesc_type_field *f;
-  struct tdesc_type_flag *flag;
   int ix, ix2, ix3;
   int printed_field_type = 0;

@@ -1686,11 +1779,11 @@ maint_print_c_tdesc_cmd (char *args, int from_tty)
 	      printed_field_type = 1;
 	    }

-	  if (((type->kind == TDESC_TYPE_UNION
-		|| type->kind == TDESC_TYPE_STRUCT)
-	       && VEC_length (tdesc_type_field, type->u.u.fields) > 0)
-	      || (type->kind == TDESC_TYPE_FLAGS
-		  && VEC_length (tdesc_type_flag, type->u.f.flags) > 0))
+	  if ((type->kind == TDESC_TYPE_UNION
+	       || type->kind == TDESC_TYPE_STRUCT
+	       || type->kind == TDESC_TYPE_FLAGS
+	       || type->kind == TDESC_TYPE_ENUM)
+	      && VEC_length (tdesc_type_field, type->u.u.fields) > 0)
 	    {
 	      printf_unfiltered ("  struct tdesc_type *type;\n");
 	      printed_desc_type = 1;
@@ -1761,33 +1854,77 @@ feature = tdesc_create_feature (result, \"%s\");\n",
 		 type->name, type->u.v.count);
 	      break;
 	    case TDESC_TYPE_STRUCT:
-	      printf_unfiltered
-		("  type = tdesc_create_struct (feature, \"%s\");\n",
-		 type->name);
-	      if (type->u.u.size != 0)
-		printf_unfiltered
-		  ("  tdesc_set_struct_size (type, %s);\n",
-		   plongest (type->u.u.size));
+	    case TDESC_TYPE_FLAGS:
+	      if (type->kind == TDESC_TYPE_STRUCT)
+		{
+		  printf_unfiltered
+		    ("  type = tdesc_create_struct (feature, \"%s\");\n",
+		     type->name);
+		  if (type->u.u.size != 0)
+		    printf_unfiltered
+		      ("  tdesc_set_struct_size (type, %d);\n",
+		       type->u.u.size);
+		}
+	      else
+		{
+		  printf_unfiltered
+		    ("  type = tdesc_create_flags (feature, \"%s\", %d);\n",
+		     type->name, type->u.u.size);
+		}
 	      for (ix3 = 0;
 		   VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
 		   ix3++)
 		{
-		  /* Going first for implicitly sized types, else part handles
-		     bitfields.  As reported on xml-tdesc.c implicitly sized types
-		     cannot contain a bitfield.  */
-		  if (f->type != NULL)
+		  const char *type_name;
+
+		  gdb_assert (f->type != NULL);
+		  type_name = f->type->name;
+
+		  /* To minimize changes to generated files, don't emit type
+		     info for fields that have defaulted types.  */
+		  if (f->start != -1)
+		    {
+		      gdb_assert (f->end != -1);
+		      if (f->type->kind == TDESC_TYPE_BOOL)
+			{
+			  gdb_assert (f->start == f->end);
+			  printf_unfiltered
+			    ("  tdesc_add_flag (type, %d, \"%s\");\n",
+			     f->start, f->name);
+			}
+		      else if ((type->u.u.size == 4
+				&& f->type->kind == TDESC_TYPE_UINT32)
+			       || (type->u.u.size == 8
+				   && f->type->kind == TDESC_TYPE_UINT64))
+			{
+			  printf_unfiltered
+			    ("  tdesc_add_bitfield (type, \"%s\", %d, %d);\n",
+			     f->name, f->start, f->end);
+			}
+		      else
+			{
+			  printf_unfiltered
+			    ("  field_type = tdesc_named_type (feature,"
+			     " \"%s\");\n",
+			     type_name);
+			  printf_unfiltered
+			    ("  tdesc_add_typed_bitfield (type, \"%s\","
+			     " %d, %d, field_type);\n",
+			     f->name, f->start, f->end);
+			}
+		    }
+		  else /* Not a bitfield.  */
 		    {
+		      gdb_assert (f->end == -1);
+		      gdb_assert (type->kind == TDESC_TYPE_STRUCT);
 		      printf_unfiltered
-			("  field_type = tdesc_named_type (feature, \"%s\");\n",
-			 f->type->name);
+			("  field_type = tdesc_named_type (feature,"
+			 " \"%s\");\n",
+			 type_name);
 		      printf_unfiltered
 			("  tdesc_add_field (type, \"%s\", field_type);\n",
 			 f->name);
 		    }
-		  else
-		    printf_unfiltered
-		      ("  tdesc_add_bitfield (type, \"%s\", %d, %d);\n",
-		       f->name, f->start, f->end);
 		}
 	      break;
 	    case TDESC_TYPE_UNION:
@@ -1806,17 +1943,16 @@ feature = tdesc_create_feature (result, \"%s\");\n",
 		     f->name);
 		}
 	      break;
-	    case TDESC_TYPE_FLAGS:
+	    case TDESC_TYPE_ENUM:
 	      printf_unfiltered
-		("  type = tdesc_create_flags (feature, \"%s\", %d);\n",
-		 type->name, (int) type->u.f.size);
+		("  type = tdesc_create_enum (feature, \"%s\", %d);\n",
+		 type->name, type->u.u.size);
 	      for (ix3 = 0;
-		   VEC_iterate (tdesc_type_flag, type->u.f.flags, ix3,
-				flag);
+		   VEC_iterate (tdesc_type_field, type->u.u.fields, ix3, f);
 		   ix3++)
 		printf_unfiltered
-		  ("  tdesc_add_flag (type, %d, \"%s\");\n",
-		   flag->start, flag->name);
+		  ("  tdesc_add_enum_value (type, %d, \"%s\");\n",
+		   f->start, f->name);
 	      break;
 	    default:
 	      error (_("C output is not supported type \"%s\"."), type->name);
diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h
index f777a92..ef97d1d 100644
--- a/gdb/target-descriptions.h
+++ b/gdb/target-descriptions.h
@@ -235,12 +235,20 @@ struct tdesc_type *tdesc_create_union (struct tdesc_feature *feature,
 struct tdesc_type *tdesc_create_flags (struct tdesc_feature *feature,
 				       const char *name,
 				       int size);
+struct tdesc_type *tdesc_create_enum (struct tdesc_feature *feature,
+				      const char *name,
+				      int size);
 void tdesc_add_field (struct tdesc_type *type, const char *field_name,
 		      struct tdesc_type *field_type);
+void tdesc_add_typed_bitfield (struct tdesc_type *type, const char *field_name,
+			       int start, int end,
+			       struct tdesc_type *field_type);
 void tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
 			 int start, int end);
 void tdesc_add_flag (struct tdesc_type *type, int start,
 		     const char *flag_name);
+void tdesc_add_enum_value (struct tdesc_type *type, int value,
+			   const char *name);
 void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
 		       int regnum, int save_restore, const char *group,
 		       int bitsize, const char *type);
diff --git a/gdb/testsuite/gdb.xml/extra-regs.xml b/gdb/testsuite/gdb.xml/extra-regs.xml
index f0db04e..cbbaf76 100644
--- a/gdb/testsuite/gdb.xml/extra-regs.xml
+++ b/gdb/testsuite/gdb.xml/extra-regs.xml
@@ -23,6 +23,30 @@
       <field name="Y" start="2" end="2"/>
     </flags>

+    <enum id="Z_values" size="4">
+      <evalue name="yes" value="1"/>
+      <evalue name="no" value="0"/>
+      <evalue name="maybe" value="2"/>
+      <evalue name="so" value="3"/>
+    </enum>
+
+    <flags id="mixed_flags" size="4">
+      <!-- Elided end and type. -->
+      <field name="A" start="0"/>
+      <!-- Elided end, unsigned int. -->
+      <field name="B" start="1" type="uint32"/>
+      <!-- Elided end, bool. -->
+      <field name="C" start="2" type="bool"/>
+      <!-- Elided type, single bitfield. -->
+      <field name="D" start="3" end="3"/>
+      <!-- Anonymous field. -->
+      <field name="" start="4" end="5"/>
+      <!-- Multi-bit bitfield, elided type. -->
+      <field name="E" start="6" end="7"/>
+      <!-- Enum bitfield. -->
+      <field name="Z" start="8" end="9" type="Z_values"/>
+    </flags>
+
     <reg name="extrareg" bitsize="32"/>
     <reg name="uintreg" bitsize="32" type="uint32"/>
     <reg name="vecreg" bitsize="32" type="v4int8"/>
@@ -30,5 +54,6 @@
     <reg name="structreg" bitsize="64" type="struct1"/>
     <reg name="bitfields" bitsize="64" type="struct2"/>
     <reg name="flags" bitsize="32" type="flags"/>
+    <reg name="mixed_flags" bitsize="32" type="mixed_flags"/>
   </feature>
 </target>
diff --git a/gdb/testsuite/gdb.xml/tdesc-regs.exp b/gdb/testsuite/gdb.xml/tdesc-regs.exp
index 80e1008..48204cd 100644
--- a/gdb/testsuite/gdb.xml/tdesc-regs.exp
+++ b/gdb/testsuite/gdb.xml/tdesc-regs.exp
@@ -106,7 +106,7 @@ foreach src ${core-regs} {
 }

 # Similarly, we need to copy files under test into the objdir.
-proc load_description { file errmsg } {
+proc load_description { file errmsg xml_file } {
     global srcdir
     global subdir
     global gdb_prompt
@@ -114,7 +114,7 @@ proc load_description { file errmsg } {
     global architecture
     global remote_filename

-    set regs_file [standard_output_file regs.xml]
+    set regs_file [standard_output_file $xml_file]

     file delete $regs_file
     set ifd [open "$srcdir/$subdir/$file" r]
@@ -135,22 +135,18 @@ proc load_description { file errmsg } {
     close $ofd

     if {[is_remote host]} {
-	set regs_file [remote_download host "$subdir/regs.xml" "regs.xml"]
+	set regs_file [remote_download host "$subdir/$xml_file" $xml_file]
     }

     # Anchor the test output, so that error messages are detected.
     set cmd "set tdesc filename [file tail $regs_file]"
-    set msg "set tdesc filename regs.xml - from $file"
+    set msg "set tdesc filename $xml_file - from $file"
     set cmd_regex [string_to_regexp $cmd]
     gdb_test_multiple $cmd $msg {
 	-re "^$cmd_regex\r\n$errmsg$gdb_prompt $" {
 	    pass $msg
 	}
     }
-
-    if {[is_remote host]} {
-	remote_file host delete "regs.xml"
-    }
 }

 if {![is_remote host]} {
@@ -158,7 +154,7 @@ if {![is_remote host]} {
 	"cd to directory holding xml"
 }

-load_description "extra-regs.xml" ""
+load_description "extra-regs.xml" "" "test-extra-regs.xml"
 gdb_test "ptype \$extrareg" "type = (int|long|long long)"
 gdb_test "ptype \$uintreg" "type = uint32_t"
gdb_test "ptype \$vecreg" "type = int8_t __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
@@ -170,7 +166,11 @@ gdb_test "ptype \$structreg" \
gdb_test "ptype \$structreg.v4" "type = int8_t __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
 gdb_test "ptype \$bitfields" \
"type = struct struct2 {\r\n *uint64_t f1 : 35;\r\n *uint64_t f2 : 1;\r\n}"
+gdb_test "ptype \$flags" \
+    "type = flag flags {\r\n *uint32_t X @0;\r\n *uint32_t Y @2;\r\n}"
+gdb_test "ptype \$mixed_flags" \
+ "type = flag mixed_flags {\r\n *bool A @0;\r\n *uint32_t B @1;\r\n *bool C @2;\r\n *uint32_t D @3;\r\n *uint32_t @4-5;\r\n *uint32_t E @6-7;\r\n *enum {yes = 1, no = 0, maybe = 2, so} Z @8-9;\r\n}"

-load_description "core-only.xml" ""
+load_description "core-only.xml" "" "test-regs.xml"
 # The extra register from the previous description should be gone.
 gdb_test "ptype \$extrareg" "type = void"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index a9b03ec..720942b 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -98,6 +98,10 @@ static void set_output_radix (char *, int, struct cmd_list_element *);

 static void set_output_radix_1 (int, unsigned);

+static void val_print_type_code_flags (struct type *type,
+				       const gdb_byte *valaddr,
+				       struct ui_file *stream);
+
 void _initialize_valprint (void);

 #define PRINT_MAX_DEFAULT 200	/* Start print_max off at this value.  */
@@ -526,28 +530,17 @@ generic_val_print_ref (struct type *type, const gdb_byte *valaddr,
     }
 }

-/* generic_val_print helper for TYPE_CODE_ENUM.  */
+/* Helper function for generic_val_print_enum.
+   This is also used to print enums in TYPE_CODE_FLAGS values.  */

 static void
-generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
-			int embedded_offset, struct ui_file *stream,
-			const struct value *original_value,
-			const struct value_print_options *options)
+generic_val_print_enum_1 (struct type *type, LONGEST val,
+			  struct ui_file *stream)
 {
   unsigned int i;
   unsigned int len;
-  LONGEST val;
-  struct gdbarch *gdbarch = get_type_arch (type);
-  int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);

-  if (options->format)
-    {
-      val_print_scalar_formatted (type, valaddr, embedded_offset,
-				  original_value, options, 0, stream);
-      return;
-    }
   len = TYPE_NFIELDS (type);
-  val = unpack_long (type, valaddr + embedded_offset * unit_size);
   for (i = 0; i < len; i++)
     {
       QUIT;
@@ -597,6 +590,29 @@ generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
     print_longest (stream, 'd', 0, val);
 }

+/* generic_val_print helper for TYPE_CODE_ENUM.  */
+
+static void
+generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
+			int embedded_offset, struct ui_file *stream,
+			const struct value *original_value,
+			const struct value_print_options *options)
+{
+  LONGEST val;
+  struct gdbarch *gdbarch = get_type_arch (type);
+  int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);
+
+  if (options->format)
+    {
+      val_print_scalar_formatted (type, valaddr, embedded_offset,
+				  original_value, options, 0, stream);
+      return;
+    }
+  val = unpack_long (type, valaddr + embedded_offset * unit_size);
+
+  generic_val_print_enum_1 (type, val, stream);
+}
+
 /* generic_val_print helper for TYPE_CODE_FLAGS.  */

 static void
@@ -1162,26 +1178,51 @@ val_print_type_code_int (struct type *type, const gdb_byte *valaddr,
     }
 }

-void
+static void
 val_print_type_code_flags (struct type *type, const gdb_byte *valaddr,
 			   struct ui_file *stream)
 {
   ULONGEST val = unpack_long (type, valaddr);
-  int bitpos, nfields = TYPE_NFIELDS (type);
+  int field, nfields = TYPE_NFIELDS (type);
+  struct gdbarch *gdbarch = get_type_arch (type);
+  struct type *bool_type = builtin_type (gdbarch)->builtin_bool;

-  fputs_filtered ("[ ", stream);
-  for (bitpos = 0; bitpos < nfields; bitpos++)
+  fputs_filtered ("[", stream);
+  for (field = 0; field < nfields; field++)
     {
-      if (TYPE_FIELD_BITPOS (type, bitpos) != -1
-	  && (val & ((ULONGEST)1 << bitpos)))
+      if (TYPE_FIELD_NAME (type, field)[0] != '\0')
 	{
-	  if (TYPE_FIELD_NAME (type, bitpos))
-	    fprintf_filtered (stream, "%s ", TYPE_FIELD_NAME (type, bitpos));
+	  struct type *field_type = TYPE_FIELD_TYPE (type, field);
+
+	  if (field_type == bool_type
+	      /* We require boolean types here to be one bit wide.  This is a
+		 problematic place to notify the user of an internal error
+		 though.  Instead just fall through and print the field as an
+		 int.  */
+	      && TYPE_FIELD_BITSIZE (type, field) == 1)
+	    {
+	      if (val & ((ULONGEST)1 << TYPE_FIELD_BITPOS (type, field)))
+		fprintf_filtered (stream, " %s",
+				  TYPE_FIELD_NAME (type, field));
+	    }
 	  else
-	    fprintf_filtered (stream, "#%d ", bitpos);
+	    {
+	      unsigned field_len = TYPE_FIELD_BITSIZE (type, field);
+	      ULONGEST field_val
+		= val >> (TYPE_FIELD_BITPOS (type, field) - field_len + 1);
+
+	      if (field_len < sizeof (ULONGEST) * TARGET_CHAR_BIT)
+		field_val &= ((ULONGEST) 1 << field_len) - 1;
+	      fprintf_filtered (stream, " %s=",
+				TYPE_FIELD_NAME (type, field));
+	      if (TYPE_CODE (field_type) == TYPE_CODE_ENUM)
+		generic_val_print_enum_1 (field_type, field_val, stream);
+	      else
+		print_longest (stream, 'd', 0, field_val);
+	    }
 	}
     }
-  fputs_filtered ("]", stream);
+  fputs_filtered (" ]", stream);
 }

 /* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
diff --git a/gdb/valprint.h b/gdb/valprint.h
index bb03024..1a83cb5 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -124,10 +124,6 @@ extern void val_print_array_elements (struct type *, const gdb_byte *, int,
 extern void val_print_type_code_int (struct type *, const gdb_byte *,
 				     struct ui_file *);

-extern void val_print_type_code_flags (struct type *type,
-				       const gdb_byte *valaddr,
-				       struct ui_file *stream);
-
 extern void val_print_scalar_formatted (struct type *,
 					const gdb_byte *, int,
 					const struct value *,
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index adfe9fd..a0fd08a 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -91,12 +91,9 @@ struct tdesc_parsing_data
   /* The struct or union we are currently parsing, or last parsed.  */
   struct tdesc_type *current_type;

-  /* The byte size of the current struct type, if specified.  Zero
-     if not specified.  */
+  /* The byte size of the current struct/flags type, if specified.  Zero
+     if not specified.  Flags values must specify a size.  */
   int current_type_size;
-
-  /* Whether the current type is a flags type.  */
-  int current_type_is_flags;
 };

 /* Handle the end of an <architecture> element and its value.  */
@@ -240,7 +237,6 @@ tdesc_start_union (struct gdb_xml_parser *parser,

   data->current_type = tdesc_create_union (data->current_feature, id);
   data->current_type_size = 0;
-  data->current_type_is_flags = 0;
 }

 /* Handle the start of a <struct> element.  Initialize the type and
@@ -259,7 +255,6 @@ tdesc_start_struct (struct gdb_xml_parser *parser,
   type = tdesc_create_struct (data->current_feature, id);
   data->current_type = type;
   data->current_type_size = 0;
-  data->current_type_is_flags = 0;

   attr = xml_find_attribute (attributes, "size");
   if (attr != NULL)
@@ -297,12 +292,34 @@ tdesc_start_flags (struct gdb_xml_parser *parser,
   type = tdesc_create_flags (data->current_feature, id, size);

   data->current_type = type;
+  data->current_type_size = size;
+}
+
+static void
+tdesc_start_enum (struct gdb_xml_parser *parser,
+		  const struct gdb_xml_element *element,
+		  void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct tdesc_parsing_data *data = user_data;
+  char *id = xml_find_attribute (attributes, "id")->value;
+  int size = * (ULONGEST *)
+    xml_find_attribute (attributes, "size")->value;
+  struct tdesc_type *type;
+
+  if (size > MAX_FIELD_SIZE)
+    {
+      gdb_xml_error (parser,
+		     _("Enum size %s is larger than maximum (%d)"),
+		     pulongest (size), MAX_FIELD_SIZE);
+    }
+  type = tdesc_create_enum (data->current_feature, id, size);
+
+  data->current_type = type;
   data->current_type_size = 0;
-  data->current_type_is_flags = 1;
 }

 /* Handle the start of a <field> element.  Attach the field to the
-   current struct or union.  */
+   current struct, union or flags.  */

 static void
 tdesc_start_field (struct gdb_xml_parser *parser,
@@ -319,9 +336,15 @@ tdesc_start_field (struct gdb_xml_parser *parser,

   attr = xml_find_attribute (attributes, "type");
   if (attr != NULL)
-    field_type_id = (char *) attr->value;
+    {
+      field_type_id = (char *) attr->value;
+      field_type = tdesc_named_type (data->current_feature, field_type_id);
+    }
   else
-    field_type_id = NULL;
+    {
+      field_type_id = NULL;
+      field_type = NULL;
+    }

   attr = xml_find_attribute (attributes, "start");
   if (attr != NULL)
@@ -355,65 +378,107 @@ tdesc_start_field (struct gdb_xml_parser *parser,
   else
     end = -1;

-  if (field_type_id != NULL)
-    {
-      if (data->current_type_is_flags)
-	gdb_xml_error (parser, _("Cannot add typed field \"%s\" to flags"),
-		       field_name);
-      if (data->current_type_size != 0)
-	gdb_xml_error (parser,
-		       _("Explicitly sized type can not "
-			 "contain non-bitfield \"%s\""),
-		       field_name);
-
-      field_type = tdesc_named_type (data->current_feature, field_type_id);
-      if (field_type == NULL)
-	gdb_xml_error (parser, _("Field \"%s\" references undefined "
-				 "type \"%s\""),
-		       field_name, field_type_id);
-
-      tdesc_add_field (data->current_type, field_name, field_type);
-    }
-  else if (start != -1 && end != -1)
+  if (start != -1)
     {
       struct tdesc_type *t = data->current_type;

-      if (data->current_type_is_flags)
-	tdesc_add_flag (t, start, field_name);
-      else
+      if (data->current_type_size == 0)
+	gdb_xml_error (parser,
+		       _("Bitfields must live in explicitly sized types"));
+
+      if (field_type_id != NULL
+	  && strcmp (field_type_id, "bool") == 0
+	  && !(start == end || end == -1))
 	{
-	  if (data->current_type_size == 0)
-	    gdb_xml_error (parser,
-			   _("Implicitly sized type can "
-			     "not contain bitfield \"%s\""),
-			   field_name);
+	  gdb_xml_error (parser,
+			 _("Boolean fields must be one bit in size"));
+	}

-	  if (end >= 64)
-	    gdb_xml_error (parser,
-			   _("Bitfield \"%s\" goes past "
-			     "64 bits (unsupported)"),
-			   field_name);
+      if (end >= 64)
+	gdb_xml_error (parser,
+		       _("Bitfield \"%s\" goes past "
+			 "64 bits (unsupported)"),
+		       field_name);

+      if (end != -1)
+	{
 	  /* Assume that the bit numbering in XML is "lsb-zero".  Most
-	     architectures other than PowerPC use this ordering.  In
-	     the future, we can add an XML tag to indicate "msb-zero"
+	     architectures other than PowerPC use this ordering.  In the
+	     future, we can add an XML tag to indicate "msb-zero"
 	     numbering.  */
 	  if (start > end)
 	    gdb_xml_error (parser, _("Bitfield \"%s\" has start after end"),
 			   field_name);
-
 	  if (end >= data->current_type_size * TARGET_CHAR_BIT)
 	    gdb_xml_error (parser,
 			   _("Bitfield \"%s\" does not fit in struct"));
+	}

-	  tdesc_add_bitfield (t, field_name, start, end);
+      if (end == -1)
+	{
+	  if (field_type != NULL)
+	    tdesc_add_typed_bitfield (t, field_name, start, start, field_type);
+	  else
+	    tdesc_add_flag (t, start, field_name);
 	}
+      else if (field_type != NULL)
+	tdesc_add_typed_bitfield (t, field_name, start, end, field_type);
+      else
+	tdesc_add_bitfield (t, field_name, start, end);
+    }
+  else if (start == -1 && end != -1)
+    gdb_xml_error (parser, _("End specified but not start"));
+  else if (field_type_id != NULL)
+    {
+ /* TDESC_TYPE_FLAGS values are explicitly sized, so the following test
+	 catches adding non-bitfield types to flags as well.  */
+      if (data->current_type_size != 0)
+	gdb_xml_error (parser,
+		       _("Explicitly sized type cannot "
+			 "contain non-bitfield \"%s\""),
+		       field_name);
+
+      if (field_type == NULL)
+	gdb_xml_error (parser, _("Field \"%s\" references undefined "
+				 "type \"%s\""),
+		       field_name, field_type_id);
+
+      tdesc_add_field (data->current_type, field_name, field_type);
     }
   else
gdb_xml_error (parser, _("Field \"%s\" has neither type nor bit position"),
 		   field_name);
 }

+/* Handle the start of an <evalue> element.  Attach the value to the
+   current enum.  */
+
+static void
+tdesc_start_enum_value (struct gdb_xml_parser *parser,
+			const struct gdb_xml_element *element,
+			void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+  struct gdb_xml_value *attr;
+  char *field_name;
+  ULONGEST ul_value;
+  int value;
+
+  field_name = (char *) xml_find_attribute (attributes, "name")->value;
+
+  attr = xml_find_attribute (attributes, "value");
+  ul_value = * (ULONGEST *) attr->value;
+  if (ul_value > INT_MAX)
+    {
+      gdb_xml_error (parser,
+		     _("Enum value %s is larger than maximum (%d)"),
+		     pulongest (ul_value), INT_MAX);
+    }
+  value = ul_value;
+
+  tdesc_add_enum_value (data->current_type, value, field_name);
+}
+
 /* Handle the start of a <vector> element.  Initialize the type and
    record it with the current feature.  */

@@ -457,12 +522,24 @@ static const struct gdb_xml_attribute field_attributes[] = {
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };

+static const struct gdb_xml_attribute enum_value_attributes[] = {
+  { "name", GDB_XML_AF_NONE, NULL, NULL },
+  { "value", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_element struct_union_children[] = {
   { "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE,
     tdesc_start_field, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };

+static const struct gdb_xml_element enum_children[] = {
+  { "evalue", enum_value_attributes, NULL, GDB_XML_EF_REPEATABLE,
+    tdesc_start_enum_value, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute reg_attributes[] = {
   { "name", GDB_XML_AF_NONE, NULL, NULL },
   { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
@@ -486,6 +563,12 @@ static const struct gdb_xml_attribute flags_attributes[] = {
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };

+static const struct gdb_xml_attribute enum_attributes[] = {
+  { "id", GDB_XML_AF_NONE, NULL, NULL },
+  { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL},
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute vector_attributes[] = {
   { "id", GDB_XML_AF_NONE, NULL, NULL },
   { "type", GDB_XML_AF_NONE, NULL, NULL },
@@ -511,6 +594,9 @@ static const struct gdb_xml_element feature_children[] = {
   { "flags", flags_attributes, struct_union_children,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_flags, NULL },
+  { "enum", enum_attributes, enum_children,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_enum, NULL },
   { "vector", vector_attributes, NULL,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_vector, NULL },


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]