This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] DWARFv5 DW_TAG_aligned_type.


Hi,

This patch is to deal with the corresponding patch to gcc:
https://gcc.gnu.org/ml/gcc-patches/2014-07/msg00667.html
Like the DW_TAG_atomic_type patch (sorry, I haven't dealt yet with all
the comments), this isn't meant to be applied as is (it is currently only
a proposal for DWARFv5). But I would like to get some comments on
the code and whether the proposed DWARF is useful. I only tested this for
C code. If other languages have a similar concept it would be nice to know
what it looks like and how it can be handled in gdb.

Thanks,

Mark

gdb/ChangeLog

	* c-typeprint.c (cp_type_print_method_args): Handle TYPE_USER_ALIGN.
	(c_type_print_varspec_prefix): Likewise.
	(c_type_print_modifier): Likewise.
	* dwarf2read.c (add_array_cv_aligned_type): New function.
	(read_tag_aligned_type): Likewise.
	(read_type_die_1): Handle DW_TAG_aligned_type.
	* gdbtypes.c (make_qualified_type): Calls...
	(make_qualified_aligned_type): New function that handles user
	alignment.
	(make_aligned_type): New function.
	(check_typedef): Handle TYPE_USER_ALIGN.
	(check_types_equal): Likewise.
	(recursive_dump_type): Likewise.
	(copy_type_recursive): Likewise.
	(copy_type): Likewise.
	* gdbtypes.h (struct type): Add user_align.
	(TYPE_USER_ALIGN): New define.
	(make_aligned_type): Define.

include/ChangeLog

	* dwarf2.def: Add DW_TAG_aligned_type and DW_AT_alignment.
---
 gdb/ChangeLog      |   21 ++++++++++++
 gdb/c-typeprint.c  |   19 ++++++++++-
 gdb/dwarf2read.c   |   58 ++++++++++++++++++++++++++++++++++
 gdb/gdbtypes.c     |   88 ++++++++++++++++++++++++++++++++++++++++------------
 gdb/gdbtypes.h     |   17 ++++++++--
 include/ChangeLog  |    4 ++
 include/dwarf2.def |    3 ++
 7 files changed, 184 insertions(+), 26 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 08fba63..cd7d3ed 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,24 @@
+2014-07-09  Mark Wielaard  <mjw@redhat.com>
+
+	* c-typeprint.c (cp_type_print_method_args): Handle TYPE_USER_ALIGN.
+	(c_type_print_varspec_prefix): Likewise.
+	(c_type_print_modifier): Likewise.
+	* dwarf2read.c (add_array_cv_aligned_type): New function.
+	(read_tag_aligned_type): Likewise.
+	(read_type_die_1): Handle DW_TAG_aligned_type.
+	* gdbtypes.c (make_qualified_type): Calls...
+	(make_qualified_aligned_type): New function that handles user
+	alignment.
+	(make_aligned_type): New function.
+	(check_typedef): Handle TYPE_USER_ALIGN.
+	(check_types_equal): Likewise.
+	(recursive_dump_type): Likewise.
+	(copy_type_recursive): Likewise.
+	(copy_type): Likewise.
+	* gdbtypes.h (struct type): Add user_align.
+	(TYPE_USER_ALIGN): New define.
+	(make_aligned_type): Define.
+
 2014-07-08  Markus Metzger  <markus.t.metzger@intel.com>
 
 	* infcmd.c (finish_backward): Turn internal error into normal error.
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 72effce..501a994 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -275,6 +275,9 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
 
       if (TYPE_ATOMIC (domain))
 	fprintf_filtered (stream, " _Atomic");
+
+      if (TYPE_USER_ALIGN (domain) != 0)
+	fprintf_filtered (stream, " _Alignas (%u)", TYPE_USER_ALIGN (domain));
     }
 }
 
@@ -313,6 +316,9 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_PTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
 				   stream, show, 1, 1, flags);
+      /* _Alignas comes before the "*' pointer unlike the other modifiers.  */
+      if (TYPE_USER_ALIGN (type) != 0)
+	fprintf_filtered (stream, " _Alignas (%u) ", TYPE_USER_ALIGN (type));
       fprintf_filtered (stream, "*");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
@@ -394,8 +400,8 @@ c_type_print_varspec_prefix (struct type *type,
     }
 }
 
