diff options
-rw-r--r-- | gdb/ChangeLog | 45 | ||||
-rw-r--r-- | gdb/NEWS | 3 | ||||
-rw-r--r-- | gdb/c-typeprint.c | 50 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 125 | ||||
-rw-r--r-- | gdb/features/gdb-target.dtd | 10 | ||||
-rw-r--r-- | gdb/gdbtypes.c | 49 | ||||
-rw-r--r-- | gdb/gdbtypes.h | 5 | ||||
-rw-r--r-- | gdb/target-descriptions.c | 302 | ||||
-rw-r--r-- | gdb/target-descriptions.h | 8 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/extra-regs.xml | 25 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/tdesc-regs.exp | 20 | ||||
-rw-r--r-- | gdb/valprint.c | 91 | ||||
-rw-r--r-- | gdb/valprint.h | 4 | ||||
-rw-r--r-- | gdb/xml-tdesc.c | 182 |
16 files changed, 724 insertions, 209 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1d59888..d78f2cc 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,50 @@ 2016-03-15 Doug Evans <dje@google.com> + Extend flags to support multibit and enum bitfields. + NEWS: Document new features. + * 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. + +2016-03-15 Doug Evans <dje@google.com> + * target-descriptions.c (struct tdesc_type) <u.u.size>: Change type from LONGEST to int. (struct tdesc_type) <u.f.size>: Ditto. @@ -3,6 +3,9 @@ *** Changes since GDB 7.11 +* GDB now supports multibit bitfields and enums in target register + descriptions. + * New Python-based convenience function $_as_string(val), which returns the textual representation of a value. This function is especially useful to obtain the text label of an enum value. 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/ChangeLog b/gdb/doc/ChangeLog index a48d1c4..c34c4f3 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,11 @@ +2016-03-15 Doug Evans <dje@google.com> + + * 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. + 2016-03-15 Pedro Alves <palves@redhat.com> * gdb.texinfo (Tracepoint Actions): Fix typo. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 71657b0..2f4da84 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40359,6 +40359,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 @@ -40559,7 +40560,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. @@ -40589,46 +40591,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> @@ -40697,6 +40737,9 @@ types. The currently supported types are: @table @code +@item bool +Boolean type, occupying a single bit. + @item int8 @itemx int16 @itemx int32 @@ -40739,6 +40782,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 1af6fff..65758bf 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -4715,38 +4715,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/ChangeLog b/gdb/testsuite/ChangeLog index 177b2d1..25154c6 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2016-03-15 Doug Evans <dje@google.com> + * 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. + +2016-03-15 Doug Evans <dje@google.com> + * gdb.base/skip.c (main): Call test_skip_file_and_function. * gdb.base/skip.exp: Remove hand calling test_skip_file_and_function. 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 }, |