* gdbtypes.c (append_composite_type_field_raw): New.
authorDaniel Jacobowitz <drow@false.org>
Mon, 1 Mar 2010 17:19:23 +0000 (17:19 +0000)
committerDaniel Jacobowitz <drow@false.org>
Mon, 1 Mar 2010 17:19:23 +0000 (17:19 +0000)
(append_composite_type_field_aligned): Use the new function.
* gdbtypes.h (append_composite_type_field_raw): Declare.
* target-descriptions.c (struct tdesc_type_field): Add start and end.
(struct tdesc_type_flag): New type.
(struct tdesc_type): Add TDESC_TYPE_STRUCT and TDESC_TYPE_FLAGS to
kind.  Add size to u.u.  Add u.f for flags.
(tdesc_gdb_type): Handle TDESC_TYPE_STRUCT and TDESC_TYPE_FLAGS.
(tdesc_free_type): Likewise.
(tdesc_create_struct, tdesc_set_struct_size, tdesc_create_flags): New.
(tdesc_add_field): Handle TDESC_TYPE_STRUCT.
(tdesc_add_bitfield, tdesc_add_flag): New.
* target-descriptions.h (tdesc_create_struct, tdesc_set_struct_size)
(tdesc_create_flags, tdesc_add_bitfield, tdesc_add_flag): Declare.
* xml-tdesc.c (struct tdesc_parsing_data): Rename current_union to
current_type.  Add current_type_size and current_type_is_flags.
(tdesc_start_union): Clear the new fields.
(tdesc_start_struct, tdesc_start_flags): New.
(tdesc_start_field): Handle struct fields, including bitfields.
(field_attributes): Make type optional.  Add start and end.
(union_children): Rename to struct_union_children.
(union_attributes): Rename to struct_union_attributes.  Add optional
size.
(flags_attributes): New.
(feature_children): Add struct and flags.
* features/gdb-target.dtd: Add flags and struct to features.
Make field type optional.  Add field start and end.

doc/
* gdb.texinfo (Types): Describe <struct> and <flags>.

testsuite/
* gdb.xml/extra-regs.xml: Add struct1, struct2, and flags
types.  Add structreg, bitfields, and flags registers.
* gdb.xml/tdesc-regs.exp: Test structreg and bitfields
registers.

12 files changed:
gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/features/gdb-target.dtd
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/target-descriptions.c
gdb/target-descriptions.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.xml/extra-regs.xml
gdb/testsuite/gdb.xml/tdesc-regs.exp
gdb/xml-tdesc.c

index 944a4ca06c17d619ac28eb67f3fac1f4ef28fa2a..bf50dd49c080339c9561390cb7beb27aa0d1e6c1 100644 (file)
@@ -1,3 +1,33 @@
+2010-03-01  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdbtypes.c (append_composite_type_field_raw): New.
+       (append_composite_type_field_aligned): Use the new function.
+       * gdbtypes.h (append_composite_type_field_raw): Declare.
+       * target-descriptions.c (struct tdesc_type_field): Add start and end.
+       (struct tdesc_type_flag): New type.
+       (struct tdesc_type): Add TDESC_TYPE_STRUCT and TDESC_TYPE_FLAGS to
+       kind.  Add size to u.u.  Add u.f for flags.
+       (tdesc_gdb_type): Handle TDESC_TYPE_STRUCT and TDESC_TYPE_FLAGS.
+       (tdesc_free_type): Likewise.
+       (tdesc_create_struct, tdesc_set_struct_size, tdesc_create_flags): New.
+       (tdesc_add_field): Handle TDESC_TYPE_STRUCT.
+       (tdesc_add_bitfield, tdesc_add_flag): New.
+       * target-descriptions.h (tdesc_create_struct, tdesc_set_struct_size)
+       (tdesc_create_flags, tdesc_add_bitfield, tdesc_add_flag): Declare.
+       * xml-tdesc.c (struct tdesc_parsing_data): Rename current_union to
+       current_type.  Add current_type_size and current_type_is_flags.
+       (tdesc_start_union): Clear the new fields.
+       (tdesc_start_struct, tdesc_start_flags): New.
+       (tdesc_start_field): Handle struct fields, including bitfields.
+       (field_attributes): Make type optional.  Add start and end.
+       (union_children): Rename to struct_union_children.
+       (union_attributes): Rename to struct_union_attributes.  Add optional
+       size.
+       (flags_attributes): New.
+       (feature_children): Add struct and flags.
+       * features/gdb-target.dtd: Add flags and struct to features.
+       Make field type optional.  Add field start and end.
+
 2010-03-01  H.J. Lu  <hongjiu.lu@intel.com>
 
        * amd64-linux-nat.c (AMD64_LINUX_USER64_CS): New.