-/* Print out "const" and "volatile" attributes,
-   and address space id if present.
+/* Print out "const", "volatile", "restrict", "_Atomic" and "_Alignas"
+   attributes, and address space id if present.
    TYPE is a pointer to the type being printed out.
    STREAM is the output destination.
    NEED_PRE_SPACE = 1 indicates an initial white space is needed.
@@ -444,6 +450,15 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
       did_print_modifier = 1;
     }
 
+  /* For pointers the _Alignas comes before the '*'.  */
+  if (TYPE_USER_ALIGN (type) != 0 && TYPE_CODE (type) != TYPE_CODE_PTR)
+    {
+      if (did_print_modifier || need_pre_space)
+	fprintf_filtered (stream, " ");
+      fprintf_filtered (stream, "_Alignas (%u)", TYPE_USER_ALIGN (type));
+      did_print_modifier = 1;
+    }
+
   address_space_id = address_space_int_to_name (get_type_arch (type),
 						TYPE_INSTANCE_FLAGS (type));
   if (address_space_id)
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 614d6b9..ee3dc1c 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -14128,6 +14128,33 @@ add_array_cv_type (struct die_info *die, struct dwarf2_cu *cu,
   return set_die_type (die, base_type, cu);
 }
 
+/* Add the given user alignment to the element type of the array.  GCC
+   outputs DWARF type qualifiers that apply to an array, not the
+   element type.  But GDB relies on the array element type to carry
+   the cv-qualifiers.  This is mimics section 6.7.3, point 9 of the
+   C11 specification (n1570).  */
+static struct type *
+add_array_cv_aligned_type (struct die_info *die, struct dwarf2_cu *cu,
+			   struct type *base_type, unsigned int user_align)
+{
+  struct type *el_type, *inner_array;
+
+  base_type = copy_type (base_type);
+  inner_array = base_type;
+
+  while (TYPE_CODE (TYPE_TARGET_TYPE (inner_array)) == TYPE_CODE_ARRAY)
+    {
+      TYPE_TARGET_TYPE (inner_array) =
+	copy_type (TYPE_TARGET_TYPE (inner_array));
+      inner_array = TYPE_TARGET_TYPE (inner_array);
+    }
+
+  el_type = TYPE_TARGET_TYPE (inner_array);
+  TYPE_TARGET_TYPE (inner_array) = make_aligned_type (el_type, user_align);
+
+  return set_die_type (die, base_type, cu);
+}
+
 static struct type *
 read_tag_const_type (struct die_info *die, struct dwarf2_cu *cu)
 {
@@ -14205,6 +14232,34 @@ read_tag_atomic_type (struct die_info *die, struct dwarf2_cu *cu)
   return set_die_type (die, cv_type, cu);
 }
 
+static struct type *
+read_tag_aligned_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+  struct type *base_type, *align_type;
+  struct attribute *attr;
+  unsigned int user_align = 0;
+
+  base_type = die_type (die, cu);
+
+  /* The die_type call above may have already set the type for this DIE.  */
+  align_type = get_die_type (die, cu);
+  if (align_type)
+    return align_type;
+
+  attr = dwarf2_attr (die, DW_AT_alignment, cu);
+  if (attr)
+    user_align = DW_UNSND (attr);
+
+  /* In case the _Alignas qualifier is applied to an array type, the
+     element type is so qualified, not the array type (section 6.7.3
+     of C99).  */
+  if (TYPE_CODE (base_type) == TYPE_CODE_ARRAY)
+    return add_array_cv_aligned_type (die, cu, base_type, user_align);
+
+  align_type = make_aligned_type (base_type, user_align);
+  return set_die_type (die, align_type, cu);
+}
+
 /* Extract all information from a DW_TAG_string_type DIE and add to
    the user defined type vector.  It isn't really a user defined type,
    but it behaves like one, with other DIE's using an AT_user_def_type
@@ -18538,6 +18593,9 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
     case DW_TAG_atomic_type:
       this_type = read_tag_atomic_type (die, cu);
       break;
+    case DW_TAG_aligned_type:
+      this_type = read_tag_aligned_type (die, cu);
+      break;
     default:
       complaint (&symfile_complaints,
 		 _("unexpected tag in read_type_die: '%s'"),
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 42ff588..e12dec7 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -565,21 +565,23 @@ address_space_int_to_name (struct gdbarch *gdbarch, int space_flag)
     return NULL;
 }
 
-/* Create a new type with instance flags NEW_FLAGS, based on TYPE.
+/* Create a new type with instance flags NEW_FLAGS, and NEW_ALIGN (if
+   stricter) based on TYPE.
 
    If STORAGE is non-NULL, create the new type instance there.
    STORAGE must be in the same obstack as TYPE.  */
 
 static struct type *
