If a CodeView struct, class, or union has as a member an anonymous struct, class, or union, this gets flattened. The sub-struct's members will appear as if they were part of their parent.
For this, we move part of get_type_num_struct into a new function add_to_fieldlist, which also handles creating an LF_INDEX overflow item if an LF_FIELDLIST grows too large. This is because add_struct_member now calls itself recursively, and so needs to handle overflows itself. gcc/ * dwarf2codeview.cc (add_to_fieldlist): New function. (add_struct_member): Call recursively to flatten structs, and call add_to_fieldlist. (add_struct_static_member): Call add_to_fieldlist. (add_struct_function): Call add_to_fieldlist. (add_struct_inheritance): Call add_to_fieldlist. (add_struct_nested_type): Call add_to_fieldlist. (get_type_num_struct): Move code to add_to_fieldlist, and move responsibility for this to subfunctions. --- gcc/dwarf2codeview.cc | 280 +++++++++++++++++++++++++----------------- 1 file changed, 167 insertions(+), 113 deletions(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 261fcea6a97..59380335991 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -5901,6 +5901,52 @@ add_struct_forward_def (dw_die_ref type) return ct->num; } +/* Add a new subtype to an LF_FIELDLIST type, and handle overflows if + necessary. */ + +static void +add_to_fieldlist (codeview_custom_type **ct, uint16_t *num_members, + codeview_subtype *el, size_t el_len) +{ + /* Add an LF_INDEX subtype if everything's too big for one + LF_FIELDLIST. */ + + if ((*ct)->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE) + { + codeview_subtype *idx; + codeview_custom_type *ct2; + + idx = (codeview_subtype *) xmalloc (sizeof (*idx)); + idx->next = NULL; + idx->kind = LF_INDEX; + idx->lf_index.type_num = 0; + + (*ct)->lf_fieldlist.last_subtype->next = idx; + (*ct)->lf_fieldlist.last_subtype = idx; + + ct2 = (codeview_custom_type *) + xmalloc (sizeof (codeview_custom_type)); + + ct2->next = *ct; + ct2->kind = LF_FIELDLIST; + ct2->lf_fieldlist.length = 0; + ct2->lf_fieldlist.subtypes = NULL; + ct2->lf_fieldlist.last_subtype = NULL; + + *ct = ct2; + } + + (*ct)->lf_fieldlist.length += el_len; + + if ((*ct)->lf_fieldlist.last_subtype) + (*ct)->lf_fieldlist.last_subtype->next = el; + else + (*ct)->lf_fieldlist.subtypes = el; + + (*ct)->lf_fieldlist.last_subtype = el; + (*num_members)++; +} + /* Add an LF_BITFIELD type, returning its number. DWARF represents bitfields as members in a struct with a DW_AT_data_bit_offset attribute, whereas in CodeView they're a distinct type. */ @@ -5933,36 +5979,69 @@ create_bitfield (dw_die_ref c) static void add_struct_member (dw_die_ref c, uint16_t accessibility, - codeview_subtype **el, size_t *el_len) + codeview_custom_type **ct, uint16_t *num_members, + unsigned int base_offset) { - *el = (codeview_subtype *) xmalloc (sizeof (**el)); - (*el)->next = NULL; - (*el)->kind = LF_MEMBER; - (*el)->lf_member.attributes = accessibility; + codeview_subtype *el; + size_t el_len; + dw_die_ref type = get_AT_ref (c, DW_AT_type); + unsigned int offset; + + offset = base_offset + get_AT_unsigned (c, DW_AT_data_member_location); + + /* If the data member is actually an anonymous struct, class, or union, + follow MSVC by flattening this into its parent. */ + if (!get_AT_string (c, DW_AT_name) && type + && (dw_get_die_tag (type) == DW_TAG_structure_type + || dw_get_die_tag (type) == DW_TAG_class_type + || dw_get_die_tag (type) == DW_TAG_union_type)) + { + dw_die_ref c2, first_child; + + first_child = dw_get_die_child (type); + c2 = first_child; + + do + { + c2 = dw_get_die_sib (c2); + + if (dw_get_die_tag (c2) == DW_TAG_member) + add_struct_member (c2, accessibility, ct, num_members, offset); + } + while (c2 != first_child); + + return; + } + + el = (codeview_subtype *) xmalloc (sizeof (*el)); + el->next = NULL; + el->kind = LF_MEMBER; + el->lf_member.attributes = accessibility; if (get_AT (c, DW_AT_data_bit_offset)) - (*el)->lf_member.type = create_bitfield (c); + el->lf_member.type = create_bitfield (c); else - (*el)->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type), - true, false); + el->lf_member.type = get_type_num (type, true, false); - (*el)->lf_member.offset.neg = false; - (*el)->lf_member.offset.num = get_AT_unsigned (c, DW_AT_data_member_location); + el->lf_member.offset.neg = false; + el->lf_member.offset.num = offset; - *el_len = 11 + cv_integer_len (&(*el)->lf_member.offset); + el_len = 11 + cv_integer_len (&el->lf_member.offset); if (get_AT_string (c, DW_AT_name)) { - (*el)->lf_member.name = xstrdup (get_AT_string (c, DW_AT_name)); - *el_len += strlen ((*el)->lf_member.name); + el->lf_member.name = xstrdup (get_AT_string (c, DW_AT_name)); + el_len += strlen (el->lf_member.name); } else { - (*el)->lf_member.name = NULL; + el->lf_member.name = NULL; } - if (*el_len % 4) - *el_len += 4 - (*el_len % 4); + if (el_len % 4) + el_len += 4 - (el_len % 4); + + add_to_fieldlist (ct, num_members, el, el_len); } /* Create an LF_STMEMBER field list subtype for a static struct member, @@ -5970,20 +6049,25 @@ add_struct_member (dw_die_ref c, uint16_t accessibility, static void add_struct_static_member (dw_die_ref c, uint16_t accessibility, - codeview_subtype **el, size_t *el_len) + codeview_custom_type **ct, uint16_t *num_members) { - *el = (codeview_subtype *) xmalloc (sizeof (**el)); - (*el)->next = NULL; - (*el)->kind = LF_STMEMBER; - (*el)->lf_static_member.attributes = accessibility; - (*el)->lf_static_member.type = get_type_num (get_AT_ref (c, DW_AT_type), - true, false); - (*el)->lf_static_member.name = xstrdup (get_AT_string (c, DW_AT_name)); - - *el_len = 9 + strlen ((*el)->lf_static_member.name); - - if (*el_len % 4) - *el_len += 4 - (*el_len % 4); + codeview_subtype *el; + size_t el_len; + + el = (codeview_subtype *) xmalloc (sizeof (*el)); + el->next = NULL; + el->kind = LF_STMEMBER; + el->lf_static_member.attributes = accessibility; + el->lf_static_member.type = get_type_num (get_AT_ref (c, DW_AT_type), + true, false); + el->lf_static_member.name = xstrdup (get_AT_string (c, DW_AT_name)); + + el_len = 9 + strlen (el->lf_static_member.name); + + if (el_len % 4) + el_len += 4 - (el_len % 4); + + add_to_fieldlist (ct, num_members, el, el_len); } /* Create a field list subtype for a struct function, returning its pointer in @@ -5994,10 +6078,12 @@ add_struct_static_member (dw_die_ref c, uint16_t accessibility, static void add_struct_function (dw_die_ref c, hash_table<method_hasher> *method_htab, - codeview_subtype **el, size_t *el_len) + codeview_custom_type **ct, uint16_t *num_members) { const char *name = get_AT_string (c, DW_AT_name); codeview_method **slot, *meth; + codeview_subtype *el; + size_t el_len; slot = method_htab->find_slot_with_hash (name, htab_hash_string (name), NO_INSERT); @@ -6006,17 +6092,17 @@ add_struct_function (dw_die_ref c, hash_table<method_hasher> *method_htab, meth = *slot; - *el = (codeview_subtype *) xmalloc (sizeof (**el)); - (*el)->next = NULL; + el = (codeview_subtype *) xmalloc (sizeof (*el)); + el->next = NULL; if (meth->count == 1) { - (*el)->kind = LF_ONEMETHOD; - (*el)->lf_onemethod.method_attribute = meth->attribute; - (*el)->lf_onemethod.method_type = meth->type; - (*el)->lf_onemethod.name = xstrdup (name); + el->kind = LF_ONEMETHOD; + el->lf_onemethod.method_attribute = meth->attribute; + el->lf_onemethod.method_type = meth->type; + el->lf_onemethod.name = xstrdup (name); - *el_len = 9 + strlen ((*el)->lf_onemethod.name); + el_len = 9 + strlen (el->lf_onemethod.name); } else { @@ -6041,16 +6127,18 @@ add_struct_function (dw_die_ref c, hash_table<method_hasher> *method_htab, add_custom_type (ct); - (*el)->kind = LF_METHOD; - (*el)->lf_method.count = meth->count; - (*el)->lf_method.method_list = ct->num; - (*el)->lf_method.name = xstrdup (name); + el->kind = LF_METHOD; + el->lf_method.count = meth->count; + el->lf_method.method_list = ct->num; + el->lf_method.name = xstrdup (name); - *el_len = 9 + strlen ((*el)->lf_method.name); + el_len = 9 + strlen (el->lf_method.name); } - if (*el_len % 4) - *el_len += 4 - (*el_len % 4); + if (el_len % 4) + el_len += 4 - (el_len % 4); + + add_to_fieldlist (ct, num_members, el, el_len); method_htab->remove_elt_with_hash (name, htab_hash_string (name)); @@ -6069,27 +6157,32 @@ add_struct_function (dw_die_ref c, hash_table<method_hasher> *method_htab, static void add_struct_inheritance (dw_die_ref c, uint16_t accessibility, - codeview_subtype **el, size_t *el_len) + codeview_custom_type **ct, uint16_t *num_members) { + codeview_subtype *el; + size_t el_len; + /* FIXME: if DW_AT_virtuality is DW_VIRTUALITY_virtual this is a virtual base class, and we should be issuing an LF_VBCLASS record instead. */ if (get_AT_unsigned (c, DW_AT_virtuality) == DW_VIRTUALITY_virtual) return; - *el = (codeview_subtype *) xmalloc (sizeof (**el)); - (*el)->next = NULL; - (*el)->kind = LF_BCLASS; - (*el)->lf_bclass.attributes = accessibility; - (*el)->lf_bclass.base_class_type = get_type_num (get_AT_ref (c, DW_AT_type), + el = (codeview_subtype *) xmalloc (sizeof (*el)); + el->next = NULL; + el->kind = LF_BCLASS; + el->lf_bclass.attributes = accessibility; + el->lf_bclass.base_class_type = get_type_num (get_AT_ref (c, DW_AT_type), true, false); - (*el)->lf_bclass.offset.neg = false; - (*el)->lf_bclass.offset.num = get_AT_unsigned (c, DW_AT_data_member_location); + el->lf_bclass.offset.neg = false; + el->lf_bclass.offset.num = get_AT_unsigned (c, DW_AT_data_member_location); - *el_len = 10 + cv_integer_len (&(*el)->lf_bclass.offset); + el_len = 10 + cv_integer_len (&el->lf_bclass.offset); - if (*el_len % 4) - *el_len += 4 - (*el_len % 4); + if (el_len % 4) + el_len += 4 - (el_len % 4); + + add_to_fieldlist (ct, num_members, el, el_len); } /* Create a new LF_MFUNCTION type for a struct function, add it to the @@ -6186,26 +6279,30 @@ is_templated_func (dw_die_ref die) contained within it. */ static void -add_struct_nested_type (dw_die_ref c, codeview_subtype **el, size_t *el_len) +add_struct_nested_type (dw_die_ref c, codeview_custom_type **ct, + uint16_t *num_members) { const char *name = get_AT_string (c, DW_AT_name); - size_t name_len; + codeview_subtype *el; + size_t name_len, el_len; if (!name) return; name_len = strlen (name); - *el = (codeview_subtype *) xmalloc (sizeof (**el)); - (*el)->next = NULL; - (*el)->kind = LF_NESTTYPE; - (*el)->lf_nesttype.type = get_type_num (c, true, false); - (*el)->lf_nesttype.name = xstrdup (name); + el = (codeview_subtype *) xmalloc (sizeof (*el)); + el->next = NULL; + el->kind = LF_NESTTYPE; + el->lf_nesttype.type = get_type_num (c, true, false); + el->lf_nesttype.name = xstrdup (name); - *el_len = 9 + name_len; + el_len = 9 + name_len; - if (*el_len % 4) - *el_len += 4 - (*el_len % 4); + if (el_len % 4) + el_len += 4 - (el_len % 4); + + add_to_fieldlist (ct, num_members, el, el_len); } /* Process a DW_TAG_structure_type, DW_TAG_class_type, or DW_TAG_union_type @@ -6319,8 +6416,6 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref) c = first_child; do { - codeview_subtype *el; - size_t el_len = 0; uint16_t accessibility; c = dw_get_die_sib (c); @@ -6330,73 +6425,32 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref) switch (dw_get_die_tag (c)) { case DW_TAG_member: - add_struct_member (c, accessibility, &el, &el_len); + add_struct_member (c, accessibility, &ct, &num_members, 0); break; case DW_TAG_variable: - add_struct_static_member (c, accessibility, &el, &el_len); + add_struct_static_member (c, accessibility, &ct, &num_members); break; case DW_TAG_subprogram: if (!is_templated_func (c)) - add_struct_function (c, method_htab, &el, &el_len); + add_struct_function (c, method_htab, &ct, &num_members); break; case DW_TAG_inheritance: - add_struct_inheritance (c, accessibility, &el, &el_len); + add_struct_inheritance (c, accessibility, &ct, &num_members); break; case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: case DW_TAG_enumeration_type: - add_struct_nested_type (c, &el, &el_len); + add_struct_nested_type (c, &ct, &num_members); break; default: break; } - - if (el_len == 0) - continue; - - /* Add an LF_INDEX subtype if everything's too big for one - LF_FIELDLIST. */ - - if (ct->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE) - { - codeview_subtype *idx; - codeview_custom_type *ct2; - - idx = (codeview_subtype *) xmalloc (sizeof (*idx)); - idx->next = NULL; - idx->kind = LF_INDEX; - idx->lf_index.type_num = 0; - - ct->lf_fieldlist.last_subtype->next = idx; - ct->lf_fieldlist.last_subtype = idx; - - ct2 = (codeview_custom_type *) - xmalloc (sizeof (codeview_custom_type)); - - ct2->next = ct; - ct2->kind = LF_FIELDLIST; - ct2->lf_fieldlist.length = 0; - ct2->lf_fieldlist.subtypes = NULL; - ct2->lf_fieldlist.last_subtype = NULL; - - ct = ct2; - } - - ct->lf_fieldlist.length += el_len; - - if (ct->lf_fieldlist.last_subtype) - ct->lf_fieldlist.last_subtype->next = el; - else - ct->lf_fieldlist.subtypes = el; - - ct->lf_fieldlist.last_subtype = el; - num_members++; } while (c != first_child); -- 2.45.2