[RFA,1/6] Add initial type alignment support

Message ID 20180424152222.8053-2-tom@tromey.com
State Superseded
Headers show
Series
  • Teach gdb about type alignment
Related show

Commit Message

Tom Tromey April 24, 2018, 3:22 p.m.
This adds some basic type alignment support to gdb.  It changes struct
type to store the alignment, and updates dwarf2read.c to handle
DW_AT_alignment.  It also adds a new gdbarch method and updates
i386-tdep.c.

None of this new functionality is used anywhere yet, so tests will
wait until the next patch.

2018-04-24  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.
---
 gdb/ChangeLog    |  21 ++++++++++
 gdb/arch-utils.c |   8 ++++
 gdb/arch-utils.h |   4 ++
 gdb/dwarf2read.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 gdb/gdbarch.c    |  23 +++++++++++
 gdb/gdbarch.h    |   6 +++
 gdb/gdbarch.sh   |   3 ++
 gdb/gdbtypes.c   | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbtypes.h   |  34 +++++++++++++++-
 gdb/i386-tdep.c  |  28 +++++++++++++
 10 files changed, 358 insertions(+), 5 deletions(-)

-- 
2.14.3

Comments

Pedro Alves April 24, 2018, 7:16 p.m. | #1
Hi Tom,

On 04/24/2018 04:22 PM, Tom Tromey wrote:

> +/* * 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.  */

>  

> @@ -831,6 +835,14 @@ struct type

>  

>    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.

>  

> @@ -841,7 +853,7 @@ struct type

>       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

> @@ -1292,6 +1304,26 @@ extern void allocate_gnat_aux_type (struct type *);

>     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 bytes, or 0 if no alignment

> +   was specified.  */

> +#define TYPE_RAW_ALIGN(thistype) type_raw_align (thistype)

> +

> +/* * Return the alignment of the type in bytes, or 0 if no alignment

> +   was specified.  */

> +extern unsigned type_raw_align (struct type *);

> +

> +/* * Return the alignment of the type in bytes.  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);


Are these represented in host bytes, or target addressable memory units?
See comments around type::length and type_length_units.  The comments above
should be clarified in that direction.

> +/* 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 &&

> +      TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) > 4)

> +    return 4;


&& on the other line.

Otherwise looks good to me, but I'd like to hear Simon's opinion.

Thanks,
Pedro Alves
Tom Tromey April 24, 2018, 8:23 p.m. | #2
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:


>> +  if (gdbarch_ptr_bit (gdbarch) == 32 &&

>> +      TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) > 4)

>> +    return 4;


Pedro> && on the other line.

Hah.  Actually I think I meant to refactor this all a bit and make an
outer if that checked gdbarch_ptr_bit.

Tom

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0db5c46f6c..94d166e310 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,24 @@ 
+2018-04-24  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-19  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
 	* thread.c (thread_apply_all_command): Fix comment.
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index cd9bd66430..e3cce491ee 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -987,6 +987,14 @@  default_in_indirect_branch_thunk (gdbarch *gdbarch, CORE_ADDR pc)
   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)
 {
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index b785b24643..77ee9af2bf 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -267,4 +267,8 @@  extern CORE_ADDR gdbarch_skip_prologue_noexcept (gdbarch *gdbarch,
 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
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 4207e4c531..0ca055675f 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -9907,6 +9907,7 @@  quirk_rust_enum (struct type *type, struct objfile *objfile)
       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;
@@ -9962,6 +9963,7 @@  quirk_rust_enum (struct type *type, struct objfile *objfile)
       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);
@@ -10027,6 +10029,7 @@  quirk_rust_enum (struct type *type, struct objfile *objfile)
       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)
@@ -15578,6 +15581,82 @@  quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile)
   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
@@ -15688,6 +15767,8 @@  read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
       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
@@ -16132,6 +16213,8 @@  read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
       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
@@ -16157,6 +16240,9 @@  read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
       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);
@@ -16381,6 +16467,8 @@  read_array_type (struct die_info *die, struct dwarf2_cu *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);
 
@@ -16445,6 +16533,8 @@  read_set_type (struct die_info *die, struct dwarf2_cu *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);
 }
 
@@ -16816,10 +16906,15 @@  read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *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))
 	{
@@ -16836,6 +16931,14 @@  read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
 	  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?  */
@@ -16843,6 +16946,7 @@  read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
     }
 
   TYPE_LENGTH (type) = byte_size;
+  set_type_align (type, alignment);
   return set_die_type (die, type, cu);
 }
 
@@ -16912,6 +17016,7 @@  read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu,
     {
       TYPE_LENGTH (type) = cu_header->addr_size;
     }
+  maybe_set_alignment (cu, die, type);
   return set_die_type (die, type, cu);
 }
 
@@ -17398,6 +17503,8 @@  read_base_type (struct die_info *die, struct dwarf2_cu *cu)
   if (name && strcmp (name, "char") == 0)
     TYPE_NOSIGN (type) = 1;
 
+  maybe_set_alignment (cu, die, type);
+
   return set_die_type (die, type, cu);
 }
 
@@ -17660,6 +17767,8 @@  read_subrange_type (struct die_info *die, struct dwarf2_cu *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.  */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 1359c2fb53..dd7c89d948 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -353,6 +353,7 @@  struct gdbarch
   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
@@ -465,6 +466,7 @@  gdbarch_alloc (const struct gdbarch_info *info,
   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;
@@ -716,6 +718,7 @@  verify_gdbarch (struct gdbarch *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"),
@@ -1441,6 +1444,9 @@  gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "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));
@@ -5100,6 +5106,23 @@  set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch,
   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.  */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 0084f199d7..3848ec50c7 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1560,6 +1560,12 @@  extern void set_gdbarch_disassembler_options (struct gdbarch *gdbarch, char ** d
 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)
 
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 4fc54cba9c..bb62e6d620 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1163,6 +1163,9 @@  m;int;addressable_memory_unit_size;void;;;default_addressable_memory_unit_size;;
 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
 }
 
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index b3a037971e..d9cd55cd23 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3013,6 +3013,125 @@  init_pointer_type (struct objfile *objfile,
   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:
+    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;
+}
+
 
 /* Queries on types.  */
 
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 552a2a2a16..59fa1e2a10 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -802,6 +802,10 @@  struct main_type
   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.  */
 
@@ -831,6 +835,14 @@  struct type
 
   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.
 
@@ -841,7 +853,7 @@  struct type
      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
@@ -1292,6 +1304,26 @@  extern void allocate_gnat_aux_type (struct type *);
    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 bytes, or 0 if no alignment
+   was specified.  */
+#define TYPE_RAW_ALIGN(thistype) type_raw_align (thistype)
+
+/* * Return the alignment of the type in bytes, or 0 if no alignment
+   was specified.  */
+extern unsigned type_raw_align (struct type *);
+
+/* * Return the alignment of the type in bytes.  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
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index bf4ca54303..e1938304bb 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8347,6 +8347,33 @@  i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
 }
 
 
+
+/* 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 &&
+      TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) > 4)
+    return 4;
+
+  if (gdbarch_ptr_bit (gdbarch) == 32
+      && 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_ptr_bit (gdbarch) == 32
+      && gdbarch_long_double_bit (gdbarch) == TYPE_LENGTH (type) * 8)
+    return 4;
+
+  return TYPE_LENGTH (type);
+}
+
+
 /* Note: This is called for both i386 and amd64.  */
 
 static struct gdbarch *
@@ -8405,6 +8432,7 @@  i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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