From patchwork Tue Jun 18 00:17:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 1948907 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=harmstone.com header.i=@harmstone.com header.a=rsa-sha256 header.s=mail header.b=Mxg4svAS; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W36p44dhkz20Wb for ; Tue, 18 Jun 2024 10:19:56 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C2C033882172 for ; Tue, 18 Jun 2024 00:19:54 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail.burntcomma.com (mail2.burntcomma.com [217.169.27.34]) by sourceware.org (Postfix) with ESMTPS id 1F4883882075 for ; Tue, 18 Jun 2024 00:17:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1F4883882075 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=harmstone.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=harmstone.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1F4883882075 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=217.169.27.34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718669922; cv=none; b=VjoHQoJtpGTWZp7D6+GMOBJIRoRlxKphdinDwdR0U7sjBstm5C4FQedrwaXynnYCdiyTQC3sdLiKX4Cd5G0E3CerI1yDUhpzUnHkA7bBauvVqEpUnVAmNiEn2AK1yUR1LrkrWm8JDfUphKvMc+FALzD34u+TQAIq+UbceI5t2Qw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718669922; c=relaxed/simple; bh=ebRjSj0yePSEJwt1m8vzq2d5PYPktadLpTjJdclcu6I=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:Mime-Version; b=us/SH7yNC/MiSPzI/Ihwidz3OUK8kHbVPLLnwQ9ExKQIuF8Xy+6ppotm3kL7ml7C25LFdytRcVZkE3BpBQLr7I9MqBpB9lirQUxcUTKb4CvsLPQQADDoRLkfPg9pw4SqHafeDbOMANlEhA3F7UxowfOAmVl+DvJV2hEDjKVmEBQ= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from localhost.localdomain (beren.burntcomma.com [IPv6:2a02:8012:8cf0:0:b62e:99ff:fee9:ad9f]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by mail.burntcomma.com (Postfix) with ESMTPSA id DE3CD3CF0021; Tue, 18 Jun 2024 01:17:21 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=harmstone.com; s=mail; t=1718669841; bh=sdpedVC1E9EcdxgNwLgOy9M13zlk2EsyLb0PqSKbDlk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Mxg4svAS2GdMQbemw33ZtLjIYQnIUrUhfAnWMgDckW4uTdGzF+f6fU2mM3i3OYtiN v57ceykriOMGbXl5xdXY22J1VRhX44zEW+ke3FcwTcWIgJMkknYSfoy0k6OUcN0Kld XLpx8iJoGI0j6XecYF8Q1GWnraF/W9dbo8fsaocw= From: Mark Harmstone To: gcc-patches@gcc.gnu.org Cc: Mark Harmstone Subject: [PATCH 07/11] Handle structs and classes for CodeView Date: Tue, 18 Jun 2024 01:17:09 +0100 Message-ID: <20240618001713.24034-8-mark@harmstone.com> In-Reply-To: <20240618001713.24034-1-mark@harmstone.com> References: <20240618001713.24034-1-mark@harmstone.com> Mime-Version: 1.0 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Translates DW_TAG_structure_type DIEs into LF_STRUCTURE symbols, and DW_TAG_class_type DIEs into LF_CLASS symbols. gcc/ * dwarf2codeview.cc (struct codeview_type): Add is_fwd_ref member. (struct codeview_subtype): Add lf_member to union. (struct codeview_custom_type): Add lf_structure to union. (struct codeview_deferred_type): New structure. (deferred_types, last_deferred_type): New variables. (get_type_num): Add new args to prototype. (write_lf_fieldlist): Handle LF_MEMBER subtypes. (write_lf_structure): New function. (write_custom_types): Call write_lf_structure. (get_type_num_pointer_type): Add in_struct argument. (get_type_num_const_type): Likewise. (get_type_num_volatile_type): Likewise. (add_enum_forward_def): Fix get_type_num call. (get_type_num_enumeration_type): Add in-struct argument. (add_deferred_type, flush_deferred_types): New functions. (add_struct_forward_def, get_type_num_struct): Likewise. (get_type_num): Handle self-referential structs. (add_variable): Fix get_type_num call. (codeview_debug_early_finish): Call flush_deferred_types. * dwarf2codeview.h (LF_CLASS, LF_STRUCTURE, LF_MEMBER): Define. --- gcc/dwarf2codeview.cc | 513 ++++++++++++++++++++++++++++++++++++++++-- gcc/dwarf2codeview.h | 3 + 2 files changed, 493 insertions(+), 23 deletions(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 475a53573e9..9c6614f6297 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -158,6 +158,7 @@ struct codeview_type { dw_die_ref die; uint32_t num; + bool is_fwd_ref; }; struct die_hasher : free_ptr_hash @@ -197,6 +198,13 @@ struct codeview_subtype { uint32_t type_num; } lf_index; + struct + { + uint16_t attributes; + uint32_t type; + codeview_integer offset; + char *name; + } lf_member; }; }; @@ -232,9 +240,25 @@ struct codeview_custom_type uint32_t fieldlist; char *name; } lf_enum; + struct + { + uint16_t num_members; + uint16_t properties; + uint32_t field_list; + uint32_t derived_from; + uint32_t vshape; + codeview_integer length; + char *name; + } lf_structure; }; }; +struct codeview_deferred_type +{ + struct codeview_deferred_type *next; + dw_die_ref type; +}; + static unsigned int line_label_num; static unsigned int func_label_num; static unsigned int sym_label_num; @@ -249,8 +273,9 @@ static uint32_t last_file_id; static codeview_symbol *sym, *last_sym; static hash_table *types_htab; static codeview_custom_type *custom_types, *last_custom_type; +static codeview_deferred_type *deferred_types, *last_deferred_type; -static uint32_t get_type_num (dw_die_ref type); +static uint32_t get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref); /* Record new line number against the current function. */ @@ -1217,6 +1242,51 @@ write_lf_fieldlist (codeview_custom_type *t) free (v->lf_enumerate.name); break; + case LF_MEMBER: + /* This is lf_member in binutils and lfMember in Microsoft's + cvinfo.h: + + struct lf_member + { + uint16_t kind; + uint16_t attributes; + uint32_t type; + uint16_t offset; + char name[]; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, LF_MEMBER); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, v->lf_member.attributes); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, v->lf_member.type); + putc ('\n', asm_out_file); + + leaf_len = 8 + write_cv_integer (&v->lf_member.offset); + + if (v->lf_member.name) + { + name_len = strlen (v->lf_member.name) + 1; + ASM_OUTPUT_ASCII (asm_out_file, v->lf_member.name, name_len); + } + else + { + name_len = 1; + ASM_OUTPUT_ASCII (asm_out_file, "", name_len); + } + + leaf_len += name_len; + write_cv_padding (4 - (leaf_len % 4)); + + free (v->lf_member.name); + break; + case LF_INDEX: /* This is lf_index in binutils and lfIndex in Microsoft's cvinfo.h: @@ -1308,6 +1378,82 @@ write_lf_enum (codeview_custom_type *t) asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num); } +/* Write an LF_STRUCTURE or LF_CLASS type (the two have the same structure). */ + +static void +write_lf_structure (codeview_custom_type *t) +{ + size_t name_len, leaf_len; + + /* This is lf_class in binutils and lfClass in Microsoft's cvinfo.h: + + struct lf_class + { + uint16_t size; + uint16_t kind; + uint16_t num_members; + uint16_t properties; + uint32_t field_list; + uint32_t derived_from; + uint32_t vshape; + uint16_t length; + char name[]; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, "%LLcv_type%x_end - %LLcv_type%x_start\n", + t->num, t->num); + + asm_fprintf (asm_out_file, "%LLcv_type%x_start:\n", t->num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, t->kind); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_structure.num_members); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_structure.properties); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_structure.field_list); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_structure.derived_from); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_structure.vshape); + putc ('\n', asm_out_file); + + leaf_len = 20 + write_cv_integer (&t->lf_structure.length); + + if (t->lf_structure.name) + { + name_len = strlen (t->lf_structure.name) + 1; + ASM_OUTPUT_ASCII (asm_out_file, t->lf_structure.name, name_len); + } + else + { + static const char unnamed_struct[] = ""; + + name_len = sizeof (unnamed_struct); + ASM_OUTPUT_ASCII (asm_out_file, unnamed_struct, name_len); + } + + leaf_len += name_len; + write_cv_padding (4 - (leaf_len % 4)); + + free (t->lf_structure.name); + + asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num); +} + /* Write the .debug$T section, which contains all of our custom type definitions. */ @@ -1341,6 +1487,11 @@ write_custom_types (void) case LF_ENUM: write_lf_enum (custom_types); break; + + case LF_STRUCTURE: + case LF_CLASS: + write_lf_structure (custom_types); + break; } free (custom_types); @@ -1527,7 +1678,7 @@ add_custom_type (codeview_custom_type *ct) LF_POINTER type and return its number. */ static uint32_t -get_type_num_pointer_type (dw_die_ref type) +get_type_num_pointer_type (dw_die_ref type, bool in_struct) { uint32_t base_type_num, byte_size; dw_die_ref base_type; @@ -1543,7 +1694,7 @@ get_type_num_pointer_type (dw_die_ref type) if (!base_type) return byte_size == 4 ? T_32PVOID : T_64PVOID; - base_type_num = get_type_num (base_type); + base_type_num = get_type_num (base_type, in_struct, false); if (base_type_num == 0) return 0; @@ -1580,7 +1731,7 @@ get_type_num_pointer_type (dw_die_ref type) its number. */ static uint32_t -get_type_num_const_type (dw_die_ref type) +get_type_num_const_type (dw_die_ref type, bool in_struct) { dw_die_ref base_type; uint32_t base_type_num; @@ -1602,7 +1753,7 @@ get_type_num_const_type (dw_die_ref type) return 0; } - base_type_num = get_type_num (base_type); + base_type_num = get_type_num (base_type, in_struct, false); if (base_type_num == 0) return 0; @@ -1625,12 +1776,13 @@ get_type_num_const_type (dw_die_ref type) returning its number. */ static uint32_t -get_type_num_volatile_type (dw_die_ref type) +get_type_num_volatile_type (dw_die_ref type, bool in_struct) { uint32_t base_type_num; codeview_custom_type *ct; - base_type_num = get_type_num (get_AT_ref (type, DW_AT_type)); + base_type_num = get_type_num (get_AT_ref (type, DW_AT_type), in_struct, + false); if (base_type_num == 0) return 0; @@ -1660,7 +1812,8 @@ add_enum_forward_def (dw_die_ref type) ct->lf_enum.count = 0; ct->lf_enum.properties = CV_PROP_FWDREF; - ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type)); + ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type), + false, false); ct->lf_enum.fieldlist = 0; ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name)); @@ -1673,7 +1826,7 @@ add_enum_forward_def (dw_die_ref type) type, returning the number of the latter. */ static uint32_t -get_type_num_enumeration_type (dw_die_ref type) +get_type_num_enumeration_type (dw_die_ref type, bool in_struct) { dw_die_ref first_child; codeview_custom_type *ct; @@ -1819,7 +1972,8 @@ get_type_num_enumeration_type (dw_die_ref type) ct->kind = LF_ENUM; ct->lf_enum.count = count; ct->lf_enum.properties = 0; - ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type)); + ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type), + in_struct, false); ct->lf_enum.fieldlist = last_type; ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name)); @@ -1828,6 +1982,292 @@ get_type_num_enumeration_type (dw_die_ref type) return ct->num; } +/* Add a DIE to our deferred_types list. This happens when we have a struct + with a pointer to a type that hasn't been defined yet, but which gets + defined later on. */ + +static void +add_deferred_type (dw_die_ref type) +{ + codeview_deferred_type *def; + + def = (codeview_deferred_type *) xmalloc (sizeof (codeview_deferred_type)); + + def->next = NULL; + def->type = type; + + if (!deferred_types) + deferred_types = def; + else + last_deferred_type->next = def; + + last_deferred_type = def; +} + +/* Flush the contents of our deferred_types list. This happens after everything + else has been written. We call get_type_num to ensure that a type gets + added to custom_types, if it hasn't been already. */ + +static void +flush_deferred_types (void) +{ + while (deferred_types) + { + codeview_deferred_type *next; + + next = deferred_types->next; + + get_type_num (deferred_types->type, false, true); + + free (deferred_types); + deferred_types = next; + } + + last_deferred_type = NULL; +} + +/* Add a forward definition for a struct or class. */ + +static uint32_t +add_struct_forward_def (dw_die_ref type) +{ + codeview_custom_type *ct; + + ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type)); + + ct->next = NULL; + + switch (dw_get_die_tag (type)) + { + case DW_TAG_class_type: + ct->kind = LF_CLASS; + break; + + case DW_TAG_structure_type: + ct->kind = LF_STRUCTURE; + break; + + default: + break; + } + + ct->lf_structure.num_members = 0; + ct->lf_structure.properties = CV_PROP_FWDREF; + ct->lf_structure.field_list = 0; + ct->lf_structure.derived_from = 0; + ct->lf_structure.vshape = 0; + ct->lf_structure.length.neg = false; + ct->lf_structure.length.num = 0; + ct->lf_structure.name = xstrdup (get_AT_string (type, DW_AT_name)); + + add_custom_type (ct); + + if (!get_AT_flag (type, DW_AT_declaration)) + add_deferred_type (type); + + return ct->num; +} + +/* Process a DW_TAG_structure_type or DW_TAG_class_type DIE, add an + LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS type, and return the number of + the latter. */ + +static uint32_t +get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref) +{ + dw_die_ref first_child; + codeview_custom_type *ct; + uint16_t num_members = 0; + uint32_t last_type; + const char *name; + + if ((in_struct && get_AT_string (type, DW_AT_name)) + || get_AT_flag (type, DW_AT_declaration)) + { + *is_fwd_ref = true; + return add_struct_forward_def (type); + } + + *is_fwd_ref = false; + + /* First, add an LF_FIELDLIST for the structure's members. We don't need to + worry about deduplication here, as ld will take care of that for us. + If there's a lot of entries, add more LF_FIELDLISTs with LF_INDEXes + pointing to the overflow lists. */ + + first_child = dw_get_die_child (type); + + ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type)); + + ct->next = NULL; + ct->kind = LF_FIELDLIST; + ct->lf_fieldlist.length = 0; + ct->lf_fieldlist.subtypes = NULL; + ct->lf_fieldlist.last_subtype = NULL; + + if (first_child) + { + dw_die_ref c; + + c = first_child; + do + { + codeview_subtype *el; + size_t el_len; + + 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)) + { + case DW_ACCESS_private: + el->lf_member.attributes = CV_ACCESS_PRIVATE; + break; + + case DW_ACCESS_protected: + el->lf_member.attributes = CV_ACCESS_PROTECTED; + 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; + } + + 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); + + /* 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); + } + + while (ct) + { + codeview_custom_type *ct2; + + ct2 = ct->next; + ct->next = NULL; + + if (ct->lf_fieldlist.last_subtype->kind == LF_INDEX) + ct->lf_fieldlist.last_subtype->lf_index.type_num = last_type; + + add_custom_type (ct); + last_type = ct->num; + + ct = ct2; + } + + /* Now add an LF_STRUCTURE / LF_CLASS, pointing to the LF_FIELDLIST we just + added. */ + + ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type)); + + ct->next = NULL; + + switch (dw_get_die_tag (type)) + { + case DW_TAG_class_type: + ct->kind = LF_CLASS; + break; + + case DW_TAG_structure_type: + ct->kind = LF_STRUCTURE; + break; + + default: + break; + } + + ct->lf_structure.num_members = num_members; + ct->lf_structure.properties = 0; + ct->lf_structure.field_list = last_type; + ct->lf_structure.derived_from = 0; + ct->lf_structure.vshape = 0; + ct->lf_structure.length.neg = false; + ct->lf_structure.length.num = get_AT_unsigned (type, DW_AT_byte_size); + + name = get_AT_string (type, DW_AT_name); + + if (name) + ct->lf_structure.name = xstrdup (name); + else + ct->lf_structure.name = NULL; + + add_custom_type (ct); + + return ct->num; +} + /* Process a DIE representing a type definition, add a CodeView type if necessary, and return its number. If it's something we can't handle, return 0. We keep a hash table so that we're not adding the same type multiple @@ -1835,9 +2275,11 @@ get_type_num_enumeration_type (dw_die_ref type) everything for us. */ static uint32_t -get_type_num (dw_die_ref type) +get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref) { codeview_type **slot, *t; + uint32_t num; + bool is_fwd_ref; if (!type) return 0; @@ -1846,47 +2288,69 @@ get_type_num (dw_die_ref type) types_htab = new hash_table (10); slot = types_htab->find_slot_with_hash (type, htab_hash_pointer (type), - INSERT); + NO_INSERT); - if (*slot) + if (slot && *slot && (!no_fwd_ref || !(*slot)->is_fwd_ref)) return (*slot)->num; - t = (codeview_type *) xmalloc (sizeof (codeview_type)); - t->die = type; + is_fwd_ref = false; switch (dw_get_die_tag (type)) { case DW_TAG_base_type: - t->num = get_type_num_base_type (type); + num = get_type_num_base_type (type); break; case DW_TAG_typedef: /* FIXME - signed longs typedef'd as "HRESULT" should get their own type (T_HRESULT) */ - t->num = get_type_num (get_AT_ref (type, DW_AT_type)); + num = get_type_num (get_AT_ref (type, DW_AT_type), in_struct, false); break; case DW_TAG_pointer_type: - t->num = get_type_num_pointer_type (type); + num = get_type_num_pointer_type (type, in_struct); break; case DW_TAG_const_type: - t->num = get_type_num_const_type (type); + num = get_type_num_const_type (type, in_struct); break; case DW_TAG_volatile_type: - t->num = get_type_num_volatile_type (type); + num = get_type_num_volatile_type (type, in_struct); break; case DW_TAG_enumeration_type: - t->num = get_type_num_enumeration_type (type); + num = get_type_num_enumeration_type (type, in_struct); + break; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + num = get_type_num_struct (type, in_struct, &is_fwd_ref); break; default: - t->num = 0; + num = 0; break; } + /* Check hash table again, and account for the fact that self-referential + structs will have created a forward reference to themselves. */ + + slot = types_htab->find_slot_with_hash (type, htab_hash_pointer (type), + INSERT); + + if (*slot && (*slot)->is_fwd_ref && !is_fwd_ref) + { + (*slot)->num = num; + (*slot)->is_fwd_ref = false; + return num; + } + + t = (codeview_type *) xmalloc (sizeof (codeview_type)); + t->die = type; + t->num = num; + t->is_fwd_ref = is_fwd_ref; + *slot = t; return t->num; @@ -1909,7 +2373,8 @@ add_variable (dw_die_ref die) s->next = NULL; s->kind = get_AT (die, DW_AT_external) ? S_GDATA32 : S_LDATA32; - s->data_symbol.type = get_type_num (get_AT_ref (die, DW_AT_type)); + s->data_symbol.type = get_type_num (get_AT_ref (die, DW_AT_type), false, + false); s->data_symbol.name = xstrdup (name); s->data_symbol.die = die; @@ -1944,6 +2409,8 @@ codeview_debug_early_finish (dw_die_ref die) c = dw_get_die_sib (c); } while (c != first_child); + + flush_deferred_types (); } #endif diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h index 3f3695625c4..d4740247d93 100644 --- a/gcc/dwarf2codeview.h +++ b/gcc/dwarf2codeview.h @@ -66,7 +66,10 @@ along with GCC; see the file COPYING3. If not see #define LF_FIELDLIST 0x1203 #define LF_INDEX 0x1404 #define LF_ENUMERATE 0x1502 +#define LF_CLASS 0x1504 +#define LF_STRUCTURE 0x1505 #define LF_ENUM 0x1507 +#define LF_MEMBER 0x150d #define LF_CHAR 0x8000 #define LF_SHORT 0x8001 #define LF_USHORT 0x8002