-make_qualified_type (struct type *type, int new_flags,
-		     struct type *storage)
+make_qualified_aligned_type (struct type *type, int new_flags,
+			     unsigned int new_align, struct type *storage)
 {
   struct type *ntype;
 
   ntype = type;
   do
     {
-      if (TYPE_INSTANCE_FLAGS (ntype) == new_flags)
+      if (TYPE_INSTANCE_FLAGS (ntype) == new_flags
+	  && TYPE_USER_ALIGN (ntype) == new_align)
 	return ntype;
       ntype = TYPE_CHAIN (ntype);
     }
@@ -616,9 +618,25 @@ make_qualified_type (struct type *type, int new_flags,
   /* Set length of new type to that of the original type.  */
   TYPE_LENGTH (ntype) = TYPE_LENGTH (type);
 
+  /* If new user alignment is stricter (bigger) than the original type
+     then use it, otherwise take the user alignment of the original
+     type.  */
+  if (new_align > TYPE_USER_ALIGN (type))
+    TYPE_USER_ALIGN (ntype) = new_align;
+  else
+    TYPE_USER_ALIGN (ntype) = TYPE_USER_ALIGN (type);
+
   return ntype;
 }
 
+static struct type *
+make_qualified_type (struct type *type, int new_flags,
+		     struct type *storage)
+{
+  return make_qualified_aligned_type (type, new_flags,
+				      TYPE_USER_ALIGN (type), storage);
+}
+
 /* Make an address-space-delimited variant of a type -- a type that
    is identical to the one supplied except that it has an address
    space attribute attached to it (such as "code" or "data").
@@ -717,6 +735,19 @@ make_atomic_type (struct type *type)
 			      NULL);
 }
 
+/* Make a '_Alignas'-qualified version of TYPE (if user_align is
+   stricter than the user alignment of TYPE).  */
+
+struct type *
+make_aligned_type (struct type *type, unsigned int user_align)
+{
+  if (user_align > TYPE_USER_ALIGN (type))
+    return make_qualified_aligned_type (type, TYPE_INSTANCE_FLAGS (type),
+					user_align, NULL);
+  else
+    return type;
+}
+
 /* Replace the contents of ntype with the type *type.  This changes the
    contents, rather than the pointer for TYPE_MAIN_TYPE (ntype); thus
    the changes are propogated to all types in the TYPE_CHAIN.
@@ -1888,9 +1919,9 @@ resolve_dynamic_type (struct type *type, CORE_ADDR addr)
    types.  Completion changes the TYPE argument, but stripping of
    typedefs does not.
 
-   Instance flags (e.g. const/volatile) are preserved as typedefs are
-   stripped.  If necessary a new qualified form of the underlying type
-   is created.
+   Instance flags (e.g. const/volatile/restrict) are preserved as typedefs
+   are stripped.  And user alignment is resolved to the strictest alignment.
+   If necessary a new qualified form of the underlying type is created.
 
    NOTE: This will return a typedef if TYPE_TARGET_TYPE for the typedef has
    not been computed and we're either in the middle of reading symbols, or
@@ -1916,8 +1947,9 @@ check_typedef (struct type *type)
 {
   struct type *orig_type = type;
   /* While we're removing typedefs, we don't want to lose qualifiers.
-     E.g., const/volatile.  */
+     E.g., const/volatile/restrict.  Or the (strictest) user alignment.  */
   int instance_flags = TYPE_INSTANCE_FLAGS (type);
+  unsigned int user_align = TYPE_USER_ALIGN (type);
 
   gdb_assert (type);
 
@@ -1931,7 +1963,8 @@ check_typedef (struct type *type)
 	  /* It is dangerous to call lookup_symbol if we are currently
 	     reading a symtab.  Infinite recursion is one danger.  */
 	  if (currently_reading_symtab)
-	    return make_qualified_type (type, instance_flags, NULL);
+	    return make_qualified_aligned_type (type, instance_flags,
+						user_align, NULL);
 
 	  name = type_name_no_tag (type);
 	  /* FIXME: shouldn't we separately check the TYPE_NAME and
@@ -1941,7 +1974,8 @@ check_typedef (struct type *type)
 	  if (name == NULL)
 	    {
 	      stub_noname_complaint ();
-	      return make_qualified_type (type, instance_flags, NULL);
+	      return make_qualified_aligned_type (type, instance_flags,
+						  user_align, NULL);
 	    }
 	  sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0);
 	  if (sym)
@@ -1967,6 +2001,7 @@ check_typedef (struct type *type)
 				| TYPE_INSTANCE_FLAG_DATA_SPACE);
 	const int ALL_CLASSES = TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL;
 	int new_instance_flags = TYPE_INSTANCE_FLAGS (type);
+	int new_user_align = TYPE_USER_ALIGN (type);
 
 	/* Treat code vs data spaces and address classes separately.  */
 	if ((instance_flags & ALL_SPACES) != 0)
@@ -1975,6 +2010,8 @@ check_typedef (struct type *type)
 	  new_instance_flags &= ~ALL_CLASSES;
 
 	instance_flags |= new_instance_flags;
+	if (new_user_align > user_align)
+	  user_align = new_user_align;
       }
     }
 
