From patchwork Thu Nov 7 04:39:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 2007837 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=aIzYCpI7; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; 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 [IPv6:2620:52:3:1:0:246e:9693:128c]) (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 4XkTrl1Wxdz1xyS for ; Thu, 7 Nov 2024 15:40:05 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 716773858C50 for ; Thu, 7 Nov 2024 04:40:02 +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 89BFE3858D28 for ; Thu, 7 Nov 2024 04:39:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 89BFE3858D28 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 89BFE3858D28 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=1730954376; cv=none; b=pfyIX+mL8QEv2nGvAlPvwuBcpTdvuCwdL8gnCRVcgMTpaI/5kgJLWUuXkYJwspjGOxtllR4oOjZP67jwYaTW8nI6HBt84UJAD9nNgWUgYSSV/TnIUSi6mZXxW+PtE0afnPiRrAUwXpz5N0br2d6iBvA3X9CE5k7T7hg5VieJ83Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730954376; c=relaxed/simple; bh=N7SzwRtWzFH13usDN44XQ0D2BiEGT90tYbNrWNmioLw=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:Mime-Version; b=T5r/G/Ryo3SBXYb+IAJx7MzYfphCPR78St/Ccnc7GA1vGWaXUyWlSwjfcE9zF3ArHJ0VZCkQgdWnIlBJ4lqrkWu28Ivy9yLG7zT79M5uhqDZ5gzWJb9mNsvnj2XBZnApjD0ZBOkZ/4BPntUG86K8759YaoY2PvtqSHAEgGIDSLE= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from localhost.localdomain (beren.burntcomma.com [IPv6:2a02:8012:8cf0:0:ce28:aaff:fe0d:6db2]) (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 3A1631F2A9F; Thu, 7 Nov 2024 04:39:26 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=harmstone.com; s=mail; t=1730954370; bh=CeK7JbABHqBz6VXOPE7gP6ImwzqKQcUuUq8BkUWg7wY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=aIzYCpI74gBGwh1UxjJkx6JZufmI9QlTJt3xMEPBQYt6H0U5uJ2ijqq9RfV0eIVj1 kYQea2ax8CegSQhQh2bOc+KLnmZ5PX3JPSl0Aof5oiW2es9FuLR+zA/V77QzlafQRQ 8JxJ+tSROo7gtvno/3z65REnY4vEQYrz8G88VEhM= From: Mark Harmstone To: gcc-patches@gcc.gnu.org Cc: Mark Harmstone Subject: [PATCH 3/4] Write S_INLINEELINES CodeView subsection Date: Thu, 7 Nov 2024 04:39:14 +0000 Message-ID: <20241107043915.2112-3-mark@harmstone.com> In-Reply-To: <20241107043915.2112-1-mark@harmstone.com> References: <20241107043915.2112-1-mark@harmstone.com> Mime-Version: 1.0 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 When outputting the .debug$S CodeView section, also write an S_INLINEELINES subsection, which records the filename and line number of the start of each inlined function. gcc/ * dwarf2codeview.cc (DEBUG_S_INLINEELINES): Define. (CV_INLINEE_SOURCE_LINE_SIGNATURE): Define. (struct codeview_inlinee_lines): Define. (struct inlinee_lines_hasher): Define. (func_htab, inlinee_lines_htab): New global variables. (get_file_id): New function. (codeview_source_line): Move file_id logic to get_file_id. (write_inlinee_lines_entry): New function. (write_inlinee_lines): New function. (codeview_debug_finish): Call write_inlinee_lines, and free func_htab and inlinee_lines_htab. (get_func_id): New function. (add_function): Move func_id logic to get_func_id. (codeview_abstract_function): New function. * dwarf2codeview.h (codeview_abstract_function): Add declaration. * dwarf2out.cc (dwarf2out_abstract_function): Call codeview_abstract_function if outputting CodeView debug info. --- gcc/dwarf2codeview.cc | 251 ++++++++++++++++++++++++++++++++++++------ gcc/dwarf2codeview.h | 1 + gcc/dwarf2out.cc | 5 + 3 files changed, 224 insertions(+), 33 deletions(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index df59fbcf288..4fcf3f5f1e2 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #define DEBUG_S_LINES 0xf2 #define DEBUG_S_STRINGTABLE 0xf3 #define DEBUG_S_FILECHKSMS 0xf4 +#define DEBUG_S_INLINEELINES 0xf6 #define CHKSUM_TYPE_MD5 1 @@ -53,6 +54,8 @@ along with GCC; see the file COPYING3. If not see #define CV_CFL_C 0x00 #define CV_CFL_CXX 0x01 +#define CV_INLINEE_SOURCE_LINE_SIGNATURE 0x0 + #define FIRST_TYPE 0x1000 #define LINE_LABEL "Lcvline" @@ -1140,6 +1143,14 @@ struct codeview_line_block codeview_line *lines, *last_line; }; +struct codeview_inlinee_lines +{ + codeview_inlinee_lines *next; + uint32_t func_id; + uint32_t file_id; + uint32_t starting_line; +}; + struct codeview_function { codeview_function *next; @@ -1411,6 +1422,21 @@ struct method_hasher : nofree_ptr_hash } }; +struct inlinee_lines_hasher : free_ptr_hash +{ + typedef uint32_t compare_type; + + static hashval_t hash (const codeview_inlinee_lines *il) + { + return il->func_id; + } + + static bool equal (const codeview_inlinee_lines *il, uint32_t func_id) + { + return il->func_id == func_id; + } +}; + static unsigned int line_label_num; static unsigned int func_label_num; static unsigned int sym_label_num; @@ -1423,10 +1449,11 @@ static codeview_function *funcs, *last_func, *cur_func; static const char* last_filename; static uint32_t last_file_id; static codeview_symbol *sym, *last_sym; -static hash_table *types_htab; +static hash_table *types_htab, *func_htab; static codeview_custom_type *custom_types, *last_custom_type; static codeview_deferred_type *deferred_types, *last_deferred_type; static hash_table *string_id_htab; +static hash_table *inlinee_lines_htab; static uint32_t get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref); static uint32_t get_type_num_subroutine_type (dw_die_ref type, bool in_struct, @@ -1435,6 +1462,39 @@ static uint32_t get_type_num_subroutine_type (dw_die_ref type, bool in_struct, int32_t this_adjustment); static void write_cv_padding (size_t padding); +/* Return the file ID corresponding to a given source filename. */ + +static uint32_t +get_file_id (const char *filename) +{ + codeview_source_file *sf = files; + + if (filename == last_filename) + return last_file_id; + + while (sf) + { + if (!strcmp (sf->filename, filename)) + { + uint32_t file_id; + + /* 0x18 is the size of the checksum entry for each file. + 0x6 bytes for the header, plus 0x10 bytes for the hash, + then padded to a multiple of 4. */ + + file_id = sf->file_num * 0x18; + last_filename = filename; + last_file_id = file_id; + + return file_id; + } + + sf = sf->next; + } + + return 0; +} + /* Allocate and initialize a codeview_function struct. */ static codeview_function * @@ -1465,7 +1525,7 @@ void codeview_source_line (unsigned int line_no, const char *filename) { codeview_line *l; - uint32_t file_id = last_file_id; + uint32_t file_id = get_file_id (filename); unsigned int label_num = ++line_label_num; targetm.asm_out.internal_label (asm_out_file, LINE_LABEL, label_num); @@ -1479,28 +1539,6 @@ codeview_source_line (unsigned int line_no, const char *filename) cur_func = f; } - if (filename != last_filename) - { - codeview_source_file *sf = files; - - while (sf) - { - if (!strcmp (sf->filename, filename)) - { - /* 0x18 is the size of the checksum entry for each file. - 0x6 bytes for the header, plus 0x10 bytes for the hash, - then padded to a multiple of 4. */ - - file_id = sf->file_num * 0x18; - last_filename = filename; - last_file_id = file_id; - break; - } - - sf = sf->next; - } - } - if (!cur_func->last_block || cur_func->last_block->file_id != file_id) { codeview_line_block *b; @@ -1899,6 +1937,66 @@ write_line_numbers (void) } } +/* Write an entry in the S_INLINEELINES subsection of .debug$S. */ + +static int +write_inlinee_lines_entry (codeview_inlinee_lines **slot, + void *ctx ATTRIBUTE_UNUSED) +{ + codeview_inlinee_lines *il = *slot; + + /* The inlinee lines data consists of a version uint32_t (0), followed by + an array of struct inlinee_source_line: + + struct inlinee_source_line + { + uint32_t function_id; + uint32_t file_id; + uint32_t line_no; + }; + + (see InlineeSourceLine in cvinfo.h) + */ + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, il->func_id); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, il->file_id); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, il->starting_line); + putc ('\n', asm_out_file); + + return 1; +} + +/* Write the S_INLINEELINES subsection of .debug$S, which lists the filename + and line number for the start of each inlined function. */ + +static void +write_inlinee_lines (void) +{ + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, DEBUG_S_INLINEELINES); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + asm_fprintf (asm_out_file, + "%LLcv_inlineelines_end - %LLcv_inlineelines_start\n"); + asm_fprintf (asm_out_file, "%LLcv_inlineelines_start:\n"); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, CV_INLINEE_SOURCE_LINE_SIGNATURE); + putc ('\n', asm_out_file); + + inlinee_lines_htab->traverse (NULL); + + asm_fprintf (asm_out_file, "%LLcv_inlineelines_end:\n"); +} + /* Treat cold sections as separate functions, for the purposes of line numbers. */ @@ -4714,6 +4812,10 @@ codeview_debug_finish (void) write_strings_table (); write_source_files (); write_line_numbers (); + + if (inlinee_lines_htab) + write_inlinee_lines (); + write_codeview_symbols (); if (custom_types) @@ -4746,8 +4848,14 @@ codeview_debug_finish (void) if (types_htab) delete types_htab; + if (func_htab) + delete func_htab; + if (string_id_htab) delete string_id_htab; + + if (inlinee_lines_htab) + delete inlinee_lines_htab; } /* Translate a DWARF base type (DW_TAG_base_type) into its CodeView @@ -6573,20 +6681,29 @@ add_lf_mfunc_id (dw_die_ref die, const char *name) return ct->num; } -/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID - symbol for this. */ +/* Generate a new LF_FUNC_ID or LF_MFUNC_ID type for a DW_TAG_subprogram DIE + and return its number, or return the existing type number if already + present. */ -static void -add_function (dw_die_ref die) +static uint32_t +get_func_id (dw_die_ref die) { const char *name = get_AT_string (die, DW_AT_name); - uint32_t func_id_type; - codeview_symbol *s; dw_die_ref spec = get_AT_ref (die, DW_AT_specification); bool do_mfunc_id = false; + codeview_type **slot, *t; + uint32_t num; if (!name) - return; + return 0; + + if (!func_htab) + func_htab = new hash_table (10); + + slot = func_htab->find_slot_with_hash (die, htab_hash_pointer (die), INSERT); + + if (slot && *slot) + return (*slot)->num; if (spec && dw_get_die_parent (spec)) { @@ -6604,9 +6721,33 @@ add_function (dw_die_ref die) } if (do_mfunc_id) - func_id_type = add_lf_mfunc_id (die, name); + num = add_lf_mfunc_id (die, name); else - func_id_type = add_lf_func_id (die, name); + num = add_lf_func_id (die, name); + + t = (codeview_type *) xmalloc (sizeof (codeview_type)); + + t->die = die; + t->num = num; + t->is_fwd_ref = false; + + *slot = t; + + return num; +} + +/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID + symbol for this. */ + +static void +add_function (dw_die_ref die) +{ + uint32_t func_id_type; + codeview_symbol *s; + + func_id_type = get_func_id (die); + if (func_id_type == 0) + return; /* Add an S_GPROC32_ID / S_LPROC32_ID symbol. */ @@ -6630,6 +6771,50 @@ add_function (dw_die_ref die) last_sym = s; } +/* If we have encountered a new inlined function, add this to + inlinee_lines_htab so that it can be output to the S_INLINEELINES subsection + of .debug$S. */ + +void +codeview_abstract_function (tree decl) +{ + codeview_inlinee_lines *il, **slot; + dw_die_ref die; + uint32_t func_id; + struct dwarf_file_data *file; + + if (!DECL_DECLARED_INLINE_P (decl)) + return; + + die = lookup_decl_die (decl); + if (!die) + return; + + func_id = get_func_id (die); + if (func_id == 0) + return; + + file = get_AT_file (die, DW_AT_decl_file); + if (!file) + return; + + if (!inlinee_lines_htab) + inlinee_lines_htab = new hash_table (10); + + slot = inlinee_lines_htab->find_slot_with_hash (func_id, func_id, INSERT); + if (*slot) + return; + + il = (codeview_inlinee_lines *) xmalloc (sizeof (codeview_inlinee_lines)); + + il->next = NULL; + il->func_id = func_id; + il->file_id = get_file_id (file->filename); + il->starting_line = get_AT_unsigned (die, DW_AT_decl_line); + + *slot = il; +} + /* Loop through the DIEs that have been output for our TU, and add CodeView symbols for them. */ diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h index 367334d68cb..3829bab093d 100644 --- a/gcc/dwarf2codeview.h +++ b/gcc/dwarf2codeview.h @@ -97,5 +97,6 @@ extern void codeview_end_epilogue (void); extern void codeview_debug_early_finish (dw_die_ref die); extern void codeview_begin_block (unsigned int, unsigned int, tree); extern void codeview_end_block (unsigned int, unsigned int); +extern void codeview_abstract_function (tree); #endif /* GCC_DWARF2CODEVIEW_H */ diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 2efcb52723a..d6774a843f0 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -23409,6 +23409,11 @@ dwarf2out_abstract_function (tree decl) if (DECL_IGNORED_P (decl)) return; +#ifdef CODEVIEW_DEBUGGING_INFO + if (codeview_debuginfo_p ()) + codeview_abstract_function (decl); +#endif + /* In LTO we're all set. We already created abstract instances early and we want to avoid creating a concrete instance of that if we don't output it. */