index 078fdb9292756bbcb3aee07ff4162b0745944bac..ab9437928a20ffebdf572ecc897f947d9c3b74b5 100644 (file)
@@ -1,3 +1,7 @@
+2010-03-01  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.texinfo (Types): Describe <struct> and <flags>.
+
 2010-02-28  Phil Muldoon  <pmuldoon@redhat.com>
 
        * gdb.texinfo (Frames In Python): Add block parameter and
index 460d0d5409dadc8db56e96c95ad4c08b485a5f60..6bb7d52125352eb902cd1b02accc32b475cbe4ce 100644 (file)
@@ -33073,6 +33073,47 @@ each of which has a @var{name} and a @var{type}:
 </union>
 @end smallexample
 
+@cindex <struct>
+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.
+
+@smallexample
+<struct id="@var{id}" size="@var{size}">
+  <field name="@var{name}" start="@var{start}" end="@var{end}"/>
+  @dots{}
+</struct>
+@end smallexample
+
+If the structure contains no bitfields, then each field has an
+explicit type, and no implicit padding is added.
+
+@smallexample
+<struct id="@var{id}">
+  <field name="@var{name}" 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}"/>
+  @dots{}
+</flags>
+@end smallexample
+
 @subsection Registers
 @cindex <reg>
 
index 3ba7eca64e64e66efb8d0a8efea5c2b031ee18a1..d5710caa771778a0b2c6718802d83d8411561884 100644 (file)
@@ -19,7 +19,8 @@
 
 <!ELEMENT compatible   (#PCDATA)>
 
-<!ELEMENT feature      ((vector | union)*, reg*)>
+<!ELEMENT feature
+       ((vector | flags | struct | union )*, reg*)>
 <!ATTLIST feature
        name            ID      #REQUIRED>
 
        type            CDATA   #REQUIRED
        count           CDATA   #REQUIRED>
 
+<!ELEMENT flags                (field+)>
+<!ATTLIST flags
+       id              CDATA   #REQUIRED
+       size            CDATA   #REQUIRED>
+
+<!ELEMENT struct       (field+)>
+<!ATTLIST struct
+       id              CDATA   #REQUIRED
+       size            CDATA   #IMPLIED>
+
 <!ELEMENT union                (field+)>
 <!ATTLIST union
        id              CDATA   #REQUIRED>
@@ -46,7 +57,9 @@
 <!ELEMENT field                EMPTY>
 <!ATTLIST field
        name            CDATA   #REQUIRED
-       type            CDATA   #REQUIRED>
+       type            CDATA   #IMPLIED
+       start           CDATA   #IMPLIED
+       end             CDATA   #IMPLIED>
 
 <!ENTITY % xinclude SYSTEM "xinclude.dtd">
 %xinclude;
index 3269a8cdc8cfd3413df03442330bfce1f6be5871..f6de8784b84ed90364205629e2bb196e4b22c452 100644 (file)
@@ -3303,10 +3303,11 @@ arch_composite_type (struct gdbarch *gdbarch, char *name, enum type_code code)
 }
 
 /* Add new field with name NAME and type FIELD to composite type T.
-   ALIGNMENT (if non-zero) specifies the minimum field alignment.  */
-void
-append_composite_type_field_aligned (struct type *t, char *name,
-                                    struct type *field, int alignment)
+   Do not set the field's position or adjust the type's length;
+   the caller should do so.  Return the new field.  */
+struct field *
+append_composite_type_field_raw (struct type *t, char *name,
+                                struct type *field)
 {
   struct field *f;
   TYPE_NFIELDS (t) = TYPE_NFIELDS (t) + 1;
@@ -3316,6 +3317,16 @@ append_composite_type_field_aligned (struct type *t, char *name,
   memset (f, 0, sizeof f[0]);
   FIELD_TYPE (f[0]) = field;
   FIELD_NAME (f[0]) = name;
+  return f;
+}
+
+/* Add new field with name NAME and type FIELD to composite type T.
+   ALIGNMENT (if non-zero) specifies the minimum field alignment.  */
+void
+append_composite_type_field_aligned (struct type *t, char *name,
+                                    struct type *field, int alignment)
+{
+  struct field *f = append_composite_type_field_raw (t, name, field);
   if (TYPE_CODE (t) == TYPE_CODE_UNION)
     {
       if (TYPE_LENGTH (t) < TYPE_LENGTH (field))
index 2859ce9bfe95844b2175cc68a8dee55c7b05b3ce..0315d861921620e7c00c73f2b1c3fb8dddf93908 100644 (file)
@@ -1249,6 +1249,8 @@ extern void append_composite_type_field_aligned (struct type *t,
                                                 char *name,
                                                 struct type *field,
                                                 int alignment);
+struct field *append_composite_type_field_raw (struct type *t, char *name,
+                                              struct type *field);
 
 /* Helper functions to construct a bit flags type.  An initially empty
    type is created using arch_flag_type().  Flags are then added using
index 9856d6f76cafeb2b199e3c02a3761cb6b41c1a52..77dd37b8d29c983d7422ae2a8aa8aa29789223fa 100644 (file)
@@ -90,9 +90,17 @@ typedef struct tdesc_type_field
 {
   char *name;
   struct tdesc_type *type;
+  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);
+
 typedef struct tdesc_type
 {
   /* The name of this type.  */
@@ -123,7 +131,9 @@ typedef struct tdesc_type
 
     /* Types defined by a target feature.  */
     TDESC_TYPE_VECTOR,
-    TDESC_TYPE_UNION
+    TDESC_TYPE_STRUCT,
+    TDESC_TYPE_UNION,
+    TDESC_TYPE_FLAGS
   } kind;
 
   /* Kind-specific data.  */
@@ -136,11 +146,19 @@ typedef struct tdesc_type
       int count;
     } v;
 
-    /* Union type.  */
+    /* Struct or union type.  */
     struct
     {
       VEC(tdesc_type_field) *fields;
+      LONGEST size;
     } u;
+
+    /* Flags type.  */
+    struct
+    {
+      VEC(tdesc_type_flag) *flags;
+      LONGEST size;
+    } f;
   } u;
 } *tdesc_type_p;
 DEF_VEC_P(tdesc_type_p);