@@ -1994,7 +2031,8 @@ check_typedef (struct type *type)
       if (name == NULL)
 	{
 	  stub_noname_complaint ();
-	  return make_qualified_type (type, instance_flags, NULL);
+	  return make_qualified_aligned_type (type, instance_flags,
+					      user_align, NULL);
 	}
       newtype = lookup_transparent_type (name);
 
@@ -2011,9 +2049,10 @@ check_typedef (struct type *type)
 	     move over any other types NEWTYPE refers to, which could
 	     be an unbounded amount of stuff.  */
 	  if (TYPE_OBJFILE (newtype) == TYPE_OBJFILE (type))
-	    type = make_qualified_type (newtype,
-					TYPE_INSTANCE_FLAGS (type),
-					type);
+	    type = make_qualified_aligned_type (newtype,
+						TYPE_INSTANCE_FLAGS (type),
+						TYPE_USER_ALIGN (type),
+						type);
 	  else
 	    type = newtype;
 	}
@@ -2032,7 +2071,8 @@ check_typedef (struct type *type)
       if (name == NULL)
 	{
 	  stub_noname_complaint ();
-	  return make_qualified_type (type, instance_flags, NULL);
+	  return make_qualified_aligned_type (type, instance_flags,
+					      user_align, NULL);
 	}
       sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0);
       if (sym)
@@ -2041,9 +2081,10 @@ check_typedef (struct type *type)
              with the complete type only if they are in the same
              objfile.  */
 	  if (TYPE_OBJFILE (SYMBOL_TYPE(sym)) == TYPE_OBJFILE (type))
-            type = make_qualified_type (SYMBOL_TYPE (sym),
-					TYPE_INSTANCE_FLAGS (type),
-					type);
+            type = make_qualified_aligned_type (SYMBOL_TYPE (sym),
+						TYPE_INSTANCE_FLAGS (type),
+						TYPE_USER_ALIGN (type),
+						type);
 	  else
 	    type = SYMBOL_TYPE (sym);
         }
@@ -2065,7 +2106,7 @@ check_typedef (struct type *type)
 	}
     }
 
-  type = make_qualified_type (type, instance_flags, NULL);
+  type = make_qualified_aligned_type (type, instance_flags, user_align, NULL);
 
   /* Cache TYPE_LENGTH for future use.  */
   TYPE_LENGTH (orig_type) = TYPE_LENGTH (type);
@@ -2881,7 +2922,8 @@ check_types_equal (struct type *type1, struct type *type2,
       || TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
       || TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
       || TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
-      || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
+      || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2)
+      || TYPE_USER_ALIGN (type1) != TYPE_USER_ALIGN (type2))
     return 0;
 
   if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
