From patchwork Wed Jul 9 22:20:57 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Wielaard X-Patchwork-Id: 1988 Received: (qmail 6042 invoked by alias); 9 Jul 2014 22:21:28 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 6022 invoked by uid 89); 9 Jul 2014 22:21:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, SPF_PASS autolearn=no version=3.3.2 X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Wed, 09 Jul 2014 22:21:23 +0000 From: Mark Wielaard To: gdb-patches@sourceware.org Cc: Tom Tromey , Joel Brobecker , Mark Wielaard Subject: [PATCH] DWARFv5 DW_TAG_aligned_type. Date: Thu, 10 Jul 2014 00:20:57 +0200 Message-Id: <1404944457-4500-1-git-send-email-mjw@redhat.com> X-Spam-Score: -2.9 (--) 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 + + * 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 * 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 + + * dwarf2.def: Add DW_TAG_aligned_type and DW_AT_alignment. + 2014-06-22 Mark Wielaard * 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. */