@@ -652,6 +670,66 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
        return type;
       }
 
+    case TDESC_TYPE_STRUCT:
+      {
+       struct type *type, *field_type;
+       struct tdesc_type_field *f;
+       int ix;
+
+       type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+       TYPE_NAME (type) = xstrdup (tdesc_type->name);
+       TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+       for (ix = 0;
+            VEC_iterate (tdesc_type_field, tdesc_type->u.u.fields, ix, f);
+            ix++)
+         {
+           if (f->type == NULL)
+             {
+               /* Bitfield.  */
+               struct field *fld;
+               struct type *field_type;
+               int bitsize, total_size;
+
+               /* This invariant should be preserved while creating
+                  types.  */
+               gdb_assert (tdesc_type->u.u.size != 0);
+               if (tdesc_type->u.u.size > 4)
+                 field_type = builtin_type (gdbarch)->builtin_uint64;
+               else
+                 field_type = builtin_type (gdbarch)->builtin_uint32;
+
+               fld = append_composite_type_field_raw (type, xstrdup (f->name),
+                                                      field_type);
+
+               /* For little-endian, BITPOS counts from the LSB of
+                  the structure and marks the LSB of the field.  For
+                  big-endian, BITPOS counts from the MSB of the
+                  structure and marks the MSB of the field.  Either
+                  way, it is the number of bits to the "left" of the
+                  field.  To calculate this in big-endian, we need
+                  the total size of the structure.  */
+               bitsize = f->end - f->start + 1;
+               total_size = tdesc_type->u.u.size * TARGET_CHAR_BIT;
+               if (gdbarch_bits_big_endian (gdbarch))
+                 FIELD_BITPOS (fld[0]) = total_size - f->start - bitsize;
+               else
+                 FIELD_BITPOS (fld[0]) = f->start;
+               FIELD_BITSIZE (fld[0]) = bitsize;
+             }
+           else
+             {
+               field_type = tdesc_gdb_type (gdbarch, f->type);
+               append_composite_type_field (type, xstrdup (f->name),
+                                            field_type);
+             }
+         }
+
+       if (tdesc_type->u.u.size != 0)
+         TYPE_LENGTH (type) = tdesc_type->u.u.size;
+       return type;
+      }
+
     case TDESC_TYPE_UNION:
       {
        struct type *type, *field_type;
@@ -668,12 +746,30 @@ tdesc_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *tdesc_type)
            field_type = tdesc_gdb_type (gdbarch, f->type);
            append_composite_type_field (type, xstrdup (f->name), field_type);
 
