From patchwork Tue Oct 31 00:28:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 159898 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:d641:0:b0:403:3b70:6f57 with SMTP id cy1csp2593701vqb; Mon, 30 Oct 2023 17:29:40 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFVTXr4fR2WTMz99Dx3S+Owo8aRXH7gkUMgkW86skAY1sNxkTx4K7wrW8CtfKC4+vYT2pbm X-Received: by 2002:a05:6214:762:b0:671:a3db:c11d with SMTP id f2-20020a056214076200b00671a3dbc11dmr6380675qvz.24.1698712180167; Mon, 30 Oct 2023 17:29:40 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1698712180; cv=pass; d=google.com; s=arc-20160816; b=jaVCFz3FnppPXSLC5Fvcj+wpT/XRsiCRV7q2Z/07iHdcDZsBigdgvVWy5vS8A8dfzp 2gwwgTswhg5/Vwi4BXzJFX+IDEw/cy590/ztwtCfjfdSUkqIhvVuQ15DFndBxoUrhhwv B1MgNK3MagKja8do17UUZgF+hcYZxnDakxqolrsFfdj8BFK6lQL0r+TfVZl7h5zxeosH BJFdJ3fVCcjSvHjkkfYPbqlws6kiUoXFQbDQCbj1nBP15VqP0fr7S9ZyZYwT53QnMMUX UW53wxU4R6lUkN3JTQwsBJ02y2jpbLUvhhNCPPYOSkTX1crxCH39zHGUVRjnlNNwLYxb 5CxQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:arc-filter:dmarc-filter:delivered-to; bh=SnusWKsfwv3ylp+njBq/iGZrG8rvX0fH8T4Oxzs5oqM=; fh=ULVDVi0LXJXve4bv6avxt5t1j9fbG672tLMzvs8AGaA=; b=ApqI/6DlkiyByQ3AyAnu1gyHlur3IU2V1iV9Y9STyIt+Z1cFWQbpmYdu6Cz3fxK676 D+D1E/KAAntOYK6pxL3jzeR6fL4/GBwGQYZT5UsYDG7uCn9uZLBihxI6WBDJHySwaTDp 4mIXsUfM2ZToGJSBubuIq5O6m8wJ1nFsflgaKe19gGGdz0Z41gHxndoAl3YiKRLAo300 t0cHa9/eI1kdwSBx++yAv9nnbTBGNQf/3QaVDeJTX2dIEHYx28UA2748ijqRXRVEDg0s 0E2FyduuPaQkw6hMnMCuOaReMo41LBUGq8NegKWdgmEz+0oGLw9tSFWMqAwCFWrsd7ub 60dw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@harmstone.com header.s=mail header.b=pU5aYOvS; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id t15-20020a0cea2f000000b0065b240236c1si135548qvp.403.2023.10.30.17.29.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Oct 2023 17:29:40 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@harmstone.com header.s=mail header.b=pU5aYOvS; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B07AB385840E for ; Tue, 31 Oct 2023 00:29:36 +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 D76D43858D20 for ; Tue, 31 Oct 2023 00:29:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D76D43858D20 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 D76D43858D20 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=1698712150; cv=none; b=uOXCS0Wd6nLWRrvWtQayMg0ElAYWl0qhCDN0O5gawTSaPxbl4Nnbnwqr530O18s9Me69u6i6knyWQBKE+wBz1xss6OD2HP3NuisBfiw0dO+EZIMSUuxQ+Bm9JlNXXW3WoYanNItflX+MuiNsWnlws5k3HKmOjKss44tCnKrsUzE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698712150; c=relaxed/simple; bh=iSyDhV2tJjpZp14pHIFTdp4TgwE4GTisJhJNf03VL/8=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:Mime-Version; b=xEjstTEDIFK5n7v5LPCGn8n+A/h0xyX2DTpa4l2VnA/sTToJO+C0ZIayJmzV+5LxPmSctVHoJ4vQ9d5LcgKu6TvIWNfa6kRmTttzpLX40kTO4wtL5vMlxzJtuMoaStDLqNf/Er55vRi3Rr4PaT5CY/iGVSvPimTj6soAtQKxl/E= 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 8475116B3C0D3; Tue, 31 Oct 2023 00:29:06 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=harmstone.com; s=mail; t=1698712146; bh=SnusWKsfwv3ylp+njBq/iGZrG8rvX0fH8T4Oxzs5oqM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=pU5aYOvSFV588y38vfKjJ5tE8Aqo25FKkXvApDQUxmz6z8+/L/3OI1mZ5RglyCN53 b5Rv6zFfyeFpEcSUTbewZ6DTgM6BAWwBuJ7QI1KG6wVzKrSGnEqp7LDQ08rIzMnTXS oIElY/bWQQCtANF5WtIKSPh92PlVrNn2e4+HZ+6Y= From: Mark Harmstone To: gcc-patches@gcc.gnu.org Cc: Mark Harmstone Subject: [PATCH v2 3/4] Output line numbers in CodeView section Date: Tue, 31 Oct 2023 00:28:18 +0000 Message-ID: <20231031002859.18892-4-mark@harmstone.com> In-Reply-To: <20231031002859.18892-1-mark@harmstone.com> References: <20231031002859.18892-1-mark@harmstone.com> Mime-Version: 1.0 X-Spam-Status: No, score=-12.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+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1781228822588003083 X-GMAIL-MSGID: 1781228822588003083 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 | 15 +++ gcc/opts.cc | 2 +- 4 files changed, 322 insertions(+), 1 deletion(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index da8315310b5..9c69ebf8998 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -39,11 +39,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 @@ -91,11 +95,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. */ @@ -290,6 +411,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 @@ -303,6 +605,7 @@ codeview_debug_finish (void) write_strings_table (); write_source_files (); + write_line_numbers (); } #endif 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 dfff6e88804..04ccb702180 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -1253,6 +1253,11 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); +#ifdef CODEVIEW_DEBUGGING_INFO + if (codeview_debuginfo_p ()) + codeview_end_epilogue (); +#endif + /* Output a label to mark the endpoint of the code generated for this function. */ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, @@ -1306,6 +1311,11 @@ dwarf2out_switch_text_section (void) } have_multiple_function_sections = true; +#ifdef CODEVIEW_DEBUGGING_INFO + if (codeview_debuginfo_p ()) + codeview_switch_text_section (); +#endif + if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); @@ -28605,6 +28615,11 @@ dwarf2out_source_line (unsigned int line, unsigned int column, dw_line_info_table *table; static var_loc_view lvugid; +#ifdef CODEVIEW_DEBUGGING_INFO + if (codeview_debuginfo_p ()) + codeview_source_line (line, filename); +#endif + /* '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));