Record LF_STMEMBER field list subtypes to represent static data members in structs.
gcc/ * dwarf2codeview.cc (enum cv_leaf_type): Add LF_STMEMBER. (struct codeview_subtype): Add lf_static_member to union. (write_lf_fieldlist): Handle LF_STMEMBER. (add_struct_member): New function. (add_struct_static_member): New function. (get_accessibility): New function. (get_type_num_struct): Split out into add_struct_member and get_accessibility, and handle static members. --- gcc/dwarf2codeview.cc | 183 +++++++++++++++++++++++++++++++----------- 1 file changed, 135 insertions(+), 48 deletions(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 2535777d4cb..610f884d73d 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -106,6 +106,7 @@ enum cv_leaf_type { LF_UNION = 0x1506, LF_ENUM = 0x1507, LF_MEMBER = 0x150d, + LF_STMEMBER = 0x150e, LF_FUNC_ID = 0x1601, LF_STRING_ID = 0x1605, LF_CHAR = 0x8000, @@ -1218,6 +1219,12 @@ struct codeview_subtype codeview_integer offset; char *name; } lf_member; + struct + { + uint16_t attributes; + uint32_t type; + char *name; + } lf_static_member; }; }; @@ -3663,6 +3670,40 @@ write_lf_fieldlist (codeview_custom_type *t) break; + case LF_STMEMBER: + /* This is lf_static_member in binutils and lfSTMember in Microsoft's + cvinfo.h: + + struct lf_static_member + { + uint16_t kind; + uint16_t attributes; + uint32_t type; + char name[]; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, LF_STMEMBER); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, v->lf_static_member.attributes); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, v->lf_static_member.type); + putc ('\n', asm_out_file); + + name_len = strlen (v->lf_static_member.name) + 1; + ASM_OUTPUT_ASCII (asm_out_file, v->lf_static_member.name, name_len); + + leaf_len = 8 + name_len; + write_cv_padding (4 - (leaf_len % 4)); + + free (v->lf_static_member.name); + break; + default: break; } @@ -4958,6 +4999,91 @@ create_bitfield (dw_die_ref c) return ct->num; } +/* Create an LF_MEMBER field list subtype for a struct member, returning its + pointer in el and its size in el_len. */ + +static void +add_struct_member (dw_die_ref c, uint16_t accessibility, + codeview_subtype **el, size_t *el_len) +{ + *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); + else + (*el)->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type), + true, false); + + (*el)->lf_member.offset.neg = false; + (*el)->lf_member.offset.num = get_AT_unsigned (c, DW_AT_data_member_location); + + *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); + } + else + { + (*el)->lf_member.name = NULL; + } + + if (*el_len % 4) + *el_len += 4 - (*el_len % 4); +} + +/* Create an LF_STMEMBER field list subtype for a static struct member, + returning its pointer in el and its size in el_len. */ + +static void +add_struct_static_member (dw_die_ref c, uint16_t accessibility, + 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); +} + +/* Translate a DWARF DW_AT_accessibility constant into its CodeView + equivalent. If implicit, follow the C++ rules. */ + +static uint16_t +get_accessibility (dw_die_ref c) +{ + switch (get_AT_unsigned (c, DW_AT_accessibility)) + { + case DW_ACCESS_private: + return CV_ACCESS_PRIVATE; + + case DW_ACCESS_protected: + return CV_ACCESS_PROTECTED; + + case DW_ACCESS_public: + return CV_ACCESS_PUBLIC; + + /* Members in a C++ struct or union are public by default, members + in a class are private. */ + default: + if (dw_get_die_tag (dw_get_die_parent (c)) == DW_TAG_class_type) + return CV_ACCESS_PRIVATE; + else + return CV_ACCESS_PUBLIC; + } +} + /* Process a DW_TAG_structure_type, DW_TAG_class_type, or DW_TAG_union_type DIE, add an LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS / LF_UNION type, and return the number of the latter. */ @@ -5002,66 +5128,27 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref) do { codeview_subtype *el; - size_t el_len; + size_t el_len = 0; + uint16_t accessibility = get_accessibility (c); c = dw_get_die_sib (c); - if (dw_get_die_tag (c) != DW_TAG_member) - continue; - - el = (codeview_subtype *) xmalloc (sizeof (*el)); - el->next = NULL; - el->kind = LF_MEMBER; - - switch (get_AT_unsigned (c, DW_AT_accessibility)) + switch (dw_get_die_tag (c)) { - case DW_ACCESS_private: - el->lf_member.attributes = CV_ACCESS_PRIVATE; + case DW_TAG_member: + add_struct_member (c, accessibility, &el, &el_len); break; - case DW_ACCESS_protected: - el->lf_member.attributes = CV_ACCESS_PROTECTED; + case DW_TAG_variable: + add_struct_static_member (c, accessibility, &el, &el_len); break; - case DW_ACCESS_public: - el->lf_member.attributes = CV_ACCESS_PUBLIC; - break; - - /* Members in a C++ struct or union are public by default, members - in a class are private. */ default: - if (dw_get_die_tag (type) == DW_TAG_class_type) - el->lf_member.attributes = CV_ACCESS_PRIVATE; - else - el->lf_member.attributes = CV_ACCESS_PUBLIC; break; } - if (get_AT (c, DW_AT_data_bit_offset)) - 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.offset.neg = false; - el->lf_member.offset.num = get_AT_unsigned (c, - DW_AT_data_member_location); - - el_len = 11; - el_len += 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); - } - else - { - el->lf_member.name = NULL; - } - - if (el_len % 4) - el_len += 4 - (el_len % 4); + if (el_len == 0) + continue; /* Add an LF_INDEX subtype if everything's too big for one LF_FIELDLIST. */ -- 2.44.2