From patchwork Tue Aug 13 00:24:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 1971716 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org 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 4WjXGL0Gb1z1yfP for ; Tue, 13 Aug 2024 10:25:12 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 13D013858C56 for ; Tue, 13 Aug 2024 00:25:10 +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 D9B273858D20 for ; Tue, 13 Aug 2024 00:24:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D9B273858D20 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 D9B273858D20 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=1723508679; cv=none; b=skF1WtdK5z9unKt8leGw0IhEFhjPMKfmjJ48kywuemfV2I5R20E6xoFkeCHJ34q1Yb5AQXhtyBI4PsV5VqTsv8CjdRxR857hpYy2zxE68JQTRIeJJgDlqtvWXXCSIpcROZdMBPBBcQ3hXyNs1t4lvANNElKBDFoj5HcnWQSXRw0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1723508679; c=relaxed/simple; bh=6773zH5pju70UCyIYPvlC0dLW3+T6uV5rZnEvmexgww=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:Mime-Version; b=fQHhYKVpJVl20+g1jlcPBiZvjh0K0FQXjiUF0feMX7bkrFKz0m/f0LqvQMquh1jYHN0ZgjTPem3HjttNbpCl/vzlDvoMbOlK0ePAJqEJtbebuvRyOUV4BepBTchHcZo0AdGx71bOBha3RwZCIiFjzaJ5aWKLVZ2e0uagzZHGd0M= 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 8FC0A418820C; Tue, 13 Aug 2024 01:24:32 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=harmstone.com; s=mail; t=1723508672; bh=DULsQKJzsbjWwKNKgg3qz4hZKsKxAPIjOgX6F+395W4=; h=From:To:Cc:Subject:Date; b=iAvewyWEIdXFEkum+WmGNCSZRqFkcG3Wr8omc3KTRXaKIxJr1inXMLIy6MG/9lQU1 Tb1jGGOH/Dsdr7NNIgz/eJ5FIdt2RY1A6eaXZ5XMGBrniA65ljE13ITHJhl0nbp1rB /NKVecLnqln/0OUztcUmmXg9KnPcZOAQRYZpH75w= From: Mark Harmstone To: gcc-patches@gcc.gnu.org Cc: Mark Harmstone Subject: [PATCH 1/3] Write CodeView information about local static variables Date: Tue, 13 Aug 2024 01:24:24 +0100 Message-ID: <20240813002426.5453-1-mark@harmstone.com> Mime-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, 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 Outputs CodeView S_LDATA32 symbols, for static variables within functions, along with S_BLOCK32 and S_END for the beginning and end of lexical blocks. gcc/ * dwarf2codeview.cc (enum cv_sym_type): Add S_END and S_BLOCK32. (write_local_s_ldata32): New function. (write_unoptimized_local_variable): New function. (write_s_block32): New function. (write_s_end): New function. (write_unoptimized_function_vars): New function. (write_function): Call write_unoptimized_function_vars. --- gcc/dwarf2codeview.cc | 258 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 7e4faaa9388..cb2d64bfcc6 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -70,6 +70,8 @@ along with GCC; see the file COPYING3. If not see /* This is enum SYM_ENUM_e in Microsoft's cvinfo.h. */ enum cv_sym_type { + S_END = 0x0006, + S_BLOCK32 = 0x1103, S_LDATA32 = 0x110c, S_GDATA32 = 0x110d, S_COMPILE3 = 0x113c, @@ -986,6 +988,260 @@ end: free (s->data_symbol.name); } +/* Write an S_LDATA32 symbol, representing a static variable within a function. + This symbol can also appear outside of a function block - see + write_data_symbol. */ + +static void +write_local_s_ldata32 (dw_die_ref die, dw_loc_descr_ref loc_ref) +{ + unsigned int label_num = ++sym_label_num; + const char *name = get_AT_string (die, DW_AT_name); + uint32_t type; + + /* This is struct datasym in binutils: + + struct datasym + { + uint16_t size; + uint16_t kind; + uint32_t type; + uint32_t offset; + uint16_t section; + char name[]; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_LDATA32); + putc ('\n', asm_out_file); + + type = get_type_num (get_AT_ref (die, DW_AT_type), false, false); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, type); + putc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secrel32 "); + output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr); + fputc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secidx "); + output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name) + 1); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); +} + +/* Write a symbol representing an unoptimized variable within a function, if + we're able to translate the DIE's DW_AT_location into its CodeView + equivalent. */ + +static void +write_unoptimized_local_variable (dw_die_ref die) +{ + dw_attr_node *loc; + dw_loc_descr_ref loc_ref; + + loc = get_AT (die, DW_AT_location); + if (!loc) + return; + + if (loc->dw_attr_val.val_class != dw_val_class_loc) + return; + + loc_ref = loc->dw_attr_val.v.val_loc; + if (!loc_ref) + return; + + switch (loc_ref->dw_loc_opc) + { + case DW_OP_addr: + write_local_s_ldata32 (die, loc_ref); + break; + + default: + break; + } +} + +/* Translate a DW_TAG_lexical_block DIE into an S_BLOCK32 symbol, representing + a block within an unoptimized function. Returns false if we're not able + to resolve the location, which will prevent the caller from issuing an + unneeded S_END. */ + +static bool +write_s_block32 (dw_die_ref die) +{ + unsigned int label_num = ++sym_label_num; + dw_attr_node *loc_low, *loc_high; + const char *label_low, *label_high; + rtx rtx_low, rtx_high; + + /* This is struct blocksym in binutils and BLOCKSYM32 in Microsoft's + cvinfo.h: + + struct blocksym + { + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t len; + uint32_t offset; + uint16_t section; + char name[]; + } ATTRIBUTE_PACKED; + */ + + loc_low = get_AT (die, DW_AT_low_pc); + if (!loc_low) + return false; + + if (loc_low->dw_attr_val.val_class != dw_val_class_lbl_id) + return false; + + label_low = loc_low->dw_attr_val.v.val_lbl_id; + if (!label_low) + return false; + + rtx_low = gen_rtx_SYMBOL_REF (Pmode, label_low); + + loc_high = get_AT (die, DW_AT_high_pc); + if (!loc_high) + return false; + + if (loc_high->dw_attr_val.val_class != dw_val_class_high_pc) + return false; + + label_high = loc_high->dw_attr_val.v.val_lbl_id; + if (!label_high) + return false; + + rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high); + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_BLOCK32); + putc ('\n', asm_out_file); + + /* The parent and end fields get filled in by the linker. */ + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, 0); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, 0); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + output_addr_const (asm_out_file, rtx_high); + fputs (" - ", asm_out_file); + output_addr_const (asm_out_file, rtx_low); + putc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secrel32 "); + output_addr_const (asm_out_file, rtx_low); + fputc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secidx "); + output_addr_const (asm_out_file, rtx_low); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_ASCII (asm_out_file, "", 1); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); + + return true; +} + +/* Write an S_END symbol, which is used to finish off a number of different + symbol types. Here we use it to mark the S_BLOCK32 as finished. */ + +static void +write_s_end (void) +{ + unsigned int label_num = ++sym_label_num; + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_END); + putc ('\n', asm_out_file); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); +} + +/* Loop through the DIEs in an unoptimized function, writing out any variables + or blocks that we encounter. */ + +static void +write_unoptimized_function_vars (dw_die_ref die) +{ + dw_die_ref first_child, c; + + first_child = dw_get_die_child (die); + + if (!first_child) + return; + + c = first_child; + do + { + c = dw_get_die_sib (c); + + switch (dw_get_die_tag (c)) + { + case DW_TAG_variable: + write_unoptimized_local_variable (c); + break; + + case DW_TAG_lexical_block: + { + bool block_started = write_s_block32 (c); + + write_unoptimized_function_vars (c); + + if (block_started) + write_s_end (); + + break; + } + + default: + break; + } + } + while (c != first_child); +} + /* Write an S_GPROC32_ID symbol, representing a global function, or an S_LPROC32_ID symbol, for a static function. */ @@ -1111,6 +1367,8 @@ write_function (codeview_symbol *s) targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); + write_unoptimized_function_vars (s->function.die); + /* Output the S_PROC_ID_END record. */ label_num = ++sym_label_num;