From patchwork Mon Oct 23 00:55:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 1853449 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; unprotected) header.d=harmstone.com header.i=@harmstone.com header.a=rsa-sha256 header.s=mail header.b=z1dDKijI; 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 4SDGx75RKgz23jn for ; Mon, 23 Oct 2023 11:56:59 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CEBA83858024 for ; Mon, 23 Oct 2023 00:56:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail.burntcomma.com (mail.burntcomma.com [IPv6:2a02:8012:8cf0:250::6d61:696c]) by sourceware.org (Postfix) with ESMTPS id 44DAD3858C41 for ; Mon, 23 Oct 2023 00:55:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 44DAD3858C41 Authentication-Results: sourceware.org; dmarc=none (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 44DAD3858C41 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a02:8012:8cf0:250::6d61:696c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698022547; cv=none; b=Aoyxo0zoO0OEFCKzVjTEE01hURFPDWz/NMoQHCwLPy/Kb4D+LKng0Kc4kcO+oJALzvaF3j77D7U68/9Kt4/aFbOjDq+WdLW1oSefF41e/DJv9gTZqIyjv/9zW4OHWJZsRFs4Jm1aOKtJPnpgvsz4eV3T7A7BWWhQE1UAhH2NMB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698022547; c=relaxed/simple; bh=hY65c1jDyHmlDqU5OLZL3n8VgY5ckJX5YibFd8CToFo=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:Mime-Version; b=Dkowk16uPiueSj8cmoAfr1Nwuvvb2xUVCjlxtBfpn+UPJdyNF7GAAc+evw7kSnVkd798vMP2SGUoft7wbagqCdEj2YXfQkizW38bWJ55wZy2w1aTTdrNyY9IoV7Nbffw4cH8lk6nFDCia58Xo3+8FGPgx3U1HhoeRel1qwSNdWU= 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 D4F9916B320A6; Mon, 23 Oct 2023 01:55:43 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=harmstone.com; s=mail; t=1698022543; bh=4ME1+U6zxKWw4qftUFo6UCPZbj/CcEcXb9XHDCKNOUY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=z1dDKijIH8/lEGYYVgTDYw5AX1qx7nyXKQbjnmHD6w/EFriW9B62R0wm9sSfD/Lxr jJGojhHuYhrv2xayPdIet3kzPklfjr3IVV8lIkOHpwhd8JRFWibzd/wgaxGXJn7h22 DAYIyugzTwDZo2PjBR+Z8WMnAtmoeVyS3dVAdly8= From: Mark Harmstone To: gcc-patches@gcc.gnu.org Cc: Mark Harmstone Subject: [PATCH 4/5] Output line numbers in CodeView section Date: Mon, 23 Oct 2023 01:55:30 +0100 Message-ID: <20231023005531.19921-4-mark@harmstone.com> In-Reply-To: <20231023005531.19921-1-mark@harmstone.com> References: <20231023005531.19921-1-mark@harmstone.com> Mime-Version: 1.0 X-Spam-Status: No, score=-13.8 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 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 Outputs the DEBUG_S_LINES block in the CodeView .debug$S section, which maps between line numbers and addresses. You'll need a fairly recent version of GAS for the .secidx directive to be recognized. --- gcc/dwarf2codeview.cc | 303 ++++++++++++++++++++++++++++++++++++++++++ gcc/dwarf2codeview.h | 3 + gcc/dwarf2out.cc | 9 ++ gcc/opts.cc | 2 +- 4 files changed, 316 insertions(+), 1 deletion(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index d93ba1ed668..4dfc0300177 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -37,11 +37,15 @@ along with GCC; see the file COPYING3. If not see #define CV_SIGNATURE_C13 4 +#define DEBUG_S_LINES 0xf2 #define DEBUG_S_STRINGTABLE 0xf3 #define DEBUG_S_FILECHKSMS 0xf4 #define CHKSUM_TYPE_MD5 1 +#define LINE_LABEL "Lcvline" +#define END_FUNC_LABEL "Lcvendfunc" + #define HASH_SIZE 16 struct codeview_string @@ -89,11 +93,128 @@ struct codeview_source_file uint8_t hash[HASH_SIZE]; }; +struct codeview_line +{ + codeview_line *next; + unsigned int line_no; + unsigned int label_num; +}; + +struct codeview_line_block +{ + codeview_line_block *next; + uint32_t file_id; + unsigned int num_lines; + codeview_line *lines, *last_line; +}; + +struct codeview_function +{ + codeview_function *next; + function *func; + unsigned int end_label; + codeview_line_block *blocks, *last_block; +}; + +static unsigned int line_label_num; +static unsigned int func_label_num; static codeview_source_file *files, *last_file; static unsigned int num_files; static uint32_t string_offset = 1; static hash_table *strings_htab; static codeview_string *strings, *last_string; +static codeview_function *funcs, *last_func; +static const char* last_filename; +static uint32_t last_file_id; + +/* Record new line number against the current function. */ + +void +codeview_source_line (unsigned int line_no, const char *filename) +{ + codeview_line *l; + uint32_t file_id = last_file_id; + unsigned int label_num = ++line_label_num; + + targetm.asm_out.internal_label (asm_out_file, LINE_LABEL, label_num); + + if (!last_func || last_func->func != cfun) + { + codeview_function *f = (codeview_function *) + xmalloc (sizeof (codeview_function)); + + f->next = NULL; + f->func = cfun; + f->end_label = 0; + f->blocks = f->last_block = NULL; + + if (!funcs) + funcs = f; + else + last_func->next = f; + + last_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 (!last_func->last_block || last_func->last_block->file_id != file_id) + { + codeview_line_block *b; + + b = (codeview_line_block *) xmalloc (sizeof (codeview_line_block)); + + b->next = NULL; + b->file_id = file_id; + b->num_lines = 0; + b->lines = b->last_line = NULL; + + if (!last_func->blocks) + last_func->blocks = b; + else + last_func->last_block->next = b; + + last_func->last_block = b; + } + + if (last_func->last_block->last_line + && last_func->last_block->last_line->line_no == line_no) + return; + + l = (codeview_line *) xmalloc (sizeof (codeview_line)); + + l->next = NULL; + l->line_no = line_no; + l->label_num = label_num; + + if (!last_func->last_block->lines) + last_func->last_block->lines = l; + else + last_func->last_block->last_line->next = l; + + last_func->last_block->last_line = l; + last_func->last_block->num_lines++; +} /* Adds string to the string table, returning its offset. If already present, this returns the offset of the existing string. */ @@ -288,6 +409,187 @@ write_source_files (void) asm_fprintf (asm_out_file, "%LLcv_filechksms_end:\n"); } +/* Write out the line number information for each function into the + .debug$S section. */ + +static void +write_line_numbers (void) +{ + unsigned int func_num = 0; + + while (funcs) + { + codeview_function *next = funcs->next; + unsigned int first_label_num; + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, DEBUG_S_LINES); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + asm_fprintf (asm_out_file, "%LLcv_lines%u_end - %LLcv_lines%u_start\n", + func_num, func_num); + + asm_fprintf (asm_out_file, "%LLcv_lines%u_start:\n", func_num); + + /* Output the header (struct cv_lines_header in binutils or + CV_DebugSLinesHeader_t in Microsoft's cvinfo.h): + + struct cv_lines_header + { + uint32_t offset; + uint16_t section; + uint16_t flags; + uint32_t length; + }; + */ + + asm_fprintf (asm_out_file, "\t.secrel32\t%L" LINE_LABEL "%u\n", + funcs->blocks->lines->label_num); + asm_fprintf (asm_out_file, "\t.secidx\t%L" LINE_LABEL "%u\n", + funcs->blocks->lines->label_num); + + /* flags */ + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, 0); + putc ('\n', asm_out_file); + + first_label_num = funcs->blocks->lines->label_num; + + /* length */ + fputs (integer_asm_op (4, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" END_FUNC_LABEL "%u - %L" LINE_LABEL "%u\n", + funcs->end_label, first_label_num); + + while (funcs->blocks) + { + codeview_line_block *next = funcs->blocks->next; + + /* Next comes the blocks, each block being a part of a function + within the same source file (struct cv_lines_block in binutils or + CV_DebugSLinesFileBlockHeader_t in Microsoft's cvinfo.h): + + struct cv_lines_block + { + uint32_t file_id; + uint32_t num_lines; + uint32_t length; + }; + */ + + /* file ID */ + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, funcs->blocks->file_id); + putc ('\n', asm_out_file); + + /* number of lines */ + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, funcs->blocks->num_lines); + putc ('\n', asm_out_file); + + /* length of code block: (num_lines * sizeof (struct cv_line)) + + sizeof (struct cv_lines_block) */ + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, (funcs->blocks->num_lines * 0x8) + 0xc); + putc ('\n', asm_out_file); + + while (funcs->blocks->lines) + { + codeview_line *next = funcs->blocks->lines->next; + + /* Finally comes the line number information (struct cv_line in + binutils or CV_Line_t in Microsoft's cvinfo.h): + + struct cv_line + { + uint32_t offset; + uint32_t line_no; + }; + + Strictly speaking line_no is a bitfield: the bottom 24 bits + are the line number, and the top bit means "is a statement". + */ + + fputs (integer_asm_op (4, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" LINE_LABEL "%u - %L" LINE_LABEL "%u\n", + funcs->blocks->lines->label_num, first_label_num); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, + 0x80000000 + | (funcs->blocks->lines->line_no & 0xffffff)); + putc ('\n', asm_out_file); + + free (funcs->blocks->lines); + + funcs->blocks->lines = next; + } + + free (funcs->blocks); + + funcs->blocks = next; + } + + free (funcs); + + asm_fprintf (asm_out_file, "%LLcv_lines%u_end:\n", func_num); + func_num++; + + funcs = next; + } +} + +/* Treat cold sections as separate functions, for the purposes of line + numbers. */ + +void +codeview_switch_text_section (void) +{ + codeview_function *f; + + if (last_func && last_func->end_label == 0) + { + unsigned int label_num = ++func_label_num; + + targetm.asm_out.internal_label (asm_out_file, END_FUNC_LABEL, + label_num); + + last_func->end_label = label_num; + } + + f = (codeview_function *) xmalloc (sizeof (codeview_function)); + + f->next = NULL; + f->func = cfun; + f->end_label = 0; + f->blocks = f->last_block = NULL; + + if (!funcs) + funcs = f; + else + last_func->next = f; + + last_func = f; +} + +/* Mark the end of the current function. */ + +void +codeview_end_epilogue (void) +{ + if (last_func && last_func->end_label == 0) + { + unsigned int label_num = ++func_label_num; + + targetm.asm_out.internal_label (asm_out_file, END_FUNC_LABEL, + label_num); + + last_func->end_label = label_num; + } +} + /* Finish CodeView debug info emission. */ void @@ -301,4 +603,5 @@ codeview_debug_finish (void) write_strings_table (); write_source_files (); + write_line_numbers (); } diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h index e2d732bb9b6..b6421b62d2e 100644 --- a/gcc/dwarf2codeview.h +++ b/gcc/dwarf2codeview.h @@ -26,6 +26,9 @@ along with GCC; see the file COPYING3. If not see /* Debug Format Interface. Used in dwarf2out.cc. */ extern void codeview_debug_finish (void); +extern void codeview_source_line (unsigned int, const char *); extern void codeview_start_source_file (const char *); +extern void codeview_switch_text_section (); +extern void codeview_end_epilogue (void); #endif /* GCC_DWARF2CODEVIEW_H */ diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 945176a91bc..c0ee99ffd40 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1253,6 +1253,9 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); + if (codeview_debuginfo_p ()) + codeview_end_epilogue (); + /* Output a label to mark the endpoint of the code generated for this function. */ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, @@ -1306,6 +1309,9 @@ dwarf2out_switch_text_section (void) } have_multiple_function_sections = true; + if (codeview_debuginfo_p ()) + codeview_switch_text_section (); + if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); @@ -28603,6 +28609,9 @@ dwarf2out_source_line (unsigned int line, unsigned int column, dw_line_info_table *table; static var_loc_view lvugid; + if (codeview_debuginfo_p ()) + codeview_source_line (line, filename); + /* 'line_info_table' information gathering is not needed when the debug info level is set to the lowest value. Also, the current DWARF-based debug formats do not use this info. */ diff --git a/gcc/opts.cc b/gcc/opts.cc index f02101ceea3..6e91b1e0ff9 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1364,7 +1364,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, opts->x_debug_nonbind_markers_p = (opts->x_optimize && opts->x_debug_info_level >= DINFO_LEVEL_NORMAL - && dwarf_debuginfo_p (opts) + && (dwarf_debuginfo_p (opts) || codeview_debuginfo_p ()) && !(opts->x_flag_selective_scheduling || opts->x_flag_selective_scheduling2));