@@ -3800,6 +3842,10 @@ recursive_dump_type (struct type *type, int spaces)
     {
       puts_filtered (" TYPE_FLAG_ATOMIC");
     }
+  if (TYPE_USER_ALIGN (type) != 0)
+    {
+      printf_filtered (" TYPE_USER_ALIGN (%u)", TYPE_USER_ALIGN (type));
+    }
   puts_filtered ("\n");
 
   printfi_filtered (spaces, "flags");
@@ -4038,6 +4084,7 @@ copy_type_recursive (struct objfile *objfile,
     TYPE_TAG_NAME (new_type) = xstrdup (TYPE_TAG_NAME (type));
 
   TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
+  TYPE_USER_ALIGN (new_type) = TYPE_USER_ALIGN (type);
   TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
 
   /* Copy the fields.  */
@@ -4135,6 +4182,7 @@ copy_type (const struct type *type)
 
   new_type = alloc_type_copy (type);
   TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
+  TYPE_USER_ALIGN (new_type) = TYPE_USER_ALIGN (type);
   TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
   memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type),
 	  sizeof (struct main_type));
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 03468f8..8d70e6b 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -752,10 +752,10 @@ struct type
 
   /* * Variant chain.  This points to a type that differs from this
      one only in qualifiers and length.  Currently, the possible
-     qualifiers are const, volatile, code-space, data-space, and
-     address class.  The length may differ only when one of the
-     address class flags are set.  The variants are linked in a
-     circular ring and share MAIN_TYPE.  */
+     qualifiers are const, volatile, restrict, code-space, data-space,
+     address class and use alignment.  The length may differ only when
+     one of the address class flags are set.  The variants are linked
+     in a circular ring and share MAIN_TYPE.  */
 
   struct type *chain;
 
@@ -797,6 +797,12 @@ struct type
   
   unsigned length;
 
+  /* * User alignment of this type.  This is what alignof(type) would
+     return when explicitly set by the user with c11 _Alignas or
+     __attribute__ ((aligned (X)).  If not explicitly set by the user
+     it is zero and the default alignment would apply.  */
+  unsigned user_align;
+
   /* * Core type, shared by a group of qualified types.  */
 
   struct main_type *main_type;
@@ -1195,6 +1201,7 @@ extern void allocate_gnat_aux_type (struct type *);
 #define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code
 #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields
 #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields
+#define TYPE_USER_ALIGN(thistype) (thistype)->user_align
 
 #define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0)
 #define TYPE_RANGE_DATA(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.bounds
@@ -1636,6 +1643,8 @@ extern struct type *make_restrict_type (struct type *);
 
 extern struct type *make_atomic_type (struct type *);
 
+extern struct type *make_aligned_type (struct type *, unsigned int);
+
 extern void replace_type (struct type *, struct type *);
 
 extern int address_space_name_to_int (struct gdbarch *, char *);
diff --git a/include/ChangeLog b/include/ChangeLog
index 23f27a9..30d82a2 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2014-07-09  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf2.def: Add DW_TAG_aligned_type and DW_AT_alignment.
+
 2014-06-22  Mark Wielaard  <mjw@redhat.com>
 
 	* dwarf2.def: Add DW_TAG_atomic_type.
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 6941922..1b34623 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -135,6 +135,7 @@ DW_TAG (DW_TAG_rvalue_reference_type, 0x42)
 DW_TAG (DW_TAG_template_alias, 0x43)
 /* DWARF 5.  */
 DW_TAG (DW_TAG_atomic_type, 0x47)
+DW_TAG (DW_TAG_aligned_type, 0x48) /* XXX not yet assigned constant.  */
 
 DW_TAG_DUP (DW_TAG_lo_user, 0x4080)
 DW_TAG_DUP (DW_TAG_hi_user, 0xffff)
@@ -310,6 +311,8 @@ DW_AT (DW_AT_data_bit_offset, 0x6b)
 DW_AT (DW_AT_const_expr, 0x6c)
 DW_AT (DW_AT_enum_class, 0x6d)
 DW_AT (DW_AT_linkage_name, 0x6e)
+/* DWARF 5.  */
+DW_TAG (DW_AT_alignment, 0x6f) /* XXX not yet assigned constant.  */
 
 DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start.  */
 DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end.  */
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]