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

Message ID 20180427140139.7957-2-tom@tromey.com
State New
Headers show
Series
  • Type alignment
Related show

Commit Message

Tom Tromey April 27, 2018, 2:01 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-27  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   | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbtypes.h   |  34 +++++++++++++++-
 gdb/i386-tdep.c  |  26 ++++++++++++
 10 files changed, 359 insertions(+), 5 deletions(-)

-- 
2.14.3

Comments

Pedro Alves April 27, 2018, 6:46 p.m. | #1
On 04/27/2018 03:01 PM, Tom Tromey wrote:
> 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.


Looks good to me.

TBC, I'm fine with addressing any comments I have made to v1,
if any need to be addressed even, after the initial merge.

Thanks,
Pedro Alves

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index cd86be7fb3..1b5abb2f0d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,24 @@ 
+2018-04-27  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-26  Andrzej Kaczmarek  <andrzej.kaczmarek@codecoup.pl>
 
 	PR remote/9665
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 2efd1264ff..9ecc80f26f 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3013,6 +3013,128 @@  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:
+      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;
+}
+
 
 /* Queries on types.  */
 
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 552a2a2a16..5f614e573a 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 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
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index bf4ca54303..fec74ee6c8 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8347,6 +8347,31 @@  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)
+    {
+      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);
+}
+
+
 /* Note: This is called for both i386 and amd64.  */
 
 static struct gdbarch *
@@ -8405,6 +8430,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