-           /* If any of the children of this union are vectors, flag the
+           /* If any of the children of a union are vectors, flag the
               union as a vector also.  This allows e.g. a union of two
               vector types to show up automatically in "info vector".  */
            if (TYPE_VECTOR (field_type))
              TYPE_VECTOR (type) = 1;
          }
+       return type;
+      }
+
+    case TDESC_TYPE_FLAGS:
+      {
+       struct type *type, *field_type;
+       struct tdesc_type_flag *f;
+       int ix;
+
+       type = arch_flags_type (gdbarch, xstrdup (tdesc_type->name),
+                               tdesc_type->u.f.size);
+       for (ix = 0;
+            VEC_iterate (tdesc_type_flag, tdesc_type->u.f.flags, 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);
 
        return type;
       }
@@ -1161,6 +1257,7 @@ tdesc_free_type (struct tdesc_type *type)
 
   switch (type->kind)
     {
+    case TDESC_TYPE_STRUCT:
     case TDESC_TYPE_UNION:
       {
        struct tdesc_type_field *f;
@@ -1175,6 +1272,20 @@ 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;
     }
@@ -1198,6 +1309,29 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
   return type;
 }
 
+struct tdesc_type *
+tdesc_create_struct (struct tdesc_feature *feature, const char *name)
+{
+  struct tdesc_type *type = XZALLOC (struct tdesc_type);
+
+  type->name = xstrdup (name);
+  type->kind = TDESC_TYPE_STRUCT;
+
+  VEC_safe_push (tdesc_type_p, feature->types, type);
+  return type;
+}
+
+/* Set the total length of TYPE.  Structs which contain bitfields may
+   omit the reserved bits, so the end of the last field may not
+   suffice.  */
+
+void
+tdesc_set_struct_size (struct tdesc_type *type, LONGEST size)
+{
+  gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+  type->u.u.size = size;
+}
+
 struct tdesc_type *
 tdesc_create_union (struct tdesc_feature *feature, const char *name)
 {
@@ -1210,13 +1344,32 @@ tdesc_create_union (struct tdesc_feature *feature, const char *name)
   return type;
 }
 
+struct tdesc_type *
+tdesc_create_flags (struct tdesc_feature *feature, const char *name,
+                   LONGEST size)
+{
+  struct tdesc_type *type = XZALLOC (struct tdesc_type);
+
+  type->name = xstrdup (name);
+  type->kind = TDESC_TYPE_FLAGS;
+  type->u.f.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).  */
+
 void
 tdesc_add_field (struct tdesc_type *type, const char *field_name,
                 struct tdesc_type *field_type)
 {
   struct tdesc_type_field f = { 0 };
 
-  gdb_assert (type->kind == TDESC_TYPE_UNION);
+  gdb_assert (type->kind == TDESC_TYPE_UNION
+             || type->kind == TDESC_TYPE_STRUCT);
 
   f.name = xstrdup (field_name);
   f.type = field_type;
@@ -1224,6 +1377,37 @@ tdesc_add_field (struct tdesc_type *type, const char *field_name,
   VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
 }
 
+/* Add a new bitfield.  */
+
+void
+tdesc_add_bitfield (struct tdesc_type *type, const char *field_name,
+                   int start, int end)
+{
+  struct tdesc_type_field f = { 0 };
+
+  gdb_assert (type->kind == TDESC_TYPE_STRUCT);
+
+  f.name = xstrdup (field_name);
+  f.start = start;
+  f.end = end;
+
+  VEC_safe_push (tdesc_type_field, type->u.u.fields, &f);
+}
+
+void
+tdesc_add_flag (struct tdesc_type *type, int start,
+               const char *flag_name)
+{
+  struct tdesc_type_flag f = { 0 };
+
+  gdb_assert (type->kind == TDESC_TYPE_FLAGS);
+
+  f.name = xstrdup (flag_name);
+  f.start = start;
+
+  VEC_safe_push (tdesc_type_flag, type->u.f.flags, &f);
+}
+
 static void
 tdesc_free_feature (struct tdesc_feature *feature)
 {
index da0564b556c7afa54274b5c2bf391c6bd4fe711c..caa72302df1307ec01839121072e44d5c47de585 100644 (file)
@@ -205,10 +205,20 @@ struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
                                        const char *name,
                                        struct tdesc_type *field_type,
                                        int count);
+struct tdesc_type *tdesc_create_struct (struct tdesc_feature *feature,
+                                       const char *name);
+void tdesc_set_struct_size (struct tdesc_type *type, LONGEST size);
 struct tdesc_type *tdesc_create_union (struct tdesc_feature *feature,
                                       const char *name);
+struct tdesc_type *tdesc_create_flags (struct tdesc_feature *feature,
+                                      const char *name,
+                                      LONGEST size);
 void tdesc_add_field (struct tdesc_type *type, const char *field_name,
                      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_create_reg (struct tdesc_feature *feature, const char *name,
                       int regnum, int save_restore, const char *group,
                       int bitsize, const char *type);
index fbc50a7404f813ccb1cdffaa412212544eda0a11..ae3a54833a6ff296c84d028164dabd0a2db49f63 100644 (file)
@@ -1,3 +1,10 @@
+2010-03-01  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.xml/extra-regs.xml: Add struct1, struct2, and flags
+       types.  Add structreg, bitfields, and flags registers.
+       * gdb.xml/tdesc-regs.exp: Test structreg and bitfields
+       registers.
+
 2010-03-01  H.J. Lu  <hongjiu.lu@intel.com>
 
        * gdb.xml/tdesc-regs.exp (architecture): New.  Set it for x86.
index 5db426bede2290dadf79b6a4790b4e3b0719fb68..f0db04e6bc632fb8965499e13e7405f6591c5fc1 100644 (file)
@@ -8,9 +8,27 @@
       <field name="v2" type="v2int16"/>
     </union>
 
+    <struct id="struct1">
+      <field name="v4" type="v4int8"/>
+      <field name="v2" type="v2int16"/>
+    </struct>
+
+    <struct id="struct2" size="8">
+      <field name="f1" start="0" end="34"/>
+      <field name="f2" start="63" end="63"/>
+    </struct>
+
+    <flags id="flags" size="4">
+      <field name="X" start="0" end="0"/>
+      <field name="Y" start="2" end="2"/>
+    </flags>
+
     <reg name="extrareg" bitsize="32"/>
     <reg name="uintreg" bitsize="32" type="uint32"/>
     <reg name="vecreg" bitsize="32" type="v4int8"/>
     <reg name="unionreg" bitsize="32" type="vecint"/>
+    <reg name="structreg" bitsize="64" type="struct1"/>
+    <reg name="bitfields" bitsize="64" type="struct2"/>
+    <reg name="flags" bitsize="32" type="flags"/>
   </feature>
 </target>
index 8eae0bd1183acd1056b4537f2f7068ac1be71b65..f37b2f3cb111ace76ce42995637d426eee3711dd 100644 (file)
@@ -141,6 +141,11 @@ gdb_test "ptype \$vecreg" "type = int8_t \\\[4\\\]"
 gdb_test "ptype \$unionreg" \
     "type = union {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
 gdb_test "ptype \$unionreg.v4" "type = int8_t \\\[4\\\]"
+gdb_test "ptype \$structreg" \
+    "type = struct struct1 {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}"
+gdb_test "ptype \$structreg.v4" "type = int8_t \\\[4\\\]"
+gdb_test "ptype \$bitfields" \
+    "type = struct struct2 {\r\n *uint64_t f1 : 35;\r\n *uint64_t f2 : 1;\r\n}"
 
 load_description "core-only.xml" ""
 # The extra register from the previous description should be gone.
index 90dacf6a85495edcbbda54ba4393cced76e9b955..1d78cad33ccdf3ce43475e8e64caef5cafa431dd 100644 (file)
@@ -85,8 +85,15 @@ struct tdesc_parsing_data
      it does not have its own.  This starts at zero.  */
   int next_regnum;
 
-  /* The union we are currently parsing, or last parsed.  */
-  struct tdesc_type *current_union;
+  /* 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.  */
+  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.  */
@@ -229,11 +236,57 @@ tdesc_start_union (struct gdb_xml_parser *parser,
   struct tdesc_parsing_data *data = user_data;
   char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
 
-  data->current_union = tdesc_create_union (data->current_feature, id);
+  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
+   record it with the current feature.  */
+
+static void
+tdesc_start_struct (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 = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+  struct tdesc_type *type;
+
+  type = tdesc_create_struct (data->current_feature, id);
+  data->current_type = type;
+  data->current_type_size = 0;
+  data->current_type_is_flags = 0;
+
+  if (VEC_length (gdb_xml_value_s, attributes) > 1)
+    {
+      int size = (int) * (ULONGEST *)
+       VEC_index (gdb_xml_value_s, attributes, 1)->value;
+      tdesc_set_struct_size (type, size);
+      data->current_type_size = size;
+    }
+}
+
+static void
+tdesc_start_flags (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 = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+  int length = (int) * (ULONGEST *)
+    VEC_index (gdb_xml_value_s, attributes, 1)->value;
+  struct tdesc_type *type;
+
+  type = tdesc_create_flags (data->current_feature, id, length);
+
+  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 union.  */
+   current struct or union.  */
 
 static void
 tdesc_start_field (struct gdb_xml_parser *parser,
@@ -241,20 +294,84 @@ tdesc_start_field (struct gdb_xml_parser *parser,
                   void *user_data, VEC(gdb_xml_value_s) *attributes)
 {
   struct tdesc_parsing_data *data = user_data;
+  int ix = 0, length;
   struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
   struct tdesc_type *field_type;
   char *field_name, *field_type_id;
+  int start, end;
 
-  field_name = attrs[0].value;
-  field_type_id = attrs[1].value;
+  length = VEC_length (gdb_xml_value_s, attributes);
 
-  field_type = tdesc_named_type (data->current_feature, field_type_id);
-  if (field_type == NULL)
-    gdb_xml_error (parser, _("Union field \"%s\" references undefined "
-                            "type \"%s\""),
-                  field_name, field_type_id);
+  field_name = attrs[ix++].value;
 
-  tdesc_add_field (data->current_union, field_name, field_type);
+  if (ix < length && strcmp (attrs[ix].name, "type") == 0)
+    field_type_id = attrs[ix++].value;
+  else
+    field_type_id = NULL;
+
+  if (ix < length && strcmp (attrs[ix].name, "start") == 0)
+    start = * (ULONGEST *) attrs[ix++].value;
+  else
+    start = -1;
+
+  if (ix < length && strcmp (attrs[ix].name, "end") == 0)
+    end = * (ULONGEST *) attrs[ix++].value;
+  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)
+    {
+      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,
+                          _("Implicitly sized type can not contain bitfield \"%s\""), 
+                          field_name);
+
+         if (end >= 64)
+           gdb_xml_error (parser,
+                          _("Bitfield \"%s\" goes past 64 bits (unsupported)"),
+                          field_name);
+
+         /* 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"
+            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);
+       }
+    }
+  else
+    gdb_xml_error (parser, _("Field \"%s\" has neither type nor bit position"),
+                  field_name);
 }
 
 /* Handle the start of a <vector> element.  Initialize the type and
@@ -287,11 +404,13 @@ tdesc_start_vector (struct gdb_xml_parser *parser,
 
 static const struct gdb_xml_attribute field_attributes[] = {
   { "name", GDB_XML_AF_NONE, NULL, NULL },
-  { "type", GDB_XML_AF_NONE, NULL, NULL },
+  { "type", GDB_XML_AF_OPTIONAL, NULL, NULL },
+  { "start", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { "end", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
-static const struct gdb_xml_element union_children[] = {
+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 }
@@ -308,8 +427,15 @@ static const struct gdb_xml_attribute reg_attributes[] = {
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
-static const struct gdb_xml_attribute union_attributes[] = {
+static const struct gdb_xml_attribute struct_union_attributes[] = {
   { "id", GDB_XML_AF_NONE, NULL, NULL },
+  { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL},
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute flags_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 }
 };
 
@@ -329,9 +455,15 @@ static const struct gdb_xml_element feature_children[] = {
   { "reg", reg_attributes, NULL,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_reg, NULL },
-  { "union", union_attributes, union_children,
+  { "struct", struct_union_attributes, struct_union_children,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_struct, NULL },
+  { "union", struct_union_attributes, struct_union_children,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_union, NULL },
+  { "flags", flags_attributes, struct_union_children,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_flags, NULL },    
   { "vector", vector_attributes, NULL,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_vector, NULL },