+2018-04-30 Tom Tromey <tom@tromey.com>
+
+ * i386-tdep.c (i386_type_align): New function.
+ (i386_gdbarch_init): Update.
+ * gdbarch.sh (type_align): New method.
+ * gdbarch.c, gdbarch.h: Rebuild.
+ * arch-utils.h (default_type_align): Declare.
+ * arch-utils.c (default_type_align): New function.
+ * gdbtypes.h (TYPE_ALIGN_BITS): New define.
+ (struct type) <align_log2>: New field.
+ <instance_flags>: Now a bitfield.
+ (TYPE_RAW_ALIGN): New macro.
+ (type_align, type_raw_align, set_type_align): Declare.
+ * gdbtypes.c (type_align, type_raw_align, set_type_align): New
+ functions.
+ * dwarf2read.c (quirk_rust_enum): Set type alignment.
+ (get_alignment, maybe_set_alignment): New functions.
+ (read_structure_type, read_enumeration_type, read_array_type)
+ (read_set_type, read_tag_pointer_type, read_tag_reference_type)
+ (read_subrange_type, read_base_type): Set type alignment.
+
2018-04-30 Simon Marchi <simon.marchi@ericsson.com>
* dwarf2read.c (read_index_from_section): Use bool.
return false;
}
+/* See arch-utils.h. */
+
+ULONGEST
+default_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+ return TYPE_LENGTH (check_typedef (type));
+}
+
void
_initialize_gdbarch_utils (void)
{
extern bool default_in_indirect_branch_thunk (gdbarch *gdbarch,
CORE_ADDR pc);
+/* Default implementation of gdbarch type_align method. */
+extern ULONGEST default_type_align (struct gdbarch *gdbarch,
+ struct type *type);
+
#endif
TYPE_FIELDS (union_type)
= (struct field *) TYPE_ZALLOC (type, 3 * sizeof (struct field));
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+ set_type_align (union_type, TYPE_RAW_ALIGN (type));
/* Put the discriminant must at index 0. */
TYPE_FIELD_TYPE (union_type, 0) = field_type;
TYPE_CODE (union_type) = TYPE_CODE_UNION;
TYPE_NFIELDS (union_type) = TYPE_NFIELDS (type);
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+ set_type_align (union_type, TYPE_RAW_ALIGN (type));
TYPE_FIELDS (union_type) = TYPE_FIELDS (type);
struct type *field_type = TYPE_FIELD_TYPE (union_type, 0);
TYPE_CODE (union_type) = TYPE_CODE_UNION;
TYPE_NFIELDS (union_type) = 1 + TYPE_NFIELDS (type);
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+ set_type_align (union_type, TYPE_RAW_ALIGN (type));
TYPE_FIELDS (union_type)
= (struct field *) TYPE_ZALLOC (union_type,
(TYPE_NFIELDS (union_type)
smash_to_methodptr_type (type, new_type);
}
+/* If the DIE has a DW_AT_alignment attribute, return its value, doing
+ appropriate error checking and issuing complaints if there is a
+ problem. */
+
+static ULONGEST
+get_alignment (struct dwarf2_cu *cu, struct die_info *die)
+{
+ struct attribute *attr = dwarf2_attr (die, DW_AT_alignment, cu);
+
+ if (attr == nullptr)
+ return 0;
+
+ if (!attr_form_is_constant (attr))
+ {
+ complaint (&symfile_complaints,
+ _("DW_AT_alignment must have constant form"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+ return 0;
+ }
+
+ ULONGEST align;
+ if (attr->form == DW_FORM_sdata)
+ {
+ LONGEST val = DW_SND (attr);
+ if (val < 0)
+ {
+ complaint (&symfile_complaints,
+ _("DW_AT_alignment value must not be negative"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+ return 0;
+ }
+ align = val;
+ }
+ else
+ align = DW_UNSND (attr);
+
+ if (align == 0)
+ {
+ complaint (&symfile_complaints,
+ _("DW_AT_alignment value must not be zero"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+ return 0;
+ }
+ if ((align & (align - 1)) != 0)
+ {
+ complaint (&symfile_complaints,
+ _("DW_AT_alignment value must be a power of 2"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+ return 0;
+ }
+
+ return align;
+}
+
+/* If the DIE has a DW_AT_alignment attribute, use its value to set
+ the alignment for TYPE. */
+
+static void
+maybe_set_alignment (struct dwarf2_cu *cu, struct die_info *die,
+ struct type *type)
+{
+ if (!set_type_align (type, get_alignment (cu, die)))
+ complaint (&symfile_complaints,
+ _("DW_AT_alignment value too large"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+}
/* Called when we find the DIE that starts a structure or union scope
(definition) to create a type for the structure or union. Fill in
TYPE_LENGTH (type) = 0;
}
+ maybe_set_alignment (cu, die, type);
+
if (producer_is_icc_lt_14 (cu) && (TYPE_LENGTH (type) == 0))
{
/* ICC<14 does not output the required DW_AT_declaration on
TYPE_LENGTH (type) = 0;
}
+ maybe_set_alignment (cu, die, type);
+
/* The enumeration DIE can be incomplete. In Ada, any type can be
declared as private in the package spec, and then defined only
inside the package body. Such types are known as Taft Amendment
TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TYPE_TARGET_TYPE (type));
if (TYPE_LENGTH (type) == 0)
TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type));
+ if (TYPE_RAW_ALIGN (type) == 0
+ && TYPE_RAW_ALIGN (TYPE_TARGET_TYPE (type)) != 0)
+ set_type_align (type, TYPE_RAW_ALIGN (TYPE_TARGET_TYPE (type)));
}
TYPE_DECLARED_CLASS (type) = dwarf2_flag_true_p (die, DW_AT_enum_class, cu);
if (name)
TYPE_NAME (type) = name;
+ maybe_set_alignment (cu, die, type);
+
/* Install the type in the die. */
set_die_type (die, type, cu);
if (attr)
TYPE_LENGTH (set_type) = DW_UNSND (attr);
+ maybe_set_alignment (cu, die, set_type);
+
return set_die_type (die, set_type, cu);
}
else
addr_class = DW_ADDR_none;
- /* If the pointer size or address class is different than the
- default, create a type variant marked as such and set the
- length accordingly. */
- if (TYPE_LENGTH (type) != byte_size || addr_class != DW_ADDR_none)
+ ULONGEST alignment = get_alignment (cu, die);
+
+ /* If the pointer size, alignment, or address class is different
+ than the default, create a type variant marked as such and set
+ the length accordingly. */
+ if (TYPE_LENGTH (type) != byte_size
+ || (alignment != 0 && TYPE_RAW_ALIGN (type) != 0
+ && alignment != TYPE_RAW_ALIGN (type))
+ || addr_class != DW_ADDR_none)
{
if (gdbarch_address_class_type_flags_p (gdbarch))
{
complaint (&symfile_complaints,
_("invalid pointer size %d"), byte_size);
}
+ else if (TYPE_RAW_ALIGN (type) != alignment)
+ {
+ complaint (&symfile_complaints,
+ _("Invalid DW_AT_alignment"
+ " - DIE at %s [in module %s]"),
+ sect_offset_str (die->sect_off),
+ objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+ }
else
{
/* Should we also complain about unhandled address classes? */
}
TYPE_LENGTH (type) = byte_size;
+ set_type_align (type, alignment);
return set_die_type (die, type, cu);
}
{
TYPE_LENGTH (type) = cu_header->addr_size;
}
+ maybe_set_alignment (cu, die, type);
return set_die_type (die, type, cu);
}
if (name && strcmp (name, "char") == 0)
TYPE_NOSIGN (type) = 1;
+ maybe_set_alignment (cu, die, type);
+
return set_die_type (die, type, cu);
}
if (attr)
TYPE_LENGTH (range_type) = DW_UNSND (attr);
+ maybe_set_alignment (cu, die, range_type);
+
set_die_type (die, range_type, cu);
/* set_die_type should be already done. */
gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size;
char ** disassembler_options;
const disasm_options_t * valid_disassembler_options;
+ gdbarch_type_align_ftype *type_align;
};
/* Create a new ``struct gdbarch'' based on information provided by
gdbarch->gcc_target_options = default_gcc_target_options;
gdbarch->gnu_triplet_regexp = default_gnu_triplet_regexp;
gdbarch->addressable_memory_unit_size = default_addressable_memory_unit_size;
+ gdbarch->type_align = default_type_align;
/* gdbarch_alloc() */
return gdbarch;
/* Skip verify of addressable_memory_unit_size, invalid_p == 0 */
/* Skip verify of disassembler_options, invalid_p == 0 */
/* Skip verify of valid_disassembler_options, invalid_p == 0 */
+ /* Skip verify of type_align, invalid_p == 0 */
if (!log.empty ())
internal_error (__FILE__, __LINE__,
_("verify_gdbarch: the following are invalid ...%s"),
"gdbarch_dump: target_desc = %s\n",
host_address_to_string (gdbarch->target_desc));
fprintf_unfiltered (file,
+ "gdbarch_dump: type_align = <%s>\n",
+ host_address_to_string (gdbarch->type_align));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
gdbarch_unwind_pc_p (gdbarch));
fprintf_unfiltered (file,
gdbarch->valid_disassembler_options = valid_disassembler_options;
}
+ULONGEST
+gdbarch_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->type_align != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_type_align called\n");
+ return gdbarch->type_align (gdbarch, type);
+}
+
+void
+set_gdbarch_type_align (struct gdbarch *gdbarch,
+ gdbarch_type_align_ftype type_align)
+{
+ gdbarch->type_align = type_align;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
extern const disasm_options_t * gdbarch_valid_disassembler_options (struct gdbarch *gdbarch);
extern void set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch, const disasm_options_t * valid_disassembler_options);
+/* Type alignment. */
+
+typedef ULONGEST (gdbarch_type_align_ftype) (struct gdbarch *gdbarch, struct type *type);
+extern ULONGEST gdbarch_type_align (struct gdbarch *gdbarch, struct type *type);
+extern void set_gdbarch_type_align (struct gdbarch *gdbarch, gdbarch_type_align_ftype *type_align);
+
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)
v;char **;disassembler_options;;;0;0;;0;pstring_ptr (gdbarch->disassembler_options)
v;const disasm_options_t *;valid_disassembler_options;;;0;0;;0;host_address_to_string (gdbarch->valid_disassembler_options)
+# Type alignment.
+m;ULONGEST;type_align;struct type *type;type;;default_type_align;;0
+
EOF
}
return t;
}
+/* See gdbtypes.h. */
+
+unsigned
+type_raw_align (struct type *type)
+{
+ if (type->align_log2 != 0)
+ return 1 << (type->align_log2 - 1);
+ return 0;
+}
+
+/* See gdbtypes.h. */
+
+unsigned
+type_align (struct type *type)
+{
+ unsigned raw_align = type_raw_align (type);
+ if (raw_align != 0)
+ return raw_align;
+
+ ULONGEST align = 0;
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_FLAGS:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_DECFLOAT:
+ {
+ struct gdbarch *arch = get_type_arch (type);
+ align = gdbarch_type_align (arch, type);
+ }
+ break;
+
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_COMPLEX:
+ case TYPE_CODE_TYPEDEF:
+ align = type_align (TYPE_TARGET_TYPE (type));
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ {
+ if (TYPE_NFIELDS (type) == 0)
+ {
+ /* An empty struct has alignment 1. */
+ align = 1;
+ break;
+ }
+ for (unsigned i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ ULONGEST f_align = type_align (TYPE_FIELD_TYPE (type, i));
+ if (f_align == 0)
+ {
+ /* Don't pretend we know something we don't. */
+ align = 0;
+ break;
+ }
+ if (f_align > align)
+ align = f_align;
+ }
+ }
+ break;
+
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_STRING:
+ /* Not sure what to do here, and these can't appear in C or C++
+ anyway. */
+ break;
+
+ case TYPE_CODE_METHODPTR:
+ case TYPE_CODE_MEMBERPTR:
+ align = TYPE_LENGTH (type);
+ break;
+
+ case TYPE_CODE_VOID:
+ align = 1;
+ break;
+
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_METHOD:
+ default:
+ break;
+ }
+
+ if ((align & (align - 1)) != 0)
+ {
+ /* Not a power of 2, so pass. */
+ align = 0;
+ }
+
+ return align;
+}
+
+/* See gdbtypes.h. */
+
+bool
+set_type_align (struct type *type, ULONGEST align)
+{
+ /* Must be a power of 2. Zero is ok. */
+ gdb_assert ((align & (align - 1)) == 0);
+
+ unsigned result = 0;
+ while (align != 0)
+ {
+ ++result;
+ align >>= 1;
+ }
+
+ if (result >= (1 << TYPE_ALIGN_BITS))
+ return false;
+
+ type->align_log2 = result;
+ return true;
+}
+
\f
/* Queries on types. */
struct dynamic_prop_list *dyn_prop_list;
};
+/* * Number of bits allocated for alignment. */
+
+#define TYPE_ALIGN_BITS 8
+
/* * A ``struct type'' describes a particular instance of a type, with
some particular qualification. */
struct type *chain;
+ /* * The alignment for this type. Zero means that the alignment was
+ not specified in the debug info. Note that this is stored in a
+ funny way: as the log base 2 (plus 1) of the alignment; so a
+ value of 1 means the alignment is 1, and a value of 9 means the
+ alignment is 256. */
+
+ unsigned align_log2 : TYPE_ALIGN_BITS;
+
/* * Flags specific to this instance of the type, indicating where
on the ring we are.
instance flags are completely inherited from the target type. No
qualifiers can be cleared by the typedef. See also
check_typedef. */
- int instance_flags;
+ unsigned instance_flags : 9;
/* * Length of storage for a value of this type. The value is the
expression in host bytes of what sizeof(type) would return. This
so you only have to call check_typedef once. Since allocate_value
calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */
#define TYPE_LENGTH(thistype) (thistype)->length
+
+/* * Return the alignment of the type in target addressable memory
+ units, or 0 if no alignment was specified. */
+#define TYPE_RAW_ALIGN(thistype) type_raw_align (thistype)
+
+/* * Return the alignment of the type in target addressable memory
+ units, or 0 if no alignment was specified. */
+extern unsigned type_raw_align (struct type *);
+
+/* * Return the alignment of the type in target addressable memory
+ units. Return 0 if the alignment cannot be determined; but note
+ that this makes an effort to compute the alignment even it it was
+ not specified in the debug info. */
+extern unsigned type_align (struct type *);
+
+/* * Set the alignment of the type. The alignment must be a power of
+ 2. Returns false if the given value does not fit in the available
+ space in struct type. */
+extern bool set_type_align (struct type *, ULONGEST);
+
/* * Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real
type, you need to do TYPE_CODE (check_type (this_type)). */
#define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code
}
\f
+
+/* Implement the type_align gdbarch function. */
+
+static ULONGEST
+i386_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+ type = check_typedef (type);
+
+ if (gdbarch_ptr_bit (gdbarch) == 32)
+ {
+ if ((TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_FLT)
+ && TYPE_LENGTH (type) > 4)
+ return 4;
+
+ /* Handle x86's funny long double. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && gdbarch_long_double_bit (gdbarch) == TYPE_LENGTH (type) * 8)
+ return 4;
+ }
+
+ return TYPE_LENGTH (type);
+}
+
+\f
/* Note: This is called for both i386 and amd64. */
static struct gdbarch *
tdep->record_regmap = i386_record_regmap;
set_gdbarch_long_long_align_bit (gdbarch, 32);
+ set_gdbarch_type_align (gdbarch, i386_type_align);
/* The format used for `long double' on almost all i386 targets is
the i387 extended floating-point format. In fact, of all targets